[asterisk-commits] murf: branch murf/bug11210 r89548 - /team/murf/bug11210/channels/chan_sip.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sun Nov 25 00:32:19 CST 2007


Author: murf
Date: Sun Nov 25 00:32:19 2007
New Revision: 89548

URL: http://svn.digium.com/view/asterisk?view=rev&rev=89548
Log:
Good time to checkpoint. compiles, but it needs a ton of work still. Roughed in most traversals and searches. Need to make sure refs are properly incr. and decr.; the right kind of traversals/locks, etc.

Modified:
    team/murf/bug11210/channels/chan_sip.c

Modified: team/murf/bug11210/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/channels/chan_sip.c?view=diff&rev=89548&r1=89547&r2=89548
==============================================================================
--- team/murf/bug11210/channels/chan_sip.c (original)
+++ team/murf/bug11210/channels/chan_sip.c Sun Nov 25 00:32:19 2007
@@ -1127,7 +1127,10 @@
  * the container and individual items, and functions to add/remove
  * references to the individual items.
  */
-static struct sip_pvt *dialoglist = NULL;
+/* static struct sip_pvt *dialoglist = NULL; */
+
+struct ao2_container *dialogs;
+
 
 /*! \brief Protect the SIP dialog list (of sip_pvt's) */
 AST_MUTEX_DEFINE_STATIC(dialoglock);
@@ -1209,6 +1212,7 @@
 
 	/* things that don't belong in flags */
 	char is_realtime;		/*!< this is a 'realtime' user */
+	char theMark;          /*!< moved out of the ASTOBJ fields; that which bears theMark should be deleted! */
 
 	int amaflags;			/*!< AMA flags for billing */
 	int callingpres;		/*!< Calling id presentation */
@@ -1280,6 +1284,7 @@
 	char rt_fromcontact;		/*!< P: copy fromcontact from realtime */
 	char host_dynamic;		/*!< P: Dynamic Peers register with Asterisk */
 	char selfdestruct;		/*!< P: Automatic peers need to destruct themselves */
+	char theMark;           /*!< moved out of ASTOBJ into struct proper; That with bears theMark should be deleted! */
 
 	int expire;			/*!<  When to expire this peer registration */
 	int capability;			/*!<  Codec capability */
@@ -1359,8 +1364,10 @@
 
 #ifdef LOW_MEMORY
 #define MAX_PEER_BUCKETS 17
+#define MAX_DIALOG_BUCKETS 17
 #else
 #define MAX_PEER_BUCKETS 563
+#define MAX_DIALOG_BUCKETS 563
 #endif
 
 #define MAX_USER_BUCKETS MAX_PEER_BUCKETS
@@ -1370,6 +1377,7 @@
 
 /*! \brief  The peer list: Peers and Friends */
 struct ao2_container *peers;
+struct ao2_container *peers_by_ip;
 
 /*! \brief  The register list: Other SIP proxies we register with and place calls to */
 static struct ast_register_list {
@@ -1404,7 +1412,10 @@
 {
 	const struct sip_peer *peer = obj;
 
-	return ast_str_hash(peer->name);
+	if (ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT))
+		return peer->addr.sin_addr.s_addr;
+	else 
+		return peer->addr.sin_addr.s_addr + peer->addr.sin_port;
 }
 
 /*!
@@ -1413,8 +1424,17 @@
 static int peer_ipcmp_cb(void *obj, void *arg, int flags)
 {
 	struct sip_peer *peer = obj, *peer2 = arg;
-
-	return !strcasecmp(peer->name, peer2->name) ? CMP_MATCH : 0;
+	
+	if (peer->addr.sin_addr.s_addr != peer2->addr.sin_addr.s_addr)
+		return 0;
+	
+	if (!ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT) && !ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) {
+		if (peer->addr.sin_port == peer2->addr.sin_port)
+			return CMP_MATCH;
+		else
+			return 0;
+	}
+	return CMP_MATCH;
 }
 
 /*!
@@ -1440,21 +1460,21 @@
 /*!
  * \note The only member of the user passed here guaranteed to be set is the name field
  */
