[asterisk-commits] may: branch may/ooh323_qsig r397688 - in /team/may/ooh323_qsig: ./ apps/ chan...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Aug 26 17:53:52 CDT 2013


Author: may
Date: Mon Aug 26 17:53:46 2013
New Revision: 397688

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=397688
Log:
Multiple revisions 393843,393857-393858,393870,393896-393897,393910,393919,393930,393968,393987,394004,394024,394037,394050

........
  r393843 | dlee | 2013-07-09 00:31:41 +0400 (Tue, 09 Jul 2013) | 1 line
  
  Oh menuconfig, why do you hate margins?
........
  r393857 | file | 2013-07-09 01:26:37 +0400 (Tue, 09 Jul 2013) | 5 lines
  
  Treat the authentication object as invalid if digest configuration is chosen and the digest is not of the correct length.
  
  (closes issue ASTERISK-22003)
  Reported by: Rusty Newton
........
  r393858 | file | 2013-07-09 01:27:18 +0400 (Tue, 09 Jul 2013) | 2 lines
  
  Tweak log message slightly.
........
  r393870 | file | 2013-07-09 15:05:48 +0400 (Tue, 09 Jul 2013) | 5 lines
  
  Ensure all pjsip_regc_* access occurs within a pjlib thread.
  
  (closes issue ASTERISK-22054)
  Reported by: Rusty Newton
........
  r393896 | rmudgett | 2013-07-09 23:38:00 +0400 (Tue, 09 Jul 2013) | 1 line
  
  Fix some stasis doxygen comments.
........
  r393897 | mmichelson | 2013-07-10 00:07:21 +0400 (Wed, 10 Jul 2013) | 6 lines
  
  Use correct function for getting bridged peer when doing direct media checks.
  
  (closes issue ASTERISK-21947)
  reported by Matt Jordan
........
  r393910 | rmudgett | 2013-07-10 01:06:21 +0400 (Wed, 10 Jul 2013) | 1 line
  
  Fix printf NULL string (null) substituion for NULL config framework default.
........
  r393919 | qwell | 2013-07-10 01:40:38 +0400 (Wed, 10 Jul 2013) | 7 lines
  
  Make SCOPED_LOCK use RAII_VAR.
  
  This fixes an issue with requiring SCOPED_LOCK to be the last variable
  declaration and removes duplicate code in the process.
  
  Review: https://reviewboard.asterisk.org/r/2665/
........
  r393930 | russell | 2013-07-10 05:56:15 +0400 (Wed, 10 Jul 2013) | 26 lines
  
  astobj2-ify the SLA code
  
  The SLA code within app_meetme was written before asotbj2 had been
  merged into Asterisk.  Worse, support for reloads did not exist at first
  and was added later as a bolt-on feature.  I knew at the time that
  reloading was not safe at all while SLA was in use, so the reload would
  be queued up to execute when the system was idle.  Unfortunately, this
  approach was still prone to errors beyond the fact that this was the
  only place in Asterisk where configuration was not reloaded
  instantly when requested.
  
  This patch converts various SLA objects to be reference counted objects
  using astobj2.  This allows reloads to be processed while the system is
  in use.  The code ensures that the objects will not disappear while one
  of the other threads is using them.  However, they will be immediately
  removed from the global trunk and station containers so no new calls
  will use them if removed from configuration.
  
  Review: https://reviewboard.asterisk.org/r/2581/
  ........
  
  Merged revisions 393928 from http://svn.asterisk.org/svn/asterisk/branches/1.8
  ........
  
  Merged revisions 393929 from http://svn.asterisk.org/svn/asterisk/branches/11
........
  r393968 | dlee | 2013-07-10 17:50:48 +0400 (Wed, 10 Jul 2013) | 1 line
  
  Corrected api-docs for channel variables
........
  r393987 | dlee | 2013-07-10 21:13:21 +0400 (Wed, 10 Jul 2013) | 1 line
  
  Document the 400 error response for originate
........
  r394004 | file | 2013-07-11 00:02:59 +0400 (Thu, 11 Jul 2013) | 5 lines
  
  Handle outbound registration failures that do not occur as a result of a real response.
  
  (closes issue ASTERISK-22064)
  Reported by: Rusty Newton
........
  r394024 | kharwell | 2013-07-11 02:26:13 +0400 (Thu, 11 Jul 2013) | 23 lines
  
  PSJIP - sip.conf to res_sip.conf script
  
  ** This script is in no way finished.
  
  Started the initial "cut" at converting a sip.conf file to a res_sip.conf file.
  Hopefully the bulk of the framework is in place and only a few minor adjustments
  need to be made when an option mapping is added that "doesn't fit".  This script
  and supporting files should be executable against python version 2.5.
  
  An OrderedDict class (backported from a newer version of python) is included.
  A MultiOrderedDict class is implemented so options, when added, should be able
  to be added in order and allowed to have multiple values.
  
  Currently the scripts supports the majority of endpoint options found in
  res_sip.conf.  Support has also been added for Aor(s) and the ACL/security
  sections.  Inside the sip_to_res_sip.py file one can see a list of options
  that still need to be mapped.
  
  Also items that still need to be done: templates, includes, parsing '=>'
  delimiter.  Note that some code is hopefully in place already to support
  templates (e.g. lookup/retrieving defaults from them).  However, the
  parsing of and adding of the section needs to be done.
