[asterisk-commits] russell: branch 1.4 r80362 - in /branches/1.4: ./ channels/ doc/ include/aste...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Aug 22 15:21:36 CDT 2007


Author: russell
Date: Wed Aug 22 15:21:36 2007
New Revision: 80362

URL: http://svn.digium.com/view/asterisk?view=rev&rev=80362
Log:
Merge changes from team/russell/iax_refcount.

This set of changes fixes problems with the handling of iax2_user and iax2_peer
objects.  It was very possible for a thread to still hold a reference to one of
these objects while a reload operation tries to delete them.  The fix here is to
ensure that all references to these objects are tracked so that they can't go away
while still in use.

To accomplish this, I used the astobj2 reference counted object model.  This
code has been in one of Luigi Rizzo's branches for a long time and was primarily
developed by one of his students, Marta Carbone.  I wanted to go ahead and bring
this in to 1.4 because there are other problems similar to the ones fixed by these
changes, so we might as well go ahead and use the new astobj if we're going to go
through all of the work necessary to fix the problems.

As a nice side benefit of these changes, peer and user handling got more efficient.
Using astobj2 lets us not hold the container lock for peers or users nearly as long
while iterating.  Also, by changing a define at the top of chan_iax2.c, the objects
will be distributed in a hash table, drastically increasing lookup speed in these
containers, which will have a very big impact on systems that have a large number of
users or peers.

The use of the hash table will be made the default in trunk.  It is not the default
in 1.4 because it changes the behavior slightly.  Previously, since peers and users
were stored in memory in the same order they were specified in the configuration file,
you could influence peer and user matching order based on the order they are specified
in the configuration.  The hash table does not guarantee any order in the container,
so this behavior will be going away.  It just means that you have to be a little
more careful ensuring that peers and users are matched explicitly and not forcing
chan_iax2 to have to guess which user is the right one based on secret, host, and
access list settings, instead of simply using the username.

If you have any questions, feel free to ask on the asterisk-dev list.

Added:
    branches/1.4/include/asterisk/astobj2.h
      - copied unchanged from r80361, team/russell/iax_refcount/include/asterisk/astobj2.h
    branches/1.4/main/astobj2.c
      - copied, changed from r80361, team/russell/iax_refcount/main/astobj2.c
Modified:
    branches/1.4/UPGRADE.txt
    branches/1.4/channels/chan_iax2.c
    branches/1.4/doc/iax.txt
    branches/1.4/include/asterisk/strings.h
    branches/1.4/main/Makefile

Modified: branches/1.4/UPGRADE.txt
URL: http://svn.digium.com/view/asterisk/branches/1.4/UPGRADE.txt?view=diff&rev=80362&r1=80361&r2=80362
==============================================================================
--- branches/1.4/UPGRADE.txt (original)
+++ branches/1.4/UPGRADE.txt Wed Aug 22 15:21:36 2007
@@ -314,6 +314,21 @@
 
 The IAX2 channel:
 
+* It is possible that previous configurations depended on the order in which
+  peers and users were specified in iax.conf for forcing the order in which
+  chan_iax2 matched against them.  This behavior is going away and is considered
+  deprecated in this version.  Avoid having ambiguous peer and user entries and
+  to make things easy on yourself, always set the "username" option for users
+  so that the remote end can match on that exactly instead of trying to infer
+  which user you want based on host.
+
+  If you would like to go ahead and use the new behavior which doesn't use the
+  order in the config file to influence matching order, then change the 
+  MAX_PEER_BUCKETS define in chan_iax2.c to a value greater than one.  An
+  example is provided there.  By changing this, you will get *much* better
+  performance on systems that do a lot of peer and user lookups as they will be
+  stored in memory in a much more efficient manner.
+
 * The "mailboxdetail" option has been deprecated.  Previously, if this option
   was not enabled, the 2 byte MSGCOUNT information element would be set to all
   1's to indicate there there is some number of messages waiting.  With this

Modified: branches/1.4/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/branches/1.4/channels/chan_iax2.c?view=diff&rev=80362&r1=80361&r2=80362
==============================================================================
--- branches/1.4/channels/chan_iax2.c (original)
+++ branches/1.4/channels/chan_iax2.c Wed Aug 22 15:21:36 2007
@@ -94,6 +94,7 @@
 #include "asterisk/netsock.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/astobj2.h"
 
 #include "iax2.h"
 #include "iax2-parser.h"
@@ -305,7 +306,6 @@
 	struct ast_ha *ha;
 	struct iax2_context *contexts;
 	struct ast_variable *vars;
-	AST_LIST_ENTRY(iax2_user) entry;
 };
 
 struct iax2_peer {
@@ -358,7 +358,6 @@
 	int smoothing;					/*!< Sample over how many units to determine historic ms */
 	
 	struct ast_ha *ha;
-	AST_LIST_ENTRY(iax2_peer) entry;
 };
 
 #define IAX2_TRUNK_PREFACE (sizeof(struct iax_frame) + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr))
@@ -632,9 +631,24 @@
 	int count;
 } iaxq;
 
