Index: channels/chan_skinny.c =================================================================== --- channels/chan_skinny.c (revision 157503) +++ channels/chan_skinny.c (working copy) @@ -957,6 +957,7 @@ *****************************/ static int skinnydebug = 0; +static int skinnyreload = 0; /* a hostname, portnumber, socket and such is usefull for VoIP protocols */ static struct sockaddr_in bindaddr; @@ -1237,7 +1238,8 @@ int transfer; \ int callwaiting; \ int mwiblink; \ - int dnd; + int dnd; \ + int prune; struct skinny_device { SKINNY_DEVICE_OPTIONS @@ -1304,6 +1306,7 @@ static int skinny_senddigit_begin(struct ast_channel *ast, char digit); static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration); static int handle_time_date_req_message(struct skinny_req *req, struct skinnysession *s); +static int skinny_reload(void); static const struct ast_channel_tech skinny_tech = { .type = "Skinny", @@ -2569,6 +2572,27 @@ } } +static char *handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) +{ + switch (cmd) { + case CLI_INIT: + e->command = "skinny reload"; + e->usage = + "Usage: skinny reload\n" + " Reloads the chan_skinny configuration\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != e->args) + return CLI_SHOWUSAGE; + + skinny_reload(); + return CLI_SUCCESS; + +} + static char *complete_skinny_devices(const char *word, int state) { struct skinny_device *d; @@ -3046,6 +3070,7 @@ AST_CLI_DEFINE(handle_skinny_show_settings, "List global Skinny settings"), AST_CLI_DEFINE(handle_skinny_set_debug, "Enable/Disable Skinny debugging"), AST_CLI_DEFINE(handle_skinny_reset, "Reset Skinny device(s)"), + AST_CLI_DEFINE(handle_skinny_reload, "Reload Skinny config"), }; static void start_rtp(struct skinny_subchannel *sub) @@ -6297,7 +6322,7 @@ int lineinuse = 0; AST_LIST_TRAVERSE(&devices, d, list) { AST_LIST_TRAVERSE(&d->lines, l2, list) { - if (l2 == l) { + if (l2 == l && strcasecmp(d->id, CDEV->id)) { ast_log(LOG_WARNING, "Line %s already used by %s. Not connecting to %s.\n", l->name, d->name, CDEV->name); lineinuse++; } @@ -6371,31 +6396,19 @@ static struct skinny_line *config_line(const char *lname, struct ast_variable *v) { - struct skinny_line *l; + struct skinny_line *l, *temp; + int update = 0; ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname); - AST_LIST_LOCK(&lines); - AST_LIST_TRAVERSE(&lines, l, all) { - if (!strcasecmp(lname, l->name)) { - ast_log(LOG_NOTICE, "Line %s already exists. Reconfiguring.\n", lname); - break; - } + if (!(l=ast_calloc(1, sizeof(*l)))) { + ast_verb(1, "Unable to allocate memory for line %s.\n", lname); + return NULL; } - if (!l) { - ast_log(LOG_NOTICE, "Creating line %s.\n", lname); - if (!(l=ast_calloc(1, sizeof(*l)))) { - ast_verb(1, "Unable to allocate memory for line %s.\n", lname); - AST_LIST_UNLOCK(&lines); - return NULL; - } - memcpy(l, default_line, sizeof(*default_line)); - ast_mutex_init(&l->lock); - ast_copy_string(l->name, lname, sizeof(l->name)); - AST_LIST_INSERT_TAIL(&lines, l, all); - } + memcpy(l, default_line, sizeof(*default_line)); + ast_mutex_init(&l->lock); + ast_copy_string(l->name, lname, sizeof(l->name)); ast_mutex_lock(&l->lock); - AST_LIST_UNLOCK(&lines); config_parse_variables(TYPE_LINE, l, v); @@ -6413,38 +6426,49 @@ AST_EVENT_IE_END); } + AST_LIST_LOCK(&lines); + if (skinnyreload){ + AST_LIST_TRAVERSE(&lines, temp, list) { + if (!strcasecmp(l->name, temp->name)) { + AST_LIST_REMOVE(&lines, temp, list); + update = 1; + } + } + } + + AST_LIST_INSERT_TAIL(&lines, l, all); + + if (update) { + ast_verb(3, "Updated line '%s'\n", l->name); + } else { + ast_verb(3, "Added line '%s'\n", l->name); + } + ast_mutex_unlock(&l->lock); return l; } static struct skinny_device *config_device(const char *dname, struct ast_variable *v) { - struct skinny_device *d; + struct skinny_device *d, *temp; + int update = 0; ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname); - AST_LIST_LOCK(&devices); - AST_LIST_TRAVERSE(&devices, d, list) { - if (!strcasecmp(dname, d->name)) { - break; - } + if (!(d = ast_calloc(1, sizeof(*d)))) { + ast_verb(1, "Unable to allocate memory for device %s.\n", dname); + return NULL; } - if (!d) { - if (!(d = ast_calloc(1, sizeof(*d)))) { - ast_verb(1, "Unable to allocate memory for device %s.\n", dname); - AST_LIST_UNLOCK(&devices); - return NULL; - } - memcpy(d, default_device, sizeof(*default_device)); - ast_mutex_init(&d->lock); - ast_copy_string(d->name, dname, sizeof(d->name)); - AST_LIST_INSERT_HEAD(&devices, d, list); - } + memcpy(d, default_device, sizeof(*default_device)); + ast_mutex_init(&d->lock); + ast_copy_string(d->name, dname, sizeof(d->name)); + ast_mutex_lock(&d->lock); - AST_LIST_UNLOCK(&devices); config_parse_variables(TYPE_DEVICE, d, v); + d->prune = 0; /* Survive a reload */ + if (!AST_LIST_FIRST(&d->lines)) { ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n"); ast_mutex_unlock(&d->lock); @@ -6454,8 +6478,31 @@ d->addr.sin_port = htons(DEFAULT_SKINNY_PORT); } + AST_LIST_LOCK(&devices); + if (skinnyreload){ + AST_LIST_TRAVERSE(&devices, temp, list) { + if (!strcasecmp(d->id, temp->id)) { + d->session = temp->session; + AST_LIST_REMOVE(&devices, temp, list); + update = 1; + } + } + } + + AST_LIST_INSERT_HEAD(&devices, d, list); + + if (update) { + ast_verb(3, "Updated device '%s'\n", d->name); + } else { + ast_verb(3, "Added device '%s'\n", d->name); + } + ast_mutex_unlock(&d->lock); - return d; + + AST_LIST_UNLOCK(&devices); + + return d; + } static int config_load(void) @@ -6601,19 +6648,53 @@ AST_LIST_UNLOCK(&devices); } -#if 0 -/* - * XXX This never worked properly anyways. - * Let's get rid of it, until we can fix it. - */ -static int reload(void) +int skinny_reload(void) { - delete_devices(); - config_load(); - restart_monitor(); - return 0; + struct skinny_device *d; + struct skinny_line *l; + struct skinny_speeddial *sd; + struct skinny_addon *a; + struct skinny_req *req; + skinnyreload = 1; + + /* Mark all devices as candidates to be pruned */ + AST_LIST_TRAVERSE(&devices, d, list) { + d->prune = 1; + } + + config_load(); + + /* Remove any devices that no longer exist in the config */ + AST_LIST_TRAVERSE(&devices, d, list) { + if (d->prune) { + ast_verb(3, "Removing device '%s'\n", d->name); + /* Delete all lines for this device */ + while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) { + free(l); + } + /* Delete all speeddials for this device */ + while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) { + free(sd); + } + /* Delete all addons for this device */ + while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) { + free(a); + } + AST_LIST_REMOVE(&devices, d, list); + free(d); + } else { + /* Do a soft reset to re-register the device */ + if (d->session) { + ast_verb(3, "Restarting device '%s'\n", d->name); + if ((req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE))) { + req->data.reset.resetType = 2; + transmit_response(d, req); + } + } + } + } + return 0; } -#endif static int load_module(void) { @@ -6647,7 +6728,7 @@ /* And start the monitor for the first time */ restart_monitor(); - return res; + return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) @@ -6721,7 +6802,14 @@ return 0; } +static int reload(void) +{ + skinny_reload(); + return 0; +} + AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Skinny Client Control Protocol (Skinny)", .load = load_module, .unload = unload_module, + .reload = reload, );