........
  r394037 | dlee | 2013-07-11 06:02:48 +0400 (Thu, 11 Jul 2013) | 1 line
  
  Fixed some CEL test crashes
........
  r394050 | dlee | 2013-07-11 08:34:49 +0400 (Thu, 11 Jul 2013) | 9 lines
  
  test_voicemail_api: fix warning found by gcc-4.8
  
  The voicemail_api test had code like strncmp(a, b, sizeof(a)), but a was a
  char pointer, instead of a literal or char array. This meant that sizeof was
  the size of the pointer, not the length of the string.
  
  Since the string is in a stringfield and should be null terminated, I just
  changed it to a plain strcmp.
........

Merged revisions 393843,393857-393858,393870,393896-393897,393910,393919,393930,393968,393987,394004,394024,394037,394050 from http://svn.asterisk.org/svn/asterisk/trunk

Added:
    team/may/ooh323_qsig/contrib/scripts/sip_to_res_sip/
      - copied from r394050, trunk/contrib/scripts/sip_to_res_sip/
Modified:
    team/may/ooh323_qsig/   (props changed)
    team/may/ooh323_qsig/apps/app_meetme.c
    team/may/ooh323_qsig/channels/chan_gulp.c
    team/may/ooh323_qsig/configs/sla.conf.sample
    team/may/ooh323_qsig/include/asterisk/lock.h
    team/may/ooh323_qsig/include/asterisk/manager.h
    team/may/ooh323_qsig/include/asterisk/stasis_channels.h
    team/may/ooh323_qsig/main/xmldoc.c
    team/may/ooh323_qsig/res/res_sip/config_auth.c
    team/may/ooh323_qsig/res/res_sip_outbound_registration.c
    team/may/ooh323_qsig/res/res_stasis_http_asterisk.c
    team/may/ooh323_qsig/res/res_stasis_http_channels.c
    team/may/ooh323_qsig/res/res_stasis_recording.c
    team/may/ooh323_qsig/res/stasis_http/ari_model_validators.c
    team/may/ooh323_qsig/res/stasis_http/ari_model_validators.h
    team/may/ooh323_qsig/rest-api/api-docs/asterisk.json
    team/may/ooh323_qsig/rest-api/api-docs/channels.json
    team/may/ooh323_qsig/tests/test_cel.c
    team/may/ooh323_qsig/tests/test_voicemail_api.c

Propchange: team/may/ooh323_qsig/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Propchange: team/may/ooh323_qsig/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Aug 26 17:53:46 2013
@@ -1,1 +1,1 @@
-/trunk:1-380157,380165-391000,391012,391016-393400,393410-393530,393542-393834
+/trunk:1-380157,380165-391000,391012,391016-393400,393410-393530,393542-393834,393843-394050

Modified: team/may/ooh323_qsig/apps/app_meetme.c
URL: http://svnview.digium.com/svn/asterisk/team/may/ooh323_qsig/apps/app_meetme.c?view=diff&rev=397688&r1=397687&r2=397688
==============================================================================
--- team/may/ooh323_qsig/apps/app_meetme.c (original)
+++ team/may/ooh323_qsig/apps/app_meetme.c Mon Aug 26 17:53:46 2013
@@ -961,17 +961,26 @@
 	/*! This option uses the values in the sla_hold_access enum and sets the
 	 * access control type for hold on this station. */
 	unsigned int hold_access:1;
-	/*! Use count for inside sla_station_exec */
-	unsigned int ref_count;
+	/*! Mark used during reload processing */
+	unsigned int mark:1;
 };
 
+/*!
+ * \brief A reference to a station
+ *
+ * This struct looks near useless at first glance.  However, its existence
+ * in the list of stations in sla_trunk means that this station references
+ * that trunk.  We use the mark to keep track of whether it needs to be
+ * removed from the sla_trunk's list of stations during a reload.
+ */
 struct sla_station_ref {
 	AST_LIST_ENTRY(sla_station_ref) entry;
 	struct sla_station *station;
+	/*! Mark used during reload processing */
+	unsigned int mark:1;
 };
 
 struct sla_trunk {
-	AST_RWLIST_ENTRY(sla_trunk) entry;
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(name);
 		AST_STRING_FIELD(device);
@@ -995,10 +1004,16 @@
 	/*! Whether this trunk is currently on hold, meaning that once a station
 	 *  connects to it, the trunk channel needs to have UNHOLD indicated to it. */
 	unsigned int on_hold:1;
-	/*! Use count for inside sla_trunk_exec */
-	unsigned int ref_count;
+	/*! Mark used during reload processing */
+	unsigned int mark:1;
 };
 
+/*!
+ * \brief A station's reference to a trunk
+ *
+ * An sla_station keeps a list of trunk_refs.  This holds metadata about the
+ * stations usage of the trunk.
+ */
 struct sla_trunk_ref {
 	AST_LIST_ENTRY(sla_trunk_ref) entry;
 	struct sla_trunk *trunk;
@@ -1012,10 +1027,12 @@
 	 *  station.  This takes higher priority than a ring delay set at
 	 *  the station level. */
 	unsigned int ring_delay;
+	/*! Mark used during reload processing */
+	unsigned int mark:1;
 };
 
-static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
-static AST_RWLIST_HEAD_STATIC(sla_trunks, sla_trunk);
+static struct ao2_container *sla_stations;
+static struct ao2_container *sla_trunks;
 
 static const char sla_registrar[] = "SLA";
 