-static AST_LIST_HEAD_STATIC(users, iax2_user);
-
-static AST_LIST_HEAD_STATIC(peers, iax2_peer);
+/*!
+ * This module will get much higher performance when doing a lot of
+ * user and peer lookups if the number of buckets is increased from 1.
+ * However, to maintain old behavior for Asterisk 1.4, these are set to
+ * 1 by default.  When using multiple buckets, search order through these
+ * containers is considered random, so you will not be able to depend on
+ * the order the entires are specified in iax.conf for matching order. */
+#ifdef LOW_MEMORY
+#define MAX_PEER_BUCKETS 1
+/* #define MAX_PEER_BUCKETS 17 */
+#else
+#define MAX_PEER_BUCKETS 1
+/* #define MAX_PEER_BUCKETS 563 */
+#endif
+static ao2_container *peers;
+
+#define MAX_USER_BUCKETS MAX_PEER_BUCKETS
+static ao2_container *users;
 
 static struct ast_firmware_list {
 	struct iax_firmware *wares;
@@ -675,7 +689,6 @@
 static void reg_source_db(struct iax2_peer *p);
 static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
 
-static void destroy_peer(struct iax2_peer *peer);
 static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt);
 
 #define IAX_IOSTATE_IDLE		0
@@ -828,7 +841,6 @@
 static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
 static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
 static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, time_t regtime);
-static void destroy_user(struct iax2_user *user);
 static void prune_peers(void);
 
 static const struct ast_channel_tech iax2_tech = {
@@ -1043,51 +1055,112 @@
 }
 
 /*!
+ * \note The only member of the peer passed here guaranteed to be set is the name field
+ */
+static int peer_hash_cb(const void *obj, const int flags)
+{
+	const struct iax2_peer *peer = obj;
+
+	return ast_str_hash(peer->name);
+}
+
+/*!
+ * \note The only member of the peer passed here guaranteed to be set is the name field
+ */
+static int peer_cmp_cb(void *obj, void *arg, int flags)
+{
+	struct iax2_peer *peer = obj, *peer2 = arg;
+
+	return !strcasecmp(peer->name, peer2->name) ? CMP_MATCH : 0;
+}
+
+/*!
+ * \note The only member of the user passed here guaranteed to be set is the name field
+ */
+static int user_hash_cb(const void *obj, const int flags)
+{
+	const struct iax2_user *user = obj;
+
+	return ast_str_hash(user->name);
+}
+
+/*!
+ * \note The only member of the user passed here guaranteed to be set is the name field
+ */
+static int user_cmp_cb(void *obj, void *arg, int flags)
+{
+	struct iax2_user *user = obj, *user2 = arg;
+
+	return !strcasecmp(user->name, user2->name) ? CMP_MATCH : 0;
+}
+
+/*!
  * \note This funtion calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call it with a pvt lock held.
  */
 static struct iax2_peer *find_peer(const char *name, int realtime) 
 {
 	struct iax2_peer *peer = NULL;
-
-	/* Grab peer from linked list */
-	AST_LIST_LOCK(&peers);
-	AST_LIST_TRAVERSE(&peers, peer, entry) {
-		if (!strcasecmp(peer->name, name)) {
-			break;
-		}
-	}
-	AST_LIST_UNLOCK(&peers);
+	struct iax2_peer tmp_peer = {
+		.name = name,
+	};
+
+	peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
 
 	/* Now go for realtime if applicable */
 	if(!peer && realtime)
 		peer = realtime_peer(name, NULL);
+
 	return peer;
 }
 
-static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int lockpeer)
+static struct iax2_peer *peer_ref(struct iax2_peer *peer)
+{
+	ao2_ref(peer, +1);
+	return peer;
+}
+
+static inline struct iax2_peer *peer_unref(struct iax2_peer *peer)
+{
+	ao2_ref(peer, -1);
+	return NULL;
+}
+
+static inline struct iax2_user *user_ref(struct iax2_user *user)
+{
+	ao2_ref(user, +1);
+	return user;
+}
+
+static inline struct iax2_user *user_unref(struct iax2_user *user)
+{
+	ao2_ref(user, -1);
+	return NULL;
+}
+
+static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
 {
 	struct iax2_peer *peer = NULL;
 	int res = 0;
-
-	if (lockpeer)
-		AST_LIST_LOCK(&peers);
-	AST_LIST_TRAVERSE(&peers, peer, entry) {
+	ao2_iterator i;
+
+	i = ao2_iterator_init(peers, 0);
+	while ((peer = ao2_iterator_next(&i))) {
 		if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
 		    (peer->addr.sin_port == sin.sin_port)) {
 			ast_copy_string(host, peer->name, len);
+			peer_unref(peer);
 			res = 1;
 			break;
 		}
-	}
-	if (lockpeer)
-		AST_LIST_UNLOCK(&peers);
+		peer_unref(peer);
+	}
+
 	if (!peer) {
 		peer = realtime_peer(NULL, &sin);
 		if (peer) {
 			ast_copy_string(host, peer->name, len);
-			if (ast_test_flag(peer, IAX_TEMPONLY))
-				destroy_peer(peer);
+			peer_unref(peer);
 			res = 1;
 		}
 	}
@@ -1095,7 +1168,7 @@
 	return res;
 }
 
