asterisk/res/res_pjsip/location.c

1479 lines
43 KiB
C
Raw Normal View History

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2013, Digium, Inc.
*
* Joshua Colp <jcolp@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#include "asterisk.h"
#include <pjsip.h>
#include <pjlib.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/logger.h"
#include "asterisk/astobj2.h"
#include "asterisk/paths.h"
#include "asterisk/sorcery.h"
#include "asterisk/taskprocessor.h"
#include "include/res_pjsip_private.h"
#include "asterisk/res_pjsip_cli.h"
#include "asterisk/statsd.h"
#include "asterisk/named_locks.h"
#include "asterisk/res_pjproject.h"
static int pj_max_hostname = PJ_MAX_HOSTNAME;
static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE;
/*! \brief Destructor for AOR */
static void aor_destroy(void *obj)
{
struct ast_sip_aor *aor = obj;
ao2_cleanup(aor->permanent_contacts);
ast_string_field_free_memory(aor);
res_pjsip_mwi: Add voicemail extension and mwi_subscribe_replaces_unsolicited res_pjsip_mwi was missing the chan_sip "vmexten" functionality which adds the Message-Account header to the MWI NOTIFY. Also, specifying mailboxes on endpoints for unsolicited mwi and on aors for subscriptions required that the admin know in advance which the client wanted. If you specified mailboxes on the endpoint, subscriptions were rejected even if you also specified mailboxes on the aor. Voicemail extension: * Added a global default_voicemail_extension which defaults to "". * Added voicemail_extension to both endpoint and aor. * Added ast_sip_subscription_get_dialog for support. * Added ast_sip_subscription_get_sip_uri for support. When an unsolicited NOTIFY is constructed, the From header is parsed, the voicemail extension from the endpoint is substituted for the user, and the result placed in the Message-Account field in the body. When a subscribed NOTIFY is constructed, the subscription dialog local uri is parsed, the voicemail_extension from the aor (looked up from the subscription resource name) is substituted for the user, and the result placed in the Message-Account field in the body. If no voicemail extension was defined, the Message-Account field is not added to the NOTIFY body. mwi_subscribe_replaces_unsolicited: * Added mwi_subscribe_replaces_unsolicited to endpoint. The previous behavior was to reject a subscribe if a previous internal subscription for unsolicited MWI was found for the mailbox. That remains the default. However, if there are mailboxes also set on the aor and the client subscribes and mwi_subscribe_replaces_unsolicited is set, the existing internal subscription is removed and replaced with the external subscription. This allows an admin to configure mailboxes on both the endpoint and aor and allows the client to select which to use. ASTERISK-25865 #close Reported-by: Ross Beer Change-Id: Ic15a9415091760539c7134a5ba3dc4a6a1217cea
2016-03-25 03:55:03 +00:00
ast_free(aor->voicemail_extension);
}
/*! \brief Allocator for AOR */
static void *aor_alloc(const char *name)
{
void *lock;
struct ast_sip_aor *aor;
lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", name);
if (!lock) {
return NULL;
}
aor = ast_sorcery_lockable_alloc(sizeof(struct ast_sip_aor), aor_destroy, lock);
ao2_ref(lock, -1);
if (!aor) {
return NULL;
}
ast_string_field_init(aor, 128);
return aor;
}
/*! \brief Internal callback function which destroys the specified contact */
static int destroy_contact(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
ast_sip_location_delete_contact(contact);
return CMP_MATCH;
}
static void aor_deleted_observer(const void *object)
{
const struct ast_sip_aor *aor = object;
const char *aor_id = ast_sorcery_object_get_id(object);
/* Give enough space for ;@ at the end, since that is our object naming scheme */
size_t prefix_len = strlen(aor_id) + sizeof(";@") - 1;
char prefix[prefix_len + 1];
struct ao2_container *contacts;
if (aor->permanent_contacts) {
ao2_callback(aor->permanent_contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, destroy_contact, NULL);
}
sprintf(prefix, "%s;@", aor_id); /* Safe */
if (!(contacts = ast_sorcery_retrieve_by_prefix(ast_sip_get_sorcery(), "contact", prefix, prefix_len))) {
return;
}
/* Destroy any contacts that may still exist that were made for this AoR */
ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, destroy_contact, NULL);
ao2_ref(contacts, -1);
}
/*! \brief Observer for contacts so state can be updated on respective endpoints */
static const struct ast_sorcery_observer aor_observer = {
.deleted = aor_deleted_observer,
};
/*! \brief Destructor for contact */
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 */
static void *contact_alloc(const char *name)
{
struct ast_sip_contact *contact = ast_sorcery_generic_alloc(sizeof(*contact), contact_destroy);
char *id = ast_strdupa(name);
char *aor = id;
char *aor_separator = NULL;
if (!contact) {
return NULL;
}
if (ast_string_field_init(contact, 256)) {
ao2_cleanup(contact);
return NULL;
}
/* Dynamic contacts are delimited with ";@" and static ones with "@@" */
if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) {
*aor_separator = '\0';
}
ast_assert(aor_separator != NULL);
ast_string_field_set(contact, aor, aor);
return contact;
}
struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name)
{
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
}
/*! \brief Internal callback function which deletes and unlinks any expired contacts */
static int contact_expire(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
/* If the contact has not yet expired it is valid */
if (ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) > 0) {
return 0;
}
ast_sip_location_delete_contact(contact);
return CMP_MATCH;
}
/*! \brief Internal callback function which links static contacts into another container */
static int contact_link_static(void *obj, void *arg, int flags)
{
struct ao2_container *dest = arg;
ao2_link(dest, obj);
return 0;
}
/*! \brief Internal callback function which removes any contact which is unreachable */
static int contact_remove_unreachable(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
struct ast_sip_contact_status *status;
int unreachable;
pjsip: Rewrite OPTIONS support with new eyes. The OPTIONS support in PJSIP has organically grown, like many things in Asterisk. It has been tweaked, changed, and adapted based on situations run into. Unfortunately this has taken its toll. Configuration file based objects have poor performance and even dynamic ones aren't that great. This change scraps the existing code and starts fresh with new eyes. It leverages all of the APIs made available such as sorcery observers and serializers to provide a better implementation. 1. The state of contacts, AORs, and endpoints relevant to the qualify process is maintained. This state can be updated by external forces (such as a device registering/unregistering) and also the reload process. This state also includes the association between endpoints and AORs. 2. AORs are scheduled and not contacts. This reduces the amount of work spent juggling scheduled items. 3. Manipulation of which AORs are being qualified and the endpoint states all occur within a serializer to reduce the conflict that can occur with multiple threads attempting to modify things. 4. Operations regarding an AOR use a serializer specific to that AOR. 5. AORs and endpoint state act as state compositors. They take input from lower level objects (contacts feed AORs, AORs feed endpoint state) and determine if a sufficient enough change has occurred to be fed further up the chain. 6. Realtime is supported by using observers to know when a contact has been registered. If state does not exist for the associated AOR then it is retrieved and becomes active as appropriate. The end result of all of this is best shown with a configuration file of 3000 endpoints each with an AOR that has a static contact. In the old code it would take over a minute to load and use all 8 of my cores. This new code takes 2-3 seconds and barely touches the CPU even while dealing with all of the OPTIONS requests. ASTERISK-26806 Change-Id: I6a5ebbfca9001dfe933eaeac4d3babd8d2e6f082
2017-12-11 18:34:53 +00:00
status = ast_sip_get_contact_status(contact);
if (!status) {
return 0;
}
unreachable = (status->status == UNAVAILABLE);
ao2_ref(status, -1);
return unreachable ? CMP_MATCH : 0;
}
struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor)
{
return ast_sip_location_retrieve_first_aor_contact_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
}
struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact_filtered(const struct ast_sip_aor *aor,
unsigned int flags)
{
struct ao2_container *contacts;
struct ast_sip_contact *contact = NULL;
contacts = ast_sip_location_retrieve_aor_contacts_filtered(aor, flags);
if (contacts && ao2_container_count(contacts)) {
/* Get the first AOR contact in the container. */
contact = ao2_callback(contacts, 0, NULL, NULL);
}
ao2_cleanup(contacts);
return contact;
}
struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor)
{
return ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
}
struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock_filtered(const struct ast_sip_aor *aor,
unsigned int flags)
{
/* Give enough space for ;@ at the end, since that is our object naming scheme */
size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
char prefix[prefix_len + 1];
struct ao2_container *contacts;
sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
if (!(contacts = ast_sorcery_retrieve_by_prefix(ast_sip_get_sorcery(), "contact", prefix, prefix_len))) {
return NULL;
}
/* Prune any expired contacts and delete them, we do this first because static contacts can never expire */
ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_expire, NULL);
/* Add any permanent contacts from the AOR */
if (aor->permanent_contacts) {
ao2_callback(aor->permanent_contacts, OBJ_NODATA, contact_link_static, contacts);
}
if (flags & AST_SIP_CONTACT_FILTER_REACHABLE) {
ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_remove_unreachable, NULL);
}
return contacts;
}
struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
{
return ast_sip_location_retrieve_aor_contacts_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
}
struct ao2_container *ast_sip_location_retrieve_aor_contacts_filtered(const struct ast_sip_aor *aor,
unsigned int flags)
{
struct ao2_container *contacts;
/* ao2_lock / ao2_unlock do not actually write aor since it has an ao2 lockobj. */
ao2_lock((void*)aor);
contacts = ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, flags);
ao2_unlock((void*)aor);
return contacts;
}
void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor,
struct ast_sip_contact **contact)
{
ast_sip_location_retrieve_contact_and_aor_from_list_filtered(aor_list, AST_SIP_CONTACT_FILTER_DEFAULT, aor, contact);
}
void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags,
struct ast_sip_aor **aor, struct ast_sip_contact **contact)
{
char *aor_name;
char *rest;
/* If the location is still empty we have nowhere to go */
if (ast_strlen_zero(aor_list) || !(rest = ast_strdupa(aor_list))) {
ast_log(LOG_WARNING, "Unable to determine contacts from empty aor list\n");
return;
}
*aor = NULL;
*contact = NULL;
while ((aor_name = ast_strip(strsep(&rest, ",")))) {
*aor = ast_sip_location_retrieve_aor(aor_name);
if (!(*aor)) {
continue;
}
*contact = ast_sip_location_retrieve_first_aor_contact_filtered(*aor, flags);
/* If a valid contact is available use its URI for dialing */
if (*contact) {
break;
}
ao2_ref(*aor, -1);
*aor = NULL;
}
}
struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
{
struct ast_sip_aor *aor;
struct ast_sip_contact *contact;
ast_sip_location_retrieve_contact_and_aor_from_list(aor_list, &aor, &contact);
ao2_cleanup(aor);
return contact;
}
static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags);
static int cli_contact_populate_container(void *obj, void *arg, int flags);
static int gather_contacts_for_aor(void *obj, void *arg, int flags)
{
struct ao2_container *aor_contacts;
struct ast_sip_aor *aor = obj;
struct ao2_container *container = arg;
aor_contacts = ast_sip_location_retrieve_aor_contacts(aor);
if (!aor_contacts) {
return 0;
}
ao2_callback(aor_contacts, OBJ_MULTIPLE | OBJ_NODATA, cli_contact_populate_container,
container);
ao2_ref(aor_contacts, -1);
return CMP_MATCH;
}
struct ao2_container *ast_sip_location_retrieve_contacts_from_aor_list(const char *aor_list)
{
struct ao2_container *contacts;
contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
if (!contacts) {
return NULL;
}
ast_sip_for_each_aor(aor_list, gather_contacts_for_aor, contacts);
return contacts;
}
struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name)
{
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
}
res_pjsip: Remove ephemeral registered contacts on transport shutdown. The fix for the issue is broken up into three parts. This is part two which handles the server side of REGISTER requests when rewrite_contact is enabled. Any registered reliable transport contact becomes invalid when the transport connection becomes disconnected. * Monitor the rewrite_contact's reliable transport REGISTER contact for shutdown. If it is shutdown then the contact must be removed because it is no longer valid. Otherwise, when the client attempts to re-REGISTER it may be blocked because the invalid contact is there. Also if we try to send a call to the endpoint using the invalid contact then the endpoint is not likely to see the request. The endpoint either won't be listening on that port for new connections or a NAT/firewall will block it. * Prune any rewrite_contact's registered reliable transport contacts on boot. The reliable transport no longer exists so the contact is invalid. * Websockets always rewrite the REGISTER contact address and the transport needs to be monitored for shutdown. * Made the websocket transport set a unique name since that is what we use as the ao2 container key. Otherwise, we would not know which transport we find when one of them shuts down. The names are also used for PJPROJECT debug logging. * Made the websocket transport post the PJSIP_TP_STATE_CONNECTED state event. Now the global keep_alive_interval option, initially idle shutdown timer, and the server REGISTER contact monitor can work on wetsocket transports. * Made the websocket transport set the PJSIP_TP_DIR_INCOMING direction. Now initially idle websockets will automatically shutdown. ASTERISK-27147 Change-Id: I397a5e7d18476830f7ffe1726adf9ee6c15964f4
2017-07-31 19:21:06 +00:00
struct ast_sip_contact *ast_sip_location_create_contact(struct ast_sip_aor *aor,
const char *uri, struct timeval expiration_time, const char *path_info,
const char *user_agent, const char *via_addr, int via_port, const char *call_id,
int prune_on_boot, struct ast_sip_endpoint *endpoint)
{
struct ast_sip_contact *contact;
char name[MAX_OBJECT_FIELD * 2 + 3];
char hash[33];
ast_md5_hash(hash, uri);
snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), hash);
contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name);
if (!contact) {
res_pjsip: Remove ephemeral registered contacts on transport shutdown. The fix for the issue is broken up into three parts. This is part two which handles the server side of REGISTER requests when rewrite_contact is enabled. Any registered reliable transport contact becomes invalid when the transport connection becomes disconnected. * Monitor the rewrite_contact's reliable transport REGISTER contact for shutdown. If it is shutdown then the contact must be removed because it is no longer valid. Otherwise, when the client attempts to re-REGISTER it may be blocked because the invalid contact is there. Also if we try to send a call to the endpoint using the invalid contact then the endpoint is not likely to see the request. The endpoint either won't be listening on that port for new connections or a NAT/firewall will block it. * Prune any rewrite_contact's registered reliable transport contacts on boot. The reliable transport no longer exists so the contact is invalid. * Websockets always rewrite the REGISTER contact address and the transport needs to be monitored for shutdown. * Made the websocket transport set a unique name since that is what we use as the ao2 container key. Otherwise, we would not know which transport we find when one of them shuts down. The names are also used for PJPROJECT debug logging. * Made the websocket transport post the PJSIP_TP_STATE_CONNECTED state event. Now the global keep_alive_interval option, initially idle shutdown timer, and the server REGISTER contact monitor can work on wetsocket transports. * Made the websocket transport set the PJSIP_TP_DIR_INCOMING direction. Now initially idle websockets will automatically shutdown. ASTERISK-27147 Change-Id: I397a5e7d18476830f7ffe1726adf9ee6c15964f4
2017-07-31 19:21:06 +00:00
return NULL;
}
ast_string_field_set(contact, uri, uri);
contact->expiration_time = expiration_time;
contact->qualify_frequency = aor->qualify_frequency;
contact->qualify_timeout = aor->qualify_timeout;
contact->authenticate_qualify = aor->authenticate_qualify;
if (path_info && aor->support_path) {
ast_string_field_set(contact, path, path_info);
}
if (!ast_strlen_zero(aor->outbound_proxy)) {
ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy);
}
if (!ast_strlen_zero(user_agent)) {
ast_string_field_set(contact, user_agent, user_agent);
}
if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
ast_string_field_set(contact, reg_server, ast_config_AST_SYSTEM_NAME);
}
if (!ast_strlen_zero(via_addr)) {
ast_string_field_set(contact, via_addr, via_addr);
}
contact->via_port = via_port;
if (!ast_strlen_zero(call_id)) {
ast_string_field_set(contact, call_id, call_id);
}
contact->endpoint = ao2_bump(endpoint);
if (endpoint) {
ast_string_field_set(contact, endpoint_name, ast_sorcery_object_get_id(endpoint));
}
res_pjsip: Remove ephemeral registered contacts on transport shutdown. The fix for the issue is broken up into three parts. This is part two which handles the server side of REGISTER requests when rewrite_contact is enabled. Any registered reliable transport contact becomes invalid when the transport connection becomes disconnected. * Monitor the rewrite_contact's reliable transport REGISTER contact for shutdown. If it is shutdown then the contact must be removed because it is no longer valid. Otherwise, when the client attempts to re-REGISTER it may be blocked because the invalid contact is there. Also if we try to send a call to the endpoint using the invalid contact then the endpoint is not likely to see the request. The endpoint either won't be listening on that port for new connections or a NAT/firewall will block it. * Prune any rewrite_contact's registered reliable transport contacts on boot. The reliable transport no longer exists so the contact is invalid. * Websockets always rewrite the REGISTER contact address and the transport needs to be monitored for shutdown. * Made the websocket transport set a unique name since that is what we use as the ao2 container key. Otherwise, we would not know which transport we find when one of them shuts down. The names are also used for PJPROJECT debug logging. * Made the websocket transport post the PJSIP_TP_STATE_CONNECTED state event. Now the global keep_alive_interval option, initially idle shutdown timer, and the server REGISTER contact monitor can work on wetsocket transports. * Made the websocket transport set the PJSIP_TP_DIR_INCOMING direction. Now initially idle websockets will automatically shutdown. ASTERISK-27147 Change-Id: I397a5e7d18476830f7ffe1726adf9ee6c15964f4
2017-07-31 19:21:06 +00:00
contact->prune_on_boot = prune_on_boot;
if (ast_sorcery_create(ast_sip_get_sorcery(), contact)) {
ao2_ref(contact, -1);
return NULL;
}
return contact;
}
int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri,
struct timeval expiration_time, const char *path_info, const char *user_agent,
const char *via_addr, int via_port, const char *call_id,
struct ast_sip_endpoint *endpoint)
{
struct ast_sip_contact *contact;
contact = ast_sip_location_create_contact(aor, uri, expiration_time, path_info,
user_agent, via_addr, via_port, call_id, 0, endpoint);
ao2_cleanup(contact);
return contact ? 0 : -1;
}
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,
const char *via_addr, int via_port, const char *call_id,
struct ast_sip_endpoint *endpoint)
{
int res;
ao2_lock(aor);
res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent,
via_addr, via_port, call_id,
endpoint);
ao2_unlock(aor);
return res;
}
int ast_sip_location_update_contact(struct ast_sip_contact *contact)
{
return ast_sorcery_update(ast_sip_get_sorcery(), contact);
}
int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
{
return ast_sorcery_delete(ast_sip_get_sorcery(), contact);
}
res_pjsip: Remove ephemeral registered contacts on transport shutdown. The fix for the issue is broken up into three parts. This is part two which handles the server side of REGISTER requests when rewrite_contact is enabled. Any registered reliable transport contact becomes invalid when the transport connection becomes disconnected. * Monitor the rewrite_contact's reliable transport REGISTER contact for shutdown. If it is shutdown then the contact must be removed because it is no longer valid. Otherwise, when the client attempts to re-REGISTER it may be blocked because the invalid contact is there. Also if we try to send a call to the endpoint using the invalid contact then the endpoint is not likely to see the request. The endpoint either won't be listening on that port for new connections or a NAT/firewall will block it. * Prune any rewrite_contact's registered reliable transport contacts on boot. The reliable transport no longer exists so the contact is invalid. * Websockets always rewrite the REGISTER contact address and the transport needs to be monitored for shutdown. * Made the websocket transport set a unique name since that is what we use as the ao2 container key. Otherwise, we would not know which transport we find when one of them shuts down. The names are also used for PJPROJECT debug logging. * Made the websocket transport post the PJSIP_TP_STATE_CONNECTED state event. Now the global keep_alive_interval option, initially idle shutdown timer, and the server REGISTER contact monitor can work on wetsocket transports. * Made the websocket transport set the PJSIP_TP_DIR_INCOMING direction. Now initially idle websockets will automatically shutdown. ASTERISK-27147 Change-Id: I397a5e7d18476830f7ffe1726adf9ee6c15964f4
2017-07-31 19:21:06 +00:00
static int prune_boot_contacts_cb(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
if (contact->prune_on_boot
&& !strcmp(contact->reg_server, ast_config_AST_SYSTEM_NAME ?: "")) {
ast_verb(3, "Removed contact '%s' from AOR '%s' due to system boot\n",
contact->uri, contact->aor);
res_pjsip: Remove ephemeral registered contacts on transport shutdown. The fix for the issue is broken up into three parts. This is part two which handles the server side of REGISTER requests when rewrite_contact is enabled. Any registered reliable transport contact becomes invalid when the transport connection becomes disconnected. * Monitor the rewrite_contact's reliable transport REGISTER contact for shutdown. If it is shutdown then the contact must be removed because it is no longer valid. Otherwise, when the client attempts to re-REGISTER it may be blocked because the invalid contact is there. Also if we try to send a call to the endpoint using the invalid contact then the endpoint is not likely to see the request. The endpoint either won't be listening on that port for new connections or a NAT/firewall will block it. * Prune any rewrite_contact's registered reliable transport contacts on boot. The reliable transport no longer exists so the contact is invalid. * Websockets always rewrite the REGISTER contact address and the transport needs to be monitored for shutdown. * Made the websocket transport set a unique name since that is what we use as the ao2 container key. Otherwise, we would not know which transport we find when one of them shuts down. The names are also used for PJPROJECT debug logging. * Made the websocket transport post the PJSIP_TP_STATE_CONNECTED state event. Now the global keep_alive_interval option, initially idle shutdown timer, and the server REGISTER contact monitor can work on wetsocket transports. * Made the websocket transport set the PJSIP_TP_DIR_INCOMING direction. Now initially idle websockets will automatically shutdown. ASTERISK-27147 Change-Id: I397a5e7d18476830f7ffe1726adf9ee6c15964f4
2017-07-31 19:21:06 +00:00
ast_sip_location_delete_contact(contact);
}
return 0;
}
void ast_sip_location_prune_boot_contacts(void)
{
struct ao2_container *contacts;
contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
if (contacts) {
ao2_callback(contacts, 0, prune_boot_contacts_cb, NULL);
ao2_ref(contacts, -1);
}
}
/*! \brief Custom handler for translating from a string timeval to actual structure */
static int expiration_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
struct ast_sip_contact *contact = obj;
return ast_get_timeval(var->value, &contact->expiration_time, ast_tv(0, 0), NULL);
}
/*! \brief Custom handler for translating from an actual structure timeval to string */
static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf)
{
const struct ast_sip_contact *contact = obj;
return (ast_asprintf(buf, "%ld", contact->expiration_time.tv_sec) < 0) ? -1 : 0;
}
static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags)
{
const struct ast_sip_contact *object_left = obj_left;
const struct ast_sip_contact *object_right = obj_right;
const char *right_key = obj_right;
int cmp;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = ast_sorcery_object_get_id(object_right);
/* Fall through */
case OBJ_SEARCH_KEY:
cmp = strcmp(ast_sorcery_object_get_id(object_left), right_key);
break;
case OBJ_SEARCH_PARTIAL_KEY:
/*
* We could also use a partial key struct containing a length
* so strlen() does not get called for every comparison instead.
*/
cmp = strncmp(ast_sorcery_object_get_id(object_left), right_key, strlen(right_key));
break;
default:
/* Sort can only work on something with a full or partial key. */
ast_assert(0);
cmp = 0;
break;
}
return cmp;
}
int ast_sip_validate_uri_length(const char *contact_uri)
{
int max_length = pj_max_hostname - 1;
char *contact = ast_strdupa(contact_uri);
char *host;
char *at;
int theres_a_port = 0;
if (strlen(contact_uri) > pjsip_max_url_size - 1) {
return -1;
}
contact = ast_strip_quoted(contact, "<", ">");
if (!strncasecmp(contact, "sip:", 4)) {
host = contact + 4;
} else if (!strncasecmp(contact, "sips:", 5)) {
host = contact + 5;
} else {
/* Not a SIP URI */
return -1;
}
at = strchr(contact, '@');
if (at) {
/* sip[s]:user@host */
host = at + 1;
}
if (host[0] == '[') {
/* Host is an IPv6 address. Just get up to the matching bracket */
char *close_bracket;
close_bracket = strchr(host, ']');
if (!close_bracket) {
return -1;
}
close_bracket++;
if (*close_bracket == ':') {
theres_a_port = 1;
}
*close_bracket = '\0';
} else {
/* uri parameters could contain ';' so trim them off first */
host = strsep(&host, ";?");
/* Host is FQDN or IPv4 address. Need to find closing delimiter */
if (strchr(host, ':')) {
theres_a_port = 1;
host = strsep(&host, ":");
}
}
if (!theres_a_port) {
max_length -= strlen("_sips.tcp.");
}
if (strlen(host) > max_length) {
return -1;
}
return 0;
}
/*! \brief Custom handler for permanent URIs */
static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
struct ast_sip_aor *aor = obj;
const char *aor_id = ast_sorcery_object_get_id(aor);
char *contacts;
char *contact_uri;
if (ast_strlen_zero(var->value)) {
return 0;
}
contacts = ast_strdupa(var->value);
while ((contact_uri = ast_strip(strsep(&contacts, ",")))) {
struct ast_sip_contact *contact;
struct ast_sip_contact_status *status;
res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph
2015-12-03 18:07:49 +00:00
char hash[33];
res_pjsip/contacts/statsd: Make contact lifecycle events more consistent It will never be perfect or even pretty, mostly because of the differences between static and dynamic contacts. Created: Can't use the contact or contact_status alloc functions because the objects come and go regardless of the actual state. Can't use the contact_apply_handler, ast_sip_location_add_contact or a sorcery created handler because they only get called for dynamic contacts. Similarly, permanent_uri_handler only gets called for static contacts. So, Matt had it right. :) ast_res_pjsip_find_or_create_contact_status is the only place it can go and not have duplicated code. Both permanent_uri_handler and contact_apply_handler call find_or_create. Removed: Can't use the destructors for the same reason as above. The only place to put this is in persistent_endpoint_contact_deleted_observer which I believe is the "correct" place but even that will handle only dynamic contacts. This doesn't called on shutdown however. There is no hook to use for static contacts that may be removed because of a config change while asterisk is in operation. I moved the cleanup of contact_status from ast_sip_location_delete_contact to the handler as well. Status Change and RTT: Although they worked fine where they were (in update_contact_status) I moved them to persistent_endpoint_contact_status_observer to make it more consistent with removed. There was logic there already to detect a state change. Finally, fixed a nit in permanent_uri_handler rmudgett reported eralier. ASTERISK-25608 #close Change-Id: I4b56e7dfc3be3baaaf6f1eac5b2068a0b79e357d Reported-by: George Joseph Tested-by: George Joseph
2015-12-04 22:23:21 +00:00
char contact_id[strlen(aor_id) + sizeof(hash) + 2];
if (ast_strlen_zero(contact_uri)) {
continue;
}
if (ast_sip_validate_uri_length(contact_uri)) {
ast_log(LOG_ERROR, "Contact uri or hostname length exceeds pjproject limit or is not a sip(s) uri: %s\n", contact_uri);
return -1;
}
if (!aor->permanent_contacts) {
aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK,
AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
if (!aor->permanent_contacts) {
return -1;
}
}
res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph
2015-12-03 18:07:49 +00:00
ast_md5_hash(hash, contact_uri);
snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, hash);
contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id);
if (!contact) {
return -1;
}
res_pjsip/contacts/statsd: Make contact lifecycle events more consistent It will never be perfect or even pretty, mostly because of the differences between static and dynamic contacts. Created: Can't use the contact or contact_status alloc functions because the objects come and go regardless of the actual state. Can't use the contact_apply_handler, ast_sip_location_add_contact or a sorcery created handler because they only get called for dynamic contacts. Similarly, permanent_uri_handler only gets called for static contacts. So, Matt had it right. :) ast_res_pjsip_find_or_create_contact_status is the only place it can go and not have duplicated code. Both permanent_uri_handler and contact_apply_handler call find_or_create. Removed: Can't use the destructors for the same reason as above. The only place to put this is in persistent_endpoint_contact_deleted_observer which I believe is the "correct" place but even that will handle only dynamic contacts. This doesn't called on shutdown however. There is no hook to use for static contacts that may be removed because of a config change while asterisk is in operation. I moved the cleanup of contact_status from ast_sip_location_delete_contact to the handler as well. Status Change and RTT: Although they worked fine where they were (in update_contact_status) I moved them to persistent_endpoint_contact_status_observer to make it more consistent with removed. There was logic there already to detect a state change. Finally, fixed a nit in permanent_uri_handler rmudgett reported eralier. ASTERISK-25608 #close Change-Id: I4b56e7dfc3be3baaaf6f1eac5b2068a0b79e357d Reported-by: George Joseph Tested-by: George Joseph
2015-12-04 22:23:21 +00:00
ast_string_field_set(contact, uri, contact_uri);
status = ast_res_pjsip_find_or_create_contact_status(contact);
if (!status) {
ao2_ref(contact, -1);
return -1;
}
ao2_ref(status, -1);
ao2_link(aor->permanent_contacts, contact);
ao2_ref(contact, -1);
}
return 0;
}
static int contact_to_var_list(void *object, void *arg, int flags)
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
{
struct ast_sip_contact_wrapper *wrapper = object;
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
struct ast_variable **var = arg;
ast_variable_list_append(&*var, ast_variable_new("contact", wrapper->contact->uri, ""));
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
return 0;
}
static int contacts_to_var_list(const void *obj, struct ast_variable **fields)
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
{
const struct ast_sip_aor *aor = obj;
ast_sip_for_each_contact(aor, contact_to_var_list, fields);
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
return 0;
}
res_pjsip_mwi: Add voicemail extension and mwi_subscribe_replaces_unsolicited res_pjsip_mwi was missing the chan_sip "vmexten" functionality which adds the Message-Account header to the MWI NOTIFY. Also, specifying mailboxes on endpoints for unsolicited mwi and on aors for subscriptions required that the admin know in advance which the client wanted. If you specified mailboxes on the endpoint, subscriptions were rejected even if you also specified mailboxes on the aor. Voicemail extension: * Added a global default_voicemail_extension which defaults to "". * Added voicemail_extension to both endpoint and aor. * Added ast_sip_subscription_get_dialog for support. * Added ast_sip_subscription_get_sip_uri for support. When an unsolicited NOTIFY is constructed, the From header is parsed, the voicemail extension from the endpoint is substituted for the user, and the result placed in the Message-Account field in the body. When a subscribed NOTIFY is constructed, the subscription dialog local uri is parsed, the voicemail_extension from the aor (looked up from the subscription resource name) is substituted for the user, and the result placed in the Message-Account field in the body. If no voicemail extension was defined, the Message-Account field is not added to the NOTIFY body. mwi_subscribe_replaces_unsolicited: * Added mwi_subscribe_replaces_unsolicited to endpoint. The previous behavior was to reject a subscribe if a previous internal subscription for unsolicited MWI was found for the mailbox. That remains the default. However, if there are mailboxes also set on the aor and the client subscribes and mwi_subscribe_replaces_unsolicited is set, the existing internal subscription is removed and replaced with the external subscription. This allows an admin to configure mailboxes on both the endpoint and aor and allows the client to select which to use. ASTERISK-25865 #close Reported-by: Ross Beer Change-Id: Ic15a9415091760539c7134a5ba3dc4a6a1217cea
2016-03-25 03:55:03 +00:00
static int voicemail_extension_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
struct ast_sip_aor *aor = obj;
aor->voicemail_extension = ast_strdup(var->value);
return aor->voicemail_extension ? 0 : -1;
}
static int voicemail_extension_to_str(const void *obj, const intptr_t *args, char **buf)
{
const struct ast_sip_aor *aor = obj;
*buf = ast_strdup(aor->voicemail_extension);
return 0;
}
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
{
char *copy;
char *name;
int res;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
if (!on_aor || ast_strlen_zero(aors)) {
return 0;
}
copy = ast_strdupa(aors);
while ((name = ast_strip(strsep(&copy, ",")))) {
struct ast_sip_aor *aor;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
aor = ast_sip_location_retrieve_aor(name);
if (aor) {
res = on_aor(aor, arg, 0);
ao2_ref(aor, -1);
if (res) {
return -1;
}
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
}
}
return 0;
}
static void contact_wrapper_destroy(void *obj)
{
struct ast_sip_contact_wrapper *wrapper = obj;
ast_free(wrapper->aor_id);
ast_free(wrapper->contact_id);
ao2_cleanup(wrapper->contact);
}
int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
ao2_callback_fn on_contact, void *arg)
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
{
struct ao2_container *contacts;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
struct ao2_iterator i;
int res = 0;
void *object = NULL;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
if (!on_contact ||
!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
return 0;
}
i = ao2_iterator_init(contacts, 0);
while ((object = ao2_iterator_next(&i))) {
RAII_VAR(struct ast_sip_contact *, contact, object, ao2_cleanup);
RAII_VAR(struct ast_sip_contact_wrapper *, wrapper, NULL, ao2_cleanup);
const char *aor_id = ast_sorcery_object_get_id(aor);
wrapper = ao2_alloc_options(sizeof(struct ast_sip_contact_wrapper),
contact_wrapper_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
if (!wrapper) {
res = -1;
break;
}
wrapper->contact_id = ast_malloc(strlen(aor_id) + strlen(contact->uri) + 2);
if (!wrapper->contact_id) {
res = -1;
break;
}
sprintf(wrapper->contact_id, "%s/%s", aor_id, contact->uri);
wrapper->aor_id = ast_strdup(aor_id);
if (!wrapper->aor_id) {
res = -1;
break;
}
wrapper->contact = contact;
ao2_bump(wrapper->contact);
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
if ((res = on_contact(wrapper, arg, 0))) {
break;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
}
}
ao2_iterator_destroy(&i);
ao2_ref(contacts, -1);
return res;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
}
int ast_sip_contact_to_str(void *object, void *arg, int flags)
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
{
struct ast_sip_contact_wrapper *wrapper = object;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
struct ast_str **buf = arg;
ast_str_append(buf, 0, "%s,", wrapper->contact_id);
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
return 0;
}
static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf)
{
struct ast_variable *objset;
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
struct ast_variable *i;
objset = ast_sorcery_objectset_create2(ast_sip_get_sorcery(), aor,
AST_HANDLER_ONLY_STRING);
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
if (!objset) {
return -1;
}
ast_str_append(buf, 0, "ObjectType: %s\r\n",
ast_sorcery_object_get_type(aor));
ast_str_append(buf, 0, "ObjectName: %s\r\n",
ast_sorcery_object_get_id(aor));
for (i = objset; i; i = i->next) {
char *camel = ast_to_camel_case(i->name);
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
if (strcmp(camel, "Contact") == 0) {
ast_free(camel);
camel = NULL;
}
ast_str_append(buf, 0, "%s: %s\r\n", S_OR(camel, "Contacts"), i->value);
ast_free(camel);
}
ast_variables_destroy(objset);
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
return 0;
}
static int contacts_to_str(const void *obj, const intptr_t *args, char **buf)
{
const struct ast_sip_aor *aor = obj;
struct ast_str *str;
str = ast_str_create(MAX_OBJECT_FIELD);
if (!str) {
*buf = NULL;
return -1;
}
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
ast_sip_for_each_contact(aor, ast_sip_contact_to_str, &str);
ast_str_truncate(str, -1);
*buf = ast_strdup(ast_str_buffer(str));
ast_free(str);
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
return *buf ? 0 : -1;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
}
static int format_ami_aor_handler(void *obj, void *arg, int flags)
{
struct ast_sip_aor *aor = obj;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
struct ast_sip_ami *ami = arg;
const struct ast_sip_endpoint *endpoint = ami->arg;
struct ast_str *buf;
struct ao2_container *contacts;
int total_contacts;
int num_permanent;
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
buf = ast_sip_create_ami_event("AorDetail", ami);
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
if (!buf) {
return -1;
}
contacts = ast_sip_location_retrieve_aor_contacts(aor);
if (!contacts) {
ast_free(buf);
return -1;
}
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
sip_aor_to_ami(aor, &buf);
total_contacts = ao2_container_count(contacts);
num_permanent = aor->permanent_contacts ?
ao2_container_count(aor->permanent_contacts) : 0;
ast_str_append(&buf, 0, "TotalContacts: %d\r\n", total_contacts);
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
ast_str_append(&buf, 0, "ContactsRegistered: %d\r\n",
total_contacts - num_permanent);
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
ast_str_append(&buf, 0, "EndpointName: %s\r\n",
ast_sorcery_object_get_id(endpoint));
astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
ami->count++;
ast_free(buf);
ao2_ref(contacts, -1);
res_pjsip: AMI commands and events. Created the following AMI commands and corresponding events for res_pjsip: PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few select attributes on each. Events: EndpointList - for each endpoint a few attributes. EndpointlistComplete - after all endpoints have been listed. PJSIPShowEndpoint - Provides a detail list of attributes for a specified endpoint. Events: EndpointDetail - attributes on an endpoint. AorDetail - raised for each AOR on an endpoint. AuthDetail - raised for each associated inbound and outbound auth TransportDetail - transport attributes. IdentifyDetail - attributes for the identify object associated with the endpoint. EndpointDetailComplete - last event raised after all detail events. PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound registrations. Events: InboundRegistrationDetail - inbound registration attributes for each registration. InboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound registrations. Events: OutboundRegistrationDetail - outbound registration attributes for each registration. OutboundRegistrationDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound subscriptions and their attributes. Events: SubscriptionDetail - on each subscription detailed attributes SubscriptionDetailComplete - raised after all detail records have been listed. (issue ASTERISK-22609) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2959/ ........ Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-11-23 17:26:57 +00:00
return 0;
}
static int format_ami_endpoint_aor(const struct ast_sip_endpoint *endpoint,
struct ast_sip_ami *ami)
{
ami->arg = (void *)endpoint;
return ast_sip_for_each_aor(endpoint->aors,
format_ami_aor_handler, ami);
}
struct ast_sip_endpoint_formatter endpoint_aor_formatter = {
.format_ami = format_ami_endpoint_aor
};
static struct ao2_container *cli_aor_get_container(const char *regex)
{
struct ao2_container *container;
struct ao2_container *s_container;
container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "aor", regex);
if (!container) {
return NULL;
}
/* Create a sorted container of aors. */
s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
if (s_container
&& ao2_container_dup(s_container, container, 0)) {
ao2_ref(s_container, -1);
s_container = NULL;
}
ao2_ref(container, -1);
return s_container;
}
static int cli_contact_populate_container(void *obj, void *arg, int flags)
{
ao2_link(arg, obj);
return 0;
}
static int cli_aor_gather_contacts(void *obj, void *arg, int flags)
{
struct ast_sip_aor *aor = obj;
return ast_sip_for_each_contact(aor, cli_contact_populate_container, arg);
}
static const char *cli_contact_get_id(const void *obj)
{
const struct ast_sip_contact_wrapper *wrapper = obj;
return wrapper->contact_id;
}
static int cli_contact_sort(const void *obj, const void *arg, int flags)
{
const struct ast_sip_contact_wrapper *left_wrapper = obj;
const struct ast_sip_contact_wrapper *right_wrapper = arg;
const char *right_key = arg;
int cmp = 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right_wrapper->contact_id;
/* Fall through */
case OBJ_SEARCH_KEY:
cmp = strcmp(left_wrapper->contact_id, right_key);
break;
case OBJ_SEARCH_PARTIAL_KEY:
cmp = strncmp(left_wrapper->contact_id, right_key, strlen(right_key));
break;
default:
cmp = 0;
break;
}
return cmp;
}
static int cli_contact_compare(void *obj, void *arg, int flags)
{
const struct ast_sip_contact_wrapper *left_wrapper = obj;
const struct ast_sip_contact_wrapper *right_wrapper = arg;
const char *right_key = arg;
int cmp = 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right_wrapper->contact_id;
/* Fall through */
case OBJ_SEARCH_KEY:
if (strcmp(left_wrapper->contact_id, right_key) == 0) {;
cmp = CMP_MATCH | CMP_STOP;
}
break;
case OBJ_SEARCH_PARTIAL_KEY:
if (strncmp(left_wrapper->contact_id, right_key, strlen(right_key)) == 0) {
cmp = CMP_MATCH;
}
break;
default:
cmp = 0;
break;
}
return cmp;
}
static int cli_contact_iterate(void *container, ao2_callback_fn callback, void *args)
{
return ast_sip_for_each_contact(container, callback, args);
}
static int cli_filter_contacts(void *obj, void *arg, int flags)
{
struct ast_sip_contact_wrapper *wrapper = obj;
regex_t *regexbuf = arg;
if (!regexec(regexbuf, wrapper->contact_id, 0, NULL, 0)) {
return 0;
}
return CMP_MATCH;
}
static int cli_gather_contact(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
RAII_VAR(struct ast_sip_contact_wrapper *, wrapper, NULL, ao2_cleanup);
if (strcmp(contact->reg_server, ast_config_AST_SYSTEM_NAME ?: "")) {
return 0;
}
wrapper = ao2_alloc_options(sizeof(struct ast_sip_contact_wrapper),
contact_wrapper_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
if (!wrapper) {
return -1;
}
wrapper->contact_id = ast_malloc(strlen(contact->aor) + strlen(contact->uri) + 2);
if (!wrapper->contact_id) {
return -1;
}
sprintf(wrapper->contact_id, "%s/%s", contact->aor, contact->uri);
wrapper->aor_id = ast_strdup(contact->aor);
if (!wrapper->aor_id) {
return -1;
}
wrapper->contact = ao2_bump(contact);
ao2_link(arg, wrapper);
return 0;
}
static struct ao2_container *cli_contact_get_container(const char *regex)
{
RAII_VAR(struct ao2_container *, aors, NULL, ao2_cleanup);
RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
RAII_VAR(struct ast_variable *, var_aor, NULL, ast_variables_destroy);
struct ao2_container *contacts_container;
regex_t regexbuf;
if (!(var_aor = ast_variable_new("contact !=", "", ""))) {
return NULL;
}
/* Retrieving all the contacts may result in finding the same contact multiple
* times. So that they don't get displayed multiple times we only allow a
* single one to be placed into the container.
*/
contacts_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
cli_contact_sort, cli_contact_compare);
if (!contacts_container) {
return NULL;
}
contacts = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "contact", regex);
if (!contacts) {
ao2_ref(contacts_container, -1);
return NULL;
}
ao2_callback(contacts, OBJ_NODATA, cli_gather_contact, contacts_container);
aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
"aor", AST_RETRIEVE_FLAG_MULTIPLE, var_aor);
if (!aors) {
ao2_ref(contacts_container, -1);
return NULL;
}
ao2_callback(aors, OBJ_NODATA, cli_aor_gather_contacts, contacts_container);
if (!ast_strlen_zero(regex)) {
if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
ao2_ref(contacts_container, -1);
return NULL;
}
ao2_callback(contacts_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_contacts, &regexbuf);
regfree(&regexbuf);
}
return contacts_container;
}
static void *cli_contact_retrieve_by_id(const char *id)
{
struct ao2_container *container;
void *obj;
container = cli_contact_get_container("");
if (!container) {
return NULL;
}
obj = ao2_find(container, id, OBJ_SEARCH_KEY);
ao2_ref(container, -1);
return obj;
}
static int cli_contact_print_header(void *obj, void *arg, int flags)
{
struct ast_sip_cli_context *context = arg;
int indent = CLI_INDENT_TO_SPACES(context->indent_level);
res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph
2015-12-03 18:07:49 +00:00
int filler = CLI_LAST_TABSTOP - indent - 23;
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph
2015-12-03 18:07:49 +00:00
"%*s: <Aor/ContactUri%*.*s> <Hash....> <Status> <RTT(ms)..>\n",
indent, "Contact", filler, filler, CLI_HEADER_FILLER);
return 0;
}
static int cli_contact_print_body(void *obj, void *arg, int flags)
{
struct ast_sip_contact_wrapper *wrapper = obj;
struct ast_sip_contact *contact = wrapper->contact;
struct ast_sip_cli_context *context = arg;
int indent;
int flexwidth;
res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph
2015-12-03 18:07:49 +00:00
const char *contact_id = ast_sorcery_object_get_id(contact);
const char *hash_start = contact_id + strlen(contact->aor) + 2;
struct ast_sip_contact_status *status;
ast_assert(contact->uri != NULL);
ast_assert(context->output_buffer != NULL);
pjsip: Rewrite OPTIONS support with new eyes. The OPTIONS support in PJSIP has organically grown, like many things in Asterisk. It has been tweaked, changed, and adapted based on situations run into. Unfortunately this has taken its toll. Configuration file based objects have poor performance and even dynamic ones aren't that great. This change scraps the existing code and starts fresh with new eyes. It leverages all of the APIs made available such as sorcery observers and serializers to provide a better implementation. 1. The state of contacts, AORs, and endpoints relevant to the qualify process is maintained. This state can be updated by external forces (such as a device registering/unregistering) and also the reload process. This state also includes the association between endpoints and AORs. 2. AORs are scheduled and not contacts. This reduces the amount of work spent juggling scheduled items. 3. Manipulation of which AORs are being qualified and the endpoint states all occur within a serializer to reduce the conflict that can occur with multiple threads attempting to modify things. 4. Operations regarding an AOR use a serializer specific to that AOR. 5. AORs and endpoint state act as state compositors. They take input from lower level objects (contacts feed AORs, AORs feed endpoint state) and determine if a sufficient enough change has occurred to be fed further up the chain. 6. Realtime is supported by using observers to know when a contact has been registered. If state does not exist for the associated AOR then it is retrieved and becomes active as appropriate. The end result of all of this is best shown with a configuration file of 3000 endpoints each with an AOR that has a static contact. In the old code it would take over a minute to load and use all 8 of my cores. This new code takes 2-3 seconds and barely touches the CPU even while dealing with all of the OPTIONS requests. ASTERISK-26806 Change-Id: I6a5ebbfca9001dfe933eaeac4d3babd8d2e6f082
2017-12-11 18:34:53 +00:00
status = ast_sip_get_contact_status(contact);
indent = CLI_INDENT_TO_SPACES(context->indent_level);
res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph
2015-12-03 18:07:49 +00:00
flexwidth = CLI_LAST_TABSTOP - indent - 9 - strlen(contact->aor) + 1;
res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph
2015-12-03 18:07:49 +00:00
ast_str_append(&context->output_buffer, 0, "%*s: %s/%-*.*s %-10.10s %-7.7s %11.3f\n",
indent,
"Contact",
contact->aor,
flexwidth, flexwidth,
contact->uri,
res_pjsip: Use a MD5 hash for static Contact IDs When 90d9a70789 was merged, it mostly tested dynamic contacts created as a result of registering a PJSIP endpoint. Contacts generated in this fashion typically have a long alphanumeric string as their object identifier, which maps reasonably well for StatsD. Unfortunately, this doesn't work in the general case. StatsD treats both '.' and ':' characters as special characters. In particular, having a ':' appear in the middle of a StatsD metric will result in the metric being rejected. This causes some obvious issues with SIP URIs. The StatsD API should not be responsible for escaping the metric name passed to it. The metric is treated as a single long string, and it would be challenging to know what to escape in the string passed to the function. Likewise, we don't want to escape the metric in PJSIP, as that involves overhead that is wasted when either res_statsd isn't loaded or enabled. This patch takes an alternative approach. The Contact ID has been changed to be "aor@@uri_hash" instead of "aor@@uri". This (a) won't contain any of the aforementioned special characters, (b) can be done on Contact creation, which has minimal impact on run-time performance, and (c) also conforms to an earlier commit that changed the ID for dynamic contacts. The downside of this is that StatsD users will have to map SHA1 hashes back to the Contacts that are emitting the statistics. To that end, the CLI commands have been updated to include the first 10 characters of the MD5 hash, which should be enough to match what is shown in Graphite (or some other StatsD backend). ASTERISK-25595 #close Change-Id: Ic674a3307280365b4a45864a3571c295b48a01e2 Reported-by: Matt Jordan Tested-by: George Joseph
2015-12-03 18:07:49 +00:00
hash_start,
ast_sip_get_contact_short_status_label(status ? status->status : UNKNOWN),
pjsip: Rewrite OPTIONS support with new eyes. The OPTIONS support in PJSIP has organically grown, like many things in Asterisk. It has been tweaked, changed, and adapted based on situations run into. Unfortunately this has taken its toll. Configuration file based objects have poor performance and even dynamic ones aren't that great. This change scraps the existing code and starts fresh with new eyes. It leverages all of the APIs made available such as sorcery observers and serializers to provide a better implementation. 1. The state of contacts, AORs, and endpoints relevant to the qualify process is maintained. This state can be updated by external forces (such as a device registering/unregistering) and also the reload process. This state also includes the association between endpoints and AORs. 2. AORs are scheduled and not contacts. This reduces the amount of work spent juggling scheduled items. 3. Manipulation of which AORs are being qualified and the endpoint states all occur within a serializer to reduce the conflict that can occur with multiple threads attempting to modify things. 4. Operations regarding an AOR use a serializer specific to that AOR. 5. AORs and endpoint state act as state compositors. They take input from lower level objects (contacts feed AORs, AORs feed endpoint state) and determine if a sufficient enough change has occurred to be fed further up the chain. 6. Realtime is supported by using observers to know when a contact has been registered. If state does not exist for the associated AOR then it is retrieved and becomes active as appropriate. The end result of all of this is best shown with a configuration file of 3000 endpoints each with an AOR that has a static contact. In the old code it would take over a minute to load and use all 8 of my cores. This new code takes 2-3 seconds and barely touches the CPU even while dealing with all of the OPTIONS requests. ASTERISK-26806 Change-Id: I6a5ebbfca9001dfe933eaeac4d3babd8d2e6f082
2017-12-11 18:34:53 +00:00
(status && (status->status == AVAILABLE)) ? ((long long) status->rtt) / 1000.0 : NAN);
ao2_cleanup(status);
return 0;
}
static int cli_aor_iterate(void *container, ao2_callback_fn callback, void *args)
{
const char *aor_list = container;
return ast_sip_for_each_aor(aor_list, callback, args);
}
static void *cli_aor_retrieve_by_id(const char *id)
{
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", id);
}
static const char *cli_aor_get_id(const void *obj)
{
return ast_sorcery_object_get_id(obj);
}
static int cli_aor_print_header(void *obj, void *arg, int flags)
{
struct ast_sip_cli_context *context = arg;
int indent = CLI_INDENT_TO_SPACES(context->indent_level);
int filler = CLI_LAST_TABSTOP - indent - 7;
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
"%*s: <Aor%*.*s> <MaxContact>\n",
indent, "Aor", filler, filler, CLI_HEADER_FILLER);
if (context->recurse) {
struct ast_sip_cli_formatter_entry *formatter_entry;
context->indent_level++;
formatter_entry = ast_sip_lookup_cli_formatter("contact");
if (formatter_entry) {
formatter_entry->print_header(NULL, context, 0);
ao2_ref(formatter_entry, -1);
}
context->indent_level--;
}
return 0;
}
static int cli_aor_print_body(void *obj, void *arg, int flags)
{
struct ast_sip_aor *aor = obj;
struct ast_sip_cli_context *context = arg;
int indent;
int flexwidth;
ast_assert(context->output_buffer != NULL);
// context->current_aor = aor;
indent = CLI_INDENT_TO_SPACES(context->indent_level);
flexwidth = CLI_LAST_TABSTOP - indent - 12;
ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %12u\n",
indent,
"Aor",
flexwidth, flexwidth,
ast_sorcery_object_get_id(aor), aor->max_contacts);
if (context->recurse) {
struct ast_sip_cli_formatter_entry *formatter_entry;
context->indent_level++;
formatter_entry = ast_sip_lookup_cli_formatter("contact");
if (formatter_entry) {
formatter_entry->iterate(aor, formatter_entry->print_body, context);
ao2_ref(formatter_entry, -1);
}
context->indent_level--;
if (context->indent_level == 0) {
ast_str_append(&context->output_buffer, 0, "\n");
}
}
if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
ast_str_append(&context->output_buffer, 0, "\n");
ast_sip_cli_print_sorcery_objectset(aor, context, 0);
}
return 0;
}
static struct ao2_container *cli_get_aors(void)
{
struct ao2_container *aors;
aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
return aors;
}
static int format_ami_aorlist_handler(void *obj, void *arg, int flags)
{
struct ast_sip_aor *aor = obj;
struct ast_sip_ami *ami = arg;
struct ast_str *buf;
buf = ast_sip_create_ami_event("AorList", ami);
if (!buf) {
return -1;
}
sip_aor_to_ami(aor, &buf);
astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
ami->count++;
ast_free(buf);
return 0;
}
static int ami_show_aors(struct mansession *s, const struct message *m)
{
struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
struct ao2_container *aors;
aors = cli_get_aors();
if (!aors) {
astman_send_error(s, m, "Could not get AORs\n");
return 0;
}
if (!ao2_container_count(aors)) {
astman_send_error(s, m, "No AORs found\n");
ao2_ref(aors, -1);
return 0;
}
astman_send_listack(s, m, "A listing of AORs follows, presented as AorList events",
"start");
ao2_callback(aors, OBJ_NODATA, format_ami_aorlist_handler, &ami);
astman_send_list_complete_start(s, m, "AorListComplete", ami.count);
astman_send_list_complete_end(s);
ao2_ref(aors, -1);
return 0;
}
static struct ast_cli_entry cli_commands[] = {
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Aors",
.command = "pjsip list aors",
.usage = "Usage: pjsip list aors [ like <pattern> ]\n"
" List the configured PJSIP Aors\n"
" Optional regular expression pattern is used to filter the list.\n"),
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Aors",
.command = "pjsip show aors",
.usage = "Usage: pjsip show aors [ like <pattern> ]\n"
" Show the configured PJSIP Aors\n"
" Optional regular expression pattern is used to filter the list.\n"),
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Aor",
.command = "pjsip show aor",
.usage = "Usage: pjsip show aor <id>\n"
" Show the configured PJSIP Aor\n"),
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Contacts",
.command = "pjsip list contacts",
.usage = "Usage: pjsip list contacts [ like <pattern> ]\n"
" List the configured PJSIP contacts\n"
" Optional regular expression pattern is used to filter the list.\n"),
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contacts",
.command = "pjsip show contacts",
.usage = "Usage: pjsip show contacts [ like <pattern> ]\n"
" Show the configured PJSIP contacts\n"
" Optional regular expression pattern is used to filter the list.\n"),
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contact",
.command = "pjsip show contact",
.usage = "Usage: pjsip show contact\n"
" Show the configured PJSIP contact\n"),
};
struct ast_sip_cli_formatter_entry *contact_formatter;
struct ast_sip_cli_formatter_entry *aor_formatter;
/*! \brief Always create a contact_status for each contact */
static int contact_apply_handler(const struct ast_sorcery *sorcery, void *object)
{
struct ast_sip_contact_status *status;
struct ast_sip_contact *contact = object;
if (ast_strlen_zero(contact->uri)) {
ast_log(LOG_ERROR, "A URI on dynamic contact '%s' is empty\n",
ast_sorcery_object_get_id(contact));
return -1;
}
status = ast_res_pjsip_find_or_create_contact_status(contact);
ao2_cleanup(status);
return status ? 0 : -1;
}
static int aor_apply_outbound_proxy(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
struct ast_sip_aor *aor = arg;
ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy);
return 0;
}
static int aor_apply_handler(const struct ast_sorcery *sorcery, void *object)
{
struct ast_sip_aor *aor = object;
if (!aor->permanent_contacts || ast_strlen_zero(aor->outbound_proxy)) {
return 0;
}
ao2_callback(aor->permanent_contacts, OBJ_NODATA | OBJ_MULTIPLE, aor_apply_outbound_proxy, aor);
return 0;
}
/*! \brief Initialize sorcery with location support */
int ast_sip_initialize_sorcery_location(void)
{
struct ast_sorcery *sorcery = ast_sip_get_sorcery();
int i;
ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
/* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
ast_sorcery_apply_default(sorcery, "contact", "astdb", "registrar");
ast_sorcery_object_set_congestion_levels(sorcery, "contact", -1,
3 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL);
ast_sorcery_apply_default(sorcery, "aor", "config", "pjsip.conf,criteria=type=aor");
if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, contact_apply_handler) ||
ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, aor_apply_handler)) {
return -1;
}
ast_sorcery_observer_add(sorcery, "aor", &aor_observer);
ast_sorcery_object_field_register(sorcery, "contact", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(sorcery, "contact", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, uri));
ast_sorcery_object_field_register(sorcery, "contact", "path", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, path));
sorcery: Create AST_SORCERY dialplan function. This patch creates the AST_SORCERY dialplan function which allows someone to retrieve any value from a sorcery-based config file. It's similar to AST_CONFIG. The creation of the function itself was fairly straightforward but it required changes to the underlying sorcery infrastructure that rippled into individual sorcery objects. The changes stemmed from inconsistencies in how sorcery created ast_variable objectsets from sorcery objects and the inconsistency in how individual objects used that feature especially when it came to parameters that can be specified multiple times like contact in aor and match in identify. You can read more here... http://lists.digium.com/pipermail/asterisk-dev/2014-February/065202.html So, what this patch does, besides actually creating the AST_SORCERY function, is the following... * Creates ast_variable_list_append which is a helper to append one ast_variable list to another. * Modifies the ast_sorcery_object_field_register functions to accept the already-defined sorcery_fields_handler callback. * Modifies ast_sorcery_objectset_create to accept a parameter indicating return type preference...a single ast_variable with all values concatenated or an ast_variable list with multiple entries. Also fixed a few bugs. * Modifies individual sorcery object implementations to use the new function definition of the ast_sorcery_object_field_register functions. * Modifies location.c and res_pjsip_endpoint_identifier_ip.c to implement sorcery_fields_handler handlers so they return multiple occurrences as an ast_variable_list. * Added a whole bunch of tests to test_sorcery. (closes issue ASTERISK-22537) Review: http://reviewboard.asterisk.org/r/3254/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2014-03-06 22:39:54 +00:00
ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, NULL, 0, 0);
ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T,
PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400);
ast_sorcery_object_field_register(sorcery, "contact", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_contact, qualify_timeout));
ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify));
ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy));
ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent));
ast_sorcery_object_field_register(sorcery, "contact", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, endpoint_name));
ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server));
ast_sorcery_object_field_register(sorcery, "contact", "via_addr", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, via_addr));
ast_sorcery_object_field_register(sorcery, "contact", "via_port", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_contact, via_port));
ast_sorcery_object_field_register(sorcery, "contact", "call_id", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, call_id));
res_pjsip: Remove ephemeral registered contacts on transport shutdown. The fix for the issue is broken up into three parts. This is part two which handles the server side of REGISTER requests when rewrite_contact is enabled. Any registered reliable transport contact becomes invalid when the transport connection becomes disconnected. * Monitor the rewrite_contact's reliable transport REGISTER contact for shutdown. If it is shutdown then the contact must be removed because it is no longer valid. Otherwise, when the client attempts to re-REGISTER it may be blocked because the invalid contact is there. Also if we try to send a call to the endpoint using the invalid contact then the endpoint is not likely to see the request. The endpoint either won't be listening on that port for new connections or a NAT/firewall will block it. * Prune any rewrite_contact's registered reliable transport contacts on boot. The reliable transport no longer exists so the contact is invalid. * Websockets always rewrite the REGISTER contact address and the transport needs to be monitored for shutdown. * Made the websocket transport set a unique name since that is what we use as the ao2 container key. Otherwise, we would not know which transport we find when one of them shuts down. The names are also used for PJPROJECT debug logging. * Made the websocket transport post the PJSIP_TP_STATE_CONNECTED state event. Now the global keep_alive_interval option, initially idle shutdown timer, and the server REGISTER contact monitor can work on wetsocket transports. * Made the websocket transport set the PJSIP_TP_DIR_INCOMING direction. Now initially idle websockets will automatically shutdown. ASTERISK-27147 Change-Id: I397a5e7d18476830f7ffe1726adf9ee6c15964f4
2017-07-31 19:21:06 +00:00
ast_sorcery_object_field_register(sorcery, "contact", "prune_on_boot", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_contact, prune_on_boot));
ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration));
ast_sorcery_object_field_register(sorcery, "aor", "maximum_expiration", "7200", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, maximum_expiration));
ast_sorcery_object_field_register(sorcery, "aor", "default_expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, default_expiration));
ast_sorcery_object_field_register(sorcery, "aor", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_aor, qualify_frequency), 0, 86400);
ast_sorcery_object_field_register(sorcery, "aor", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_aor, qualify_timeout));
ast_sorcery_object_field_register(sorcery, "aor", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, authenticate_qualify));
ast_sorcery_object_field_register(sorcery, "aor", "max_contacts", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, max_contacts));
ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_var_list, 0, 0);
ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
res_pjsip_mwi: Add voicemail extension and mwi_subscribe_replaces_unsolicited res_pjsip_mwi was missing the chan_sip "vmexten" functionality which adds the Message-Account header to the MWI NOTIFY. Also, specifying mailboxes on endpoints for unsolicited mwi and on aors for subscriptions required that the admin know in advance which the client wanted. If you specified mailboxes on the endpoint, subscriptions were rejected even if you also specified mailboxes on the aor. Voicemail extension: * Added a global default_voicemail_extension which defaults to "". * Added voicemail_extension to both endpoint and aor. * Added ast_sip_subscription_get_dialog for support. * Added ast_sip_subscription_get_sip_uri for support. When an unsolicited NOTIFY is constructed, the From header is parsed, the voicemail extension from the endpoint is substituted for the user, and the result placed in the Message-Account field in the body. When a subscribed NOTIFY is constructed, the subscription dialog local uri is parsed, the voicemail_extension from the aor (looked up from the subscription resource name) is substituted for the user, and the result placed in the Message-Account field in the body. If no voicemail extension was defined, the Message-Account field is not added to the NOTIFY body. mwi_subscribe_replaces_unsolicited: * Added mwi_subscribe_replaces_unsolicited to endpoint. The previous behavior was to reject a subscribe if a previous internal subscription for unsolicited MWI was found for the mailbox. That remains the default. However, if there are mailboxes also set on the aor and the client subscribes and mwi_subscribe_replaces_unsolicited is set, the existing internal subscription is removed and replaced with the external subscription. This allows an admin to configure mailboxes on both the endpoint and aor and allows the client to select which to use. ASTERISK-25865 #close Reported-by: Ross Beer Change-Id: Ic15a9415091760539c7134a5ba3dc4a6a1217cea
2016-03-25 03:55:03 +00:00
ast_sorcery_object_field_register_custom(sorcery, "aor", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy));
ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path));
ast_sip_register_endpoint_formatter(&endpoint_aor_formatter);
contact_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!contact_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for contact_formatter\n");
return -1;
}
contact_formatter->name = "contact";
contact_formatter->print_header = cli_contact_print_header;
contact_formatter->print_body = cli_contact_print_body;
contact_formatter->get_container = cli_contact_get_container;
contact_formatter->iterate = cli_contact_iterate;
contact_formatter->get_id = cli_contact_get_id;
contact_formatter->retrieve_by_id = cli_contact_retrieve_by_id;
aor_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!aor_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for aor_formatter\n");
return -1;
}
aor_formatter->name = "aor";
aor_formatter->print_header = cli_aor_print_header;
aor_formatter->print_body = cli_aor_print_body;
aor_formatter->get_container = cli_aor_get_container;
aor_formatter->iterate = cli_aor_iterate;
aor_formatter->get_id = cli_aor_get_id;
aor_formatter->retrieve_by_id = cli_aor_retrieve_by_id;
ast_sip_register_cli_formatter(contact_formatter);
ast_sip_register_cli_formatter(aor_formatter);
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
if (ast_manager_register_xml("PJSIPShowAors", EVENT_FLAG_SYSTEM, ami_show_aors)) {
return -1;
}
/*
* Reset StatsD gauges in case we didn't shut down cleanly.
* Note that this must done here, as contacts will create the contact_status
* object before PJSIP options handling is initialized.
*/
res_pjsip/contacts/statsd: Make contact lifecycle events more consistent It will never be perfect or even pretty, mostly because of the differences between static and dynamic contacts. Created: Can't use the contact or contact_status alloc functions because the objects come and go regardless of the actual state. Can't use the contact_apply_handler, ast_sip_location_add_contact or a sorcery created handler because they only get called for dynamic contacts. Similarly, permanent_uri_handler only gets called for static contacts. So, Matt had it right. :) ast_res_pjsip_find_or_create_contact_status is the only place it can go and not have duplicated code. Both permanent_uri_handler and contact_apply_handler call find_or_create. Removed: Can't use the destructors for the same reason as above. The only place to put this is in persistent_endpoint_contact_deleted_observer which I believe is the "correct" place but even that will handle only dynamic contacts. This doesn't called on shutdown however. There is no hook to use for static contacts that may be removed because of a config change while asterisk is in operation. I moved the cleanup of contact_status from ast_sip_location_delete_contact to the handler as well. Status Change and RTT: Although they worked fine where they were (in update_contact_status) I moved them to persistent_endpoint_contact_status_observer to make it more consistent with removed. There was logic there already to detect a state change. Finally, fixed a nit in permanent_uri_handler rmudgett reported eralier. ASTERISK-25608 #close Change-Id: I4b56e7dfc3be3baaaf6f1eac5b2068a0b79e357d Reported-by: George Joseph Tested-by: George Joseph
2015-12-04 22:23:21 +00:00
for (i = 0; i <= REMOVED; i++) {
ast_statsd_log_full_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, 0, 1.0, ast_sip_get_contact_status_label(i));
}
return 0;
}
int ast_sip_destroy_sorcery_location(void)
{
ast_sorcery_observer_remove(ast_sip_get_sorcery(), "aor", &aor_observer);
ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
ast_sip_unregister_cli_formatter(contact_formatter);
ast_sip_unregister_cli_formatter(aor_formatter);
ast_manager_unregister("PJSIPShowAors");
ast_sip_unregister_endpoint_formatter(&endpoint_aor_formatter);
res_pjsip: make it unloadable (take 2) Due to the original patch causing memory corruptions it was removed until the problem could be resolved. This patch is the original patch plus some added locking around stasis router subcription that was needed to avoid the memory corruption. Description of the original problem and patch (still applicable): The res_pjsip module was previously unloadable. With this patch it can now be unloaded. This patch is based off the original patch on the issue (listed below) by Corey Farrell with a few modifications. Namely, removed a few changes not required to make the module unloadable and also fixed a bug that would cause asterisk to crash on unloading. This patch is the first step (should hopefully be followed by another/others at some point) in allowing res_pjsip and the modules that depend on it to be unloadable. At this time, res_pjsip and some of the modules that depend on res_pjsip cannot be unloaded without causing problems of some sort. The goal of this patch is to get res_pjsip and only res_pjsip to be able to unload successfully and/or shutdown without incident (crashes, leaks, etc...). Other dependent modules may still cause problems on unload. Basically made sure, with the patch applied, that res_pjsip (with no other dependent modules loaded) could be succesfully unloaded and Asterisk could shutdown without any leaks or crashes that pertained directly to res_pjsip. ASTERISK-24485 #close Reported by: Corey Farrell Review: https://reviewboard.asterisk.org/r/4363/ patches: pjsip_unload-broken-r1.patch submitted by Corey Farrell (license 5909) ........ Merged revisions 431179 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@431180 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2015-01-27 19:12:56 +00:00
return 0;
}