@@ -1027,10 +1044,6 @@
 	SLA_EVENT_DIAL_STATE,
 	/*! The state of a ringing trunk has changed */
 	SLA_EVENT_RINGING_TRUNK,
-	/*! A reload of configuration has been requested */
-	SLA_EVENT_RELOAD,
-	/*! Poke the SLA thread so it can check if it can perform a reload */
-	SLA_EVENT_CHECK_RELOAD,
 };
 
 struct sla_event {
@@ -1086,8 +1099,6 @@
 	/*! Attempt to handle CallerID, even though it is known not to work
 	 *  properly in some situations. */
 	unsigned int attempt_callerid:1;
-	/*! A reload has been requested */
-	unsigned int reload:1;
 } sla = {
 	.thread = AST_PTHREADT_NULL,
 };
@@ -2117,7 +2128,8 @@
 
 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	const struct sla_trunk *trunk;
+	struct ao2_iterator i;
+	struct sla_trunk *trunk;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -2135,12 +2147,17 @@
 	            "=== Configured SLA Trunks ===================================\n"
 	            "=============================================================\n"
 	            "===\n");
-	AST_RWLIST_RDLOCK(&sla_trunks);
-	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
+	i = ao2_iterator_init(sla_trunks, 0);
+	for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
 		struct sla_station_ref *station_ref;
 		char ring_timeout[16] = "(none)";
-		if (trunk->ring_timeout)
+
+		ao2_lock(trunk);
+
+		if (trunk->ring_timeout) {
 			snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
+		}
+
 		ast_cli(a->fd, "=== ---------------------------------------------------------\n"
 		            "=== Trunk Name:       %s\n"
 		            "=== ==> Device:       %s\n"
@@ -2154,13 +2171,16 @@
 		            ring_timeout,
 		            trunk->barge_disabled ? "No" : "Yes",
 		            sla_hold_str(trunk->hold_access));
-		AST_RWLIST_RDLOCK(&sla_stations);
-		AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
+
+		AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
 			ast_cli(a->fd, "===    ==> Station name: %s\n", station_ref->station->name);
-		AST_RWLIST_UNLOCK(&sla_stations);
+		}
+
 		ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
-	}
-	AST_RWLIST_UNLOCK(&sla_trunks);
+
+		ao2_unlock(trunk);
+	}
+	ao2_iterator_destroy(&i);
 	ast_cli(a->fd, "=============================================================\n\n");
 
 	return CLI_SUCCESS;
@@ -2182,7 +2202,8 @@
 
 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	const struct sla_station *station;
+	struct ao2_iterator i;
+	struct sla_station *station;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -2200,11 +2221,14 @@
 	            "=== Configured SLA Stations =================================\n"
 	            "=============================================================\n"
 	            "===\n");
-	AST_RWLIST_RDLOCK(&sla_stations);
-	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
+	i = ao2_iterator_init(sla_stations, 0);
+	for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
 		struct sla_trunk_ref *trunk_ref;
 		char ring_timeout[16] = "(none)";
 		char ring_delay[16] = "(none)";
+
+		ao2_lock(station);
+
 		if (station->ring_timeout) {
 			snprintf(ring_timeout, sizeof(ring_timeout), 
 				"%u", station->ring_timeout);
@@ -2225,7 +2249,6 @@
 		            S_OR(station->autocontext, "(none)"), 
 		            ring_timeout, ring_delay,
 		            sla_hold_str(station->hold_access));
-		AST_RWLIST_RDLOCK(&sla_trunks);
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
 			if (trunk_ref->ring_timeout) {
 				snprintf(ring_timeout, sizeof(ring_timeout),
@@ -2245,11 +2268,12 @@
 			            trunkstate2str(trunk_ref->state),
 			            ring_timeout, ring_delay);
 		}
-		AST_RWLIST_UNLOCK(&sla_trunks);
 		ast_cli(a->fd, "=== ---------------------------------------------------------\n"
 		            "===\n");
-	}
-	AST_RWLIST_UNLOCK(&sla_stations);
+
+		ao2_unlock(station);
+	}
+	ao2_iterator_destroy(&i);
 	ast_cli(a->fd, "============================================================\n"
 	            "\n");
 
@@ -2393,11 +2417,16 @@
 	struct sla_event *event;
 
 	if (sla.thread == AST_PTHREADT_NULL) {
+		ao2_ref(station, -1);
+		ao2_ref(trunk_ref, -1);
 		return;
 	}
 
-	if (!(event = ast_calloc(1, sizeof(*event))))
+	if (!(event = ast_calloc(1, sizeof(*event)))) {
+		ao2_ref(station, -1);
+		ao2_ref(trunk_ref, -1);
 		return;
+	}
 
 	event->type = type;
 	event->trunk_ref = trunk_ref;
@@ -2431,6 +2460,7 @@
 	struct sla_station *station;
 	struct sla_trunk_ref *trunk_ref = NULL;
 	char *trunk_name;
+	struct ao2_iterator i;
 
 	trunk_name = ast_strdupa(conf->confno);
 	strsep(&trunk_name, "_");
@@ -2439,16 +2469,23 @@
 		return;
 	}
 