-static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, const char *host)
+static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host)
 {
 	struct chan_iax2_pvt *tmp;
 	jb_conf jbconf;
@@ -1251,7 +1324,7 @@
 /*!
  * \note Calling this function while holding another pvt lock can cause a deadlock.
  */
-static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer, int sockfd)
+static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd)
 {
 	int res = 0;
 	int x;
@@ -1288,7 +1361,7 @@
 		 * this is just checking for a peer that has that IP/port and
 		 * assuming that we have a user of the same name.  This isn't always
 		 * correct, but it will be changed if needed after authentication. */
-		if (!iax2_getpeername(*sin, host, sizeof(host), lockpeer))
+		if (!iax2_getpeername(*sin, host, sizeof(host)))
 			snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 		gettimeofday(&now, NULL);
 		for (x=1;x<TRUNK_CALL_START;x++) {
@@ -1302,7 +1375,7 @@
 			ast_log(LOG_WARNING, "No more space\n");
 			return 0;
 		}
-		iaxs[x] = new_iax(sin, lockpeer, host);
+		iaxs[x] = new_iax(sin, host);
 		update_max_nontrunk();
 		if (iaxs[x]) {
 			if (option_debug && iaxdebug)
@@ -1804,18 +1877,19 @@
 
 static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
 {
-	struct iax2_user *user = NULL;
-
 	/* Decrement AUTHREQ count if needed */
 	if (ast_test_flag(pvt, IAX_MAXAUTHREQ)) {
-		AST_LIST_LOCK(&users);
-		AST_LIST_TRAVERSE(&users, user, entry) {
-			if (!strcmp(user->name, pvt->username)) {
-				user->curauthreq--;
-				break;
-			}
-		}
-		AST_LIST_UNLOCK(&users);
+		struct iax2_user *user;
+		struct iax2_user tmp_user = {
+			.name = pvt->username,
+		};
+
+		user = ao2_find(users, &tmp_user, OBJ_POINTER);
+		if (user) {
+			ast_atomic_fetchadd_int(&user->curauthreq, -1);
+			user_unref(user);	
+		}
+
 		ast_clear_flag(pvt, IAX_MAXAUTHREQ);
 	}
 	/* No more pings or lagrq's */
@@ -2054,6 +2128,7 @@
 		} else {
 			ast_cli(fd, "SORRY peer %s is not eligible for this operation.\n", argv[3]);
 		}
+		peer_unref(peer);
 	} else {
 		ast_cli(fd, "SORRY peer %s was not found in the cache.\n", argv[3]);
 	}
@@ -2180,8 +2255,7 @@
 		ast_cli(fd, "%s\n",status);
 		ast_cli(fd, "  Qualify      : every %dms when OK, every %dms when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, peer->smoothing ? "On" : "Off");
 		ast_cli(fd,"\n");
-		if (ast_test_flag(peer, IAX_TEMPONLY))
-			destroy_peer(peer);
+		peer_unref(peer);
 	} else {
 		ast_cli(fd,"Peer %s not found.\n", argv[3]);
 		ast_cli(fd,"\n");
@@ -2193,20 +2267,23 @@
 static char *complete_iax2_show_peer(const char *line, const char *word, int pos, int state)
 {
 	int which = 0;
-	struct iax2_peer *p = NULL;
+	struct iax2_peer *peer;
 	char *res = NULL;
 	int wordlen = strlen(word);
+	ao2_iterator i;
 
 	/* 0 - iax2; 1 - show; 2 - peer; 3 - <peername> */
-	if (pos == 3) {
-		AST_LIST_LOCK(&peers);
-		AST_LIST_TRAVERSE(&peers, p, entry) {
-			if (!strncasecmp(p->name, word, wordlen) && ++which > state) {
-				res = ast_strdup(p->name);
-				break;
-			}
-		}
-		AST_LIST_UNLOCK(&peers);
+	if (pos != 3)
+		return NULL;
+
+	i = ao2_iterator_init(peers, 0);
+	while ((peer = ao2_iterator_next(&i))) {
+		if (!strncasecmp(peer->name, word, wordlen) && ++which > state) {
+			res = ast_strdup(peer->name);
+			peer_unref(peer);
+			break;
+		}
+		peer_unref(peer);
 	}
 
 	return res;
@@ -2620,8 +2697,7 @@
 			if (strcasecmp(tmp->value, "friend") &&
 			    strcasecmp(tmp->value, "peer")) {
 				/* Whoops, we weren't supposed to exist! */
-				destroy_peer(peer);
-				peer = NULL;
+				peer = peer_unref(peer);
 				break;
 			} 
 		} else if (!strcasecmp(tmp->name, "regseconds")) {
@@ -2648,9 +2724,7 @@
 				ast_sched_del(sched, peer->expire);
 			peer->expire = ast_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, (void*)peer->name);
 		}
-		AST_LIST_LOCK(&peers);
-		AST_LIST_INSERT_HEAD(&peers, peer, entry);
-		AST_LIST_UNLOCK(&peers);
+		ao2_link(peers, peer_ref(peer));
 		if (ast_test_flag(peer, IAX_DYNAMIC))
 			reg_source_db(peer);
 	} else {
@@ -2707,9 +2781,7 @@
 
 	if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
 		ast_set_flag(user, IAX_RTCACHEFRIENDS);
-		AST_LIST_LOCK(&users);
-		AST_LIST_INSERT_HEAD(&users, user, entry);
-		AST_LIST_UNLOCK(&users);
+		ao2_link(users, user_ref(user));
 	} else {
 		ast_set_flag(user, IAX_TEMPONLY);	
 	}
@@ -2753,6 +2825,7 @@
 	struct ast_hostent ahp;
 	struct hostent *hp;
 	struct iax2_peer *peer;
+	int res = -1;
 
 	ast_clear_flag(cai, IAX_SENDANI | IAX_TRUNK);
 	cai->sockfd = defaultsockfd;
@@ -2778,18 +2851,12 @@
 	cai->found = 1;
 	
 	/* if the peer has no address (current or default), return failure */
-	if (!(peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr)) {
-		if (ast_test_flag(peer, IAX_TEMPONLY))
-			destroy_peer(peer);
-		return -1;
-	}
+	if (!(peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr))
+		goto return_unref;
 
 	/* if the peer is being monitored and is currently unreachable, return failure */
-	if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0))) {
-		if (ast_test_flag(peer, IAX_TEMPONLY))
-			destroy_peer(peer);
-		return -1;
-	}
+	if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0)))
+		goto return_unref;
 
 	ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
 	cai->maxtime = peer->maxms;
