Merge "dns: Make query sets hold on to queries for their lifetime."
authorMatt Jordan <mjordan@digium.com>
Wed, 22 Apr 2015 19:26:02 +0000 (14:26 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Wed, 22 Apr 2015 19:26:02 +0000 (14:26 -0500)
include/asterisk/utils.h
res/res_pjsip_mwi.c

index f3f5719..664e347 100644 (file)
@@ -1031,19 +1031,13 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size);
  */
 
 #if defined(__clang__)
-
-#if defined(__has_feature) && __has_feature(blocks)
 typedef void (^_raii_cleanup_block_t)(void);
 static inline void _raii_cleanup_block(_raii_cleanup_block_t *b) { (*b)(); }
 
 #define RAII_VAR(vartype, varname, initval, dtor)                                                                \
     _raii_cleanup_block_t _raii_cleanup_ ## varname __attribute__((cleanup(_raii_cleanup_block),unused)) = NULL; \
-    vartype varname = initval;                                                                                   \
-    _raii_cleanup_ ## varname = ^{ dtor(varname); }
-
-#else
-       #error "CLANG must support the 'blocks' feature to compile Asterisk."
-#endif /* #if defined(__has_feature) && __has_feature(blocks) */
+    __block vartype varname = initval;                                                                           \
+    _raii_cleanup_ ## varname = ^{ {(void)dtor(varname);} }
 
 #elif defined(__GNUC__)
 
