Add reload support to chan_skinny.

Special thanks goes to DEA who had to redo this patch twice
because we first put unload/load support in and later redid the way
we configure devices and lines.

(closes issue #10297)
Reported by: DEA
Patches:
      skinny-reload-trunkv2.diff uploaded by wedhorn (license 30)
      skinny-reload-trunk-v4.txt uploaded by DEA (license 3)
	  With mods by me based on feedback from wedhorn and Russell and seanbright
Tested by: DEA, mvanbaak, pj

Review: http://reviewboard.digium.com/r/130/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@179122 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.6.2
Michiel van Baak 16 years ago
parent 796ec24ed5
commit 99ad18c4c5

@ -970,6 +970,7 @@ int skinny_header_size = 12;
*****************************/
static int skinnydebug = 0;
static int skinnyreload = 0;
/* a hostname, portnumber, socket and such is usefull for VoIP protocols */
static struct sockaddr_in bindaddr;
@ -1181,7 +1182,8 @@ struct skinny_subchannel {
int immediate; \
int hookstate; \
int nat; \
int canreinvite;
int canreinvite; \
int prune;
struct skinny_line {
SKINNY_LINE_OPTIONS
@ -1212,6 +1214,7 @@ struct skinny_line_options{
.capability = 0,
.getforward = 0,
.needdestroy = 0,
.prune = 0,
.hookstate = SKINNY_ONHOOK,
};
struct skinny_line_options *default_line = &default_line_struct;
@ -1256,7 +1259,8 @@ struct skinny_addon {
int transfer; \
int callwaiting; \
int mwiblink; \
int dnd;
int dnd; \
int prune;
struct skinny_device {
SKINNY_DEVICE_OPTIONS
@ -1284,6 +1288,7 @@ struct skinny_device_options{
.dnd = 0,
.confcapability = AST_FORMAT_ULAW | AST_FORMAT_ALAW,
.capability = 0,
.prune = 0,
};
struct skinny_device_options *default_device = &default_device_struct;
@ -1324,6 +1329,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 void mwi_event_cb(const struct ast_event *event, void *userdata);
static int skinny_reload(void);
static const struct ast_channel_tech skinny_tech = {
.type = "Skinny",
@ -2718,6 +2724,27 @@ static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct as
}
}
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;
@ -3521,6 +3548,7 @@ static struct ast_cli_entry cli_skinny[] = {
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)
@ -6786,7 +6814,7 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
if (type & (TYPE_DEVICE)) {
struct skinny_line *l;
AST_LIST_TRAVERSE(&lines, l, all) {
if (!strcasecmp(v->value, l->name)) {
if (!strcasecmp(v->value, l->name) && !l->prune) {
/* FIXME: temp solution about line conflicts */
struct skinny_device *d;
@ -6794,7 +6822,7 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
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++;
}
@ -6868,32 +6896,35 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
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);
/* We find the old line and remove it just before the new
line is created */
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);
AST_LIST_TRAVERSE(&lines, temp, all) {
if (!strcasecmp(lname, temp->name) && temp->prune) {
update = 1;
break;
}
}
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);
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);
ast_mutex_lock(&l->lock);
AST_LIST_UNLOCK(&lines);
config_parse_variables(TYPE_LINE, l, v);
if (!ast_strlen_zero(l->mailbox)) {
@ -6911,32 +6942,43 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
}
ast_mutex_unlock(&l->lock);
/* We do not want to unlink or free the line yet, it needs
to be available to detect a device reconfig when we load the
devices. Old lines will be pruned after the reload completes */
ast_verb(3, "%s config for line '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), l->name);
return l;
}
static struct skinny_device *config_device(const char *dname, struct ast_variable *v)
{
struct skinny_device *d;
struct skinny_device *d, *temp;
struct skinny_line *l, *ltemp;
struct skinny_subchannel *sub;
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)) {
AST_LIST_TRAVERSE(&devices, temp, list) {
if (!strcasecmp(dname, temp->name) && temp->prune) {
update = 1;
break;
}
}
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);
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_TAIL(&devices, d, list);
ast_mutex_lock(&d->lock);
AST_LIST_UNLOCK(&devices);
@ -6951,8 +6993,52 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
}
if (skinnyreload){
AST_LIST_LOCK(&devices);
AST_LIST_TRAVERSE(&devices, temp, list) {
if (strcasecmp(d->id, temp->id) || !temp->prune || !temp->session) {
continue;
}
ast_mutex_lock(&d->lock);
d->session = temp->session;
d->session->device = d;
AST_LIST_LOCK(&d->lines);
AST_LIST_TRAVERSE(&d->lines, l, list){
l->device = d;
AST_LIST_LOCK(&temp->lines);
AST_LIST_TRAVERSE(&temp->lines, ltemp, list) {
if (strcasecmp(l->name, ltemp->name)) {
continue;
}
ast_mutex_lock(&ltemp->lock);
l->instance = ltemp->instance;
l->hookstate = ltemp->hookstate;
if (!AST_LIST_EMPTY(&ltemp->sub)) {
ast_mutex_lock(&l->lock);
l->sub = ltemp->sub;
AST_LIST_TRAVERSE(&l->sub, sub, list) {
sub->parent = l;
}
ast_mutex_unlock(&l->lock);
}
ast_mutex_unlock(&ltemp->lock);
}
AST_LIST_UNLOCK(&temp->lines);
}
AST_LIST_UNLOCK(&d->lines);
ast_mutex_unlock(&d->lock);
}
AST_LIST_UNLOCK(&devices);
}
ast_mutex_unlock(&d->lock);
return d;
ast_verb(3, "%s config for device '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), d->name);
return d;
}
static int config_load(void)
@ -7102,19 +7188,87 @@ static void delete_devices(void)
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;
if (skinnyreload) {
ast_verb(3, "Chan_skinny is already reloading.\n");
return 0;
}
skinnyreload = 1;
/* Mark all devices and lines as candidates to be pruned */
AST_LIST_LOCK(&devices);
AST_LIST_TRAVERSE(&devices, d, list) {
d->prune = 1;
}
AST_LIST_UNLOCK(&devices);
AST_LIST_LOCK(&lines);
AST_LIST_TRAVERSE(&lines, l, all) {
l->prune = 1;
}
AST_LIST_UNLOCK(&lines);
config_load();
/* Remove any devices that no longer exist in the config */
AST_LIST_LOCK(&devices);
AST_LIST_TRAVERSE_SAFE_BEGIN(&devices, d, list) {
if (!d->prune) {
continue;
}
ast_verb(3, "Removing device '%s'\n", d->name);
/* Delete all lines for this device.
We do not want to free the line here, that
will happen below. */
while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
}
/* 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_CURRENT(list);
free(d);
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&devices);
AST_LIST_LOCK(&lines);
AST_LIST_TRAVERSE_SAFE_BEGIN(&lines, l, all) {
if (l->prune) {
AST_LIST_REMOVE_CURRENT(all);
free(l);
}
}
AST_LIST_TRAVERSE_SAFE_END;
AST_LIST_UNLOCK(&lines);
AST_LIST_TRAVERSE(&devices, d, list) {
/* Do a soft reset to re-register the devices after
cleaning up the removed devices and lines */
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);
}
}
}
skinnyreload = 0;
return 0;
}
#endif
static int load_module(void)
{
@ -7158,7 +7312,7 @@ static int load_module(void)
/* And start the monitor for the first time */
restart_monitor();
return res;
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
@ -7237,7 +7391,14 @@ static int unload_module(void)
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,
);

Loading…
Cancel
Save