-	AST_RWLIST_RDLOCK(&sla_stations);
-	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
+	i = ao2_iterator_init(sla_stations, 0);
+	while ((station = ao2_iterator_next(&i))) {
+		ao2_lock(station);
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
-			if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
+			if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
+				ao2_ref(trunk_ref, 1);
 				break;
-		}
-		if (trunk_ref)
+			}
+		}
+		ao2_unlock(station);
+		if (trunk_ref) {
+			/* station reference given to sla_queue_event_full() */
 			break;
-	}
-	AST_RWLIST_UNLOCK(&sla_stations);
+		}
+		ao2_ref(station, -1);
+	}
+	ao2_iterator_destroy(&i);
 
 	if (!trunk_ref) {
 		ast_debug(1, "Trunk not found for event!\n");
@@ -5776,34 +5813,30 @@
 	ast_config_destroy(cfg);
 }
 
-/*! \brief Find an SLA trunk by name
- * \note This must be called with the sla_trunks container locked
+/*!
+ * \internal
+ * \brief Find an SLA trunk by name
  */
 static struct sla_trunk *sla_find_trunk(const char *name)
 {
-	struct sla_trunk *trunk = NULL;
-
-	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
-		if (!strcasecmp(trunk->name, name))
-			break;
-	}
-
-	return trunk;
-}
-
-/*! \brief Find an SLA station by name
- * \note This must be called with the sla_stations container locked
+	struct sla_trunk tmp_trunk = {
+		.name = name,
+	};
+
+	return ao2_find(sla_trunks, &tmp_trunk, OBJ_POINTER);
+}
+
+/*!
+ * \internal
+ * \brief Find an SLA station by name
  */
 static struct sla_station *sla_find_station(const char *name)
 {
-	struct sla_station *station = NULL;
-
-	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
-		if (!strcasecmp(station->name, name))
-			break;
-	}
-
-	return station;
+	struct sla_station tmp_station = {
+		.name = name,
+	};
+
+	return ao2_find(sla_stations, &tmp_station, OBJ_POINTER);
 }
 
 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
@@ -5827,9 +5860,11 @@
 	return 0;
 }
 
-/*! \brief Find a trunk reference on a station by name
+/*!
+ * \brief Find a trunk reference on a station by name
  * \param station the station
  * \param name the trunk's name
+ * \pre sla_station is locked
  * \return a pointer to the station's trunk reference.  If the trunk
  *         is not found, it is not idle and barge is disabled, or if
  *         it is on hold and private hold is set, then NULL will be returned.
@@ -5856,16 +5891,32 @@
 		break;
 	}
 
+	if (trunk_ref) {
+		ao2_ref(trunk_ref, 1);
+	}
+
 	return trunk_ref;
 }
 
+static void sla_station_ref_destructor(void *obj)
+{
+	struct sla_station_ref *station_ref = obj;
+
+	if (station_ref->station) {
+		ao2_ref(station_ref->station, -1);
+		station_ref->station = NULL;
+	}
+}
+
 static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
 {
 	struct sla_station_ref *station_ref;
 
-	if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
+	if (!(station_ref = ao2_alloc(sizeof(*station_ref), sla_station_ref_destructor))) {
 		return NULL;
-
+	}
+
+	ao2_ref(station, 1);
 	station_ref->station = station;
 
 	return station_ref;
@@ -5878,10 +5929,46 @@
 	if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
 		return NULL;
 
+	ao2_ref(station, 1);
 	ringing_station->station = station;
 	ringing_station->ring_begin = ast_tvnow();
 
 	return ringing_station;
+}
+
+static void sla_ringing_station_destroy(struct sla_ringing_station *ringing_station)
+{
+	if (ringing_station->station) {
+		ao2_ref(ringing_station->station, -1);
+		ringing_station->station = NULL;
+	}
+
+	ast_free(ringing_station);
+}
+
+static struct sla_failed_station *sla_create_failed_station(struct sla_station *station)
+{
+	struct sla_failed_station *failed_station;
+
+	if (!(failed_station = ast_calloc(1, sizeof(*failed_station)))) {
+		return NULL;
+	}
+
+	ao2_ref(station, 1);
+	failed_station->station = station;
+	failed_station->last_try = ast_tvnow();
+
+	return failed_station;
+}
+
+static void sla_failed_station_destroy(struct sla_failed_station *failed_station)
+{
+	if (failed_station->station) {
+		ao2_ref(failed_station->station, -1);
+		failed_station->station = NULL;
+	}
+
+	ast_free(failed_station);
 }
 
 static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
@@ -5906,18 +5993,25 @@
 {
 	struct sla_station *station;
 	struct sla_trunk_ref *trunk_ref;
-
-	AST_LIST_TRAVERSE(&sla_stations, station, entry) {
+	struct ao2_iterator i;
+
+	i = ao2_iterator_init(sla_stations, 0);
+	while ((station = ao2_iterator_next(&i))) {
+		ao2_lock(station);
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
 			if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
-				|| trunk_ref == exclude)
+					|| trunk_ref == exclude) {
 				continue;
+			}
 			trunk_ref->state = state;
 			ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE,
 					     "SLA:%s_%s", station->name, trunk->name);
 			break;
 		}
-	}
+		ao2_unlock(station);
+		ao2_ref(station, -1);
+	}
+	ao2_iterator_destroy(&i);
 }
 
 struct run_station_args {
@@ -5935,8 +6029,8 @@
 
 static void *run_station(void *data)
 {
-	struct sla_station *station;
-	struct sla_trunk_ref *trunk_ref;
+	RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
+	RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
 	struct ast_str *conf_name = ast_str_create(16);
 	struct ast_flags64 conf_flags = { 0 };
 	struct ast_conference *conf;
@@ -5979,6 +6073,8 @@
 	return NULL;
 }
 
+static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk);
+
 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
 {
 	char buf[80];
@@ -5988,10 +6084,11 @@
 	admin_exec(NULL, buf);
 	sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
 
-	while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
-		ast_free(station_ref);
-
-	ast_free(ringing_trunk);
+	while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry))) {
+		ao2_ref(station_ref, -1);
+	}
+
+	sla_ringing_trunk_destroy(ringing_trunk);
 }
 
 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
@@ -6026,7 +6123,7 @@
 	}
 
 done:
-	ast_free(ringing_station);
+	sla_ringing_station_destroy(ringing_station);
 }
 
 static void sla_dial_state_callback(struct ast_dial *dial)
@@ -6078,8 +6175,10 @@
 			if (rm)
 				AST_LIST_REMOVE_CURRENT(entry);
 
-			if (trunk_ref)
+			if (trunk_ref) {
+				ao2_ref(s_trunk_ref, 1);
 				*trunk_ref = s_trunk_ref;
+			}
 
 			break;
 		}
@@ -6097,7 +6196,7 @@
 	struct sla_ringing_station *ringing_station;
 
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
-		struct sla_trunk_ref *s_trunk_ref = NULL;
+		RAII_VAR(struct sla_trunk_ref *, s_trunk_ref, NULL, ao2_cleanup);
 		struct sla_ringing_trunk *ringing_trunk = NULL;
 		struct run_station_args args;
 		enum ast_dial_result dial_res;
@@ -6130,7 +6229,7 @@
 				ast_dial_join(ringing_station->station->dial);
 				ast_dial_destroy(ringing_station->station->dial);
 				ringing_station->station->dial = NULL;
-				ast_free(ringing_station);
+				sla_ringing_station_destroy(ringing_station);
 				break;
 			}
 			/* Track the channel that answered this trunk */
