[asterisk-commits] kmoore: branch 10 r346087 - in /branches/10: ./ channels/ include/asterisk/ res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Nov 23 11:14:45 CST 2011


Author: kmoore
Date: Wed Nov 23 11:14:41 2011
New Revision: 346087

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=346087
Log:
Fix res_jabber resource leaks

This should fix almost all resource leaks in res_jabber that involve
ASTOBJ_CONTAINER_FIND and resolves an ambiguous situation where
ast_aji_get_client would sometimes bump an object's refcount and sometimes not.

Review: https://reviewboard.asterisk.org/r/1553
........

Merged revisions 346086 from http://svn.asterisk.org/svn/asterisk/branches/1.8

Modified:
    branches/10/   (props changed)
    branches/10/channels/chan_gtalk.c
    branches/10/channels/chan_jingle.c
    branches/10/include/asterisk/jabber.h
    branches/10/res/res_jabber.c

Propchange: branches/10/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Modified: branches/10/channels/chan_gtalk.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_gtalk.c?view=diff&rev=346087&r1=346086&r2=346087
==============================================================================
--- branches/10/channels/chan_gtalk.c (original)
+++ branches/10/channels/chan_gtalk.c Wed Nov 23 11:14:41 2011
@@ -248,9 +248,17 @@
 static void gtalk_member_destroy(struct gtalk *obj)
 {
 	obj->cap = ast_format_cap_destroy(obj->cap);
+	if (obj->connection) {
+		ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
+	}
+	if (obj->buddy) {
+		ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
+	}
 	ast_free(obj);
 }
 
+/* XXX This could be a source of reference leaks given that the CONTAINER_FIND
+ * macros bump the refcount while the traversal does not. */
 static struct gtalk *find_gtalk(char *name, char *connection)
 {
 	struct gtalk *gtalk = NULL;
@@ -995,7 +1003,7 @@
 {
 	struct gtalk_pvt *tmp = NULL;
 	struct aji_resource *resources = NULL;
-	struct aji_buddy *buddy;
+	struct aji_buddy *buddy = NULL;
 	char idroster[200];
 	char *data, *exten = NULL;
 	struct ast_sockaddr bindaddr_tmp;
@@ -1023,7 +1031,13 @@
 			snprintf(idroster, sizeof(idroster), "%s", them);
 		} else {
 			ast_log(LOG_ERROR, "no gtalk capable clients to talk to.\n");
+			if (buddy) {
+				ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			}
 			return NULL;
+		}
+		if (buddy) {
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
 		}
 	}
 	if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
