[svn-commits] qwell: branch qwell/ari_channel_mute r394145 - in /team/qwell/ari_channel_mut...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Jul 11 13:35:47 CDT 2013


Author: qwell
Date: Thu Jul 11 13:35:43 2013
New Revision: 394145

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

........
  r393857 | file | 2013-07-08 16:26:37 -0500 (Mon, 08 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-08 16:27:18 -0500 (Mon, 08 Jul 2013) | 2 lines
  
  Tweak log message slightly.
........
  r393870 | file | 2013-07-09 06:05:48 -0500 (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 14:38:00 -0500 (Tue, 09 Jul 2013) | 1 line
  
  Fix some stasis doxygen comments.
........
  r393897 | mmichelson | 2013-07-09 15:07:21 -0500 (Tue, 09 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-09 16:06:21 -0500 (Tue, 09 Jul 2013) | 1 line
  
  Fix printf NULL string (null) substituion for NULL config framework default.
........
  r393919 | qwell | 2013-07-09 16:40:38 -0500 (Tue, 09 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-09 20:56:15 -0500 (Tue, 09 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 08:50:48 -0500 (Wed, 10 Jul 2013) | 1 line
  
  Corrected api-docs for channel variables
........
  r393987 | dlee | 2013-07-10 12:13:21 -0500 (Wed, 10 Jul 2013) | 1 line
  
  Document the 400 error response for originate
........
  r394004 | file | 2013-07-10 15:02:59 -0500 (Wed, 10 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-10 17:26:13 -0500 (Wed, 10 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-10 21:02:48 -0500 (Wed, 10 Jul 2013) | 1 line
  
  Fixed some CEL test crashes
........
  r394050 | dlee | 2013-07-10 23:34:49 -0500 (Wed, 10 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.
........
  r394065 | dlee | 2013-07-11 08:56:26 -0500 (Thu, 11 Jul 2013) | 1 line
  
  Apply defaults to ari.conf's general section
........
  r394076 | dlee | 2013-07-11 09:39:55 -0500 (Thu, 11 Jul 2013) | 11 lines
  
  Change ARI user config to use a type field
  
  When I initially wrote the configuration support for ARI users, I
  determined the section type by a category prefix (i.e., [user-admin]).
  
  This is neither idiomatic Asterisk configuration, nor is it really
  that user friendly. This patch replaces the category prefix with a
  type field in the section, which is much cleaner.
  
  Review: https://reviewboard.asterisk.org/r/2664/
........
  r394089 | dlee | 2013-07-11 10:37:51 -0500 (Thu, 11 Jul 2013) | 12 lines
  
  Correct test_cel cleanup.
  
  When I corrected the CEL test crash in r394037, I didn't quite pay attention
  to how the globals and locals were being shuffled around in the cleanup
  callback. I removed the nulling of the global variables, which caused them
  to be double cleaned.
  
  This patch puts the global nulling code back (since the vars are cleaned up
  by RAII_VARs), and removes the explicit ao2_cleanup() (since they were no-ops,
  because the variables had just been nulled).
........
  r394103 | file | 2013-07-11 11:23:41 -0500 (Thu, 11 Jul 2013) | 2 lines
  
  Tweak the subscription failure warning message to include endpoint name and context.
........

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

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

Propchange: team/qwell/ari_channel_mute/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/qwell/ari_channel_mute/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Propchange: team/qwell/ari_channel_mute/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Jul 11 13:35:43 2013
@@ -1,1 +1,1 @@
-/trunk:1-393847
+/trunk:1-394144

Modified: team/qwell/ari_channel_mute/apps/app_meetme.c
URL: http://svnview.digium.com/svn/asterisk/team/qwell/ari_channel_mute/apps/app_meetme.c?view=diff&rev=394145&r1=394144&r2=394145
==============================================================================
--- team/qwell/ari_channel_mute/apps/app_meetme.c (original)
+++ team/qwell/ari_channel_mute/apps/app_meetme.c Thu Jul 11 13:35:43 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;
-

[... 1388 lines stripped ...]



More information about the svn-commits mailing list