index 9c275af..2ab7dfe 100644 (file)
@@ -100,12 +100,14 @@ struct mwi_stasis_subscription {
  */
 struct mwi_subscription {
        /*! Container of \ref mwi_stasis_subscription structures.
-        * A single MWI subscription may be fore multiple mailboxes, thus
+        * A single MWI subscription may be for multiple mailboxes, thus
         * requiring multiple stasis subscriptions
         */
        struct ao2_container *stasis_subs;
        /*! The SIP subscription. Unsolicited MWI does not use this */
        struct ast_sip_subscription *sip_sub;
+       /*! AORs we should react to for unsolicited MWI NOTIFY */
+       char *aors;
        /*! Is the MWI solicited (i.e. Initiated with an external SUBSCRIBE) ? */
        unsigned int is_solicited;
        /*! Identifier for the subscription.
@@ -196,6 +198,7 @@ static void mwi_subscription_destructor(void *obj)
        ast_debug(3, "Destroying MWI subscription for endpoint %s\n", sub->id);
        ao2_cleanup(sub->sip_sub);
        ao2_cleanup(sub->stasis_subs);
+       ast_free(sub->aors);
 }
 
 static struct mwi_subscription *mwi_subscription_alloc(struct ast_sip_endpoint *endpoint,
@@ -232,6 +235,14 @@ static struct mwi_subscription *mwi_subscription_alloc(struct ast_sip_endpoint *
        }
        sub->is_solicited = is_solicited;
 
+       if (!is_solicited && !ast_strlen_zero(endpoint->aors)) {
+               sub->aors = ast_strdup(endpoint->aors);
+               if (!sub->aors) {
+                       ao2_ref(sub, -1);
+                       return NULL;
+               }
+       }
+
        ast_debug(3, "Created %s MWI subscription for endpoint %s\n", is_solicited ? "solicited" : "unsolicited", sub->id);
 
        return sub;
@@ -796,21 +807,32 @@ static int serialized_cleanup(void *userdata)
        return 0;
 }
 
+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;
+
+       if (ast_sip_push_task(serializer, serialized_notify, ao2_bump(mwi_sub))) {
+               ao2_ref(mwi_sub, -1);
+       }
+
+       return 0;
+}
+
 static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
                struct stasis_message *msg)
 {
        struct mwi_subscription *mwi_sub = userdata;
 
        if (stasis_subscription_final_message(sub, msg)) {
-               ao2_ref(mwi_sub, +1);
-               ast_sip_push_task(NULL, serialized_cleanup, mwi_sub);
+               if (ast_sip_push_task(NULL, serialized_cleanup, ao2_bump(mwi_sub))) {
+                       ao2_ref(mwi_sub, -1);
+               }
                return;
        }
 
        if (ast_mwi_state_type() == stasis_message_type(msg)) {
-               struct ast_taskprocessor *serializer = mwi_sub->is_solicited ? ast_sip_subscription_get_serializer(mwi_sub->sip_sub) : NULL;
-               ao2_ref(mwi_sub, +1);
-               ast_sip_push_task(serializer, serialized_notify, mwi_sub);
+               send_notify(mwi_sub, NULL, 0);
        }
 }
 
@@ -858,6 +880,7 @@ static int unsubscribe(void *obj, void *arg, int flags)
        struct mwi_subscription *mwi_sub = obj;
 
        ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
+
        return CMP_MATCH;
 }
 
@@ -887,6 +910,83 @@ static void create_mwi_subscriptions(void)
        ao2_ref(mwi_subscriptions, -1);
 }
 
+/*! \brief Function called to send MWI NOTIFY on any unsolicited mailboxes relating to this AOR */
+static int send_contact_notify(void *obj, void *arg, int flags)
+{
+       struct mwi_subscription *mwi_sub = obj;
+       const char *aor = arg;
+
+       if (!mwi_sub->aors || !strstr(mwi_sub->aors, aor)) {
+               return 0;
+       }
+
+       if (ast_sip_push_task(NULL, serialized_notify, ao2_bump(mwi_sub))) {
+               ao2_ref(mwi_sub, -1);
+       }
+
+       return 0;
+}
+
+
+/*! \brief Function called when a contact is created or updated */
+static void mwi_contact_changed_observer(const void *object)
+{
+       char *id = ast_strdupa(ast_sorcery_object_get_id(object)), *aor = NULL;
+       struct ao2_container *mwi_subscriptions = ao2_global_obj_ref(unsolicited_mwi);
+
+       if (!mwi_subscriptions) {
+               return;
+       }
+
+       aor = strsep(&id, ";@");
+
+       ao2_callback(mwi_subscriptions, OBJ_NODATA, send_contact_notify, aor);
+       ao2_ref(mwi_subscriptions, -1);
+}
+
+/*! \brief Observer for contacts so unsolicited MWI is sent when a contact changes */
+static const struct ast_sorcery_observer mwi_contact_observer = {
+       .created = mwi_contact_changed_observer,
+       .updated = mwi_contact_changed_observer,
+};
+
+/*! \brief Task invoked to send initial MWI NOTIFY for unsolicited */
+static int send_initial_notify_all(void *obj)
+{
+       struct ao2_container *mwi_subscriptions = ao2_global_obj_ref(unsolicited_mwi);
+
+       if (!mwi_subscriptions) {
+               return 0;
+       }
+
+       ao2_callback(mwi_subscriptions, OBJ_NODATA, send_notify, NULL);
+       ao2_ref(mwi_subscriptions, -1);
+
+       return 0;
+}
+
+/*! \brief Event callback which fires initial unsolicited MWI NOTIFY messages when we're fully booted */
+static void mwi_startup_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+{
+       struct ast_json_payload *payload;
+       const char *type;
+
+       if (stasis_message_type(message) != ast_manager_get_generic_type()) {
+               return;
+       }
+
+       payload = stasis_message_data(message);
+       type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
+
+       if (strcmp(type, "FullyBooted")) {
+               return;
+       }
+
+       ast_sip_push_task(NULL, send_initial_notify_all, NULL);
+
+       stasis_unsubscribe(sub);
+}
+
 static int reload(void)
 {
        create_mwi_subscriptions();
@@ -901,6 +1001,14 @@ static int load_module(void)
                return AST_MODULE_LOAD_DECLINE;
        }
        create_mwi_subscriptions();
+       ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer);
+
+       if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
+               ast_sip_push_task(NULL, send_initial_notify_all, NULL);
+       } else {
+               stasis_subscribe_pool(ast_manager_get_topic(), mwi_startup_event_cb, NULL);
+       }
+
        return AST_MODULE_LOAD_SUCCESS;
 }
 
@@ -910,6 +1018,7 @@ static int unload_module(void)
        if (mwi_subscriptions) {
                ao2_callback(mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
                ao2_global_obj_release(unsolicited_mwi);
+               ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &mwi_contact_observer);
        }
        ast_sip_unregister_subscription_handler(&mwi_handler);
        return 0;