@@ -6141,12 +6240,14 @@
 			/* Now, start a thread that will connect this station to the trunk.  The rest of
 			 * the code here sets up the thread and ensures that it is able to save the arguments
 			 * before they are no longer valid since they are allocated on the stack. */
+			ao2_ref(s_trunk_ref, 1);
 			args.trunk_ref = s_trunk_ref;
+			ao2_ref(ringing_station->station, 1);
 			args.station = ringing_station->station;
 			args.cond = &cond;
 			args.cond_lock = &cond_lock;
-			ast_free(ringing_trunk);
-			ast_free(ringing_station);
+			sla_ringing_trunk_destroy(ringing_trunk);
+			sla_ringing_station_destroy(ringing_station);
 			ast_mutex_init(&cond_lock);
 			ast_cond_init(&cond, NULL);
 			ast_mutex_lock(&cond_lock);
@@ -6200,7 +6301,7 @@
 			continue;
 		if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
 			AST_LIST_REMOVE_CURRENT(entry);
-			ast_free(failed_station);
+			sla_failed_station_destroy(failed_station);
 			break;
 		}
 		res = 1;
@@ -6253,11 +6354,9 @@
 	if (res != AST_DIAL_RESULT_TRYING) {
 		struct sla_failed_station *failed_station;
 		ast_dial_destroy(dial);
-		if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
-			return -1;
-		failed_station->station = station;
-		failed_station->last_try = ast_tvnow();
-		AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
+		if ((failed_station = sla_create_failed_station(station))) {
+			AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
+		}
 		return -1;
 	}
 	if (!(ringing_station = sla_create_ringing_station(station))) {
@@ -6296,6 +6395,8 @@
 		if (trunk_ref->trunk == trunk)
 			break;
 	}
+
+	ao2_ref(trunk_ref, 1);
 
 	return trunk_ref;
 }
@@ -6308,7 +6409,7 @@
 static int sla_check_station_delay(struct sla_station *station, 
 	struct sla_ringing_trunk *ringing_trunk)
 {
-	struct sla_trunk_ref *trunk_ref;
+	RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
 	unsigned int delay = UINT_MAX;
 	int time_left, time_elapsed;
 
@@ -6401,7 +6502,7 @@
 			ast_dial_join(ringing_station->station->dial);
 			ast_dial_destroy(ringing_station->station->dial);
 			ringing_station->station->dial = NULL;
-			ast_free(ringing_station);
+			sla_ringing_station_destroy(ringing_station);
 		}
 	}
 	AST_LIST_TRAVERSE_SAFE_END
@@ -6558,8 +6659,10 @@
 {
 	struct sla_station *station;
 	int res = 0;
-
-	AST_LIST_TRAVERSE(&sla_stations, station, entry) {
+	struct ao2_iterator i;
+
+	i = ao2_iterator_init(sla_stations, 0);
+	for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
 		struct sla_ringing_trunk *ringing_trunk;
 		int time_left;
 
@@ -6589,6 +6692,7 @@
 		if (time_left < *timeout)
 			*timeout = time_left;
 	}
+	ao2_iterator_destroy(&i);
 
 	return res;
 }
@@ -6630,47 +6734,19 @@
 	return 1;
 }
 