@@ -1309,6 +1323,9 @@
 	if (!strcasecmp(client->name, "guest")){
 		/* the guest account is not tied to any configured XMPP client,
 		   let's set it now */
+		if (client->connection) {
+			ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
+		}
 		client->connection = ast_aji_get_client(from);
 		if (!client->connection) {
 			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
@@ -1909,6 +1926,9 @@
 	if (!strcasecmp(client->name, "guest")){
 		/* the guest account is not tied to any configured XMPP client,
 		   let's set it now */
+		if (client->connection) {
+			ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
+		}
 		client->connection = ast_aji_get_client(sender);
 		if (!client->connection) {
 			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
@@ -2239,6 +2259,9 @@
 					ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
 						ASTOBJ_WRLOCK(iterator);
 						ASTOBJ_WRLOCK(member);
+						if (member->connection) {
+							ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
+						}
 						member->connection = NULL;
 						iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_NS, IKS_RULE_DONE);
 						iks_filter_add_rule(iterator->f, gtalk_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, GOOGLE_JINGLE_NS, IKS_RULE_DONE);

Modified: branches/10/channels/chan_jingle.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_jingle.c?view=diff&rev=346087&r1=346086&r2=346087
==============================================================================
--- branches/10/channels/chan_jingle.c (original)
+++ branches/10/channels/chan_jingle.c Wed Nov 23 11:14:41 2011
@@ -228,9 +228,17 @@
 static void jingle_member_destroy(struct jingle *obj)
 {
 	obj->cap = ast_format_cap_destroy(obj->cap);
+	if (obj->connection) {
+		ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
+	}
+	if (obj->buddy) {
+		ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
+	}
 	ast_free(obj);
 }
 
+/* XXX This could be a source of reference leaks given that the CONTAINER_FIND
+ * macros bump the refcount while the traversal does not. */
 static struct jingle *find_jingle(char *name, char *connection)
 {
 	struct jingle *jingle = NULL;
@@ -744,7 +752,7 @@
 {
 	struct jingle_pvt *tmp = NULL;
 	struct aji_resource *resources = NULL;
-	struct aji_buddy *buddy;
+	struct aji_buddy *buddy = NULL;
 	char idroster[200];
 	struct ast_sockaddr bindaddr_tmp;
 
@@ -752,8 +760,9 @@
 	if (!sid && !strchr(from, '/')) {	/* I started call! */
 		if (!strcasecmp(client->name, "guest")) {
 			buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, from);
-			if (buddy)
+			if (buddy) {
 				resources = buddy->resources;
+			}
 		} else if (client->buddy)
 			resources = client->buddy->resources;
 		while (resources) {
@@ -766,7 +775,13 @@
 			snprintf(idroster, sizeof(idroster), "%s/%s", from, resources->resource);
 		else {
 			ast_log(LOG_ERROR, "no jingle capable clients to talk to.\n");
+			if (buddy) {
+				ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			}
 			return NULL;
+		}
+		if (buddy) {
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
 		}
 	}
 	if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
@@ -1007,15 +1022,18 @@
 		tmp = tmp->next;
 	}
 
- 	if (!strcasecmp(client->name, "guest")){
- 		/* the guest account is not tied to any configured XMPP client,
- 		   let's set it now */
- 		client->connection = ast_aji_get_client(from);
- 		if (!client->connection) {
- 			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
- 			return -1;
- 		}
- 	}
+	if (!strcasecmp(client->name, "guest")){
+		/* the guest account is not tied to any configured XMPP client,
+		   let's set it now */
+		if (client->connection) {
+			ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
+		}
+		client->connection = ast_aji_get_client(from);
+		if (!client->connection) {
+			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
+			return -1;
+		}
+	}
 
 	p = jingle_alloc(client, pak->from->partial, iks_find_attrib(pak->query, JINGLE_SID));
 	if (!p) {
@@ -1552,6 +1570,9 @@
 	if (!strcasecmp(client->name, "guest")){
 		/* the guest account is not tied to any configured XMPP client,
 		   let's set it now */
+		if (client->connection) {
+			ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
+		}
 		client->connection = ast_aji_get_client(sender);
 		if (!client->connection) {
 			ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
@@ -1882,6 +1903,9 @@
 					ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
 						ASTOBJ_WRLOCK(iterator);
 						ASTOBJ_WRLOCK(member);
+						if (member->connection) {
+							ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
+						}
 						member->connection = NULL;
 						iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS,	JINGLE_NS, IKS_RULE_DONE);
 						iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS,	JINGLE_DTMF_NS, IKS_RULE_DONE);

Modified: branches/10/include/asterisk/jabber.h
URL: http://svnview.digium.com/svn/asterisk/branches/10/include/asterisk/jabber.h?view=diff&rev=346087&r1=346086&r2=346087
==============================================================================
--- branches/10/include/asterisk/jabber.h (original)
+++ branches/10/include/asterisk/jabber.h Wed Nov 23 11:14:41 2011
@@ -213,7 +213,12 @@
 /*! Join/leave existing Chat session */
 int ast_aji_join_chat(struct aji_client *client, char *room, char *nick);
 int ast_aji_leave_chat(struct aji_client *client, char *room, char *nick);
+/*! Get a client via its name. Increases refcount of client by 1 */
 struct aji_client *ast_aji_get_client(const char *name);
 struct aji_client_container *ast_aji_get_clients(void);
+/*! Destructor function for buddies to be used with ASTOBJ_UNREF */
+void ast_aji_buddy_destroy(struct aji_buddy *obj);
+/*! Destructor function for clients to be used with ASTOBJ_UNREF after calls to ast_aji_get_client */
+void ast_aji_client_destroy(struct aji_client *obj);
 
 #endif

Modified: branches/10/res/res_jabber.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/res/res_jabber.c?view=diff&rev=346087&r1=346086&r2=346087
==============================================================================
--- branches/10/res/res_jabber.c (original)
+++ branches/10/res/res_jabber.c Wed Nov 23 11:14:41 2011
@@ -287,8 +287,6 @@
 
 /*-- Forward declarations */
 static void aji_message_destroy(struct aji_message *obj);
-static void aji_buddy_destroy(struct aji_buddy *obj);
-static void aji_client_destroy(struct aji_client *obj);
 static int aji_is_secure(struct aji_client *client);
 #ifdef HAVE_OPENSSL
 static int aji_start_tls(struct aji_client *client);
@@ -419,10 +417,10 @@
  * \param obj aji_client The structure we will delete.
  * \return void.
  */
-static void aji_client_destroy(struct aji_client *obj)
+void ast_aji_client_destroy(struct aji_client *obj)
 {
 	struct aji_message *tmp;
-	ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, aji_buddy_destroy);
+	ASTOBJ_CONTAINER_DESTROYALL(&obj->buddies, ast_aji_buddy_destroy);
 	ASTOBJ_CONTAINER_DESTROY(&obj->buddies);
 	iks_filter_delete(obj->f);
 	iks_parser_delete(obj->p);
@@ -441,7 +439,7 @@
  * \param obj aji_buddy The structure we will delete.
  * \return void.
  */
-static void aji_buddy_destroy(struct aji_buddy *obj)
+void ast_aji_buddy_destroy(struct aji_buddy *obj)
 {
 	struct aji_resource *tmp;
 
@@ -677,12 +675,15 @@
 	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
 	if (!buddy) {
 		ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return -1;
 	}
 	r = aji_find_resource(buddy, jid.resource);
 	if (!r && buddy->resources) {
 		r = buddy->resources;
 	}
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	if (!r) {
 		ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
 	} else {
@@ -741,12 +742,15 @@
 	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, jid.screenname);
 	if (!buddy) {
 		ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return -1;
 	}
 	r = aji_find_resource(buddy, jid.resource);
 	if (!r && buddy->resources) {
 		r = buddy->resources;
 	}
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	if (!r) {
 		ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
 	} else {
@@ -803,17 +807,10 @@
 		return -1;
 	}
 
-	client = ast_aji_get_client(args.account);
-	if (!client) {
-		ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
-		return -1;
-	}
-
 	parse = ast_strdupa(args.jid);
 	AST_NONSTANDARD_APP_ARGS(jid, parse, '/');
 	if (jid.argc < 1 || jid.argc > 2 || strlen(args.jid) > AJI_MAX_JIDLEN) {
 		ast_log(LOG_WARNING, "Invalid JID : %s\n", parse);
-		ASTOBJ_UNREF(client, aji_client_destroy);
 		return -1;
 	}
 
@@ -823,7 +820,6 @@
 		sscanf(args.timeout, "%d", &timeout);
 		if (timeout <= 0) {
 			ast_log(LOG_WARNING, "Invalid timeout specified: '%s'\n", args.timeout);
-			ASTOBJ_UNREF(client, aji_client_destroy);
 			return -1;
 		}
 	}
@@ -831,12 +827,19 @@
 	jidlen = strlen(jid.screenname);
 	resourcelen = ast_strlen_zero(jid.resource) ? 0 : strlen(jid.resource);
 
+	client = ast_aji_get_client(args.account);
+	if (!client) {
+		ast_log(LOG_WARNING, "Could not find client %s, exiting\n", args.account);
+		return -1;
+	}
+
 	ast_debug(3, "Waiting for an XMPP message from %s\n", args.jid);
 
 	start = ast_tvnow();
 
 	if (ast_autoservice_start(chan) < 0) {
 		ast_log(LOG_WARNING, "Cannot start autoservice for channel %s\n", chan->name);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return -1;
 	}
 
@@ -905,7 +908,7 @@
 		diff = ast_tvdiff_ms(ast_tvnow(), start);
 	}
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	if (ast_autoservice_stop(chan) < 0) {
 		ast_log(LOG_WARNING, "Cannot stop autoservice for channel %s\n", chan->name);
 	}
@@ -1017,14 +1020,13 @@
 		return -1;
 	}
 
+	if (strchr(args.jid, '/')) {
+		ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
+		return -1;
+	}
+
 	if (!(client = ast_aji_get_client(args.sender))) {
 		ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
-		return -1;
-	}
-
-	if (strchr(args.jid, '/')) {
-		ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n");
-		ASTOBJ_UNREF(client, aji_client_destroy);
 		return -1;
 	}
 
@@ -1044,7 +1046,7 @@
 		ast_log(LOG_ERROR, "Problem with specified jid of '%s'\n", args.jid);
 	}
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return 0;
 }
 
@@ -1078,16 +1080,16 @@
 		return -1;
 	}
 
