summaryrefslogtreecommitdiff
path: root/res/res_pjsip_mwi.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2015-04-14 16:04:46 -0300
committerJoshua Colp <jcolp@digium.com>2015-04-22 05:41:46 -0500
commit190fa4f333e61da0fb8df885a97665552a2081bd (patch)
treea61237c511626056f08c5c1c128da0e13fe10cba /res/res_pjsip_mwi.c
parentbfdc766bf6248cba18297d90e4cac5dd0f08896c (diff)
res_pjsip_mwi: Send unsolicited MWI NOTIFY on startup and when endpoint registers.
Currently the res_pjsip_mwi module only sends an unsolicited MWI NOTIFY upon a mailbox state change (such as a new message being left, or one being deleted). In practice this is not sufficient to keep clients aware of the current MWI status. This change makes the module send unsolicited MWI NOTIFY on startup so that clients are guaranteed to have the most up to date MWI information. It also makes clients receive an unsolicited MWI NOTIFY upon registration so if they are unaware of the current MWI status they receive it. ASTERISK-24982 #close Reported by: Joshua Colp Change-Id: I043f20230227e91218f18a82c7d5bb2aa62b1d58
Diffstat (limited to 'res/res_pjsip_mwi.c')
-rw-r--r--res/res_pjsip_mwi.c121
1 files changed, 115 insertions, 6 deletions
diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c
index 9c275af46..2ab7dfee0 100644
--- a/res/res_pjsip_mwi.c
+++ b/res/res_pjsip_mwi.c
@@ -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;