-static int sla_load_config(int reload);
-
-/*!
- * \internal
- * \brief Check if we can do a reload of SLA, and do it if we can
- * \pre sla.lock is locked.
- */
-static void sla_check_reload(void)
-{
-	struct sla_station *station;
-	struct sla_trunk *trunk;
-
-	if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks)
-		|| !AST_LIST_EMPTY(&sla.ringing_stations) || !AST_LIST_EMPTY(&sla.failed_stations)) {
-		return;
-	}
-
-	AST_RWLIST_RDLOCK(&sla_stations);
-	AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
-		if (station->ref_count)
-			break;
-	}
-	AST_RWLIST_UNLOCK(&sla_stations);
-	if (station) {
-		return;
-	}
-
-	AST_RWLIST_RDLOCK(&sla_trunks);
-	AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
-		if (trunk->ref_count || trunk->chan || trunk->active_stations || trunk->hold_stations) {
-			break;
-		}
-	}
-	AST_RWLIST_UNLOCK(&sla_trunks);
-	if (trunk) {
-		return;
-	}
-
-	/* yay */
-	sla_load_config(1);
-	sla.reload = 0;
+static void sla_event_destroy(struct sla_event *event)
+{
+	if (event->trunk_ref) {
+		ao2_ref(event->trunk_ref, -1);
+		event->trunk_ref = NULL;
+	}
+
+	if (event->station) {
+		ao2_ref(event->station, -1);
+		event->station = NULL;
+	}
+
+	ast_free(event);
 }
 
 static void *sla_thread(void *data)
@@ -6709,27 +6785,21 @@
 			case SLA_EVENT_RINGING_TRUNK:
 				sla_handle_ringing_trunk_event();
 				break;
-			case SLA_EVENT_RELOAD:
-				sla.reload = 1;
-			case SLA_EVENT_CHECK_RELOAD:
-				break;
-			}
-			ast_free(event);
+			}
+			sla_event_destroy(event);
 			ast_mutex_lock(&sla.lock);
 		}
-
-		if (sla.reload) {
-			sla_check_reload();
-		}
 	}
 
 	ast_mutex_unlock(&sla.lock);
 
-	while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
-		ast_free(ringing_station);
-
-	while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
-		ast_free(failed_station);
+	while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry))) {
+		sla_ringing_station_destroy(ringing_station);
+	}
+
+	while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry))) {
+		sla_failed_station_destroy(failed_station);
+	}
 
 	return NULL;
 }
@@ -6750,7 +6820,8 @@
 	char conf_name[MAX_CONFNUM];
 	struct ast_conference *conf;
 	struct ast_flags64 conf_flags = { 0 };
-	struct sla_trunk_ref *trunk_ref = args->trunk_ref;
+	RAII_VAR(struct sla_trunk_ref *, trunk_ref, args->trunk_ref, ao2_cleanup);
+	RAII_VAR(struct sla_station *, station, args->station, ao2_cleanup);
 	int caller_is_saved;
 	struct ast_party_caller caller;
 	int last_state = 0;
@@ -6822,8 +6893,8 @@
 			break;
 
 		/* check that SLA station that originated trunk call is still alive */
-		if (args->station && ast_device_state(args->station->device) == AST_DEVICE_NOT_INUSE) {
-			ast_debug(3, "Originating station device %s no longer active\n", args->station->device);
+		if (station && ast_device_state(station->device) == AST_DEVICE_NOT_INUSE) {
+			ast_debug(3, "Originating station device %s no longer active\n", station->device);
 			trunk_ref->trunk->chan = NULL;
 			break;
 		}
@@ -6876,15 +6947,19 @@
 	return NULL;
 }
 
-/*! \brief For a given station, choose the highest priority idle trunk
+/*!
+ * \brief For a given station, choose the highest priority idle trunk
+ * \pre sla_station is locked
  */
 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
 {
 	struct sla_trunk_ref *trunk_ref = NULL;
 
 	AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
-		if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
+		if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) {
+			ao2_ref(trunk_ref, 1);
 			break;
+		}
 	}
 
 	return trunk_ref;
@@ -6893,8 +6968,8 @@
 static int sla_station_exec(struct ast_channel *chan, const char *data)
 {
 	char *station_name, *trunk_name;
-	struct sla_station *station;
-	struct sla_trunk_ref *trunk_ref = NULL;
+	RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
+	RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
 	char conf_name[MAX_CONFNUM];
 	struct ast_flags64 conf_flags = { 0 };
 	struct ast_conference *conf;
@@ -6914,25 +6989,21 @@
 		return 0;
 	}
 
-	AST_RWLIST_WRLOCK(&sla_stations);
 	station = sla_find_station(station_name);
-	if (station)
-		ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
-	AST_RWLIST_UNLOCK(&sla_stations);
 
 	if (!station) {
 		ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
 		pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);
 		return 0;
 	}
 
-	AST_RWLIST_RDLOCK(&sla_trunks);
+	ao2_lock(station);
 	if (!ast_strlen_zero(trunk_name)) {
 		trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
-	} else
+	} else {
 		trunk_ref = sla_choose_idle_trunk(station);
-	AST_RWLIST_UNLOCK(&sla_trunks);
+	}
+	ao2_unlock(station);
 
 	if (!trunk_ref) {
 		if (ast_strlen_zero(trunk_name))
@@ -6942,8 +7013,6 @@
 				"'%s' due to access controls.\n", trunk_name);
 		}
 		pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