+	if (strchr(args.jid, '/')) {
+		ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
+		return -1;
+	}
+
 	if (!(client = ast_aji_get_client(args.sender))) {
 		ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender);
 		return -1;
 	}
 
-	if (strchr(args.jid, '/')) {
-		ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n");
-		ASTOBJ_UNREF(client, aji_client_destroy);
-		return -1;
-	}
 	if (!ast_strlen_zero(args.nick)) {
 		snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick);
 	} else {
@@ -1101,7 +1103,7 @@
 	if (!ast_strlen_zero(args.jid) && strchr(args.jid, '@')) {
 		ast_aji_leave_chat(client, args.jid, nick);
 	}
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return 0;
 }
 
@@ -1142,6 +1144,7 @@
 	if (strchr(args.recipient, '@') && !ast_strlen_zero(args.message)) {
 		ast_aji_send_chat(client, args.recipient, args.message);
 	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return 0;
 }
 
@@ -1167,7 +1170,6 @@
 		return -1;
 	}
 
-
 	ast_debug(1, "Sending message to '%s' from '%s'\n", dest, client->name);
 
 	res = ast_aji_send_chat(client, dest, ast_msg_get_body(msg));
@@ -1175,11 +1177,7 @@
 		ast_log(LOG_WARNING, "Failed to send xmpp message (%d).\n", res);
 	}
 