@@ -2817,9 +2884,7 @@
 			*key++ = '\0';
 		if (!key || ast_db_get(family, key, cai->secret, sizeof(cai->secret))) {
 			ast_log(LOG_WARNING, "Unable to retrieve database password for family/key '%s'!\n", peer->dbsecret);
-			if (ast_test_flag(peer, IAX_TEMPONLY))
-				destroy_peer(peer);
-			return -1;
+			goto return_unref;
 		}
 	}
 
@@ -2831,10 +2896,12 @@
 		sin->sin_port = peer->defaddr.sin_port;
 	}
 
-	if (ast_test_flag(peer, IAX_TEMPONLY))
-		destroy_peer(peer);
-
-	return 0;
+	res = 0;
+
+return_unref:
+	peer_unref(peer);
+
+	return res;
 }
 
 static void __auto_congest(void *nothing)
@@ -3410,18 +3477,20 @@
 	
 static int iax2_getpeertrunk(struct sockaddr_in sin)
 {
-	struct iax2_peer *peer = NULL;
+	struct iax2_peer *peer;
 	int res = 0;
-
-	AST_LIST_LOCK(&peers);
-	AST_LIST_TRAVERSE(&peers, peer, entry) {
+	ao2_iterator i;
+
+	i = ao2_iterator_init(peers, 0);
+	while ((peer = ao2_iterator_next(&i))) {
 		if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
 		    (peer->addr.sin_port == sin.sin_port)) {
 			res = ast_test_flag(peer, IAX_TRUNK);
+			peer_unref(peer);
 			break;
 		}
-	}
-	AST_LIST_UNLOCK(&peers);
+		peer_unref(peer);
+	}
 
 	return res;
 }
@@ -4139,6 +4208,7 @@
 	struct iax2_user *user = NULL;
 	char auth[90];
 	char *pstr = "";
+	ao2_iterator i;
 
 	switch (argc) {
 	case 5:
@@ -4155,8 +4225,9 @@
 	}
 
 	ast_cli(fd, FORMAT, "Username", "Secret", "Authen", "Def.Context", "A/C","Codec Pref");
-	AST_LIST_LOCK(&users);
-	AST_LIST_TRAVERSE(&users, user, entry) {
+	i = ao2_iterator_init(users, 0);
+	for (user = ao2_iterator_next(&i); user; 
+		user_unref(user), user = ao2_iterator_next(&i)) {
 		if (havepattern && regexec(&regexbuf, user->name, 0, NULL, 0))
 			continue;
 		
@@ -4177,9 +4248,7 @@
 		ast_cli(fd, FORMAT2, user->name, auth, user->authmethods, 
 			user->contexts ? user->contexts->context : context,
 			user->ha ? "Yes" : "No", pstr);
-		
-	}
-	AST_LIST_UNLOCK(&users);
+	}
 
 	if (havepattern)
 		regfree(&regexbuf);
@@ -4197,6 +4266,7 @@
 	int online_peers = 0;
 	int offline_peers = 0;
 	int unmonitored_peers = 0;
+	ao2_iterator i;
 
 #define FORMAT2 "%-15.15s  %-15.15s %s  %-15.15s  %-8s  %s %-10s%s"
 #define FORMAT "%-15.15s  %-15.15s %s  %-15.15s  %-5d%s  %s %-10s%s"
@@ -4245,8 +4315,9 @@
 	else
 		ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", term);
 
-	AST_LIST_LOCK(&peers);
-	AST_LIST_TRAVERSE(&peers, peer, entry) {
+	i = ao2_iterator_init(peers, 0);
+	for (peer = ao2_iterator_next(&i); peer; 
+		peer_unref(peer), peer = ao2_iterator_next(&i)) {
 		char nm[20];
 		char status[20];
 		char srch[2000];
@@ -4295,7 +4366,6 @@
 				peer->encmethods ? "(E)" : "   ", status, term);
 		total_peers++;
 	}
-	AST_LIST_UNLOCK(&peers);
 
 	if (s)
 		astman_append(s,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
@@ -4761,6 +4831,7 @@
 	int bestscore = 0;
 	int gotcapability = 0;
 	struct ast_variable *v = NULL, *tmpvar = NULL;
+	ao2_iterator i;
 
 	if (!iaxs[callno])
 		return res;
@@ -4815,8 +4886,8 @@
 		return res;
 	}
 	/* Search the userlist for a compatible entry, and fill in the rest */
-	AST_LIST_LOCK(&users);
-	AST_LIST_TRAVERSE(&users, user, entry) {
+	i = ao2_iterator_init(users, 0);
+	while ((user = ao2_iterator_next(&i))) {
 		if ((ast_strlen_zero(iaxs[callno]->username) ||				/* No username specified */
 			!strcmp(iaxs[callno]->username, user->name))	/* Or this username specified */
 			&& ast_apply_ha(user->ha, sin) 	/* Access is permitted from this IP */
@@ -4824,6 +4895,8 @@
 			     apply_context(user->contexts, iaxs[callno]->context))) {			/* Context is permitted */
 			if (!ast_strlen_zero(iaxs[callno]->username)) {
 				/* Exact match, stop right now. */
+				if (best)
+					user_unref(best);
 				best = user;
 				break;
 			} else if (ast_strlen_zero(user->secret) && ast_strlen_zero(user->inkeys)) {
@@ -4832,13 +4905,19 @@
 					/* There was host authentication and we passed, bonus! */
 					if (bestscore < 4) {
 						bestscore = 4;
+						if (best)
+							user_unref(best);
 						best = user;
+						continue;
 					}
 				} else {
 					/* No host access, but no secret, either, not bad */
 					if (bestscore < 3) {
 						bestscore = 3;
+						if (best)
+							user_unref(best);
 						best = user;
+						continue;
 					}
 				}
 			} else {
@@ -4846,26 +4925,31 @@
 					/* Authentication, but host access too, eh, it's something.. */
 					if (bestscore < 2) {
 						bestscore = 2;
+						if (best)
+							user_unref(best);
 						best = user;
+						continue;
 					}
 				} else {
 					/* Authentication and no host access...  This is our baseline */
 					if (bestscore < 1) {
 						bestscore = 1;
+						if (best)
+							user_unref(best);
 						best = user;
+						continue;
 					}
 				}
 			}
 		}
-	}
-	AST_LIST_UNLOCK(&users);
+		user_unref(user);
+	}
 	user = best;
 	if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
 		user = realtime_user(iaxs[callno]->username);
 		if (user && !ast_strlen_zero(iaxs[callno]->context) &&			/* No context specified */
 		    !apply_context(user->contexts, iaxs[callno]->context)) {		/* Context is permitted */
-			destroy_user(user);
-			user = NULL;
+			user = user_unref(user);
 		}
 	}
 	if (user) {
@@ -4944,9 +5028,8 @@
 				ast_string_field_set(iaxs[callno], secret, buf);
 		} else
 			ast_string_field_set(iaxs[callno], secret, user->secret);
-		if (ast_test_flag(user, IAX_TEMPONLY))
-			destroy_user(user);
 		res = 0;
+		user = user_unref(user);
 	}
 	ast_set2_flag(iaxs[callno], iax2_getpeertrunk(*sin), IAX_TRUNK);	
 	return res;
@@ -4992,7 +5075,6 @@
  */
 static int authenticate_request(int call_num)
 {
-	struct iax2_user *user = NULL;
 	struct iax_ie_data ied;
 	int res = -1, authreq_restrict = 0;
 	char challenge[10];
@@ -5002,17 +5084,18 @@
 
 	/* If an AUTHREQ restriction is in place, make sure we can send an AUTHREQ back */
 	if (ast_test_flag(p, IAX_MAXAUTHREQ)) {
-		AST_LIST_LOCK(&users);
-		AST_LIST_TRAVERSE(&users, user, entry) {
-			if (!strcmp(user->name, p->username)) {
-				if (user->curauthreq == user->maxauthreq)
-					authreq_restrict = 1;
-				else
-					user->curauthreq++;
-				break;
-			}
-		}
-		AST_LIST_UNLOCK(&users);
+		struct iax2_user *user, tmp_user = {
+			.name = p->username,	
+		};
+
+		user = ao2_find(users, &tmp_user, OBJ_POINTER);
+		if (user) {
+			if (user->curauthreq == user->maxauthreq)
+				authreq_restrict = 1;
+			else
+				user->curauthreq++;
+			user = user_unref(user);
+		}
 	}
 
 	/* If the AUTHREQ limit test failed, send back an error */
@@ -5051,21 +5134,19 @@
 	char rsasecret[256] = "";
 	int res = -1; 
 	int x;
-	struct iax2_user *user = NULL;
-
-	AST_LIST_LOCK(&users);
-	AST_LIST_TRAVERSE(&users, user, entry) {
-		if (!strcmp(user->name, p->username))
-			break;
-	}
+	struct iax2_user *user, tmp_user = {
+		.name = p->username,	
+	};
+
+	user = ao2_find(users, &tmp_user, OBJ_POINTER);
 	if (user) {
 		if (ast_test_flag(p, IAX_MAXAUTHREQ)) {
-			user->curauthreq--;
+			ast_atomic_fetchadd_int(&user->curauthreq, -1);
 			ast_clear_flag(p, IAX_MAXAUTHREQ);
 		}
 		ast_string_field_set(p, host, user->name);
-	}
-	AST_LIST_UNLOCK(&users);
+		user = user_unref(user);
+	}
 
 	if (!ast_test_flag(&p->state, IAX_STATE_AUTHENTICATED))
 		return res;
@@ -5127,11 +5208,12 @@
 	char md5secret[256] = "";
 	char rsasecret[256] = "";
 	char secret[256] = "";
-	struct iax2_peer *p;
+	struct iax2_peer *p = NULL;
 	struct ast_key *key;
 	char *keyn;
 	int x;
 	int expire = 0;
+	int res = -1;
 
 	ast_clear_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED | IAX_STATE_UNCHANGED);
 	/* iaxs[callno]->peer[0] = '\0'; not necc. any more-- stringfield is pre-inited to null string */
@@ -5158,23 +5240,19 @@
 	if (!p || !iaxs[callno]) {
 		if (authdebug && !p)
 			ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
-		return -1;
+		goto return_unref;
 	}
 
 	if (!ast_test_flag(p, IAX_DYNAMIC)) {
 		if (authdebug)
 			ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
+		goto return_unref;
 	}
 
 	if (!ast_apply_ha(p->ha, sin)) {
 		if (authdebug)
 			ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
+		goto return_unref;
 	}
 	if (!inaddrcmp(&p->addr, sin))
 		ast_set_flag(&iaxs[callno]->state, IAX_STATE_UNCHANGED);
@@ -5200,16 +5278,12 @@
 			if (!keyn) {
 				if (authdebug)
 					ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
-				if (ast_test_flag(p, IAX_TEMPONLY))
-					destroy_peer(p);
-				return -1;
+				goto return_unref;
 			}
 		} else {
 			if (authdebug)
 				ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer);