-		ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);
 		return 0;
 	}
 
@@ -6972,7 +7041,7 @@
 			answer_trunk_chan(ringing_trunk->trunk->chan);
 			sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
 
-			free(ringing_trunk);
+			sla_ringing_trunk_destroy(ringing_trunk);
 
 			/* Queue up reprocessing ringing trunks, and then ringing stations again */
 			sla_queue_event(SLA_EVENT_RINGING_TRUNK);
@@ -6992,6 +7061,8 @@
 			.cond_lock = &cond_lock,
 			.cond = &cond,
 		};
+		ao2_ref(trunk_ref, 1);
+		ao2_ref(station, 1);
 		sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
 		/* Create a thread to dial the trunk and dump it into the conference.
 		 * However, we want to wait until the trunk has been dialed and the
@@ -7011,8 +7082,6 @@
 			pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
 			sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
 			trunk_ref->chan = NULL;
-			ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
-			sla_queue_event(SLA_EVENT_CHECK_RELOAD);
 			return 0;
 		}
 	}
@@ -7045,19 +7114,28 @@
 	
 	pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
 
-	ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
-	sla_queue_event(SLA_EVENT_CHECK_RELOAD);
-
 	return 0;
 }
 
+static void sla_trunk_ref_destructor(void *obj)
+{
+	struct sla_trunk_ref *trunk_ref = obj;
+
+	if (trunk_ref->trunk) {
+		ao2_ref(trunk_ref->trunk, -1);
+		trunk_ref->trunk = NULL;
+	}
+}
+
 static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
 {
 	struct sla_trunk_ref *trunk_ref;
 
-	if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
+	if (!(trunk_ref = ao2_alloc(sizeof(*trunk_ref), sla_trunk_ref_destructor))) {
 		return NULL;
-
+	}
+
+	ao2_ref(trunk, 1);
 	trunk_ref->trunk = trunk;
 
 	return trunk_ref;
@@ -7067,9 +7145,11 @@
 {
 	struct sla_ringing_trunk *ringing_trunk;
 
-	if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
+	if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) {
 		return NULL;
-	
+	}
+
+	ao2_ref(trunk, 1);
 	ringing_trunk->trunk = trunk;
 	ringing_trunk->ring_begin = ast_tvnow();
 
@@ -7082,6 +7162,16 @@
 	sla_queue_event(SLA_EVENT_RINGING_TRUNK);
 
 	return ringing_trunk;
+}
+
+static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk)
+{
+	if (ringing_trunk->trunk) {
+		ao2_ref(ringing_trunk->trunk, -1);
+		ringing_trunk->trunk = NULL;
+	}
+
+	ast_free(ringing_trunk);
 }
 
 enum {
@@ -7102,7 +7192,7 @@
 	char conf_name[MAX_CONFNUM];
 	struct ast_conference *conf;
 	struct ast_flags64 conf_flags = { 0 };
-	struct sla_trunk *trunk;
+	RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
 	struct sla_ringing_trunk *ringing_trunk;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(trunk_name);
@@ -7126,16 +7216,11 @@
 		}
 	}
 
-	AST_RWLIST_WRLOCK(&sla_trunks);
 	trunk = sla_find_trunk(args.trunk_name);
-	if (trunk)
-		ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
-	AST_RWLIST_UNLOCK(&sla_trunks);
 
 	if (!trunk) {
 		ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
 		return 0;
 	}
 
@@ -7143,8 +7228,6 @@
 		ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
 			args.trunk_name);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
-		ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
 		return 0;
 	}
 
@@ -7152,8 +7235,6 @@
 
 	if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
-		ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
 		return 0;
 	}
 
@@ -7161,8 +7242,6 @@
 	conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
 	if (!conf) {
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
-		ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
-		sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
 		return 0;
 	}
 	ast_set_flag64(&conf_flags, 
@@ -7196,46 +7275,37 @@
 	AST_LIST_TRAVERSE_SAFE_END;
 	ast_mutex_unlock(&sla.lock);
 	if (ringing_trunk) {
-		ast_free(ringing_trunk);
+		sla_ringing_trunk_destroy(ringing_trunk);
 		pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
 		/* Queue reprocessing of ringing trunks to make stations stop ringing
 		 * that shouldn't be ringing after this trunk stopped. */
 		sla_queue_event(SLA_EVENT_RINGING_TRUNK);
 	}
 
-	ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
-	sla_queue_event(SLA_EVENT_CHECK_RELOAD);	
-
 	return 0;
 }
 
 static enum ast_device_state sla_state(const char *data)
 {
 	char *buf, *station_name, *trunk_name;
-	struct sla_station *station;
+	RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
 	struct sla_trunk_ref *trunk_ref;
 	enum ast_device_state res = AST_DEVICE_INVALID;
 
 	trunk_name = buf = ast_strdupa(data);
 	station_name = strsep(&trunk_name, "_");
 
-	AST_RWLIST_RDLOCK(&sla_stations);
-	AST_LIST_TRAVERSE(&sla_stations, station, entry) {
-		if (strcasecmp(station_name, station->name))
-			continue;
-		AST_RWLIST_RDLOCK(&sla_trunks);
+	station = sla_find_station(station_name);
+	if (station) {
+		ao2_lock(station);
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
-			if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
+			if (!strcasecmp(trunk_name, trunk_ref->trunk->name)) {
+				res = sla_state_to_devstate(trunk_ref->state);
 				break;
-		}
-		if (!trunk_ref) {
-			AST_RWLIST_UNLOCK(&sla_trunks);
-			break;
-		}
-		res = sla_state_to_devstate(trunk_ref->state);
-		AST_RWLIST_UNLOCK(&sla_trunks);
-	}
-	AST_RWLIST_UNLOCK(&sla_stations);
+			}
+		}
+		ao2_unlock(station);
+	}
 
 	if (res == AST_DEVICE_INVALID) {
 		ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
@@ -7245,26 +7315,39 @@
 	return res;
 }
 
