diff options
author | Kinsey Moore <kmoore@digium.com> | 2011-11-23 17:16:33 +0000 |
---|---|---|
committer | Kinsey Moore <kmoore@digium.com> | 2011-11-23 17:16:33 +0000 |
commit | e6ca7680812d1ecbf45419ca92bcadacbd6fa47f (patch) | |
tree | 04c71e8b003cc527bf960a9b0e8343ee84b0c02b /res | |
parent | 76394a727f5b18fbb0506ddcecfa6494d7cff31c (diff) |
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
........
Merged revisions 346087 from http://svn.asterisk.org/svn/asterisk/branches/10
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@346088 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res')
-rw-r--r-- | res/res_jabber.c | 198 |
1 files changed, 107 insertions, 91 deletions
diff --git a/res/res_jabber.c b/res/res_jabber.c index 40c7bb27c..870508d03 100644 --- a/res/res_jabber.c +++ b/res/res_jabber.c @@ -287,8 +287,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") /*-- 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 @@ static struct ast_flags pubsubflags = { 0 }; * \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 @@ static void aji_client_destroy(struct aji_client *obj) * \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 @@ static int aji_status_exec(struct ast_channel *chan, const char *data) 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 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha 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 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch 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 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch 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 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch 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 @@ static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, ch 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 @@ static int aji_join_exec(struct ast_channel *chan, const char *data) return -1; } - if (!(client = ast_aji_get_client(args.sender))) { - ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender); + if (strchr(args.jid, '/')) { + ast_log(LOG_ERROR, "Invalid room name : resource must not be appended\n"); 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); + if (!(client = ast_aji_get_client(args.sender))) { + ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender); return -1; } @@ -1044,7 +1046,7 @@ static int aji_join_exec(struct ast_channel *chan, const char *data) 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 @@ static int aji_leave_exec(struct ast_channel *chan, const char *data) return -1; } - if (!(client = ast_aji_get_client(args.sender))) { - ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender); + if (strchr(args.jid, '/')) { + ast_log(LOG_ERROR, "Invalid room name, resource must not be appended\n"); 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); + if (!(client = ast_aji_get_client(args.sender))) { + ast_log(LOG_ERROR, "Could not find sender connection: '%s'\n", args.sender); return -1; } + if (!ast_strlen_zero(args.nick)) { snprintf(nick, AJI_MAX_RESJIDLEN, "%s", args.nick); } else { @@ -1101,7 +1103,7 @@ static int aji_leave_exec(struct ast_channel *chan, const char *data) 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 @@ static int aji_send_exec(struct ast_channel *chan, const char *data) 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 @@ static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *fr 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 @@ static int msg_send_cb(const struct ast_msg *msg, const char *to, const char *fr 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 @@ static int aji_sendgroup_exec(struct ast_channel *chan, const char *data) 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 @@ static void aji_log_hook(void *data, const char *xmpp, size_t size, int is_incom } } - ASTOBJ_UNREF(client, aji_client_destroy); + ASTOBJ_UNREF(client, ast_aji_client_destroy); } /*! @@ -1621,12 +1619,12 @@ static int aji_act_hook(void *data, int type, iks *node) 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 @@ static int aji_act_hook(void *data, int type, iks *node) 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 @@ static int aji_act_hook(void *data, int type, iks *node) 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 @@ static int aji_act_hook(void *data, int type, iks *node) 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 @@ static int aji_act_hook(void *data, int type, iks *node) 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 @@ static int aji_act_hook(void *data, int type, iks *node) 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 @@ static int aji_register_approve_handler(void *data, ikspak *pak) 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 @@ static int aji_register_query_handler(void *data, ikspak *pak) } 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 @@ static int aji_ditems_handler(void *data, ikspak *pak) iks_delete(feature); } - ASTOBJ_UNREF(client, aji_client_destroy); + ASTOBJ_UNREF(client, ast_aji_client_destroy); return IKS_FILTER_EAT; } @@ -2054,7 +2053,8 @@ static int aji_client_info_handler(void *data, ikspak *pak) 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 @@ static int aji_client_info_handler(void *data, ikspak *pak) } 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 @@ static int aji_dinfo_handler(void *data, ikspak *pak) 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 @@ static int aji_dinfo_handler(void *data, ikspak *pak) 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 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak) 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 @@ static void aji_handle_presence(struct aji_client *client, ikspak *pak) } 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 @@ static void aji_handle_subscribe(struct aji_client *client, ikspak *pak) 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 @@ static void *aji_recv_loop(void *data) 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 @@ static int aji_register_transport(void *data, ikspak *pak) 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 @@ static int aji_register_transport2(void *data, ikspak *pak) 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 @@ static void aji_pruneregister(struct aji_client *client) 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 @@ static int aji_filter_roster(void *data, ikspak *pak) 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 @@ static int aji_filter_roster(void *data, ikspak *pak) 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 @@ static int aji_filter_roster(void *data, ikspak *pak) 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 @@ static int aji_client_connect(void *data, ikspak *pak) 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 @@ int ast_aji_disconnect(struct aji_client *client) #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 @@ static void aji_mwi_cb(const struct ast_event *ast_event, void *data) 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 @@ static void aji_devstate_cb(const struct ast_event *ast_event, void *data) 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 @@ static int aji_handle_pubsub_error(void *data, ikspak *pak) 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 @@ static int aji_handle_pubsub_error(void *data, ikspak *pak) 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 @@ static int aji_receive_node_list(void *data, ikspak* pak) 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 @@ ast_cli_args *a) 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 @@ static char *aji_cli_purge_pubsub_nodes(struct ast_cli_entry *e, int cmd, struct } else { aji_delete_pubsub_node(client, a->argv[4]); } + ASTOBJ_UNREF(client, ast_aji_client_destroy); return CLI_SUCCESS; } @@ -3790,6 +3799,7 @@ static char *aji_cli_delete_pubsub_node(struct ast_cli_entry *e, int cmd, struct 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 @@ static char *aji_cli_create_collection(struct ast_cli_entry *e, int cmd, struct 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 @@ static char *aji_cli_create_leafnode(struct ast_cli_entry *e, int cmd, struct as 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 @@ static char *aji_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) //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 @@ static int aji_create_client(char *label, struct ast_variable *var, int debug) } if (!flag) { ASTOBJ_UNLOCK(client); - ASTOBJ_UNREF(client, aji_client_destroy); + ASTOBJ_UNREF(client, ast_aji_client_destroy); return 1; } @@ -4505,9 +4517,11 @@ static int aji_create_transport(char *label, struct aji_client *client) { 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 @@ static int aji_create_transport(char *label, struct aji_client *client) 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 @@ static int aji_create_transport(char *label, struct aji_client *client) } } 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_transport(char *label, struct aji_client *client) 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 @@ static int aji_create_buddy(char *label, struct aji_client *client) ASTOBJ_WRLOCK(buddy); ast_copy_string(buddy->name, label, sizeof(buddy->name)); ASTOBJ_UNLOCK(buddy); - if (flag) { - ASTOBJ_CONTAINER_LINK(&client->buddies, buddy); - } else { + if (needs_unref) { ASTOBJ_UNMARK(buddy); - ASTOBJ_UNREF(buddy, aji_buddy_destroy); + ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy); + } else { + ASTOBJ_CONTAINER_LINK(&client->buddies, buddy); } return 1; } @@ -4632,17 +4654,10 @@ static int aji_load_config(int reload) } /*! - * \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 @@ struct aji_client *ast_aji_get_client(const char *name) aux = strsep(&aux, "/"); } if (!strncasecmp(aux, name, strlen(aux))) { - client = iterator; + client = ASTOBJ_REF(iterator); } }); } @@ -4711,6 +4726,7 @@ static int manager_jabber_send(struct mansession *s, const struct message *m) } 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 @@ static int aji_reload(int reload) } 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 @@ static int unload_module(void) 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); |