-			if (ast_test_flag(p, IAX_TEMPONLY))
-				destroy_peer(p);
-			return -1;
+			goto return_unref;
 		}
 	} else if (!ast_strlen_zero(md5secret) && (p->authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(iaxs[callno]->challenge)) {
 		struct MD5Context md5;
@@ -5233,26 +5307,20 @@
 		} else {
 			if (authdebug)
 				ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret);
-			if (ast_test_flag(p, IAX_TEMPONLY))
-				destroy_peer(p);
-			return -1;
+			goto return_unref;
 		}
 	} else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) {
 		/* They've provided a plain text password and we support that */
 		if (strcmp(secret, p->secret)) {
 			if (authdebug)
 				ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
-			if (ast_test_flag(p, IAX_TEMPONLY))
-				destroy_peer(p);
-			return -1;
+			goto return_unref;
 		} else
 			ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
 	} else if (!ast_strlen_zero(md5secret) || !ast_strlen_zero(secret)) {
 		if (authdebug)
 			ast_log(LOG_NOTICE, "Inappropriate authentication received\n");
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
+		goto return_unref;
 	}
 	ast_string_field_set(iaxs[callno], peer, peer);
 	/* Choose lowest expiry number */
@@ -5261,10 +5329,13 @@
 
 	ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
 
-	if (ast_test_flag(p, IAX_TEMPONLY))
-		destroy_peer(p);
-
-	return 0;
+	res = 0;
+
+return_unref:
+	if (p)
+		peer_unref(p);
+
+	return res;
 }
 
 static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, aes_encrypt_ctx *ecx, aes_decrypt_ctx *dcx)
@@ -5351,8 +5422,8 @@
 		/* Normal password authentication */
 		res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, &p->ecx, &p->dcx);
 	} else {
-		AST_LIST_LOCK(&peers);
-		AST_LIST_TRAVERSE(&peers, peer, entry) {
+		ao2_iterator i = ao2_iterator_init(peers, 0);
+		while ((peer = ao2_iterator_next(&i))) {
 			if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name)) 
 			    /* No peer specified at our end, or this is the peer */
 			    && (ast_strlen_zero(peer->username) || (!strcmp(peer->username, p->username)))
@@ -5361,11 +5432,11 @@
 			    /* No specified host, or this is our host */
 				) {
 				res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
+				peer_unref(peer);
 				if (!res)
 					break;	
 			}
 		}
-		AST_LIST_UNLOCK(&peers);
 		if (!peer) {
 			/* We checked our list and didn't find one.  It's unlikely, but possible, 
 			   that we're trying to authenticate *to* a realtime peer */
@@ -5374,13 +5445,11 @@
 			if ((peer = realtime_peer(peer_name, NULL))) {
 				ast_mutex_lock(&iaxsl[callno]);
 				if (!(p = iaxs[callno])) {
-					if (ast_test_flag(peer, IAX_TEMPONLY))
-						destroy_peer(peer);
+					peer_unref(peer);
 					return -1;
 				}
 				res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
-				if (ast_test_flag(peer, IAX_TEMPONLY))
-					destroy_peer(peer);
+				peer_unref(peer);
 			}
 			if (!peer) {
 				ast_mutex_lock(&iaxsl[callno]);
@@ -5684,42 +5753,36 @@
 static void __expire_registry(void *data)
 {
 	char *name = data;
-	struct iax2_peer *p = NULL;
-
-	/* Go through and grab this peer... and if it needs to be removed... then do it */
-	AST_LIST_LOCK(&peers);
-	AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, p, entry) {
-		if (!strcasecmp(p->name, name)) {
-			p->expire = -1;
-			break;
-		}
-	}
-	AST_LIST_TRAVERSE_SAFE_END
-	AST_LIST_UNLOCK(&peers);
-
-	/* Peer is already gone for whatever reason */
-	if (!p)
+	struct iax2_peer *peer = NULL;
+	struct iax2_peer tmp_peer = {
+		.name = name,
+	};
+
+	peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
+	if (!peer)
 		return;
 
-	ast_log(LOG_DEBUG, "Expiring registration for peer '%s'\n", p->name);
-	if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
-		realtime_update_peer(p->name, &p->addr, 0);
-	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", p->name);
+	peer->expire = -1;
+
+	ast_log(LOG_DEBUG, "Expiring registration for peer '%s'\n", peer->name);
+	if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(peer, IAX_TEMPONLY|IAX_RTCACHEFRIENDS)))
+		realtime_update_peer(peer->name, &peer->addr, 0);
+	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
 	/* Reset the address */
-	memset(&p->addr, 0, sizeof(p->addr));
+	memset(&peer->addr, 0, sizeof(peer->addr));
 	/* Reset expiry value */
-	p->expiry = min_reg_expire;
-	if (!ast_test_flag(p, IAX_TEMPONLY))
-		ast_db_del("IAX/Registry", p->name);
-	register_peer_exten(p, 0);
-	ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
+	peer->expiry = min_reg_expire;
+	if (!ast_test_flag(peer, IAX_TEMPONLY))
+		ast_db_del("IAX/Registry", peer->name);
+	register_peer_exten(peer, 0);
+	ast_device_state_changed("IAX2/%s", peer->name); /* Activate notification */
 	if (iax2_regfunk)
-		iax2_regfunk(p->name, 0);
-
-	if (ast_test_flag(p, IAX_RTAUTOCLEAR)) {
-		ast_set_flag(p, IAX_DELME);
-		prune_peers();
-	}
+		iax2_regfunk(peer->name, 0);
+
+	if (ast_test_flag(peer, IAX_RTAUTOCLEAR))
+		ao2_unlink(peers, peer);
+
+	peer_unref(peer);
 }
 
 static int expire_registry(void *data)
@@ -5786,6 +5849,7 @@
 	char data[80];
 	int version;
 	const char *peer_name;
+	int res = -1;
 
 	memset(&ied, 0, sizeof(ied));
 
@@ -5799,11 +5863,8 @@
 		return -1;
 	}
 	ast_mutex_lock(&iaxsl[callno]);
-	if (!iaxs[callno]) {
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
-	}
+	if (!iaxs[callno])
+		goto return_unref;
 
 	if (ast_test_flag((&globalflags), IAX_RTUPDATE) && (ast_test_flag(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
 		if (sin->sin_addr.s_addr) {
@@ -5844,9 +5905,8 @@
 
 	/* Make sure our call still exists, an INVAL at the right point may make it go away */
 	if (!iaxs[callno]) {
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return 0;
+		res = 0;
+		goto return_unref;
 	}
 
 	/* Store socket fd */
@@ -5893,9 +5953,13 @@
 	version = iax_check_version(devtype);
 	if (version) 
 		iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
-	if (ast_test_flag(p, IAX_TEMPONLY))
-		destroy_peer(p);
-	return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
+
+	res = 0;
+
+return_unref:
+	peer_unref(p);
+
+	return res ? res : send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
 }
 
 static int registry_authrequest(int callno)
@@ -5904,6 +5968,7 @@
 	struct iax2_peer *p;
 	char challenge[10];
 	const char *peer_name;
+	int res = -1;
 
 	peer_name = ast_strdupa(iaxs[callno]->peer);
 
@@ -5911,28 +5976,29 @@
 	ast_mutex_unlock(&iaxsl[callno]);
 	p = find_peer(peer_name, 1);
 	ast_mutex_lock(&iaxsl[callno]);
-	if (!iaxs[callno]) {
-		if (p && ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return -1;
-	}
-	if (p) {
-		memset(&ied, 0, sizeof(ied));
-		iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods);
-		if (p->authmethods & (IAX_AUTH_RSA | IAX_AUTH_MD5)) {
-			/* Build the challenge */
-			snprintf(challenge, sizeof(challenge), "%d", (int)ast_random());
-			ast_string_field_set(iaxs[callno], challenge, challenge);
-			/* snprintf(iaxs[callno]->challenge, sizeof(iaxs[callno]->challenge), "%d", (int)ast_random()); */
-			iax_ie_append_str(&ied, IAX_IE_CHALLENGE, iaxs[callno]->challenge);
-		}
-		iax_ie_append_str(&ied, IAX_IE_USERNAME, peer_name);
-		if (ast_test_flag(p, IAX_TEMPONLY))
-			destroy_peer(p);
-		return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);;
-	} 
-	ast_log(LOG_WARNING, "No such peer '%s'\n", peer_name);
-	return 0;
+	if (!iaxs[callno])
+		goto return_unref;
+	if (!p) {
+		ast_log(LOG_WARNING, "No such peer '%s'\n", peer_name);
+		goto return_unref;
+	}
+	
+	memset(&ied, 0, sizeof(ied));
+	iax_ie_append_short(&ied, IAX_IE_AUTHMETHODS, p->authmethods);
+	if (p->authmethods & (IAX_AUTH_RSA | IAX_AUTH_MD5)) {
+		/* Build the challenge */
+		snprintf(challenge, sizeof(challenge), "%d", (int)ast_random());
+		ast_string_field_set(iaxs[callno], challenge, challenge);
+		iax_ie_append_str(&ied, IAX_IE_CHALLENGE, iaxs[callno]->challenge);
+	}
+	iax_ie_append_str(&ied, IAX_IE_USERNAME, peer_name);
+
+	res = 0;
+
+return_unref:
+	peer_unref(p);
+
+	return res ? res : send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);;
 }
 
 static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_in *sin)
@@ -6643,7 +6709,7 @@
 		}
 
 		/* This is a video frame, get call number */