-	/* 
-	 * XXX Reference leak here.  See note with ast_aji_get_client() about the problems
-	 * with that function.
-	 */
-
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return res == IKS_OK ? 0 : -1;
 }
 
@@ -1234,7 +1232,7 @@
 		res = ast_aji_send_groupchat(client, nick, args.groupchat, args.message);
 	}
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	if (res != IKS_OK) {
 		return -1;
 	}
@@ -1549,7 +1547,7 @@
 		}
 
 	}
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 }
 
 /*!
@@ -1621,12 +1619,12 @@
 
 	if (!node) {
 		ast_log(LOG_ERROR, "aji_act_hook was called with out a packet\n"); /* most likely cause type is IKS_NODE_ERROR lost connection */
-		ASTOBJ_UNREF(client, aji_client_destroy);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return IKS_HOOK;
 	}
 
 	if (client->state == AJI_DISCONNECTING) {
-		ASTOBJ_UNREF(client, aji_client_destroy);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return IKS_HOOK;
 	}
 
@@ -1655,13 +1653,13 @@
 			if (client->usetls && !aji_is_secure(client)) {
 #ifndef HAVE_OPENSSL
 				ast_log(LOG_ERROR, "TLS connection cannot be established. Please install OpenSSL and its development libraries on this system, or disable the TLS option in your configuration file\n");
-				ASTOBJ_UNREF(client, aji_client_destroy);
+				ASTOBJ_UNREF(client, ast_aji_client_destroy);
 				return IKS_HOOK;
 #else
 				if (aji_start_tls(client) == IKS_NET_TLSFAIL) {
 					ast_log(LOG_ERROR, "Could not start TLS\n");
-					ASTOBJ_UNREF(client, aji_client_destroy);
-					return IKS_HOOK;		
+					ASTOBJ_UNREF(client, ast_aji_client_destroy);
+					return IKS_HOOK;
 				}
 #endif
 				break;
@@ -1730,7 +1728,7 @@
 
 						ret = aji_start_sasl(client, features, client->jid->user, client->password);
 						if (ret != IKS_OK) {
-							ASTOBJ_UNREF(client, aji_client_destroy);
+							ASTOBJ_UNREF(client, ast_aji_client_destroy);
 							return IKS_HOOK;
 						}
 						break;
@@ -1745,12 +1743,12 @@
 			break;
 		case IKS_NODE_ERROR:
 			ast_log(LOG_ERROR, "JABBER: Node Error\n");
-			ASTOBJ_UNREF(client, aji_client_destroy);
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
 			return IKS_HOOK;
 			break;
 		case IKS_NODE_STOP:
 			ast_log(LOG_WARNING, "JABBER: Disconnected\n");
-			ASTOBJ_UNREF(client, aji_client_destroy);
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
 			return IKS_HOOK;
 			break;
 		}
@@ -1782,12 +1780,12 @@
 
 		case IKS_NODE_ERROR:
 			ast_log(LOG_ERROR, "JABBER: Node Error\n");
-			ASTOBJ_UNREF(client, aji_client_destroy);
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
 			return IKS_HOOK;
 
 		case IKS_NODE_STOP:
 			ast_log(LOG_WARNING, "JABBER: Disconnected\n");
-			ASTOBJ_UNREF(client, aji_client_destroy);
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
 			return IKS_HOOK;
 		}
 	}
@@ -1822,7 +1820,7 @@
 	if (node)
 		iks_delete(node);
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_OK;
 }
 /*!
@@ -1865,7 +1863,7 @@
 	iks_delete(presence);
 	iks_delete(x);
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 }
 /*!
@@ -1936,7 +1934,8 @@
 	}
 	iks_delete(iq);
 	iks_delete(query);
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 }
 
@@ -2032,7 +2031,7 @@
 		iks_delete(feature);
 	}
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 
 }
@@ -2054,7 +2053,8 @@
 	if (pak->subtype == IKS_TYPE_RESULT) {
 		if (!resource) {
 			ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
-			ASTOBJ_UNREF(client, aji_client_destroy);
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
 			return IKS_FILTER_EAT;
 		}
 		if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
@@ -2097,7 +2097,8 @@
 	} else if (pak->subtype == IKS_TYPE_ERROR) {
 		ast_log(LOG_NOTICE, "User %s does not support discovery.\n", pak->from->full);
 	}
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 }
 
@@ -2115,16 +2116,17 @@
 	struct aji_resource *resource = NULL;
 	struct aji_buddy *buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
 
-	resource = aji_find_resource(buddy, pak->from->resource);
 	if (pak->subtype == IKS_TYPE_ERROR) {
 		ast_log(LOG_WARNING, "Received error from a client, turn on jabber debug!\n");
-		ASTOBJ_UNREF(client, aji_client_destroy);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return IKS_FILTER_EAT;
 	}
+	resource = aji_find_resource(buddy, pak->from->resource);
 	if (pak->subtype == IKS_TYPE_RESULT) {
 		if (!resource) {
 			ast_log(LOG_NOTICE, "JABBER: Received client info from %s when not requested.\n", pak->from->full);
-			ASTOBJ_UNREF(client, aji_client_destroy);
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+			ASTOBJ_UNREF(client, ast_aji_client_destroy);
 			return IKS_FILTER_EAT;
 		}
 		if (iks_find_with_attrib(pak->query, "feature", "var", "http://www.google.com/xmpp/protocol/voice/v1")) {
@@ -2239,7 +2241,8 @@
 		iks_delete(feature);
 	}
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 }
 
@@ -2448,6 +2451,8 @@
 
 		if (!found) {
 			ast_log(LOG_ERROR, "Out of memory!\n");
+			ASTOBJ_UNLOCK(buddy);
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
 			return;
 		}
 		ast_copy_string(found->resource, pak->from->resource, sizeof(found->resource));
@@ -2481,7 +2486,7 @@
 	}
 
 	ASTOBJ_UNLOCK(buddy);
-	ASTOBJ_UNREF(buddy, aji_buddy_destroy);
+	ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
 
 	node = iks_find_attrib(iks_find(pak->x, "c"), "node");
 	ver = iks_find_attrib(iks_find(pak->x, "c"), "ver");
@@ -2606,6 +2611,8 @@
 		buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, pak->from->partial);
 		if (!buddy && pak->from->partial) {
 			aji_create_buddy(pak->from->partial, client);
+		} else if (buddy) {
+			ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
 		}
 	default:
 		if (option_verbose > 4) {
@@ -2821,7 +2828,7 @@
 			ast_log(LOG_WARNING, "JABBER: socket read error\n");
 		}
 	} while (client);
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return 0;
 }
 
@@ -2877,7 +2884,7 @@
 
 	if (send)
 		iks_delete(send);
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 
 }
@@ -2927,7 +2934,7 @@
 		iks_delete(reguser);
 	if (regpass)
 		iks_delete(regpass);
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 }
 #endif
@@ -2983,7 +2990,7 @@
 	iks_delete(removeitem);
 	iks_delete(send);
 
-	ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, aji_buddy_destroy);
+	ASTOBJ_CONTAINER_PRUNE_MARKED(&client->buddies, ast_aji_buddy_destroy);
 }
 
 /*!
@@ -3042,7 +3049,7 @@
 			buddy = ast_calloc(1, sizeof(*buddy));
 			if (!buddy) {
 				ast_log(LOG_WARNING, "Out of memory\n");
-				ASTOBJ_UNREF(client, aji_client_destroy);
+				ASTOBJ_UNREF(client, ast_aji_client_destroy);
 				return 0;
 			}
 			ASTOBJ_INIT(buddy);
@@ -3062,7 +3069,7 @@
 			ASTOBJ_UNLOCK(buddy);
 			if (buddy) {
 				ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
-				ASTOBJ_UNREF(buddy, aji_buddy_destroy);
+				ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
 			}
 		}
 		x = iks_next(x);
@@ -3071,7 +3078,7 @@
 	iks_delete(x);
 	aji_pruneregister(client);
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 }
 
@@ -3155,7 +3162,7 @@
 		ast_log(LOG_ERROR, "Out of memory.\n");
 	}
 
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return res;
 }
 
@@ -3206,7 +3213,7 @@
 #endif
 		iks_disconnect(client->p);
 		iks_parser_delete(client->p);
-		ASTOBJ_UNREF(client, aji_client_destroy);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	}
 
 	return 1;
@@ -3240,7 +3247,7 @@
 	snprintf(newmsgs, sizeof(newmsgs), "%d",
 		ast_event_get_ie_uint(ast_event, AST_EVENT_IE_NEWMSGS));
 	aji_publish_mwi(client, mailbox, context, oldmsgs, newmsgs);
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 
 }
 /*!
@@ -3265,7 +3272,7 @@
 	device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE);
 	device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE));
 	aji_publish_device_state(client, device, device_state);
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 }
 
 /*!
@@ -3556,7 +3563,7 @@
 		iks_insert_node(request, orig_pubsub);
 		ast_aji_send(client, request);
 		iks_delete(request);
-		ASTOBJ_UNREF(client, aji_client_destroy);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return IKS_FILTER_EAT;
 	} else if (!strcasecmp(iks_name(orig_request), "subscribe")) {
 		if (ast_test_flag(&pubsubflags, AJI_XEP0248)) {
@@ -3565,7 +3572,7 @@
 			aji_create_pubsub_node(client, NULL, node_name, NULL);
 		}
 	}
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 }
 
@@ -3627,7 +3634,7 @@
 	if (item) {
 		iks_delete(item);
 	}
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return IKS_FILTER_EAT;
 }
 
@@ -3666,13 +3673,14 @@
 		if (a->argc == 5) {
 			collection = a->argv[4];
 		}
-        if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
+		if (!(client = ASTOBJ_CONTAINER_FIND(&clients, name))) {
 			ast_cli(a->fd, "Unable to find client '%s'!\n", name);
 			return CLI_FAILURE;
 		}
 
 		ast_cli(a->fd, "Listing pubsub nodes.\n");
 		aji_request_pubsub_nodes(client, collection);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return CLI_SUCCESS;
 }
 
@@ -3715,6 +3723,7 @@
 	} else {
 		aji_delete_pubsub_node(client, a->argv[4]);
 	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return CLI_SUCCESS;
 }
 
@@ -3790,6 +3799,7 @@
 		return CLI_FAILURE;
 	}
 	aji_delete_pubsub_node(client, a->argv[4]);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return CLI_SUCCESS;
 }
 
@@ -3939,6 +3949,7 @@
 
 		ast_cli(a->fd, "Creating test PubSub node collection.\n");
 		aji_create_pubsub_collection(client, collection_name);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return CLI_SUCCESS;
 }
 
@@ -3979,6 +3990,7 @@
 
 	ast_cli(a->fd, "Creating test PubSub node collection.\n");
 	aji_create_pubsub_leaf(client, collection_name, leaf_name);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	return CLI_SUCCESS;
 }
 
@@ -4288,7 +4300,7 @@
 		//ast_verbose("	Message from: %s with id %s @ %s	%s\n",tmp->from, S_OR(tmp->id,""), ctime(&tmp->arrived), S_OR(tmp->message, ""));
 	}
 	AST_LIST_UNLOCK(&client->messages);
-	ASTOBJ_UNREF(client, aji_client_destroy);
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 
 	return CLI_SUCCESS;
 }
@@ -4448,7 +4460,7 @@
 	}
 	if (!flag) {
 		ASTOBJ_UNLOCK(client);
-		ASTOBJ_UNREF(client, aji_client_destroy);
+		ASTOBJ_UNREF(client, ast_aji_client_destroy);
 		return 1;
 	}
 
@@ -4505,9 +4517,11 @@
 {
 	char *server = NULL, *buddyname = NULL, *user = NULL, *pass = NULL;
 	struct aji_buddy *buddy = NULL;
+	int needs_unref = 1;
 
 	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies,label);
 	if (!buddy) {
+		needs_unref = 0;
 		buddy = ast_calloc(1, sizeof(*buddy));
 		if (!buddy) {
 			ast_log(LOG_WARNING, "Out of memory\n");
@@ -4532,6 +4546,10 @@
 						ast_copy_string(buddy->user, user, sizeof(buddy->user));
 						ast_copy_string(buddy->name, buddyname, sizeof(buddy->name));
 						ast_copy_string(buddy->server, server, sizeof(buddy->server));
+						if (needs_unref) {
+							ASTOBJ_UNMARK(buddy);
+							ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+						}
 						return 1;
 					}
 				}
@@ -4539,8 +4557,12 @@
 		}
 	}
 	ASTOBJ_UNLOCK(buddy);
-	ASTOBJ_UNMARK(buddy);
-	ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
+	if (needs_unref) {
+		ASTOBJ_UNMARK(buddy);
+		ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	} else {
+		ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
+	}
 	return 0;
 }
 #endif
@@ -4555,10 +4577,10 @@
 static int aji_create_buddy(char *label, struct aji_client *client)
 {
 	struct aji_buddy *buddy = NULL;
-	int flag = 0;
+	int needs_unref = 1;
 	buddy = ASTOBJ_CONTAINER_FIND(&client->buddies, label);
 	if (!buddy) {
-		flag = 1;
+		needs_unref = 0;
 		buddy = ast_calloc(1, sizeof(*buddy));
 		if (!buddy) {
 			ast_log(LOG_WARNING, "Out of memory\n");
@@ -4569,11 +4591,11 @@
 	ASTOBJ_WRLOCK(buddy);
 	ast_copy_string(buddy->name, label, sizeof(buddy->name));
 	ASTOBJ_UNLOCK(buddy);
-	if (flag) {
+	if (needs_unref) {
+		ASTOBJ_UNMARK(buddy);
+		ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
+	} else {
 		ASTOBJ_CONTAINER_LINK(&client->buddies, buddy);
-	} else {
-		ASTOBJ_UNMARK(buddy);
-		ASTOBJ_UNREF(buddy, aji_buddy_destroy);
 	}
 	return 1;
 }
@@ -4632,17 +4654,10 @@
 }
 
 /*!
- * \brief grab a aji_client structure by label name or JID
+ * \brief grab a aji_client structure by label name or JID. Bumps the refcount.
  * (without the resource string)
  * \param name label or JID
  * \return aji_client.
- *
- * XXX \bug This function leads to reference leaks all over the place.
- *          ASTOBJ_CONTAINER_FIND() returns a reference, but if the
- *          client is found via the traversal, no reference is returned.
- *          None of the calling code releases references.  This code needs
- *          to be changed to always return a reference, and all of the users
- *          need to be fixed to release them.
  */
 struct aji_client *ast_aji_get_client(const char *name)
 {
@@ -4658,7 +4673,7 @@
 				aux = strsep(&aux, "/");
 			}
 			if (!strncasecmp(aux, name, strlen(aux))) {
-				client = iterator;
+				client = ASTOBJ_REF(iterator);
 			}
 		});
 	}
@@ -4711,6 +4726,7 @@
 	} else {
 		astman_append(s, "Response: Error\r\n");
 	}
+	ASTOBJ_UNREF(client, ast_aji_client_destroy);
 	if (!ast_strlen_zero(id)) {
 		astman_append(s, "ActionID: %s\r\n", id);
 	}
@@ -4733,7 +4749,7 @@
 	} else if (res == -1)
 		return 1;
 
-	ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, aji_client_destroy);
+	ASTOBJ_CONTAINER_PRUNE_MARKED(&clients, ast_aji_client_destroy);
 	ASTOBJ_CONTAINER_TRAVERSE(&clients, 1, {
 		ASTOBJ_RDLOCK(iterator);
 		if (iterator->state == AJI_DISCONNECTED) {
@@ -4784,7 +4800,7 @@
 		ast_aji_disconnect(iterator);
 	});
 
-	ASTOBJ_CONTAINER_DESTROYALL(&clients, aji_client_destroy);
+	ASTOBJ_CONTAINER_DESTROYALL(&clients, ast_aji_client_destroy);
 	ASTOBJ_CONTAINER_DESTROY(&clients);
 
 	ast_cond_destroy(&message_received_condition);




More information about the asterisk-commits mailing list