Merge "res_pjsip_mwi: Set up unsolicited MWI upon registration."
This commit is contained in:
commit
3f1fe83633
|
@ -168,6 +168,8 @@ struct ast_sip_contact {
|
|||
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"
|
||||
|
@ -952,12 +954,14 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
|
|||
* \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
|
||||
|
|
|
@ -53,6 +53,7 @@ static void contact_destroy(void *obj)
|
|||
struct ast_sip_contact *contact = obj;
|
||||
|
||||
ast_string_field_free_memory(contact);
|
||||
ao2_cleanup(contact->endpoint);
|
||||
}
|
||||
|
||||
/*! \brief Allocator for contact */
|
||||
|
@ -228,7 +229,8 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
|
|||
}
|
||||
|
||||
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 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
|
|||
ast_string_field_set(contact, user_agent, user_agent);
|
||||
}
|
||||
|
||||
contact->endpoint = ao2_bump(endpoint);
|
||||
|
||||
return ast_sorcery_create(ast_sip_get_sorcery(), contact);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 mwi_sub_cmp(void *obj, void *arg, int flags)
|
|||
|
||||
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 @@ static int get_message_count(void *obj, void *arg, int flags)
|
|||
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 int unsubscribe_stasis(void *obj, void *arg, int flags)
|
|||
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 @@ static int add_mwi_datastore(struct mwi_subscription *sub)
|
|||
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 add_mwi_datastore(struct mwi_subscription *sub)
|
|||
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 @@ static int mwi_on_aor(void *obj, void *arg, int flags)
|
|||
|
||||
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 @@ static void mwi_to_ami(struct ast_sip_subscription *sub,
|
|||
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 @@ static void mwi_to_ami(struct ast_sip_subscription *sub,
|
|||
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,14 +846,38 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags
|
|||
{
|
||||
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);
|
||||
if (!aggregate_sub) {
|
||||
|
@ -859,18 +889,20 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags
|
|||
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 int unsubscribe(void *obj, void *arg, int flags)
|
|||
|
||||
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 @@ static void create_mwi_subscriptions(void)
|
|||
* 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 @@ static int send_contact_notify(void *obj, void *arg, int flags)
|
|||
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 @@ static int load_module(void)
|
|||
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 load_module(void)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -500,7 +500,7 @@ static int rx_task(void *data)
|
|||
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue