diff options
Diffstat (limited to 'res')
-rw-r--r-- | res/ari/resource_events.c | 4 | ||||
-rw-r--r-- | res/res_pjproject.c | 2 | ||||
-rw-r--r-- | res/res_pjsip/location.c | 5 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 2 | ||||
-rw-r--r-- | res/res_pjsip_config_wizard.c | 16 | ||||
-rw-r--r-- | res/res_pjsip_exten_state.c | 7 | ||||
-rw-r--r-- | res/res_pjsip_history.c | 30 | ||||
-rw-r--r-- | res/res_pjsip_outbound_registration.c | 6 | ||||
-rw-r--r-- | res/res_pjsip_pubsub.c | 28 | ||||
-rw-r--r-- | res/res_pjsip_session.c | 119 | ||||
-rw-r--r-- | res/res_pjsip_t38.c | 13 | ||||
-rw-r--r-- | res/res_stasis_playback.c | 6 | ||||
-rw-r--r-- | res/stasis/app.c | 9 | ||||
-rw-r--r-- | res/stasis/messaging.c | 12 |
14 files changed, 184 insertions, 75 deletions
diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c index 4be5d0223..992c562a7 100644 --- a/res/ari/resource_events.c +++ b/res/ari/resource_events.c @@ -108,7 +108,9 @@ static void stasis_app_message_handler( msg_application); } else if (!session->ws_session) { /* If the websocket is NULL, the message goes to the queue */ - AST_VECTOR_APPEND(&session->message_queue, message); + if (!AST_VECTOR_APPEND(&session->message_queue, message)) { + ast_json_ref(message); + } ast_log(LOG_WARNING, "Queued '%s' message for Stasis app '%s'; websocket is not ready\n", msg_type, diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 86b2502e5..6137898a3 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -234,7 +234,7 @@ static void capture_buildopts_cb(int level, const char *data, int len) } dup = ast_strdup(ast_skip_blanks(data)); - if (AST_VECTOR_ADD_SORTED(&buildopts, dup, strcmp)) { + if (dup && AST_VECTOR_ADD_SORTED(&buildopts, dup, strcmp)) { ast_free(dup); } } diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 9945c7c10..0d7b3da31 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1219,6 +1219,11 @@ static int contact_apply_handler(const struct ast_sorcery *sorcery, void *object struct ast_sip_contact_status *status; struct ast_sip_contact *contact = object; + if (ast_strlen_zero(contact->uri)) { + ast_log(LOG_ERROR, "A URI on dynamic contact '%s' is empty\n", + ast_sorcery_object_get_id(contact)); + return -1; + } status = ast_res_pjsip_find_or_create_contact_status(contact); ao2_cleanup(status); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index a6afe5e53..168d86989 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -508,6 +508,8 @@ int ast_sip_auth_vector_init(struct ast_sip_auth_vector *auths, const char *valu goto failure; } if (AST_VECTOR_APPEND(auths, val)) { + ast_free(val); + goto failure; } } diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c index 1526dc2e2..3a761a7c7 100644 --- a/res/res_pjsip_config_wizard.c +++ b/res/res_pjsip_config_wizard.c @@ -1001,7 +1001,10 @@ static int wizard_apply_handler(const struct ast_sorcery *sorcery, struct object char *hosts = ast_strdupa(remote_hosts); while ((host = ast_strsep(&hosts, ',', AST_STRSEP_TRIM))) { - AST_VECTOR_APPEND(&remote_hosts_vector, ast_strdup(host)); + host = ast_strdup(host); + if (host && AST_VECTOR_APPEND(&remote_hosts_vector, host)) { + ast_free(host); + } } } @@ -1168,15 +1171,22 @@ static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery /* We're only interested in memory wizards with the pjsip_wizard tag. */ if (wizard_args && !strcmp(wizard_args, "pjsip_wizard")) { otw = ast_malloc(sizeof(*otw) + strlen(object_type) + 1); + if (!otw) { + return; + } + otw->sorcery = sorcery; otw->wizard = wizard; otw->wizard_data = wizard_data; otw->last_config = NULL; strcpy(otw->object_type, object_type); /* Safe */ AST_VECTOR_RW_WRLOCK(&object_type_wizards); - AST_VECTOR_APPEND(&object_type_wizards, otw); + if (AST_VECTOR_APPEND(&object_type_wizards, otw)) { + ast_free(otw); + } else { + ast_debug(1, "Wizard mapped for object_type '%s'\n", object_type); + } AST_VECTOR_RW_UNLOCK(&object_type_wizards); - ast_debug(1, "Wizard mapped for object_type '%s'\n", object_type); } } diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 95a40829e..3e756134c 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -729,8 +729,11 @@ static int exten_state_publisher_state_cb(const char *context, const char *exten } ao2_ref(publisher, +1); - AST_VECTOR_APPEND(&pub_data->pubs, publisher); - ast_debug(5, "'%s' will publish exten state\n", publisher->name); + if (AST_VECTOR_APPEND(&pub_data->pubs, publisher)) { + ao2_ref(publisher, -1); + } else { + ast_debug(5, "'%s' will publish exten state\n", publisher->name); + } } ao2_iterator_destroy(&publisher_iter); diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c index 4e7dbd007..ed374d605 100644 --- a/res/res_pjsip_history.c +++ b/res/res_pjsip_history.c @@ -705,10 +705,13 @@ static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata) pj_sockaddr_cp(&entry->dst, &tdata->tp_info.dst_addr); ast_mutex_lock(&history_lock); - AST_VECTOR_APPEND(&vector_history, entry); + if (AST_VECTOR_APPEND(&vector_history, entry)) { + ao2_ref(entry, -1); + entry = NULL; + } ast_mutex_unlock(&history_lock); - if (log_level != -1) { + if (log_level != -1 && entry) { char line[256]; sprint_list_entry(entry, line, sizeof(line)); @@ -745,10 +748,13 @@ static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata) } ast_mutex_lock(&history_lock); - AST_VECTOR_APPEND(&vector_history, entry); + if (AST_VECTOR_APPEND(&vector_history, entry)) { + ao2_ref(entry, -1); + entry = NULL; + } ast_mutex_unlock(&history_lock); - if (log_level != -1) { + if (log_level != -1 && entry) { char line[256]; sprint_list_entry(entry, line, sizeof(line)); @@ -959,7 +965,9 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr /* If this is not an operator, push it to the stack */ if (!it_queue->op) { - AST_VECTOR_APPEND(&stack, it_queue); + if (AST_VECTOR_APPEND(&stack, it_queue)) { + goto error; + } continue; } @@ -1035,7 +1043,11 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr if (!result) { goto error; } - AST_VECTOR_APPEND(&stack, result); + if (AST_VECTOR_APPEND(&stack, result)) { + expression_token_free(result); + + goto error; + } } /* @@ -1056,6 +1068,7 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr } result = final->result; ast_free(final); + AST_VECTOR_FREE(&stack); return result; @@ -1098,6 +1111,7 @@ static struct vector_history_t *filter_history(struct ast_cli_args *a) queue = build_expression_queue(a); if (!queue) { + AST_VECTOR_PTR_FREE(output); return NULL; } @@ -1118,7 +1132,9 @@ static struct vector_history_t *filter_history(struct ast_cli_args *a) } else if (!res) { continue; } else { - AST_VECTOR_APPEND(output, ao2_bump(entry)); + if (AST_VECTOR_APPEND(output, ao2_bump(entry))) { + ao2_cleanup(entry); + } } } ast_mutex_unlock(&history_lock); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 7fa6e2c10..d9afcd284 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1385,10 +1385,10 @@ static int sip_outbound_registration_perform(void *data) AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(®istration->outbound_auths)); for (i = 0; i < AST_VECTOR_SIZE(®istration->outbound_auths); ++i) { - const char *name = ast_strdup(AST_VECTOR_GET(®istration->outbound_auths, i)); + char *name = ast_strdup(AST_VECTOR_GET(®istration->outbound_auths, i)); - if (name) { - AST_VECTOR_APPEND(&state->client_state->outbound_auths, name); + if (name && AST_VECTOR_APPEND(&state->client_state->outbound_auths, name)) { + ast_free(name); } } state->client_state->retry_interval = registration->retry_interval; diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 62b187951..42b1a659b 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -938,7 +938,9 @@ static void build_node_children(struct ast_sip_endpoint *endpoint, const struct } ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n", resource, parent->resource); - AST_VECTOR_APPEND(&parent->children, current); + if (AST_VECTOR_APPEND(&parent->children, current)) { + tree_node_destroy(current); + } } else { ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n", resource, resp); @@ -953,7 +955,9 @@ static void build_node_children(struct ast_sip_endpoint *endpoint, const struct build_node_children(endpoint, handler, child_list, current, visited); if (AST_VECTOR_SIZE(¤t->children) > 0) { ast_debug(1, "List %s had no successful children.\n", resource); - AST_VECTOR_APPEND(&parent->children, current); + if (AST_VECTOR_APPEND(&parent->children, current)) { + tree_node_destroy(current); + } } else { ast_debug(2, "List %s had successful children. Adding to parent %s\n", resource, parent->resource); @@ -1194,6 +1198,10 @@ static struct ast_sip_subscription *create_virtual_subscriptions(const struct as if (AST_VECTOR_APPEND(&sub->children, child)) { ast_debug(1, "Child subscription to resource %s could not be appended\n", child_node->resource); + destroy_subscription(child); + /* Have to release tree here too because a ref was added + * to child that destroy_subscription() doesn't release. */ + ao2_cleanup(tree); } } @@ -2139,7 +2147,9 @@ static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub, bp->part->body = body; pj_list_insert_before(&bp->part->hdr, bp->cid); - AST_VECTOR_APPEND(parts, bp); + if (AST_VECTOR_APPEND(parts, bp)) { + ast_free(bp); + } } /*! @@ -2200,6 +2210,7 @@ static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscr /* This can happen if issuing partial state and no children of the list have changed state */ if (AST_VECTOR_SIZE(&body_parts) == 0) { + free_body_parts(&body_parts); return NULL; } @@ -2207,6 +2218,7 @@ static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscr rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state); if (!rlmi_part) { + free_body_parts(&body_parts); return NULL; } pjsip_multipart_add_part(pool, multipart, rlmi_part); @@ -4602,7 +4614,10 @@ static int list_item_handler(const struct aco_option *opt, ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item); continue; } - if (AST_VECTOR_APPEND(&list->items, ast_strdup(item))) { + + item = ast_strdup(item); + if (!item || AST_VECTOR_APPEND(&list->items, item)) { + ast_free(item); return -1; } } @@ -4738,7 +4753,10 @@ static int populate_list(struct resource_list *list, const char *event, const ch ast_copy_string(list->event, event, sizeof(list->event)); for (i = 0; i < num_resources; ++i) { - if (AST_VECTOR_APPEND(&list->items, ast_strdup(resources[i]))) { + char *resource = ast_strdup(resources[i]); + + if (!resource || AST_VECTOR_APPEND(&list->items, resource)) { + ast_free(resource); return -1; } } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 4724d46ce..781d3e4eb 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -174,7 +174,8 @@ void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler * ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler); } -struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) +static struct ast_sip_session_media_state *internal_sip_session_media_state_alloc( + size_t sessions, size_t read_callbacks) { struct ast_sip_session_media_state *media_state; @@ -183,12 +184,12 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) return NULL; } - if (AST_VECTOR_INIT(&media_state->sessions, DEFAULT_NUM_SESSION_MEDIA) < 0) { + if (AST_VECTOR_INIT(&media_state->sessions, sessions) < 0) { ast_free(media_state); return NULL; } - if (AST_VECTOR_INIT(&media_state->read_callbacks, DEFAULT_NUM_SESSION_MEDIA) < 0) { + if (AST_VECTOR_INIT(&media_state->read_callbacks, read_callbacks) < 0) { AST_VECTOR_FREE(&media_state->sessions); ast_free(media_state); return NULL; @@ -197,6 +198,12 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) return media_state; } +struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) +{ + return internal_sip_session_media_state_alloc( + DEFAULT_NUM_SESSION_MEDIA, DEFAULT_NUM_SESSION_MEDIA); +} + void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state) { int index; @@ -225,7 +232,9 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_clone(const stru return NULL; } - cloned = ast_sip_session_media_state_alloc(); + cloned = internal_sip_session_media_state_alloc( + AST_VECTOR_SIZE(&media_state->sessions), + AST_VECTOR_SIZE(&media_state->read_callbacks)); if (!cloned) { return NULL; } @@ -452,7 +461,11 @@ struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_ses } } - AST_VECTOR_REPLACE(&media_state->sessions, position, session_media); + if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) { + ao2_ref(session_media, -1); + + return NULL; + } /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */ if (!media_state->default_session[type] && ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) { @@ -678,7 +691,10 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd if (!stream) { return -1; } - ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream); + if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) { + ast_stream_free(stream); + return -1; + } } session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i); @@ -1588,7 +1604,11 @@ int ast_sip_session_refresh(struct ast_sip_session *session, } ast_stream_set_state(cloned, AST_STREAM_STATE_REMOVED); - ast_stream_topology_append_stream(media_state->topology, cloned); + if (ast_stream_topology_append_stream(media_state->topology, cloned) < 0) { + ast_stream_free(cloned); + ast_sip_session_media_state_free(media_state); + return -1; + } } /* If the resulting media state matches the existing active state don't bother doing a session refresh */ @@ -1745,7 +1765,10 @@ static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_ /* As this is only called on an incoming SDP offer before processing it is not possible * for streams and their media sessions to exist. */ - ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream); + if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) { + ast_stream_free(stream); + return -1; + } session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i); if (!session_media) { @@ -3459,6 +3482,36 @@ static void session_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e) /* XXX STUB */ } +static int session_end_if_disconnected(int id, pjsip_inv_session *inv) +{ + struct ast_sip_session *session; + + if (inv->state != PJSIP_INV_STATE_DISCONNECTED) { + return 0; + } + + /* + * We are locking because ast_sip_dialog_get_session() needs + * the dialog locked to get the session by other threads. + */ + pjsip_dlg_inc_lock(inv->dlg); + session = inv->mod_data[id]; + inv->mod_data[id] = NULL; + pjsip_dlg_dec_lock(inv->dlg); + + /* + * Pass the session ref held by session->inv_session to + * session_end_completion(). + */ + if (session + && ast_sip_push_task(session->serializer, session_end_completion, session)) { + /* Do it anyway even though this is not the right thread. */ + session_end_completion(session); + } + + return 1; +} + static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) { ast_sip_session_response_cb cb; @@ -3483,6 +3536,17 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans /* The session has ended. Ignore the transaction change. */ return; } + + /* + * If the session is disconnected really nothing else to do unless currently transacting + * a BYE. If a BYE then hold off destruction until the transaction timeout occurs. This + * has to be done for BYEs because sometimes the dialog can be in a disconnected + * state but the BYE request transaction has not yet completed. + */ + if (tsx->method.id != PJSIP_BYE_METHOD && session_end_if_disconnected(id, inv)) { + return; + } + switch (e->body.tsx_state.type) { case PJSIP_EVENT_TX_MSG: /* When we create an outgoing request, we do not have access to the transaction that @@ -3605,49 +3669,12 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } break; case PJSIP_EVENT_TRANSPORT_ERROR: - if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { - /* - * Clear the module data now to block session_inv_on_state_changed() - * from calling session_end() if it hasn't already done so. - */ - inv->mod_data[id] = NULL; - - /* - * Pass the session ref held by session->inv_session to - * session_end_completion(). - */ - if (session - && ast_sip_push_task(session->serializer, session_end_completion, session)) { - /* Do it anyway even though this is not the right thread. */ - session_end_completion(session); - } - return; - } - break; case PJSIP_EVENT_TIMER: /* * The timer event is run by the pjsip monitor thread and not * by the session serializer. */ - if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { - /* - * We are locking because ast_sip_dialog_get_session() needs - * the dialog locked to get the session by other threads. - */ - pjsip_dlg_inc_lock(inv->dlg); - session = inv->mod_data[id]; - inv->mod_data[id] = NULL; - pjsip_dlg_dec_lock(inv->dlg); - - /* - * Pass the session ref held by session->inv_session to - * session_end_completion(). - */ - if (session - && ast_sip_push_task(session->serializer, session_end_completion, session)) { - /* Do it anyway even though this is not the right thread. */ - session_end_completion(session); - } + if (session_end_if_disconnected(id, inv)) { return; } break; diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 48cbab37b..8f1905f6e 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -363,7 +363,11 @@ static struct ast_sip_session_media_state *t38_create_media_state(struct ast_sip } ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV); - ast_stream_topology_set_stream(media_state->topology, 0, stream); + if (ast_stream_topology_set_stream(media_state->topology, 0, stream)) { + ast_stream_free(stream); + ast_sip_session_media_state_free(media_state); + return NULL; + } caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!caps) { @@ -371,9 +375,14 @@ static struct ast_sip_session_media_state *t38_create_media_state(struct ast_sip return NULL; } - ast_format_cap_append(caps, ast_format_t38, 0); ast_stream_set_formats(stream, caps); + /* stream holds a reference to cap, release the local reference + * now so we don't have to deal with it in the error condition. */ ao2_ref(caps, -1); + if (ast_format_cap_append(caps, ast_format_t38, 0)) { + ast_sip_session_media_state_free(media_state); + return NULL; + } session_media = ast_sip_session_media_state_add(session, media_state, AST_MEDIA_TYPE_IMAGE, 0); if (!session_media) { diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c index c6f21365b..ca0446b89 100644 --- a/res/res_stasis_playback.c +++ b/res/res_stasis_playback.c @@ -497,7 +497,11 @@ struct stasis_app_playback *stasis_app_control_play_uri( /* safe */ strcpy(media_uri, media[i]); - AST_VECTOR_APPEND(&playback->medias, media_uri); + if (AST_VECTOR_APPEND(&playback->medias, media_uri)) { + ao2_ref(playback, -1); + ast_free(media_uri); + return NULL; + } } if (skipms == 0) { diff --git a/res/stasis/app.c b/res/stasis/app.c index 0b44bf3c6..a1ef5c0b6 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -588,6 +588,7 @@ static int message_received_handler(const char *endpoint_id, struct ast_json *js { RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup); struct ast_json *json_endpoint; + struct ast_json *message; struct stasis_app *app = pvt; char *tech; char *resource; @@ -613,11 +614,15 @@ static int message_received_handler(const char *endpoint_id, struct ast_json *js return -1; } - app_send(app, ast_json_pack("{s: s, s: o, s: o, s: o}", + message = ast_json_pack("{s: s, s: o, s: o, s: o}", "type", "TextMessageReceived", "timestamp", ast_json_timeval(ast_tvnow(), NULL), "endpoint", json_endpoint, - "message", ast_json_ref(json_msg))); + "message", ast_json_ref(json_msg)); + if (message) { + app_send(app, message); + ast_json_unref(message); + } return 0; } diff --git a/res/stasis/messaging.c b/res/stasis/messaging.c index d398bb6d4..77a58745a 100644 --- a/res/stasis/messaging.c +++ b/res/stasis/messaging.c @@ -457,7 +457,11 @@ static struct message_subscription *get_or_create_subscription(struct ast_endpoi ao2_link(endpoint_subscriptions, sub); } else { ast_rwlock_wrlock(&tech_subscriptions_lock); - AST_VECTOR_APPEND(&tech_subscriptions, ao2_bump(sub)); + if (AST_VECTOR_APPEND(&tech_subscriptions, ao2_bump(sub))) { + /* Release the ao2_bump that was for the vector and allocation references. */ + ao2_ref(sub, -2); + sub = NULL; + } ast_rwlock_unlock(&tech_subscriptions_lock); } @@ -485,7 +489,11 @@ int messaging_app_subscribe_endpoint(const char *app_name, struct ast_endpoint * ao2_unlock(sub); return -1; } - AST_VECTOR_APPEND(&sub->applications, tuple); + if (AST_VECTOR_APPEND(&sub->applications, tuple)) { + ao2_ref(tuple, -1); + ao2_unlock(sub); + return -1; + } ao2_unlock(sub); ast_debug(3, "App '%s' subscribed to messages from endpoint '%s'\n", app_name, endpoint ? ast_endpoint_get_id(endpoint) : "-- ALL --"); |