[Asterisk-code-review] res pjsip mwi: Set up unsolicited MWI upon registration. (asterisk[13])
Mark Michelson
asteriskteam at digium.com
Thu Jun 25 09:52:04 CDT 2015
Mark Michelson has submitted this change and it was merged.
Change subject: res_pjsip_mwi: Set up unsolicited MWI upon registration.
......................................................................
res_pjsip_mwi: Set up unsolicited MWI upon registration.
The res_pjsip_mwi previously required a reload to set up the proper
subscriptions to allow unsolicited MWI to work. This change
makes it so the act of registering will also cause this to occur.
This is particularly useful if realtime is involved as no reload
needs to occur within Asterisk to cause the MWI information
to get sent.
ASTERISK-25180 #close
Change-Id: Id847b47de4b8b3ab8858455ccc2f07b0f915f252
---
M include/asterisk/res_pjsip.h
M res/res_pjsip/location.c
M res/res_pjsip_mwi.c
M res/res_pjsip_registrar.c
4 files changed, 126 insertions(+), 68 deletions(-)
Approvals:
Mark Michelson: Looks good to me, approved; Verified
Matt Jordan: Looks good to me, but someone else must approve
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index d4ab164..24706c9 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -168,6 +168,8 @@
int authenticate_qualify;
/*! Qualify timeout. 0 is diabled. */
double qualify_timeout;
+ /*! Endpoint that added the contact, only available in observers */
+ struct ast_sip_endpoint *endpoint;
};
#define CONTACT_STATUS "contact_status"
@@ -962,12 +964,14 @@
* \param expiration_time Optional expiration time of the contact
* \param path_info Path information
* \param user_agent User-Agent header from REGISTER request
+ * \param endpoint The endpoint that resulted in the contact being added
*
* \retval -1 failure
* \retval 0 success
*/
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
- struct timeval expiration_time, const char *path_info, const char *user_agent);
+ struct timeval expiration_time, const char *path_info, const char *user_agent,
+ struct ast_sip_endpoint *endpoint);
/*!
* \brief Update a contact
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
index 37f39ba..d87410d 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -53,6 +53,7 @@
struct ast_sip_contact *contact = obj;
ast_string_field_free_memory(contact);
+ ao2_cleanup(contact->endpoint);
}
/*! \brief Allocator for contact */
@@ -228,7 +229,8 @@
}
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
- struct timeval expiration_time, const char *path_info, const char *user_agent)
+ struct timeval expiration_time, const char *path_info, const char *user_agent,
+ struct ast_sip_endpoint *endpoint)
{
char name[MAX_OBJECT_FIELD * 2 + 3];
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
@@ -256,6 +258,8 @@
ast_string_field_set(contact, user_agent, user_agent);
}
+ contact->endpoint = ao2_bump(endpoint);
+
return ast_sorcery_create(ast_sip_get_sorcery(), contact);
}
diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c
index 76e0e4c..eae0293 100644
--- a/res/res_pjsip_mwi.c
+++ b/res/res_pjsip_mwi.c
@@ -40,7 +40,7 @@
#include "asterisk/app.h"
struct mwi_subscription;
-AO2_GLOBAL_OBJ_STATIC(unsolicited_mwi);
+static struct ao2_container *unsolicited_mwi;
#define STASIS_BUCKETS 13
#define MWI_BUCKETS 53
@@ -297,7 +297,7 @@
static int get_message_count(void *obj, void *arg, int flags)
{
- RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+ struct stasis_message *msg;
struct mwi_stasis_subscription *mwi_stasis = obj;
struct ast_sip_message_accumulator *counter = arg;
struct ast_mwi_state *mwi_state;
@@ -310,6 +310,9 @@
mwi_state = stasis_message_data(msg);
counter->old_msgs += mwi_state->old_msgs;
counter->new_msgs += mwi_state->new_msgs;
+
+ ao2_ref(msg, -1);
+
return 0;
}
@@ -479,22 +482,24 @@
static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
{
struct mwi_subscription *mwi_sub;
- RAII_VAR(struct ast_datastore *, mwi_datastore,
- ast_sip_subscription_get_datastore(sub, MWI_DATASTORE), ao2_cleanup);
+ struct ast_datastore *mwi_datastore;
+ mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
if (!mwi_datastore) {
return;
}
mwi_sub = mwi_datastore->data;
ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
+
+ ao2_ref(mwi_datastore, -1);
}
static struct ast_datastore_info mwi_ds_info = { };
static int add_mwi_datastore(struct mwi_subscription *sub)
{
- RAII_VAR(struct ast_datastore *, mwi_datastore, NULL, ao2_cleanup);
+ struct ast_datastore *mwi_datastore;
mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, MWI_DATASTORE);
if (!mwi_datastore) {
@@ -503,6 +508,7 @@
mwi_datastore->data = sub;
ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore);
+ ao2_ref(mwi_datastore, -1);
return 0;
}
@@ -517,18 +523,12 @@
static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint *endpoint,
const char *mailbox)
{
- struct ao2_container *unsolicited = ao2_global_obj_ref(unsolicited_mwi);
struct ao2_iterator *mwi_subs;
struct mwi_subscription *mwi_sub;
const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
int ret = 0;
- if (!unsolicited) {
- return 0;
- }
-
- mwi_subs = ao2_find(unsolicited, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE);
- ao2_cleanup(unsolicited);
+ mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE);
if (!mwi_subs) {
return 0;
@@ -597,11 +597,15 @@
mailboxes = ast_strdupa(aor->mailboxes);
while ((mailbox = strsep(&mailboxes, ","))) {
- RAII_VAR(struct mwi_stasis_subscription *, mwi_stasis_sub,
- mwi_stasis_subscription_alloc(mailbox, sub), ao2_cleanup);
- if (mwi_stasis_sub) {
- ao2_link(sub->stasis_subs, mwi_stasis_sub);
+ struct mwi_stasis_subscription *mwi_stasis_sub;
+
+ mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub);
+ if (!mwi_stasis_sub) {
+ continue;
}
+
+ ao2_link(sub->stasis_subs, mwi_stasis_sub);
+ ao2_ref(mwi_stasis_sub, -1);
}
return 0;
@@ -768,9 +772,9 @@
struct ast_str **buf)
{
struct mwi_subscription *mwi_sub;
- RAII_VAR(struct ast_datastore *, mwi_datastore,
- ast_sip_subscription_get_datastore(sub, MWI_DATASTORE), ao2_cleanup);
+ struct ast_datastore *mwi_datastore;
+ mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
if (!mwi_datastore) {
return;
}
@@ -781,6 +785,8 @@
ast_str_append(buf, 0, "Mailboxes: ");
mwi_subscription_mailboxes_str(mwi_sub->stasis_subs, buf);
ast_str_append(buf, 0, "\r\n");
+
+ ao2_ref(mwi_datastore, -1);
}
static int serialized_notify(void *userdata)
@@ -840,13 +846,37 @@
{
RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup);
struct ast_sip_endpoint *endpoint = obj;
- struct ao2_container *mwi_subscriptions = arg;
- char *mailboxes;
- char *mailbox;
+ char *endpoint_aors, *aor_name, *mailboxes, *mailbox;
+ struct ao2_container *contacts = NULL;
if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) {
return 0;
}
+
+ endpoint_aors = ast_strdupa(endpoint->aors);
+
+ while ((aor_name = strsep(&endpoint_aors, ","))) {
+ RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
+
+ if (!aor) {
+ continue;
+ }
+
+ contacts = ast_sip_location_retrieve_aor_contacts(aor);
+ if (!contacts || (ao2_container_count(contacts) == 0)) {
+ ao2_cleanup(contacts);
+ contacts = NULL;
+ continue;
+ }
+
+ break;
+ }
+
+ if (!contacts) {
+ return 0;
+ }
+
+ ao2_ref(contacts, -1);
if (endpoint->subscription.mwi.aggregate) {
aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL);
@@ -859,18 +889,20 @@
while ((mailbox = strsep(&mailboxes, ","))) {
struct mwi_subscription *sub = aggregate_sub ?:
mwi_subscription_alloc(endpoint, 0, NULL);
- RAII_VAR(struct mwi_stasis_subscription *, mwi_stasis_sub,
- mwi_stasis_subscription_alloc(mailbox, sub), ao2_cleanup);
+ struct mwi_stasis_subscription *mwi_stasis_sub;
+
+ mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub);
if (mwi_stasis_sub) {
ao2_link(sub->stasis_subs, mwi_stasis_sub);
+ ao2_ref(mwi_stasis_sub, -1);
}
- if (!aggregate_sub) {
- ao2_link(mwi_subscriptions, sub);
- ao2_cleanup(sub);
+ if (!aggregate_sub && sub) {
+ ao2_link_flags(unsolicited_mwi, sub, OBJ_NOLOCK);
+ ao2_ref(sub, -1);
}
}
if (aggregate_sub) {
- ao2_link(mwi_subscriptions, aggregate_sub);
+ ao2_link_flags(unsolicited_mwi, aggregate_sub, OBJ_NOLOCK);
}
return 0;
}
@@ -886,13 +918,11 @@
static void create_mwi_subscriptions(void)
{
- struct ao2_container *mwi_subscriptions = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp);
- RAII_VAR(struct ao2_container *, old_mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup);
- RAII_VAR(struct ao2_container *, endpoints, ast_sorcery_retrieve_by_fields(
- ast_sip_get_sorcery(), "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL),
- ao2_cleanup);
+ struct ao2_container *endpoints;
- if (!mwi_subscriptions) {
+ endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "endpoint",
+ AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+ if (!endpoints) {
return;
}
@@ -902,12 +932,12 @@
* and resubscribing, up-to-date mailbox state will be sent out to the endpoint when the
* new stasis subscription is established
*/
- if (old_mwi_subscriptions) {
- ao2_callback(old_mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
- }
- ao2_callback(endpoints, OBJ_NODATA, create_mwi_subscriptions_for_endpoint, mwi_subscriptions);
- ao2_global_obj_replace_unref(unsolicited_mwi, mwi_subscriptions);
- ao2_ref(mwi_subscriptions, -1);
+ ao2_lock(unsolicited_mwi);
+ ao2_callback(unsolicited_mwi, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
+ ao2_callback(endpoints, OBJ_NODATA, create_mwi_subscriptions_for_endpoint, NULL);
+ ao2_unlock(unsolicited_mwi);
+
+ ao2_ref(endpoints, -1);
}
/*! \brief Function called to send MWI NOTIFY on any unsolicited mailboxes relating to this AOR */
@@ -927,40 +957,56 @@
return 0;
}
-
-/*! \brief Function called when a contact is created or updated */
-static void mwi_contact_changed_observer(const void *object)
+/*! \brief Function called when a contact is updated */
+static void mwi_contact_updated(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);
+ ao2_callback(unsolicited_mwi, OBJ_NODATA, send_contact_notify, aor);
+}
+
+/*! \brief Function called when a contact is added */
+static void mwi_contact_added(const void *object)
+{
+ const struct ast_sip_contact *contact = object;
+ struct ao2_iterator *mwi_subs;
+ struct mwi_subscription *mwi_sub;
+ const char *endpoint_id = ast_sorcery_object_get_id(contact->endpoint);
+
+ if (ast_strlen_zero(contact->endpoint->subscription.mwi.mailboxes)) {
+ return;
+ }
+
+ 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);
+ }
+ ao2_iterator_destroy(mwi_subs);
+ }
+
+ create_mwi_subscriptions_for_endpoint(contact->endpoint, NULL, 0);
+
+ ao2_unlock(unsolicited_mwi);
+
+ mwi_contact_updated(object);
}
/*! \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,
+ .created = mwi_contact_added,
+ .updated = mwi_contact_updated,
};
/*! \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);
+ ao2_callback(unsolicited_mwi, OBJ_NODATA, send_notify, NULL);
return 0;
}
@@ -1000,6 +1046,13 @@
if (ast_sip_register_subscription_handler(&mwi_handler)) {
return AST_MODULE_LOAD_DECLINE;
}
+
+ unsolicited_mwi = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp);
+ if (!unsolicited_mwi) {
+ ast_sip_unregister_subscription_handler(&mwi_handler);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
create_mwi_subscriptions();
ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer);
@@ -1014,12 +1067,9 @@
static int unload_module(void)
{
- RAII_VAR(struct ao2_container *, mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup);
- 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);
- }
+ ao2_callback(unsolicited_mwi, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
+ ao2_ref(unsolicited_mwi, -1);
+ ast_sorcery_observer_remove(ast_sip_get_sorcery(), "contact", &mwi_contact_observer);
ast_sip_unregister_subscription_handler(&mwi_handler);
return 0;
}
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index e1eaf69..fed4393 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -500,7 +500,7 @@
if (ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(),
ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL,
- user_agent)) {
+ user_agent, task_data->endpoint)) {
ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
contact_uri, aor_name);
continue;
--
To view, visit https://gerrit.asterisk.org/676
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Id847b47de4b8b3ab8858455ccc2f07b0f915f252
Gerrit-PatchSet: 3
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Owner: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Mark Michelson <mmichelson at digium.com>
Gerrit-Reviewer: Matt Jordan <mjordan at digium.com>
More information about the asterisk-code-review
mailing list