-static int reg_hash_cb(const void *obj, const int flags)
-{
-	const struct sip_registry *reg = obj;
-
-	return ast_str_hash(reg->name);
+static int dialog_hash_cb(const void *obj, const int flags)
+{
+	const struct sip_pvt *pvt = obj;
+
+	return ast_str_hash(pvt->callid);
 }
 
 /*!
  * \note The only member of the user passed here guaranteed to be set is the name field
  */
-static int reg_cmp_cb(void *obj, void *arg, int flags)
-{
-	struct sip_registry *reg = obj, *reg2 = arg;
-
-	return !strcasecmp(reg->name, reg2->name) ? CMP_MATCH : 0;
+static int dialog_cmp_cb(void *obj, void *arg, int flags)
+{
+	struct sip_registry *pvt = obj, *pvt2 = arg;
+
+	return !strcasecmp(pvt->callid, pvt2->callid) ? CMP_MATCH : 0;
 }
 
 static int temp_pvt_init(void *);
@@ -1656,7 +1676,7 @@
 static int expire_register(const void *data);
 static void *do_monitor(void *data);
 static int restart_monitor(void);
-static int sip_addrcmp(char *name, struct sockaddr_in *sin);	/* Support for peer matching */
+/* static int sip_addrcmp(char *name, struct sockaddr_in *sin);	Support for peer matching */
 static int sip_refer_allocate(struct sip_pvt *p);
 static void ast_quiet_chan(struct ast_channel *chan);
 static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
@@ -1734,7 +1754,9 @@
 static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime);
 static int update_call_counter(struct sip_pvt *fup, int event);
 static void sip_destroy_peer(struct sip_peer *peer);
+static void sip_destroy_peer_fn(void *peer);
 static void sip_destroy_user(struct sip_user *user);
+static void sip_destroy_user_fn(void *user);
 static int sip_poke_peer(struct sip_peer *peer);
 static void set_peer_defaults(struct sip_peer *peer);
 static struct sip_peer *temp_peer(const char *name);
@@ -3011,6 +3033,11 @@
 
 	while ((mailbox = AST_LIST_REMOVE_HEAD(&peer->mailboxes, entry)))
 		destroy_mailbox(mailbox);
+}
+
+static void sip_destroy_peer_fn(void *peer)
+{
+	sip_destroy_peer(peer);
 }
 
 /*! \brief Destroy peer object from memory */
@@ -3235,6 +3262,7 @@
 				global_rtautoclear * 1000, expire_register, (void *) peer);
 		}
 		ao2_link(peers, peer);
+		ao2_link(peers_by_ip, peer);
 	} else {
 		peer->is_realtime = 1;
 	}
@@ -3248,6 +3276,9 @@
 	return peer;
 }
 
+
+
+#ifdef NO_MORE
 /*! \brief Support routine for find_peer */
 static int sip_addrcmp(char *name, struct sockaddr_in *sin)
 {
@@ -3257,6 +3288,7 @@
 					(ast_test_flag(&p->flags[0], SIP_INSECURE_PORT) &&
 					(p->addr.sin_addr.s_addr == sin->sin_addr.s_addr)));
 }
+#endif
 
 /*! \brief Locate peer by name or ip address 
  *	This is used on incoming SIP message to find matching peer on ip
@@ -3267,17 +3299,25 @@
 	struct sip_peer tmp_peer;
 	
 	ast_copy_string(tmp_peer.name, peer, sizeof(tmp_peer.name));
+	tmp_peer.addr.sin_addr.s_addr = sin->sin_addr.s_addr;
+	tmp_peer.addr.sin_port = sin->sin_port;
 	
 	if (peer)
 		p = ao2_find(peers, &tmp_peer, OBJ_POINTER);
 	else /* search by addr? */
-		p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp);
+		p = ao2_find(peers_by_ip, &tmp_peer, OBJ_POINTER); /* WAS:  p = ASTOBJ_CONTAINER_FIND_FULL(&peerl, sin, name, sip_addr_hashfunc, 1, sip_addrcmp); */
 
 	if (!p && realtime)
 		p = realtime_peer(peer, sin);
 
 	return p;
 }
+
+static void sip_destroy_user_fn(void *user)
+{
+	sip_destroy_user(user);
+}
+
 
 /*! \brief Remove user object from in-memory storage */
 static void sip_destroy_user(struct sip_user *user)
@@ -3348,7 +3388,7 @@
 	struct sip_user *u;
 
 	ast_copy_string(tmp.name, name, sizeof(tmp.name));
-	u = ao2_find(users, &tmp_user, OBJ_POINTER);
+	u = ao2_find(users, &tmp, OBJ_POINTER);
 
 	if (!u && realtime)
 		u = realtime_user(name);
@@ -3700,7 +3740,7 @@
 /*! \brief Execute destruction of SIP dialog structure, release memory */
 static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
 {
-	struct sip_pvt *cur, *prev = NULL;
+	struct sip_pvt *cur;
 	struct sip_pkt *cp;
 
 	if (sip_debug_test_pvt(p))
@@ -3771,12 +3811,7 @@
 	/* Lock dialog list before removing ourselves from the list */
 	if (lockdialoglist)
 		dialoglist_lock();
-	for (prev = NULL, cur = dialoglist; cur; prev = cur, cur = cur->next) {
-		if (cur == p) {
-			UNLINK(cur, dialoglist, prev);
-			break;
-		}
-	}
+	cur = ao2_find(dialogs, p, OBJ_POINTER|OBJ_UNLINK);
 	if (lockdialoglist)
 		dialoglist_unlock();
 	if (!cur) {
@@ -3917,6 +3952,12 @@
 	} else /* u must be set */
 		unref_user(u);
 	return 0;
+}
+
+
+static void sip_destroy_fn(void *p)
+{
+	sip_destroy(p);
 }
 
 /*! \brief Destroy SIP call structure.
@@ -5072,7 +5113,7 @@
 {
 	struct sip_pvt *p;
 
-	if (!(p = ast_calloc(1, sizeof(*p))))
+	if (!(p = ao2_alloc(sizeof(*p), sip_destroy_fn)))
 		return NULL;
 
 	if (ast_string_field_init(p, 512)) {
@@ -5191,10 +5232,9 @@
 	ast_string_field_set(p, context, default_context);
 
 	/* Add to active dialog list */