-		fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, 1, fd);
+		fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd);
 		minivid = 1;
 	} else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000)) {
 		unsigned char metatype;
@@ -6701,7 +6767,7 @@
 				/* Stop if we don't have enough data */
 				if (len > res)
 					break;
-				fr->callno = find_callno(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, 1, fd);
+				fr->callno = find_callno(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, fd);
 				if (fr->callno) {
 					ast_mutex_lock(&iaxsl[fr->callno]);
 					/* If it's a valid call, deliver the contents.  If not, we
@@ -6788,7 +6854,7 @@
 	}
 
 	if (!fr->callno)
-		fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, 1, fd);
+		fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd);
 
 	if (fr->callno > 0)
 		ast_mutex_lock(&iaxsl[fr->callno]);
@@ -8239,7 +8305,7 @@
 	if (!reg->callno) {
 		if (option_debug)
 			ast_log(LOG_DEBUG, "Allocate call number\n");
-		reg->callno = find_callno(0, 0, &reg->addr, NEW_FORCE, 1, defaultsockfd);
+		reg->callno = find_callno(0, 0, &reg->addr, NEW_FORCE, defaultsockfd);
 		if (reg->callno < 1) {
 			ast_log(LOG_WARNING, "Unable to create call for registration\n");
 			return -1;
@@ -8299,7 +8365,7 @@
 	memset(&ied, 0, sizeof(ied));
 	iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos);
 
-	callno = find_callno(0, 0, &sin, NEW_FORCE, 1, cai.sockfd);
+	callno = find_callno(0, 0, &sin, NEW_FORCE, cai.sockfd);
 	if (!callno)
 		return -1;
 
@@ -8411,6 +8477,15 @@
 	return 0;
 }
 
+static int iax2_poke_peer_cb(void *obj, void *arg, int flags)
+{
+	struct iax2_peer *peer = obj;
+
+	iax2_poke_peer(peer, 0);
+
+	return 0;
+}
+
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
 {
 	if (!peer->maxms || !peer->addr.sin_addr.s_addr) {
@@ -8430,7 +8505,7 @@
 	}
 	if (heldcall)
 		ast_mutex_unlock(&iaxsl[heldcall]);
-	peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, 0, peer->sockfd);
+	peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd);
 	if (heldcall)
 		ast_mutex_lock(&iaxsl[heldcall]);
 	if (peer->callno < 1) {
@@ -8504,7 +8579,7 @@
 	if (pds.port)
 		sin.sin_port = htons(atoi(pds.port));
 
-	callno = find_callno(0, 0, &sin, NEW_FORCE, 1, cai.sockfd);
+	callno = find_callno(0, 0, &sin, NEW_FORCE, cai.sockfd);
 	if (callno < 1) {
 		ast_log(LOG_WARNING, "Unable to create call\n");
 		*cause = AST_CAUSE_CONGESTION;
@@ -8801,7 +8876,31 @@
 	}
 }
 
-		
+static void peer_destructor(void *obj)
+{
+	struct iax2_peer *peer = obj;
+
+	ast_free_ha(peer->ha);
+
+	/* Delete it, it needs to disappear */
+	if (peer->expire > -1)
+		ast_sched_del(sched, peer->expire);
+	if (peer->pokeexpire > -1)
+		ast_sched_del(sched, peer->pokeexpire);
+	if (peer->callno > 0) {
+		ast_mutex_lock(&iaxsl[peer->callno]);
+		iax2_destroy(peer->callno);
+		ast_mutex_unlock(&iaxsl[peer->callno]);
+	}
+
+	register_peer_exten(peer, 0);
+
+	if (peer->dnsmgr)
+		ast_dnsmgr_release(peer->dnsmgr);
+
+	ast_string_field_free_pools(peer);
+}
+
 /*! \brief Create peer structure based on configuration */
 static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly)
 {
@@ -8810,38 +8909,31 @@
 	int maskfound=0;
 	int found=0;
 	int firstpass=1;
-
-	AST_LIST_LOCK(&peers);
+	struct iax2_peer tmp_peer = {
+		.name = name,
+	};
+
 	if (!temponly) {
-		AST_LIST_TRAVERSE(&peers, peer, entry) {
-			if (!strcmp(peer->name, name)) {	
-				if (!ast_test_flag(peer, IAX_DELME))
-					firstpass = 0;
-				break;
-			}
-		}
-	} else
-		peer = NULL;	
+		peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
+		if (peer && !ast_test_flag(peer, IAX_DELME))
+			firstpass = 0;
+	}
+
 	if (peer) {
 		found++;
 		if (firstpass) {
 			oldha = peer->ha;
 			peer->ha = NULL;
 		}
-		AST_LIST_REMOVE(&peers, peer, entry);
-		AST_LIST_UNLOCK(&peers);
- 	} else {
-		AST_LIST_UNLOCK(&peers);
-		if ((peer = ast_calloc(1, sizeof(*peer)))) {
-			peer->expire = -1;
-			peer->pokeexpire = -1;
-			peer->sockfd = defaultsockfd;
-			if (ast_string_field_init(peer, 32)) {
-				free(peer);
-				peer = NULL;
-			}
-		}
-	}
+		ao2_unlink(peers, peer);
+	} else if ((peer = ao2_alloc(sizeof(*peer), peer_destructor))) {
+		peer->expire = -1;
+		peer->pokeexpire = -1;
+		peer->sockfd = defaultsockfd;
+		if (ast_string_field_init(peer, 32))
+			peer = peer_unref(peer);
+	}
+
 	if (peer) {
 		if (firstpass) {
 			ast_copy_flags(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF);
@@ -8927,8 +9019,7 @@
 					ast_clear_flag(peer, IAX_DYNAMIC);
 					if (ast_dnsmgr_lookup(v->value, &peer->addr.sin_addr, &peer->dnsmgr)) {
 						ast_string_field_free_pools(peer);
-						free(peer);
-						return NULL;
+						return peer_unref(peer);
 					}
 					if (!peer->addr.sin_port)
 						peer->addr.sin_port = htons(IAX_DEFAULT_PORTNO);
@@ -8938,8 +9029,7 @@
 			} else if (!strcasecmp(v->name, "defaultip")) {
 				if (ast_get_ip(&peer->defaddr, v->value)) {
 					ast_string_field_free_pools(peer);
-					free(peer);
-					return NULL;
+					return peer_unref(peer);
 				}
 			} else if (!strcasecmp(v->name, "sourceaddress")) {
 				peer_set_srcaddr(peer, v->value);
@@ -9045,6 +9135,19 @@
 	return peer;
 }
 
+static void user_destructor(void *obj)
+{
+	struct iax2_user *user = obj;
+
+	ast_free_ha(user->ha);
+	free_context(user->contexts);
+	if(user->vars) {
+		ast_variables_destroy(user->vars);
+		user->vars = NULL;
+	}
+	ast_string_field_free_pools(user);
+}
+
 /*! \brief Create in-memory user structure from configuration */
 static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly)
 {
@@ -9057,18 +9160,15 @@
 	int oldcurauthreq = 0;
 	char *varname = NULL, *varval = NULL;
 	struct ast_variable *tmpvar = NULL;
-	
-	AST_LIST_LOCK(&users);
+	struct iax2_user tmp_user = {
+		.name = name,
+	};
+
 	if (!temponly) {
-		AST_LIST_TRAVERSE(&users, user, entry) {
-			if (!strcmp(user->name, name)) {	
-				if (!ast_test_flag(user, IAX_DELME))
-					firstpass = 0;
-				break;

[... 424 lines stripped ...]



More information about the asterisk-commits mailing list