<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/12792">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  Benjamin Keith Ford: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><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, 251 insertions(+), 40 deletions(-)<br><br></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 2ea5f89..c89d383 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>@@ -665,7 +668,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>@@ -676,18 +679,22 @@</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%);">+</span><br><span>  if (mwi_stasis->mwi_subscriber) {</span><br><span>                 ast_debug(3, "Removing stasis subscription to mailbox %s\n", mwi_stasis->mailbox);</span><br><span>              mwi_stasis->mwi_subscriber = ast_mwi_unsubscribe_and_join(mwi_stasis->mwi_subscriber);</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-</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%);">+                int recreate, 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> </span><br><span>        mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);</span><br><span>      if (!mwi_datastore) {</span><br><span>@@ -695,10 +702,25 @@</span><br><span>        }</span><br><span> </span><br><span>        mwi_sub = mwi_datastore->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);</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.</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%);">+            ao2_lock(unsolicited_mwi);</span><br><span style="color: hsl(120, 100%, 40%);">+            create_unsolicited_mwi_subscriptions(endpoint, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+         ao2_unlock(unsolicited_mwi);</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_cleanup(endpoint);</span><br><span> }</span><br><span> </span><br><span> static void mwi_ds_destroy(void *data)</span><br><span>@@ -734,43 +756,165 @@</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 Allow and/or replace the unsolicited subscription</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Checks to see if solicited subscription is allowed. If allowed, and an</span><br><span style="color: hsl(120, 100%, 40%);">+ * unsolicited one exists then prepare for replacement by removing the</span><br><span style="color: hsl(120, 100%, 40%);">+ * current unsolicited subscription.</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 allow_and_or_replace_unsolicited(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.</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%);">+                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>@@ -796,19 +940,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 (!allow_and_or_replace_unsolicited(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>@@ -954,6 +1102,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>@@ -1090,12 +1239,25 @@</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%);">+ * \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 recreate Whether or not unsolicited subscriptions are potentially being recreated</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%);">+              int recreate, 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;</span><br><span style="color: hsl(120, 100%, 40%);">+      char *mailbox;</span><br><span style="color: hsl(120, 100%, 40%);">+        int sub_added = 0;</span><br><span> </span><br><span>       if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) {</span><br><span>              return 0;</span><br><span>@@ -1104,45 +1266,83 @@</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 && !recreate) {</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>            }</span><br><span>    }</span><br><span> </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>   mailboxes = ast_strdupa(endpoint->subscription.mwi.mailboxes);</span><br><span>    while ((mailbox = ast_strip(strsep(&mailboxes, ",")))) {</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>                sub = aggregate_sub ?: mwi_subscription_alloc(endpoint, 0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!sub) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub);</span><br><span>                if (mwi_stasis_sub) {</span><br><span>                        ao2_link(sub->stasis_subs, mwi_stasis_sub);</span><br><span>                       ao2_ref(mwi_stasis_sub, -1);</span><br><span>                 }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (!aggregate_sub && sub) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!aggregate_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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (aggregate_sub && !sub_added) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* If aggregation track if at least one subscription has been added */</span><br><span style="color: hsl(120, 100%, 40%);">+                        sub_added = 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>  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 && sub_added) {</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, 0, 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>@@ -1347,11 +1547,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>@@ -1384,6 +1593,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/+/12792">change 12792</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/+/12792"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 17 </div>
<div style="display:none"> Gerrit-Change-Id: Iec2ec12d9431097e97ed5f37119963aee41af7b1 </div>
<div style="display:none"> Gerrit-Change-Number: 12792 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>