-	dialoglist_lock();
-	p->next = dialoglist;
-	dialoglist = dialog_ref(p);
-	dialoglist_unlock();
+	
+	ao2_link(dialogs, p);
+	
 	ast_debug(1, "Allocating new SIP dialog for %s - %s (%s)\n", callid ? callid : "(No Call-ID)", sip_methods[intended_method].text, p->rtp ? "With RTP" : "No RTP");
 	return p;
 }
@@ -5214,6 +5254,7 @@
 	const char *from = get_header(req, "From");
 	const char *to = get_header(req, "To");
 	const char *cseq = get_header(req, "Cseq");
+	struct sip_pvt tmp_dialog, *sip_pvt_ptr;
 
 	/* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
 	/* get_header always returns non-NULL so we must use ast_strlen_zero() */
@@ -5247,45 +5288,44 @@
 			return NULL;
 		}
 	}
-
+	
 	dialoglist_lock();
-	for (p = dialoglist; p; p = p->next) {
-		/* In pedantic, we do not want packets with bad syntax to be connected to a PVT */
-		int found = FALSE;
-		if (ast_strlen_zero(p->callid))
-			continue;
-		if (req->method == SIP_REGISTER)
-			found = (!strcmp(p->callid, callid));
-		else 
-			found = (!strcmp(p->callid, callid) && 
-			(!pedanticsipchecking || !tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, tag))) ;
-
-		ast_debug(5, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag);
-
-		/* If we get a new request within an existing to-tag - check the to tag as well */
-		if (pedanticsipchecking && found  && req->method != SIP_RESPONSE) {	/* SIP Request */
-			if (p->tag[0] == '\0' && totag[0]) {
-				/* We have no to tag, but they have. Wrong dialog */
-				found = FALSE;
-			} else if (totag[0]) {			/* Both have tags, compare them */
-				if (strcmp(totag, p->tag)) {
-					found = FALSE;		/* This is not our packet */
+	if (!ast_string_field_init(&tmp_dialog, 100)) {
+		ast_string_field_set(&tmp_dialog, callid, callid);
+	
+		sip_pvt_ptr = ao2_find(dialogs, &tmp_dialog, OBJ_POINTER);
+		if (sip_pvt_ptr) {
+			if (!(!pedanticsipchecking || !tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, tag)))
+			{
+				ao2_ref(sip_pvt_ptr,-1); /* basically, if the extra pedanticssipchecking constraints don't pan out,
+											the the match is defeated. There should be no other entry that matches
+											the callid */
+				sip_pvt_ptr = 0;
+			}
+			/* If we get a new request within an existing to-tag - check the to tag as well */
+			if (pedanticsipchecking && sip_pvt_ptr  && req->method != SIP_RESPONSE) {	/* SIP Request */
+				if (sip_pvt_ptr->tag[0] == '\0' && totag[0]) {
+					/* We have no to tag, but they have. Wrong dialog */
+					sip_pvt_ptr = NULL;
+				} else if (totag[0]) {			/* Both have tags, compare them */
+					if (strcmp(totag, sip_pvt_ptr->tag)) {
+						sip_pvt_ptr = NULL;		/* This is not our packet */
+					}
 				}
+				if (!sip_pvt_ptr)
+					ast_debug(5, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", p->callid, totag, sip_methods[req->method].text);
 			}
-			if (!found)
-				ast_debug(5, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", p->callid, totag, sip_methods[req->method].text);
-		}
-
-
-		if (found) {
+		}
+		ast_string_field_free_memory(&tmp_dialog);
+		if (sip_pvt_ptr) {
 			/* Found the call */
-			sip_pvt_lock(p);
+			sip_pvt_lock(sip_pvt_ptr);
 			dialoglist_unlock();
-			return p;
+			return sip_pvt_ptr;
 		}
 	}
 	dialoglist_unlock();
-	
+
 	/* See if the method is capable of creating a dialog */
 	if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) {
 		if (intended_method == SIP_REFER) {
@@ -5375,7 +5415,7 @@
 			return -1;
 		}
 	}
-	if (!(reg = ao2_alloc(sizeof(*reg), sip_registry_destroy))) {
+	if (!(reg = ast_calloc(1,sizeof(*reg)))) {
 		ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry entry\n");
 		return -1;
 	}
@@ -5387,6 +5427,7 @@
 	}
 
 	regobjs++;
+	ASTOBJ_INIT(reg);
 	ast_string_field_set(reg, callback, callback);
 	if (!ast_strlen_zero(username))
 		ast_string_field_set(reg, username, username);
@@ -8707,7 +8748,9 @@
 
 	if (peer->selfdestruct ||
 	    ast_test_flag(&peer->flags[1], SIP_PAGE2_RTAUTOCLEAR)) {
-		peer = ao2_find(peers, peer, OBJ_POINTER|OBJ_UNLINK);	/* Remove from peer list */
+		struct sip_peer *peer3;
+		peer3 = ao2_find(peers, peer, OBJ_POINTER|OBJ_UNLINK);	/* Remove from peer list */
+		peer3 = ao2_find(peers_by_ip, peer, OBJ_POINTER|OBJ_UNLINK);	/* Remove from peer list */
 		unref_peer(peer);		/* Remove from memory */
 	}
 
@@ -9748,52 +9791,42 @@
 */
 static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag) 
 {
-	struct sip_pvt *sip_pvt_ptr;
+	struct sip_pvt *sip_pvt_ptr, tmp_dialog;
 
 
 	if (totag)
 		ast_debug(4, "Looking for callid %s (fromtag %s totag %s)\n", callid, fromtag ? fromtag : "<no fromtag>", totag ? totag : "<no totag>");
 
 	/* Search dialogs and find the match */
-	dialoglist_lock();
-	for (sip_pvt_ptr = dialoglist; sip_pvt_ptr; sip_pvt_ptr = sip_pvt_ptr->next) {
-		if (!strcmp(sip_pvt_ptr->callid, callid)) {
-			int match = 1;
+	if (!ast_string_field_init(&tmp_dialog, 100)) {
+		ast_string_field_set(&tmp_dialog, callid, callid);
+	
+		sip_pvt_ptr = ao2_find(dialogs, &tmp_dialog, OBJ_POINTER);
+		if (sip_pvt_ptr) {
 			char *ourtag = sip_pvt_ptr->tag;
-
 			/* Go ahead and lock it (and its owner) before returning */
 			sip_pvt_lock(sip_pvt_ptr);
 
-			/* Check if tags match. If not, this is not the call we want
-			   (With a forking SIP proxy, several call legs share the
-			   call id, but have different tags)
-			*/
 			if (pedanticsipchecking && (strcmp(fromtag, sip_pvt_ptr->theirtag) || (!ast_strlen_zero(totag) && strcmp(totag, ourtag))))
-				match = 0;
-
-			if (!match) {
+			{
 				sip_pvt_unlock(sip_pvt_ptr);
-				continue;
+				ast_debug(4, "Matched %s call for callid=%s - But the pedantic check rejected the match; their tag is %s Our tag is %s\n",
+						  ast_test_flag(&sip_pvt_ptr->flags[0], SIP_OUTGOING) ? "OUTGOING": "INCOMING", sip_pvt_ptr->callid, 
+						  sip_pvt_ptr->theirtag, sip_pvt_ptr->tag);
+				return 0;
 			}
-
-			if (totag)				 
+			sip_pvt_unlock(sip_pvt_ptr);
+			
+			if (totag)
 				ast_debug(4, "Matched %s call - their tag is %s Our tag is %s\n",
 					ast_test_flag(&sip_pvt_ptr->flags[0], SIP_OUTGOING) ? "OUTGOING": "INCOMING",
 					sip_pvt_ptr->theirtag, sip_pvt_ptr->tag);
-
-			/* deadlock avoidance... */
-			while (sip_pvt_ptr->owner && ast_channel_trylock(sip_pvt_ptr->owner)) {
-				sip_pvt_unlock(sip_pvt_ptr);
-				usleep(1);
-				sip_pvt_lock(sip_pvt_ptr);
-			}
-			break;
-		}
-	}
-	dialoglist_unlock();
-	if (!sip_pvt_ptr)
-		ast_debug(4, "Found no match for callid %s to-tag %s from-tag %s\n", callid, totag, fromtag);
-	return sip_pvt_ptr;
+		}
+		
+		ast_string_field_free_memory(&tmp_dialog);
+		return sip_pvt_ptr;
+	}
+	return NULL;
 }
 
 /*! \brief Call transfer support (the REFER method) 
@@ -10816,17 +10849,17 @@
 
 	while ((user = ao2_iterator_next(&i))) {
 
-		if (havepattern && regexec(&regexbuf, iterator->name, 0, NULL, 0)) {
-			ao2_unlock(iterator);
+		if (havepattern && regexec(&regexbuf, user->name, 0, NULL, 0)) {
+			ao2_unlock(user);
 			continue;
 		}
 
-		ast_cli(a->fd, FORMAT, iterator->name, 
-			iterator->secret, 
-			iterator->accountcode,
-			iterator->context,
-			cli_yesno(iterator->ha != NULL),
-			nat2str(ast_test_flag(&iterator->flags[0], SIP_NAT)));
+		ast_cli(a->fd, FORMAT, user->name, 
+			user->secret, 
+			user->accountcode,
+			user->context,
+			cli_yesno(user->ha != NULL),
+			nat2str(ast_test_flag(&user->flags[0], SIP_NAT)));
 	}
 
 	if (havepattern)
@@ -11072,9 +11105,9 @@
 	if (a->argc != 3)
 		return CLI_SHOWUSAGE;
 	ast_cli(a->fd, "-= User objects: %d static, %d realtime =-\n\n", suserobjs, ruserobjs);
-	ao2_callback(users, 0, user_dump_func, &fd);
+	ao2_callback(users, 0, user_dump_func, &a->fd);
 	ast_cli(a->fd, "-= Peer objects: %d static, %d realtime, %d autocreate =-\n\n", speerobjs, rpeerobjs, apeerobjs);
-	ao2_callback(users, 0, peer_dump_func, &fd);
+	ao2_callback(users, 0, peer_dump_func, &a->fd);
 	ast_cli(a->fd, "-= Registry objects: %d =-\n\n", regobjs);
 	ASTOBJ_CONTAINER_DUMP(a->fd, tmp, sizeof(tmp), &regl);
 	return CLI_SUCCESS;
@@ -11147,6 +11180,27 @@
 			ast_context_destroy(ast_context_find(stalecontext), "SIP");
 	}
 }
+
+static int peer_prune_marked_func(void *userobj, void *arg, int flags)
+{
+	struct sip_peer *peer = userobj;
+	if (peer->theMark) {
+		ao2_unlink(peers,peer);
+		ao2_ref(peer,-1);
+	}
+	return 0;
+}
+
+static int user_prune_marked_func(void *userobj, void *arg, int flags)
+{
+	struct sip_user *user = userobj;
+	if (user->theMark) {
+		ao2_unlink(users,user);
+		ao2_ref(user,-1);
+	}
+	return 0;
+}
+
 
 /*! \brief Remove temporary realtime objects from memory (CLI) */
 static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -11242,12 +11296,12 @@
 					continue;
 				};
 				if (ast_test_flag(&pi->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
-					ASTOBJ_MARK(pi);
+					pi->theMark = 1;
 					pruned++;
 				}
 			}
 			if (pruned) {
-				ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, sip_destroy_peer);
+				ao2_callback(peers, 0, peer_prune_marked_func, 0);
 				ast_cli(a->fd, "%d peers pruned.\n", pruned);
 			} else
 				ast_cli(a->fd, "No peers found to prune.\n");
@@ -11263,12 +11317,12 @@
 					continue;
 				};
 				if (ast_test_flag(&ui->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
-					ASTOBJ_MARK(iterator);
+					ui->theMark = 1;
 					pruned++;
 				}
-			} while (0) );
+			}
 			if (pruned) {
-				ASTOBJ_CONTAINER_PRUNE_MARKED(&userl, sip_destroy_user);
+				ao2_callback(users, 0, user_prune_marked_func, 0);
 				ast_cli(a->fd, "%d users pruned.\n", pruned);
 			} else
 				ast_cli(a->fd, "No users found to prune.\n");