-static void destroy_trunk(struct sla_trunk *trunk)
-{
+static int sla_trunk_release_refs(void *obj, void *arg, int flags)
+{
+	struct sla_trunk *trunk = obj;
 	struct sla_station_ref *station_ref;
 
-	if (!ast_strlen_zero(trunk->autocontext))
-		ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
-
-	while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
-		ast_free(station_ref);
-
-	ast_string_field_free_memory(trunk);
-	ast_free(trunk);
-}
-
-static void destroy_station(struct sla_station *station)
-{
+	while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) {
+		ao2_ref(station_ref, -1);
+	}
+
+	return 0;
+}
+
+static int sla_station_release_refs(void *obj, void *arg, int flags)
+{
+	struct sla_station *station = obj;
 	struct sla_trunk_ref *trunk_ref;
 
+	while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) {
+		ao2_ref(trunk_ref, -1);
+	}
+
+	return 0;
+}
+
+static void sla_station_destructor(void *obj)
+{
+	struct sla_station *station = obj;
+
+	ast_debug(1, "sla_station destructor for '%s'\n", station->name);
+
 	if (!ast_strlen_zero(station->autocontext)) {
-		AST_RWLIST_RDLOCK(&sla_trunks);
+		struct sla_trunk_ref *trunk_ref;
+
 		AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
 			char exten[AST_MAX_EXTENSION];
 			char hint[AST_MAX_APP];
@@ -7275,31 +7358,43 @@
 			ast_context_remove_extension(station->autocontext, hint, 
 				PRIORITY_HINT, sla_registrar);
 		}
-		AST_RWLIST_UNLOCK(&sla_trunks);
-	}
-
-	while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
-		ast_free(trunk_ref);
+	}
+
+	sla_station_release_refs(station, NULL, 0);
 
 	ast_string_field_free_memory(station);
-	ast_free(station);
+}
+
+static int sla_trunk_hash(const void *obj, const int flags)
+{
+	const struct sla_trunk *trunk = obj;
+
+	return ast_str_case_hash(trunk->name);
+}
+
+static int sla_trunk_cmp(void *obj, void *arg, int flags)
+{
+	struct sla_trunk *trunk = obj, *trunk2 = arg;
+
+	return !strcasecmp(trunk->name, trunk2->name) ? CMP_MATCH | CMP_STOP : 0;
+}
+
+static int sla_station_hash(const void *obj, const int flags)
+{
+	const struct sla_station *station = obj;
+
+	return ast_str_case_hash(station->name);
+}
+
+static int sla_station_cmp(void *obj, void *arg, int flags)
+{
+	struct sla_station *station = obj, *station2 = arg;
+
+	return !strcasecmp(station->name, station2->name) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 static void sla_destroy(void)
 {
-	struct sla_trunk *trunk;
-	struct sla_station *station;
-
-	AST_RWLIST_WRLOCK(&sla_trunks);
-	while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
-		destroy_trunk(trunk);
-	AST_RWLIST_UNLOCK(&sla_trunks);
-
-	AST_RWLIST_WRLOCK(&sla_stations);
-	while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
-		destroy_station(station);
-	AST_RWLIST_UNLOCK(&sla_stations);
-
 	if (sla.thread != AST_PTHREADT_NULL) {
 		ast_mutex_lock(&sla.lock);
 		sla.stop = 1;
@@ -7313,6 +7408,15 @@
 
 	ast_mutex_destroy(&sla.lock);
 	ast_cond_destroy(&sla.cond);
+
+	ao2_callback(sla_trunks, 0, sla_trunk_release_refs, NULL);
+	ao2_callback(sla_stations, 0, sla_station_release_refs, NULL);
+
+	ao2_ref(sla_trunks, -1);
+	sla_trunks = NULL;
+
+	ao2_ref(sla_stations, -1);
+	sla_stations = NULL;
 }
 
 static int sla_check_device(const char *device)
@@ -7328,11 +7432,27 @@
 	return 0;
 }
 
+static void sla_trunk_destructor(void *obj)
+{
+	struct sla_trunk *trunk = obj;
+
+	ast_debug(1, "sla_trunk destructor for '%s'\n", trunk->name);
+
+	if (!ast_strlen_zero(trunk->autocontext)) {
+		ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
+	}
+
+	sla_trunk_release_refs(trunk, NULL, 0);
+
+	ast_string_field_free_memory(trunk);
+}
+
 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
 {
-	struct sla_trunk *trunk;
+	RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
 	struct ast_variable *var;
 	const char *dev;
+	int existing_trunk = 0;
 
 	if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
 		ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
@@ -7340,16 +7460,25 @@
 	}
 
 	if (sla_check_device(dev)) {
-		ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",

[... 1199 lines stripped ...]



More information about the asterisk-commits mailing list