<p>Kevin Harwell has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/12790">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_mwi: add better handling of solicited vs unsolicited subscriptions<br><br>res_pjsip_mwi allows both solicited and unsolicited MWI subscription types.<br>While both can be set in the configuration for a given endpoint/aor, only<br>one is allowed. Precedence is given to unsolicited. Meaning if an endpoint/aor<br>is configured to allow both types then the solicited subscription is rejected<br>when it comes in. However, there is a configuration option to override that<br>behavior:<br><br>mwi_subscribe_replaces_unsolicited<br><br>When set to "yes" then when a solicited subscription comes in instead of<br>rejecting it Asterisk is suppose to replace the unsolicited one if it exists.<br>Prior to this patch there was a bug in Asterisk that allowed the solicted one<br>to be added, but did not remove the unsolicited. As a matter of fact a new<br>unsolicited subscription got added everytime a SIP register was received.<br>Over time this eventually could "flood" a phone with SIP notifies.<br><br>This patch fixes that behavior to now make it work as expected. If configured<br>to do so a solicited subscription now properly replaces the unsolicited one.<br>As well when an unsubscribe is received the unsolicited subscription is<br>restored. Logic was also put in to handle reloads, and any configuration changes<br>that might result from that. For instance, if a solicited subscription had<br>previously replaced an unsolicited one, but after reload it was configured to<br>not allow that then the solicited one needs to be shutdown, and the unsolicited<br>one added.<br><br>ASTERISK-28488<br><br>Change-Id: Iec2ec12d9431097e97ed5f37119963aee41af7b1<br>---<br>M res/res_pjsip_mwi.c<br>1 file changed, 269 insertions(+), 41 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/90/12790/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c</span><br><span>index abd7ac0..6d43eae 100644</span><br><span>--- a/res/res_pjsip_mwi.c</span><br><span>+++ b/res/res_pjsip_mwi.c</span><br><span>@@ -42,6 +42,7 @@</span><br><span> </span><br><span> struct mwi_subscription;</span><br><span> static struct ao2_container *unsolicited_mwi;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ao2_container *solicited_mwi;</span><br><span> </span><br><span> static char *default_voicemail_extension;</span><br><span> </span><br><span>@@ -119,6 +120,8 @@</span><br><span> char *aors;</span><br><span> /*! Is the MWI solicited (i.e. Initiated with an external SUBSCRIBE) ? */</span><br><span> unsigned int is_solicited;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! True if this subscription is to be terminated */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int terminate;</span><br><span> /*! Identifier for the subscription.</span><br><span> * The identifier is the same as the corresponding endpoint's stasis ID.</span><br><span> * Used as a hash key</span><br><span>@@ -672,7 +675,7 @@</span><br><span> </span><br><span> ao2_cleanup(aor);</span><br><span> ao2_cleanup(endpoint);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_sip_subscription_notify(sub->sip_sub, &data, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_subscription_notify(sub->sip_sub, &data, sub->terminate);</span><br><span> </span><br><span> return;</span><br><span> }</span><br><span>@@ -683,28 +686,65 @@</span><br><span> static int unsubscribe_stasis(void *obj, void *arg, int flags)</span><br><span> {</span><br><span> struct mwi_stasis_subscription *mwi_stasis = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_str **mailboxes = arg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (mwi_stasis->stasis_sub) {</span><br><span> ast_debug(3, "Removing stasis subscription to mailbox %s\n", mwi_stasis->mailbox);</span><br><span> mwi_stasis->stasis_sub = stasis_unsubscribe_and_join(mwi_stasis->stasis_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (arg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_append(mailboxes, 0, "%s,", mwi_stasis->mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> return CMP_MATCH;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int create_unsolicited_mwi_subscriptions(struct ast_sip_endpoint *endpoint,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *mailboxes, int send_now);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)</span><br><span> {</span><br><span> struct mwi_subscription *mwi_sub;</span><br><span> struct ast_datastore *mwi_datastore;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_endpoint *endpoint = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_str *mailboxes;</span><br><span> </span><br><span> mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);</span><br><span> if (!mwi_datastore) {</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ mailboxes = ast_str_create(128);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!mailboxes) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> mwi_sub = mwi_datastore->data;</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * While iterating collect the mailboxes just in case we have to re-establish</span><br><span style="color: hsl(120, 100%, 40%);">+ * an unsolicited subscription for any of them.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, &mailboxes);</span><br><span> ast_sip_subscription_remove_datastore(sub, MWI_DATASTORE);</span><br><span style="color: hsl(120, 100%, 40%);">+ endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", mwi_sub->id);</span><br><span> </span><br><span> ao2_ref(mwi_datastore, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlink(solicited_mwi, mwi_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * When a solicited subscription is removed it's possible an unsolicited one</span><br><span style="color: hsl(120, 100%, 40%);">+ * needs to be [re-]created. Attempt to establish unsolicited MWI for the</span><br><span style="color: hsl(120, 100%, 40%);">+ * collected mailboxes</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (unsolicited_mwi && endpoint) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_truncate(mailboxes, -1); /* Remove trailing comma */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(unsolicited_mwi);</span><br><span style="color: hsl(120, 100%, 40%);">+ create_unsolicited_mwi_subscriptions(endpoint, ast_str_buffer(mailboxes), 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(unsolicited_mwi);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(endpoint, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(mailboxes);</span><br><span> }</span><br><span> </span><br><span> static void mwi_ds_destroy(void *data)</span><br><span>@@ -740,43 +780,164 @@</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Determines if an endpoint is receiving unsolicited MWI for a particular mailbox.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Determine if an MWI subscription already exists for the given endpoint/mailbox</span><br><span> *</span><br><span style="color: hsl(0, 100%, 40%);">- * \param endpoint The endpoint to check</span><br><span style="color: hsl(0, 100%, 40%);">- * \param mailbox The candidate mailbox</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval 0 The endpoint does not receive unsolicited MWI for this mailbox</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval 1 The endpoint receives unsolicited MWI for this mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * Search the given container, and attempt to find out if the given endpoint has a</span><br><span style="color: hsl(120, 100%, 40%);">+ * current subscription within. If so pass back the associated mwi_subscription and</span><br><span style="color: hsl(120, 100%, 40%);">+ * mwi_stasis_subscription objects.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note If a subscription is located then the caller is responsible for removing the</span><br><span style="color: hsl(120, 100%, 40%);">+ * references to the passed back mwi_subscription and mwi_stasis_subscription objects.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Must be called with the given container already locked.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param container The ao2_container to search</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param endpoint The endpoint to find</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mailbox The mailbox potentially subscribed</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mwi_sub [out] May contain the located mwi_subscription</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mwi_stasis [out] May contain the located mwi_stasis_subscription</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 if a subscription was located, 0 otherwise</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint *endpoint,</span><br><span style="color: hsl(0, 100%, 40%);">- const char *mailbox)</span><br><span style="color: hsl(120, 100%, 40%);">+static int has_mwi_subscription(struct ao2_container *container,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_endpoint *endpoint, const char *mailbox,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mwi_subscription **mwi_sub, struct mwi_stasis_subscription **mwi_stasis)</span><br><span> {</span><br><span> struct ao2_iterator *mwi_subs;</span><br><span style="color: hsl(0, 100%, 40%);">- struct mwi_subscription *mwi_sub;</span><br><span style="color: hsl(0, 100%, 40%);">- const char *endpoint_id = ast_sorcery_object_get_id(endpoint);</span><br><span style="color: hsl(0, 100%, 40%);">- int ret = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE);</span><br><span style="color: hsl(120, 100%, 40%);">+ *mwi_sub = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ *mwi_stasis = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mwi_subs = ao2_find(container, ast_sorcery_object_get_id(endpoint),</span><br><span style="color: hsl(120, 100%, 40%);">+ OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK);</span><br><span> if (!mwi_subs) {</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- for (; (mwi_sub = ao2_iterator_next(mwi_subs)) && !ret; ao2_cleanup(mwi_sub)) {</span><br><span style="color: hsl(0, 100%, 40%);">- struct mwi_stasis_subscription *mwi_stasis;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- mwi_stasis = ao2_find(mwi_sub->stasis_subs, mailbox, OBJ_SEARCH_KEY);</span><br><span style="color: hsl(0, 100%, 40%);">- if (mwi_stasis) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (endpoint->subscription.mwi.subscribe_replaces_unsolicited) {</span><br><span style="color: hsl(0, 100%, 40%);">- unsubscribe_stasis(mwi_stasis, NULL, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_unlink(mwi_sub->stasis_subs, mwi_stasis);</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- ret = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_cleanup(mwi_stasis);</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((*mwi_sub = ao2_iterator_next(mwi_subs))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *mwi_stasis = ao2_find((*mwi_sub)->stasis_subs, mailbox, OBJ_SEARCH_KEY);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*mwi_stasis) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If found then caller is responsible for unrefs of passed back objects */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(*mwi_sub, -1);</span><br><span> }</span><br><span> </span><br><span> ao2_iterator_destroy(mwi_subs);</span><br><span style="color: hsl(0, 100%, 40%);">- return ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ return *mwi_stasis ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Determine if a solicited MWI subscription is allowed</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param endpoint The endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mailbox The mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 if a solicited subscription is allowed for the endpoint/mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * 0 otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int is_solicited_allowed(struct ast_sip_endpoint *endpoint, const char *mailbox)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mwi_subscription *mwi_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mwi_stasis_subscription *mwi_stasis;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!has_mwi_subscription(unsolicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If no unsolicited subscription then allow the solicited one */</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!endpoint->subscription.mwi.subscribe_replaces_unsolicited) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Has unsolicited subscription and can't replace, so disallow */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_stasis, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_sub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * The unsolicited subscription exists, and it is allowed to be replaced.</span><br><span style="color: hsl(120, 100%, 40%);">+ * So, first remove the unsolicited stasis subscription, and if aggregation</span><br><span style="color: hsl(120, 100%, 40%);">+ * is not enabled then also remove the mwi_subscription object as well.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(1, "Unsolicited subscription being replaced by solicited for "</span><br><span style="color: hsl(120, 100%, 40%);">+ "endpoint '%s' mailbox '%s'\n", ast_sorcery_object_get_id(endpoint), mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ unsubscribe_stasis(mwi_stasis, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlink(mwi_sub->stasis_subs, mwi_stasis);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!endpoint->subscription.mwi.aggregate) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlink(unsolicited_mwi, mwi_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_stasis, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_sub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* This solicited subscription is replacing an unsolicited one, so allow */</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int send_notify(void *obj, void *arg, int flags);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Determine if an unsolicited MWI subscription is allowed</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param endpoint The endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mailbox The mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 if an unsolicited subscription is allowed for the endpoint/mailbox</span><br><span style="color: hsl(120, 100%, 40%);">+ * 0 otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int is_unsolicited_allowed(struct ast_sip_endpoint *endpoint, const char *mailbox)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mwi_subscription *mwi_sub;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mwi_stasis_subscription *mwi_stasis;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(mailbox)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * First check if an unsolicited subscription exists. If it does then we don't</span><br><span style="color: hsl(120, 100%, 40%);">+ * want to add another one. Note, however if aggregation is enabled then the</span><br><span style="color: hsl(120, 100%, 40%);">+ * mwi_subscription object already exists, but we still need to do the other</span><br><span style="color: hsl(120, 100%, 40%);">+ * checks to see if the stasis subscription for the mailbox needs to be allowed.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!endpoint->subscription.mwi.aggregate &&</span><br><span style="color: hsl(120, 100%, 40%);">+ has_mwi_subscription(unsolicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_stasis, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_sub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * If there is no unsolicited subscription, next check to see if a solicited</span><br><span style="color: hsl(120, 100%, 40%);">+ * subscription exists for the endpoint/mailbox. If not, then allow.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!has_mwi_subscription(solicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * If however, a solicited subscription does exist then we'll need to see if that</span><br><span style="color: hsl(120, 100%, 40%);">+ * subscription is allowed to replace the unsolicited one. If is allowed to replace</span><br><span style="color: hsl(120, 100%, 40%);">+ * then disallow the unsolicited one.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (endpoint->subscription.mwi.subscribe_replaces_unsolicited) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_stasis, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_sub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Otherwise, shutdown the solicited subscription and allow the unsolicited */</span><br><span style="color: hsl(120, 100%, 40%);">+ mwi_sub->terminate = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ send_notify(mwi_sub, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_stasis, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(mwi_sub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span>@@ -802,19 +963,23 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* A reload could be taking place so lock while checking if allowed */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(unsolicited_mwi);</span><br><span> mailboxes = ast_strdupa(aor->mailboxes);</span><br><span> while ((mailbox = ast_strip(strsep(&mailboxes, ",")))) {</span><br><span> if (ast_strlen_zero(mailbox)) {</span><br><span> continue;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!is_solicited_allowed(endpoint, mailbox)) {</span><br><span> ast_debug(1, "Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. "</span><br><span> "Denying MWI subscription to %s\n", ast_sorcery_object_get_id(endpoint), mailbox,</span><br><span> ast_sorcery_object_get_id(aor));</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(unsolicited_mwi);</span><br><span> return -1;</span><br><span> }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(unsolicited_mwi);</span><br><span> </span><br><span> return 0;</span><br><span> }</span><br><span>@@ -960,6 +1125,7 @@</span><br><span> ast_sip_subscription_remove_datastore(sip_sub, MWI_DATASTORE);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_link(solicited_mwi, sub);</span><br><span> ao2_cleanup(sub);</span><br><span> ao2_cleanup(endpoint);</span><br><span> return 0;</span><br><span>@@ -1096,12 +1262,28 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! \note Called with the unsolicited_mwi container lock held. */</span><br><span style="color: hsl(0, 100%, 40%);">-static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create unsolicited MWI subscriptions for an endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The optional "mailboxes" parameter if given is expected to be a comma separated list</span><br><span style="color: hsl(120, 100%, 40%);">+ * of mailboxes. If given it's assumed these mailboxes are a subset of those found</span><br><span style="color: hsl(120, 100%, 40%);">+ * on the endpoint, and are iterated over instead for subscription creations.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Call with the unsolicited_mwi container lock held.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param endpoint An endpoint object</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mailboxes Optional comma separated list of mailboxes</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param send_now Whether or not to send a notify once the subscription is created</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int create_unsolicited_mwi_subscriptions(struct ast_sip_endpoint *endpoint,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *mailboxes, int send_now)</span><br><span> {</span><br><span> RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup);</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_sip_endpoint *endpoint = obj;</span><br><span style="color: hsl(0, 100%, 40%);">- char *mailboxes, *mailbox;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *mailboxes_copy;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *mailbox;</span><br><span> </span><br><span> if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) {</span><br><span> return 0;</span><br><span>@@ -1110,25 +1292,41 @@</span><br><span> if (endpoint->subscription.mwi.aggregate) {</span><br><span> const char *endpoint_id = ast_sorcery_object_get_id(endpoint);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Check if subscription exists */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check if aggregate subscription exists */</span><br><span> aggregate_sub = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_NOLOCK);</span><br><span style="color: hsl(0, 100%, 40%);">- if (aggregate_sub) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * If enabled there should only ever exist a single aggregate subscription object</span><br><span style="color: hsl(120, 100%, 40%);">+ * for an endpoint. So if it exists just return unless subscriptions are potentially</span><br><span style="color: hsl(120, 100%, 40%);">+ * being added back in. If that's the case then continue.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (aggregate_sub && !mailboxes) {</span><br><span> return 0;</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (!aggregate_sub) {</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!aggregate_sub) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0; /* No MWI aggregation for you */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * If this is not a pre-existing aggregation object, then force</span><br><span style="color: hsl(120, 100%, 40%);">+ * iteration over all the endpoint's mailboxes vs. a given subset.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ mailboxes = NULL;</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- mailboxes = ast_strdupa(endpoint->subscription.mwi.mailboxes);</span><br><span style="color: hsl(0, 100%, 40%);">- while ((mailbox = ast_strip(strsep(&mailboxes, ",")))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Lock solicited so we don't potentially add to both containers */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(solicited_mwi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mailboxes_copy = ast_strdupa(mailboxes ?: endpoint->subscription.mwi.mailboxes);</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((mailbox = ast_strip(strsep(&mailboxes_copy, ",")))) {</span><br><span> struct mwi_subscription *sub;</span><br><span> struct mwi_stasis_subscription *mwi_stasis_sub;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* check if subscription exists */</span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_strlen_zero(mailbox) ||</span><br><span style="color: hsl(0, 100%, 40%);">- (!aggregate_sub && endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!is_unsolicited_allowed(endpoint, mailbox)) {</span><br><span> continue;</span><br><span> }</span><br><span> </span><br><span>@@ -1140,15 +1338,34 @@</span><br><span> }</span><br><span> if (!aggregate_sub && sub) {</span><br><span> ao2_link_flags(unsolicited_mwi, sub, OBJ_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (send_now) {</span><br><span style="color: hsl(120, 100%, 40%);">+ send_notify(sub, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> ao2_ref(sub, -1);</span><br><span> }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (aggregate_sub) {</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_link_flags(unsolicited_mwi, aggregate_sub, OBJ_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ao2_container_count(aggregate_sub->stasis_subs)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_link_flags(unsolicited_mwi, aggregate_sub, OBJ_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (send_now) {</span><br><span style="color: hsl(120, 100%, 40%);">+ send_notify(aggregate_sub, NULL, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* No stasis subscriptions then no MWI data to aggregate */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(aggregate_sub, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(solicited_mwi);</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return create_unsolicited_mwi_subscriptions(obj, arg, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int unsubscribe(void *obj, void *arg, int flags)</span><br><span> {</span><br><span> struct mwi_subscription *mwi_sub = obj;</span><br><span>@@ -1353,11 +1570,20 @@</span><br><span> ast_log(AST_LOG_WARNING, "Failed to create MWI serializer pool. The default SIP pool will be used for MWI\n");</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ solicited_mwi = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MWI_BUCKETS,</span><br><span style="color: hsl(120, 100%, 40%);">+ mwi_sub_hash, NULL, mwi_sub_cmp);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!solicited_mwi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ mwi_serializer_pool_shutdown();</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_unregister_subscription_handler(&mwi_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> unsolicited_mwi = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MWI_BUCKETS,</span><br><span> mwi_sub_hash, NULL, mwi_sub_cmp);</span><br><span> if (!unsolicited_mwi) {</span><br><span> mwi_serializer_pool_shutdown();</span><br><span> ast_sip_unregister_subscription_handler(&mwi_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(solicited_mwi, -1);</span><br><span> return AST_MODULE_LOAD_DECLINE;</span><br><span> }</span><br><span> </span><br><span>@@ -1390,6 +1616,8 @@</span><br><span> ao2_ref(unsolicited_mwi, -1);</span><br><span> unsolicited_mwi = NULL;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(solicited_mwi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> mwi_serializer_pool_shutdown();</span><br><span> </span><br><span> ast_sip_unregister_subscription_handler(&mwi_handler);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/12790">change 12790</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/12790"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Iec2ec12d9431097e97ed5f37119963aee41af7b1 </div>
<div style="display:none"> Gerrit-Change-Number: 12790 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>