summaryrefslogtreecommitdiff
path: root/res/res_pjsip_mwi.c
diff options
context:
space:
mode:
Diffstat (limited to 'res/res_pjsip_mwi.c')
-rw-r--r--res/res_pjsip_mwi.c86
1 files changed, 59 insertions, 27 deletions
diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c
index eae029376..06587daf7 100644
--- a/res/res_pjsip_mwi.c
+++ b/res/res_pjsip_mwi.c
@@ -138,9 +138,17 @@ static struct mwi_stasis_subscription *mwi_stasis_subscription_alloc(const char
/* Safe strcpy */
strcpy(mwi_stasis_sub->mailbox, mailbox);
+
+ ast_debug(3, "Creating stasis MWI subscription to mailbox %s for endpoint %s\n",
+ mailbox, mwi_sub->id);
ao2_ref(mwi_sub, +1);
- ast_debug(3, "Creating stasis MWI subscription to mailbox %s for endpoint %s\n", mailbox, mwi_sub->id);
mwi_stasis_sub->stasis_sub = stasis_subscribe_pool(topic, mwi_stasis_cb, mwi_sub);
+ if (!mwi_stasis_sub->stasis_sub) {
+ /* Failed to subscribe. */
+ ao2_ref(mwi_stasis_sub, -1);
+ ao2_ref(mwi_sub, -1);
+ mwi_stasis_sub = NULL;
+ }
return mwi_stasis_sub;
}
@@ -491,25 +499,41 @@ static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
mwi_sub = mwi_datastore->data;
ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
+ ast_sip_subscription_remove_datastore(sub, MWI_DATASTORE);
ao2_ref(mwi_datastore, -1);
}
-static struct ast_datastore_info mwi_ds_info = { };
+static void mwi_ds_destroy(void *data)
+{
+ struct mwi_subscription *sub = data;
+
+ ao2_ref(sub, -1);
+}
+
+static struct ast_datastore_info mwi_ds_info = {
+ .destroy = mwi_ds_destroy,
+};
static int add_mwi_datastore(struct mwi_subscription *sub)
{
struct ast_datastore *mwi_datastore;
+ int res;
mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, MWI_DATASTORE);
if (!mwi_datastore) {
return -1;
}
+ ao2_ref(sub, +1);
mwi_datastore->data = sub;
- ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore);
+ /*
+ * NOTE: Adding the datastore to the subscription creates a ref loop
+ * that must be manually broken.
+ */
+ res = ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore);
ao2_ref(mwi_datastore, -1);
- return 0;
+ return res;
}
/*!
@@ -621,8 +645,8 @@ static struct mwi_subscription *mwi_create_subscription(
}
if (add_mwi_datastore(sub)) {
- ast_log(LOG_WARNING, "Unable to allocate datastore on MWI "
- "subscription from %s\n", sub->id);
+ ast_log(LOG_WARNING, "Unable to add datastore for MWI subscription to %s\n",
+ sub->id);
ao2_ref(sub, -1);
return NULL;
}
@@ -633,25 +657,26 @@ static struct mwi_subscription *mwi_create_subscription(
static struct mwi_subscription *mwi_subscribe_single(
struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub, const char *name)
{
- RAII_VAR(struct ast_sip_aor *, aor,
- ast_sip_location_retrieve_aor(name), ao2_cleanup);
+ struct ast_sip_aor *aor;
struct mwi_subscription *sub;
+ aor = ast_sip_location_retrieve_aor(name);
if (!aor) {
/*! I suppose it's possible for the AOR to disappear on us
* between accepting the subscription and sending the first
* NOTIFY...
*/
- ast_log(LOG_WARNING, "Unable to locate aor %s. MWI "
- "subscription failed.\n", name);
+ ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n",
+ name);
return NULL;
}
- if (!(sub = mwi_create_subscription(endpoint, sip_sub))) {
- return NULL;
+ sub = mwi_create_subscription(endpoint, sip_sub);
+ if (sub) {
+ mwi_on_aor(aor, sub, 0);
}
- mwi_on_aor(aor, sub, 0);
+ ao2_ref(aor, -1);
return sub;
}
@@ -661,7 +686,6 @@ static struct mwi_subscription *mwi_subscribe_all(
struct mwi_subscription *sub;
sub = mwi_create_subscription(endpoint, sip_sub);
-
if (!sub) {
return NULL;
}
@@ -683,16 +707,15 @@ static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
}
aor = ast_sip_location_retrieve_aor(resource);
-
if (!aor) {
- ast_log(LOG_WARNING, "Unable to locate aor %s. MWI "
- "subscription failed.\n", resource);
+ ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n",
+ resource);
return 404;
}
if (ast_strlen_zero(aor->mailboxes)) {
- ast_log(LOG_NOTICE, "AOR %s has no configured mailboxes. "
- "MWI subscription failed\n", resource);
+ ast_log(LOG_NOTICE, "AOR %s has no configured mailboxes. MWI subscription failed.\n",
+ resource);
return 404;
}
@@ -715,12 +738,19 @@ static int mwi_subscription_established(struct ast_sip_subscription *sip_sub)
} else {
sub = mwi_subscribe_single(endpoint, sip_sub, resource);
}
-
if (!sub) {
ao2_cleanup(endpoint);
return -1;
}
+ if (!ao2_container_count(sub->stasis_subs)) {
+ /*
+ * We setup no MWI subscriptions so remove the MWI datastore
+ * to break the ref loop.
+ */
+ ast_sip_subscription_remove_datastore(sip_sub, MWI_DATASTORE);
+ }
+
ao2_cleanup(sub);
ao2_cleanup(endpoint);
return 0;
@@ -752,16 +782,16 @@ static void *mwi_get_notify_data(struct ast_sip_subscription *sub)
static void mwi_subscription_mailboxes_str(struct ao2_container *stasis_subs,
struct ast_str **str)
{
- int num = ao2_container_count(stasis_subs);
-
+ int is_first = 1;
struct mwi_stasis_subscription *node;
struct ao2_iterator i = ao2_iterator_init(stasis_subs, 0);
while ((node = ao2_iterator_next(&i))) {
- if (--num) {
- ast_str_append(str, 0, "%s,", node->mailbox);
- } else {
+ if (is_first) {
+ is_first = 0;
ast_str_append(str, 0, "%s", node->mailbox);
+ } else {
+ ast_str_append(str, 0, ",%s", node->mailbox);
}
ao2_ref(node, -1);
}
@@ -816,7 +846,9 @@ static int serialized_cleanup(void *userdata)
static int send_notify(void *obj, void *arg, int flags)
{
struct mwi_subscription *mwi_sub = obj;
- struct ast_taskprocessor *serializer = mwi_sub->is_solicited ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub) : NULL;
+ struct ast_taskprocessor *serializer = mwi_sub->is_solicited
+ ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub)
+ : NULL;
if (ast_sip_push_task(serializer, serialized_notify, ao2_bump(mwi_sub))) {
ao2_ref(mwi_sub, -1);
@@ -842,6 +874,7 @@ static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
}
}
+/*! \note Called with the unsolicited_mwi conainer lock held. */
static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags)
{
RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup);
@@ -982,7 +1015,6 @@ static void mwi_contact_added(const void *object)
ao2_lock(unsolicited_mwi);
mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK | OBJ_UNLINK);
-
if (mwi_subs) {
for (; (mwi_sub = ao2_iterator_next(mwi_subs)); ao2_cleanup(mwi_sub)) {
unsubscribe(mwi_sub, NULL, 0);