@@ -11282,6 +11336,7 @@
 				if (!ast_test_flag(&peer->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
 					ast_cli(a->fd, "Peer '%s' is not a Realtime peer, cannot be pruned.\n", name);
 					ao2_link(peers, peer);
+					ao2_link(peers_by_ip, peer);
 				} else
 					ast_cli(a->fd, "Peer '%s' pruned.\n", name);
 				unref_peer(peer);
@@ -12053,7 +12108,7 @@
 				cur->subscribed == MWI_NOTIFICATION ? "<none>" : ast_extension_state2str(cur->laststate), 
 				subscription_type2str(cur->subscribed),
 				cur->subscribed == MWI_NOTIFICATION ? S_OR(mailbox_str->str, "<none>") : "<none>"
-);
+				);
 			arg->numchans++;
 		}
 
@@ -12067,8 +12122,8 @@
  */
 static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	struct sip_pvt *cur;
 	struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 };
+
 
 	if (cmd == CLI_INIT) {
 		e->command = "sip show {channels|subscriptions}";
@@ -12090,12 +12145,8 @@
 		ast_cli(arg.fd, FORMAT3, "Peer", "User", "Call ID", "Extension", "Last state", "Type", "Mailbox");
 
 	/* iterate on the container and invoke the callback on each item */
-	dialoglist_lock();
-	for (cur = dialoglist; cur; cur = cur->next) {
-		show_channels_cb(cur, &arg, 0);
-	}
-	dialoglist_unlock();
-
+	ao2_callback(dialogs, 0, show_channels_cb, 0);
+	
 	/* print summary information */
 	ast_cli(arg.fd, "%d active SIP %s%s\n", arg.numchans,
 		(arg.subscriptions ? "subscription" : "dialog"),
@@ -12111,26 +12162,27 @@
  * given position. As many functions of this kind, each invokation has
  * O(state) time complexity so be careful in using it.
  */
+
+
 static char *complete_sipch(const char *line, const char *word, int pos, int state)
 {
 	int which=0;
 	struct sip_pvt *cur;
 	char *c = NULL;
 	int wordlen = strlen(word);
-
-	dialoglist_lock();
-	for (cur = dialoglist; cur; cur = cur->next) {
+	struct ao2_iterator i;
+
+	i = ao2_iterator_init(dialogs, 0);
+	
+	while ((cur = ao2_iterator_next(&i))) {
 		if (!strncasecmp(word, cur->callid, wordlen) && ++which > state) {
 			c = ast_strdup(cur->callid);
+			ao2_ref(cur,-1);
 			break;
 		}
-	}
-	dialoglist_unlock();
+		ao2_ref(cur,-1);
+	}
 	return c;
-}
-
-static int peer_complete_func(void *obj, void *arg, int flags)
-{
 }
 
 
@@ -12148,7 +12200,7 @@
 		if (!strncasecmp(word, peer->name, wordlen) &&
 				(!flags2 || ast_test_flag(&peer->flags[1], flags2)) &&
 				++which > state)
-			result = ast_strdup(iterator->name);
+			result = ast_strdup(peer->name);
 		if (result)
 			break;
 	}
@@ -12161,15 +12213,18 @@
        char *result = NULL;
        int wordlen = strlen(word);
        int which = 0;
-
-       ASTOBJ_CONTAINER_TRAVERSE(&peerl, !result, do {
-               ASTOBJ_WRLOCK(iterator); /* was WRLOCK */
-               if (!strncasecmp(word, iterator->name, wordlen) &&
-                               (!flags2 || ast_test_flag(&iterator->flags[1], flags2)) &&
-                               ++which > state && iterator->expire > 0)
-                       result = ast_strdup(iterator->name);
-               ao2_unlock(iterator);
-       } while(0) );
+	   struct ao2_iterator i;
+	   struct sip_peer *peer;
+
+	   i = ao2_iterator_init(peers, 0);
+	   while ((peer = ao2_iterator_next(&i))) {
+		   if (!strncasecmp(word, peer->name, wordlen) &&
+			   (!flags2 || ast_test_flag(&peer->flags[1], flags2)) &&
+			   ++which > state && peer->expire > 0)
+			   result = ast_strdup(peer->name);
+		   if (result)
+			   break;
+       }
        return result;
 }
 
