[asterisk-commits] mvanbaak: trunk r179122 - /trunk/channels/chan_skinny.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Feb 27 14:34:06 CST 2009


Author: mvanbaak
Date: Fri Feb 27 14:34:00 2009
New Revision: 179122

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=179122
Log:
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/

Modified:
    trunk/channels/chan_skinny.c

Modified: trunk/channels/chan_skinny.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/channels/chan_skinny.c?view=diff&rev=179122&r1=179121&r2=179122
==============================================================================
--- trunk/channels/chan_skinny.c (original)
+++ trunk/channels/chan_skinny.c Fri Feb 27 14:34:00 2009
@@ -970,6 +970,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;
@@ -1181,7 +1182,8 @@
 	int immediate;					\
 	int hookstate;					\
 	int nat;					\
-	int canreinvite;
+	int canreinvite;				\
+	int prune;
 
 struct skinny_line {
 	SKINNY_LINE_OPTIONS
@@ -1212,6 +1214,7 @@
  	.capability = 0,
 	.getforward = 0,
  	.needdestroy = 0,
+	.prune = 0,
 	.hookstate = SKINNY_ONHOOK,
 };
 struct skinny_line_options *default_line = &default_line_struct;
@@ -1256,7 +1259,8 @@
 	int transfer;						\
 	int callwaiting;					\
 	int mwiblink;						\
-	int dnd;
+	int dnd;						\
+	int prune;
 
 struct skinny_device {
 	SKINNY_DEVICE_OPTIONS
@@ -1284,6 +1288,7 @@
  	.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_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_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 @@
 	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 @@
  			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 @@
 						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 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 @@
  	}
  
  	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 @@
  		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 @@
 	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)
-{
-	delete_devices();
-	config_load();
-	restart_monitor();
-	return 0;
-}
-#endif
+int skinny_reload(void)
+{
+	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;
+}
 
 static int load_module(void)
 {
@@ -7158,7 +7312,7 @@
 	/* 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 @@
 	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,
 );




More information about the asterisk-commits mailing list