Index: channels/chan_skinny.c =================================================================== --- channels/chan_skinny.c (revision 144636) +++ 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; @@ -1238,6 +1239,7 @@ int lastcallreference; int capability; int earlyrtp; + int prune; struct sockaddr_in addr; struct in_addr ourip; AST_LIST_HEAD(, skinny_line) lines; @@ -1277,6 +1279,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", @@ -2549,6 +2552,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; @@ -3026,11 +3050,12 @@ AST_CLI_DEFINE(handle_skinny_show_settings, "List global Skinny settings"), AST_CLI_DEFINE(handle_skinny_set_debug, "Enable/Disable Skinny debugging", .deprecate_cmd = &cli_skinny_set_debug_deprecated), AST_CLI_DEFINE(handle_skinny_reset, "Reset Skinny device(s)"), + AST_CLI_DEFINE(handle_skinny_reload, "Reload Skinny config"), }; -static struct skinny_device *build_device(const char *cat, struct ast_variable *v) +static void build_device(const char *cat, struct ast_variable *v) { - struct skinny_device *d; + struct skinny_device *d, *temp; struct skinny_line *l; struct skinny_speeddial *sd; struct skinny_addon *a; @@ -3039,9 +3064,11 @@ int lineInstance = 1; int speeddialInstance = 1; int y = 0; + int update = 0; + if (!(d = ast_calloc(1, sizeof(*d)))) { - return NULL; + return; } else { ast_copy_string(d->name, cat, sizeof(d->name)); d->lastlineinstance = 1; @@ -3053,11 +3080,12 @@ memset(device_vmexten, 0, sizeof(device_vmexten)); d->earlyrtp = 1; + d->prune = 0; while(v) { if (!strcasecmp(v->name, "host")) { if (ast_get_ip(&d->addr, v->value)) { ast_free(d); - return NULL; + return; } } else if (!strcasecmp(v->name, "port")) { d->addr.sin_port = htons(atoi(v->value)); @@ -3137,7 +3165,7 @@ ast_copy_string(parkinglot, v->value, sizeof(parkinglot)); } else if (!strcasecmp(v->name, "speeddial")) { if (!(sd = ast_calloc(1, sizeof(*sd)))) { - return NULL; + return; } else { char buf[256]; char *stringp = buf, *exten, *context, *label; @@ -3167,7 +3195,7 @@ } } else if (!strcasecmp(v->name, "addon")) { if (!(a = ast_calloc(1, sizeof(*a)))) { - return NULL; + return; } else { ast_mutex_init(&a->lock); ast_copy_string(a->type, v->value, sizeof(a->type)); @@ -3176,7 +3204,7 @@ } } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) { if (!(l = ast_calloc(1, sizeof(*l)))) { - return NULL; + return; } else { ast_mutex_init(&l->lock); ast_copy_string(l->name, v->value, sizeof(l->name)); @@ -3247,13 +3275,34 @@ if (!AST_LIST_FIRST(&d->lines)) { ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n"); - return NULL; + return; } if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) { d->addr.sin_port = htons(DEFAULT_SKINNY_PORT); } } - return d; + + 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; + } + } + } + if (update) { + AST_LIST_INSERT_HEAD(&devices, d, list); + ast_verb(3, "Updated device '%s'\n", d->name); + + } else { + AST_LIST_INSERT_HEAD(&devices, d, list); + ast_verb(3, "Added device '%s'\n", d->name); + } + AST_LIST_UNLOCK(&devices); + + return; } static void start_rtp(struct skinny_subchannel *sub) @@ -6206,7 +6255,6 @@ struct ast_config *cfg; struct ast_variable *v; char *cat; - struct skinny_device *d; int oldport = ntohs(bindaddr.sin_port); char *stringp, *context, *oldregcontext; char newcontexts[AST_MAX_CONTEXT], oldcontexts[AST_MAX_CONTEXT]; @@ -6323,13 +6371,7 @@ if (!strcasecmp(cat, "general")) { /* Nothing to do */ } else { - d = build_device(cat, ast_variable_browse(cfg, cat)); - if (d) { - ast_verb(3, "Added device '%s'\n", d->name); - AST_LIST_LOCK(&devices); - AST_LIST_INSERT_HEAD(&devices, d, list); - AST_LIST_UNLOCK(&devices); - } + build_device(cat, ast_variable_browse(cfg, cat)); } cat = ast_category_browse(cfg, cat); } @@ -6408,20 +6450,54 @@ 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) +static int skinny_reload(void) { - delete_devices(); + 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; + } + reload_config(); - restart_monitor(); + + /* 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) { int res = 0; @@ -6454,7 +6530,7 @@ /* And start the monitor for the first time */ restart_monitor(); - return res; + return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) @@ -6528,7 +6604,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, );