@@ -12206,17 +12261,23 @@
 	char *result = NULL;
 	int wordlen = strlen(word);
 	int which = 0;
-
-	ASTOBJ_CONTAINER_TRAVERSE(&userl, !result, do {
+	struct ao2_iterator i;
+	struct sip_user *user;
+
+	i = ao2_iterator_init(users, 0);
+
+	while ((user = ao2_iterator_next(&i))) {
 		/* locking of the object is not required because only the name and flags are being compared */
-		if (!strncasecmp(word, iterator->name, wordlen)) {
-			if (flags2 && !ast_test_flag(&iterator->flags[1], flags2))
+		if (!strncasecmp(word, user->name, wordlen)) {
+			if (flags2 && !ast_test_flag(&user->flags[1], flags2))
 				continue;
 			if (++which > state) {
-				result = ast_strdup(iterator->name);
+				result = ast_strdup(user->name);
 			}
 		}
-	} while(0) );
+		if (result)
+			break;
+	}
 	return result;
 }
 
@@ -12265,6 +12326,7 @@
 	struct sip_pvt *cur;
 	size_t len;
 	int found = 0;
+	struct ao2_iterator i;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -12281,7 +12343,10 @@
 		return CLI_SHOWUSAGE;
 	len = strlen(a->argv[3]);
 	dialoglist_lock();
-	for (cur = dialoglist; cur; cur = cur->next) {
+	
+	i = ao2_iterator_init(dialogs, 0);
+
+	while ((cur = ao2_iterator_next(&i))) {
 		if (!strncasecmp(cur->callid, a->argv[3], len)) {
 			char formatbuf[BUFSIZ/2];
 			ast_cli(a->fd,"\n");
@@ -12346,6 +12411,7 @@
 	struct sip_pvt *cur;
 	size_t len;
 	int found = 0;
+	struct ao2_iterator i;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -12364,7 +12430,8 @@
 		ast_cli(a->fd, "\n***Note: History recording is currently DISABLED.  Use 'sip history' to ENABLE.\n");
 	len = strlen(a->argv[3]);
 	dialoglist_lock();
-	for (cur = dialoglist; cur; cur = cur->next) {
+	i = ao2_iterator_init(dialogs, 0);
+	while ((cur = ao2_iterator_next(&i))) {
 		if (!strncasecmp(cur->callid, a->argv[3], len)) {
 			struct sip_history *hist;
 			int x = 0;
@@ -16086,6 +16153,7 @@
 	const char *accept = get_header(req, "Accept");
 	int resubscribe = (p->subscribed != NONE);
 	char *temp, *event;
+	struct ao2_iterator i;
 
 	if (p->initreq.headers) {	
 		/* We already have a dialog */
@@ -16307,7 +16375,7 @@
 		if (p->subscribed == MWI_NOTIFICATION) {
 			transmit_response(p, "200 OK", req);
 			if (p->relatedpeer) {	/* Send first notification */
-				ASTOBJ_WRLOCK(p->relatedpeer); /* was WRLOCK */
+				ao2_lock(p->relatedpeer); /* was WRLOCK */
 				sip_send_mwi_to_peer(p->relatedpeer, NULL, 0);
 				ao2_unlock(p->relatedpeer);
 			}
@@ -16334,7 +16402,10 @@
 			ignored (or generate errors)
 			*/
 			dialoglist_lock();
-			for (p_old = dialoglist; p_old; p_old = p_old->next) {
+
+			i = ao2_iterator_init(dialogs, 0);
+
+			while ((p_old = ao2_iterator_next(&i))) {
 				if (p_old == p)
 					continue;
 				if (p_old->initreq.method != SIP_SUBSCRIBE)
@@ -16887,6 +16958,7 @@
 	struct sip_pvt *dialog;
 	time_t t;
 	int reloading;
+	struct ao2_iterator i;
 
 	/* Add an I/O event to our SIP UDP socket */
 	if (sipsock > -1) 
@@ -16913,6 +16985,7 @@
 		}
 
 		/* Check for dialogs needing to be killed */
+
 		dialoglist_lock();
 restartsearch:		
 		t = time(NULL);
@@ -16920,7 +16993,10 @@
 		   of time since the last time we did it (when MWI is being sent, we can
 		   get back to this point every millisecond or less)
 		*/
-		for (dialog = dialoglist; dialog; dialog = dialog->next) {
+
+		i = ao2_iterator_init(dialogs, 0);
+
+		while ((dialog = ao2_iterator_next(&i))) {
 			sip_pvt_lock(dialog);
 			/* Check RTP timeouts and kill calls if we have a timeout set and do not get RTP */
 			check_rtp_timeout(dialog, t);
@@ -17590,7 +17666,7 @@
 	struct ast_flags mask[2] = {{(0)}};
 
 
-	if (!(user = ao2_alloc(sizeof(*user), sip_destroy_user)))
+	if (!(user = ao2_alloc(sizeof(*user), sip_destroy_user_fn)))
 		return NULL;
 		
 	suserobjs++;
@@ -17739,7 +17815,7 @@
 {
 	struct sip_peer *peer;
 
-	if (!(peer = ao2_alloc(sizeof(*peer), sip_destroy_peer)))
+	if (!(peer = ao2_alloc(sizeof(*peer), sip_destroy_peer_fn)))
 		return NULL;
 
 	apeerobjs++;
@@ -17791,22 +17867,26 @@
 	struct ast_flags peerflags[2] = {{(0)}};
 	struct ast_flags mask[2] = {{(0)}};
 	char callback[256] = "";
-
-	if (!realtime)
+	struct sip_peer tmp_peer;
+	
+	if (!realtime) {
 		/* Note we do NOT use find_peer here, to avoid realtime recursion */
 		/* We also use a case-sensitive comparison (unlike find_peer) so
 		   that case changes made to the peer name will be properly handled
 		   during reload
 		*/
-		peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&peerl, name, name, 0, 0, strcmp);
-
+		strcpy(tmp_peer.name, name);
+		/* peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL(&peerl, name, name, 0, 0, strcmp); */
+		peer = ao2_find(peers, &tmp_peer, OBJ_POINTER|OBJ_UNLINK);
+	}
+	
 	if (peer) {
 		/* Already in the list, remove it and it will be added back (or FREE'd)  */
 		found++;
-		if (!(peer->objflags & ASTOBJ_FLAG_MARKED))
+		if (!(peer->theMark))
 			firstpass = 0;
  	} else {
-		if (!(peer = ao2_alloc(sizeof(*peer),sip_destroy_peer)))
+		if (!(peer = ao2_alloc(sizeof(*peer),sip_destroy_peer_fn)))
 			return NULL;
 
 		if (realtime) {
@@ -18046,7 +18126,7 @@
 		sip_send_mwi_to_peer(peer, NULL, 1);
 	}
 
-	ASTOBJ_UNMARK(peer);
+	peer->theMark = 0;
 
 	ast_free_ha(oldha);
 	if (!ast_strlen_zero(callback)) { /* build string from peer info */
@@ -18059,6 +18139,13 @@
 		}
 	}
 	return peer;
+}
+
+static int peer_markall_func(void *userobj, void *arg, int flags)
+{
+	struct sip_peer *peer = userobj;
+	peer->theMark = 1;
+	return 0;
 }
 
 /*! \brief Re-read SIP.conf config file
@@ -18124,7 +18211,7 @@
 		ast_debug(4, "--------------- Done destroying user list\n");
 		ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
 		ast_debug(4, "--------------- Done destroying registry list\n");
-		ASTOBJ_CONTAINER_MARKALL(&peerl);
+		ao2_callback(peers, 0, peer_markall_func, 0);
 	}
 
 	/* Initialize copy of current global_regcontext for later use in removing stale contexts */
@@ -18525,6 +18612,7 @@
 					if (peer) {
 						ast_device_state_changed("SIP/%s", peer->name);
 						ao2_link(peers, peer);
+						ao2_link(peers_by_ip, peer);
 						unref_peer(peer);
 						peer_count++;
 					}
@@ -18593,6 +18681,7 @@
 				peer = build_peer(cat, ast_variable_browse(cfg, cat), NULL, 0);
 				if (peer) {
 					ao2_link(peers, peer);
+					ao2_link(peers_by_ip, peer);
 					unref_peer(peer);
 					peer_count++;
 				}
@@ -19150,18 +19239,19 @@
 static void sip_poke_all_peers(void)
 {
 	int ms = 0;
+	struct ao2_iterator i;
+	struct sip_peer *peer;
+
+	i = ao2_iterator_init(peers, 0);
 	
 	if (!speerobjs)	/* No peers, just give up */
 		return;
 
-	ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
-		ASTOBJ_WRLOCK(iterator); /* was WRLOCK */
+	while ((peer = ao2_iterator_next(&i))) {
 		ms += 100;
-		iterator->pokeexpire = ast_sched_replace(iterator->pokeexpire, 
-			sched, ms, sip_poke_peer_s, iterator);
-		ao2_unlock(iterator);
-	} while (0)
-	);
+		peer->pokeexpire = ast_sched_replace(peer->pokeexpire, 
+			sched, ms, sip_poke_peer_s, peer);
+	}
 }
 
 /*! \brief Send all known registrations */
@@ -19191,7 +19281,8 @@
 	reload_config(reason);
 
 	/* Prune peers who still are supposed to be deleted */
-	ASTOBJ_CONTAINER_PRUNE_MARKED(&peerl, sip_destroy_peer);
+	ao2_callback(peers, 0, peer_prune_marked_func, 0);
+	
 	ast_debug(4, "--------------- Done destroying pruned peers\n");
 
 	/* Send qualify (OPTIONS) to all peers */
@@ -19272,6 +19363,9 @@
     /* if the number of objects gets above MAX_XXX_BUCKETS, things will slow down */
 	users = ao2_container_alloc(MAX_USER_BUCKETS, user_hash_cb, user_cmp_cb);
 	peers = ao2_container_alloc(MAX_PEER_BUCKETS, peer_hash_cb, peer_cmp_cb);
+	peers_by_ip = ao2_container_alloc(MAX_PEER_BUCKETS, peer_iphash_cb, peer_ipcmp_cb);
+	dialogs = ao2_container_alloc(MAX_DIALOG_BUCKETS, dialog_hash_cb, dialog_cmp_cb);
+	
 	ASTOBJ_CONTAINER_INIT(&regl); /* Registry object list -- not searched for anything */
 
 	if (!(sched = sched_context_create())) {
@@ -19342,8 +19436,9 @@
 /*! \brief PBX unload module API */
 static int unload_module(void)
 {
-	struct sip_pvt *p, *pl;
+	struct sip_pvt *p;
 	struct ast_context *con;
+	struct ao2_iterator i;
 	
 	/* First, take us out of the channel type list */
 	ast_channel_unregister(&sip_tech);
@@ -19373,7 +19468,8 @@
 
 	dialoglist_lock();
 	/* Hangup all dialogs if they have an owner */
-	for (p = dialoglist; p ; p = p->next) {
+	i = ao2_iterator_init(dialogs, 0);
+	while ((p = ao2_iterator_next(&i))) {
 		if (p->owner)
 			ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
 	}
@@ -19390,22 +19486,26 @@
 
 	dialoglist_lock();
 	/* Destroy all the dialogs and free their memory */
-	p = dialoglist;
-	while (p) {
-		pl = p;
-		p = p->next;
-		__sip_destroy(pl, TRUE, TRUE);
-	}
-	dialoglist = NULL;
+	i = ao2_iterator_init(dialogs, 0);
+	while ((p = ao2_iterator_next(&i))) {
+		ao2_unlink(dialogs,p);
+		ao2_ref(p,-1); 
+	}
 	dialoglist_unlock();
 
 	/* Free memory for local network address mask */
 	ast_free_ha(localaddr);
 
+	ao2_ref(peers, -1);
+	ao2_ref(peers_by_ip, -1);
+	ao2_ref(users, -1);
+	ao2_ref(dialogs, -1);
+#ifdef NO_MORE	
 	ASTOBJ_CONTAINER_DESTROYALL(&userl, sip_destroy_user);
 	ASTOBJ_CONTAINER_DESTROY(&userl);
 	ASTOBJ_CONTAINER_DESTROYALL(&peerl, sip_destroy_peer);
 	ASTOBJ_CONTAINER_DESTROY(&peerl);
+#endif
 	ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
 	ASTOBJ_CONTAINER_DESTROY(&regl);
 




More information about the asterisk-commits mailing list