31#include <pjsip_simple.h>
446 .name = {
"PubSub Module", 13 },
447 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
451#define MOD_DATA_PERSISTENCE "sub_persistence"
452#define MOD_DATA_MSG "sub_msg"
460#define PUBLICATIONS_BUCKETS 37
463#define DEFAULT_PUBLISH_EXPIRES 3600
466#define DATASTORE_BUCKETS 53
469#define DEFAULT_EXPIRES 3600
636 "TerminateInProgress",
767 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
769 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
800 if (!sub_tree->
evsub) {
806 ast_debug(3,
"Transport destroyed. Removing subscription '%s->%s' prune on boot: %d\n",
811 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
861 char tag[PJ_GUID_STRING_LENGTH + 1];
867 "subscription_persistence",
NULL);
869 pjsip_dialog *dlg = sub_tree->
dlg;
893 ast_debug(3,
"Updating persistence for '%s->%s' prune on boot: %s\n",
902 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
903 pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
NULL);
913 (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
917 ast_debug(3,
"adding transport monitor on %s for '%s->%s' prune on boot: %d\n",
918 rdata->tp_info.transport->obj_name,
932 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
946 if (rdata->msg_info.msg_buf) {
975 ast_debug(3,
"Unregistering transport monitor on %s '%s->%s'\n",
991 size_t num_accept,
const char *
body_type);
996 pjsip_event_hdr *event_header;
1000 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str_event_name, rdata->msg_info.msg->hdr.next);
1001 if (!event_header) {
1003 endpoint ? endpoint :
"Unknown");
1011 endpoint ? endpoint :
"Unknown");
1030 "multipart/related",
1031 "application/rlmi+xml",
1057 pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
1059 size_t num_accept_headers = 0;
1061 while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
1065 for (i = 0; i < accept_header->count && num_accept_headers <
AST_SIP_MAX_ACCEPT; ++i) {
1067 ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i],
sizeof(accept[num_accept_headers]));
1068 ++num_accept_headers;
1073 if (num_accept_headers == 0) {
1078 num_accept_headers = 1;
1091 pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
1093 while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
1096 for (i = 0; i < supported_header->count; i++) {
1097 if (!pj_stricmp2(&supported_header->values[i],
"eventlist")) {
1136 ast_log(
LOG_WARNING,
"Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
1228#define NEW_SUBSCRIBE(notifier, endpoint, resource, rdata) notifier->new_subscribe_with_rdata ? notifier->new_subscribe_with_rdata(endpoint, resource, rdata) : notifier->new_subscribe(endpoint, resource)
1262 ast_debug(1,
"Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1269 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1272 handler->notifier->get_resource_display_name(endpoint, resource, display_name,
sizeof(display_name));
1277 "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1281 ast_debug(2,
"Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1287 ast_debug(2,
"Subscription to leaf resource %s resulted in error response %d\n",
1291 ast_debug(2,
"Resource %s (child of %s) is a list\n", resource, parent->
resource);
1294 ast_debug(1,
"Cannot build children of resource %s due to allocation failure\n", resource);
1299 ast_debug(1,
"List %s had no successful children.\n", resource);
1304 ast_debug(2,
"List %s had successful children. Adding to parent %s\n",
1378 ast_debug(2,
"Subscription '%s->%s' is not to a list\n",
1387 ast_debug(2,
"Subscription '%s->%s' is a list\n",
1427 ast_debug(2,
"Removing subscription '%s->%s' from list of subscriptions\n",
1439 ast_debug(3,
"Destroying SIP subscription from '%s->%s'\n",
1475 pjsip_sip_uri *request_uri;
1479 ast_log(
LOG_ERROR,
"No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n",
resource);
1492 if (!
sub->datastores) {
1498 if (!
sub->body_text) {
1503 sub->uri = pjsip_sip_uri_create(
tree->
dlg->pool, PJ_FALSE);
1504 request_uri = pjsip_uri_get_uri(msg->line.req.uri);
1505 pjsip_sip_uri_assign(
tree->
dlg->pool,
sub->uri, request_uri);
1517 sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1545 sub->body_generator = generator;
1556 ast_debug(1,
"Child subscription to resource %s could not be created\n",
1562 ast_debug(1,
"Child subscription to resource %s could not be appended\n",
1590 if (
sub->handler->subscription_shutdown) {
1591 sub->handler->subscription_shutdown(
sub);
1618 ast_debug(3,
"Destroying subscription tree %p '%s->%s'\n",
1625 if (sub_tree->
dlg) {
1638 ast_debug(3,
"Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1723 *dlg_status = PJ_ENOMEM;
1730 if (*dlg_status != PJ_EEXISTS) {
1741 pjsip_ua_unregister_dlg(pjsip_ua_instance(),
dlg);
1743 dlg->local.tag_hval = pj_hash_calc_tolower(0,
NULL, &
dlg->local.info->tag);
1744 pjsip_ua_register_dlg(pjsip_ua_instance(),
dlg);
1757 pjsip_dlg_dec_lock(
dlg);
1759#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
1760 pjsip_evsub_add_ref(sub_tree->
evsub);
1764 pjsip_msg_clone(
dlg->pool, rdata->msg_info.msg));
1808 pjsip_rx_data *rdata = recreate_data->
rdata;
1814 size_t resource_size;
1817 pjsip_expires_hdr *expires_header;
1819 const pj_str_t *
user;
1822 resource_size = pj_strlen(
user) + 1;
1834 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not get subscription handler.\n",
1842 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Body generator not available.\n",
1855 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: The endpoint was not found\n",
1862 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1863 rdata->msg_info.msg->hdr.next);
1864 if (!expires_header) {
1865 expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1866 if (!expires_header) {
1867 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not update expires header.\n",
1873 pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1879 ast_debug(3,
"Expired subscription retrived from persistent store '%s' %s\n",
1885 expires_header->ivalue = expires;
1887 memset(&tree, 0,
sizeof(tree));
1890 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1891 pj_status_t dlg_status;
1894 &tree, &dlg_status, persistence);
1896 if (dlg_status != PJ_EEXISTS) {
1897 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not create subscription tree.\n",
1910 ind->
expires = expires_header->ivalue;
1935 pj_pool_t *pool = arg;
1937 pjsip_rx_data rdata;
1942 ast_debug(3,
"Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1950 ast_debug(3,
"Expired subscription retrived from persistent store '%s' %s\n",
1957 pj_pool_reset(pool);
1958 rdata.tp_info.pool = pool;
1963 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: The message could not be parsed\n",
1969 if (
rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1970 ast_log(
LOG_NOTICE,
"Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1979 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1988 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
2005 PJSIP_POOL_RDATA_INC);
2007 ast_log(
LOG_WARNING,
"Could not create a memory pool for recreating SIP subscriptions\n");
2015 ao2_ref(persisted_subscriptions, -1);
2035 if (strcmp(
type,
"FullyBooted")) {
2053 if (!on_subscription) {
2059 if (on_subscription(i, arg)) {
2079 if (sub_tree->
dlg) {
2108 dlg =
sub->tree->dlg;
2112 return pjsip_msg_find_hdr_by_name(msg, &
name,
NULL);
2123 pjsip_tx_data *tdata;
2140 ast_log(
LOG_WARNING,
"No contacts configured for endpoint %s. Unable to create SIP subsription\n",
2161 if (pjsip_evsub_initiate(
evsub,
NULL, -1, &tdata) == PJ_SUCCESS) {
2162 pjsip_evsub_send_request(sub_tree->
evsub, tdata);
2168 pjsip_evsub_terminate(
evsub, PJ_TRUE);
2181 return sub->tree->dlg;
2193 return sub->tree->serializer;
2221 for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
2222 buf = pj_pool_alloc(tdata->pool, buf_size);
2223 size = pjsip_msg_print(tdata->msg,
buf, buf_size);
2230 tdata->buf.start =
buf;
2231 tdata->buf.cur = tdata->buf.start;
2232 tdata->buf.end = tdata->buf.start + buf_size;
2239#ifdef TEST_FRAMEWORK
2241 pjsip_evsub *evsub = sub_tree->
evsub;
2247 pjsip_tx_data_dec_ref(tdata);
2251 res = pjsip_evsub_send_request(sub_tree->
evsub, tdata);
2258 pjsip_evsub_get_state_name(evsub),
2261 return (res == PJ_SUCCESS ? 0 : -1);
2278static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi,
const pjsip_generic_string_hdr *cid,
2279 const char *resource_name,
const pjsip_sip_uri *resource_uri, pjsip_evsub_state
state)
2281 static pj_str_t cid_name = {
"cid", 3 };
2282 pj_xml_node *resource;
2284 pj_xml_node *instance;
2285 pj_xml_attr *cid_attr;
2287 char uri[PJSIP_MAX_URL_SIZE];
2288 char name_sanitized[PJSIP_MAX_URL_SIZE];
2291 const pj_str_t cid_stripped = {
2292 .ptr = cid->hvalue.ptr + 1,
2293 .slen = cid->hvalue.slen - 2,
2300 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri,
sizeof(uri));
2304 pj_strdup2(pool, &
name->content, name_sanitized);
2310 state == PJSIP_EVSUB_STATE_TERMINATED ?
"terminated" :
"active");
2316 cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2317 pj_xml_add_attr(instance, cid_attr);
2333 pjsip_generic_string_hdr *
cid;
2363 static const pj_str_t cid_name = {
"Content-ID", 10 };
2364 pjsip_generic_string_hdr *cid;
2370 alloc_size =
sizeof(
id) + pj_strlen(&
sub->uri->host) + 3;
2371 cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2372 cid_value.slen = sprintf(cid_value.ptr,
"<%s@%.*s>",
2374 (
int) pj_strlen(&
sub->uri->host), pj_strbuf(&
sub->uri->host));
2375 cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2383 pj_xml_node *rlmi = msg_body->data;
2385 num_printed = pj_xml_print(rlmi,
buf, size, PJ_TRUE);
2395 const pj_xml_node *rlmi = data;
2397 return pj_xml_clone(pool, rlmi);
2420 pjsip_multipart_part *rlmi_part;
2421 char version_str[32];
2422 char uri[PJSIP_MAX_URL_SIZE];
2423 pjsip_generic_string_hdr *cid;
2432 snprintf(version_str,
sizeof(version_str),
"%u",
sub->version++);
2445 rlmi_part = pjsip_multipart_create_part(pool);
2447 rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2448 pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &
rlmi_media_type);
2450 rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2455 pj_list_insert_before(&rlmi_part->hdr,
cid);
2461 unsigned int force_full_state);
2497 bp->
state =
sub->subscription_state;
2516 pjsip_msg_body *body;
2530 bp->
part = pjsip_multipart_create_part(pool);
2531 bp->
part->body = body;
2532 pj_list_insert_before(&bp->
part->hdr, bp->
cid);
2547 pjsip_media_type media_type;
2548 pjsip_param *media_type_param;
2550 pj_str_t pj_boundary;
2552 pjsip_media_type_init2(&media_type,
"multipart",
"related");
2554 media_type_param = pj_pool_alloc(pool,
sizeof(*media_type_param));
2555 pj_list_init(media_type_param);
2557 pj_strdup2(pool, &media_type_param->name,
"type");
2558 pj_strdup2(pool, &media_type_param->value,
"\"application/rlmi+xml\"");
2560 pj_list_insert_before(&media_type.param, media_type_param);
2563 return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2579 unsigned int force_full_state)
2582 pjsip_multipart_part *rlmi_part;
2583 pjsip_msg_body *multipart;
2585 unsigned int use_full_state = force_full_state ? 1 :
sub->full_state;
2608 pjsip_multipart_add_part(pool, multipart, rlmi_part);
2611 pjsip_multipart_add_part(pool, multipart,
AST_VECTOR_GET(&body_parts, i)->part);
2626 unsigned int force_full_state)
2628 pjsip_msg_body *body;
2643 body = pjsip_msg_body_create(pool, &
type, &subtype, &
text);
2660 pjsip_require_hdr *require;
2662 require = pjsip_require_hdr_create(pool);
2663 pj_strdup2(pool, &require->values[0],
"eventlist");
2673 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2691 pjsip_evsub *evsub = sub_tree->
evsub;
2692 pjsip_tx_data *tdata;
2701 NULL,
NULL, &tdata) != PJ_SUCCESS) {
2706 if (!tdata->msg->body) {
2707 pjsip_tx_data_dec_ref(tdata);
2713 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2735 pjsip_dialog *
dlg = sub_tree->
dlg;
2737 pjsip_dlg_inc_lock(
dlg);
2750 pjsip_dlg_dec_lock(
dlg);
2763 ?
"SUBSCRIPTION_TERMINATED" :
"SUBSCRIPTION_STATE_CHANGED",
2766 pjsip_dlg_dec_lock(
dlg);
2804 pjsip_dialog *
dlg =
sub->tree->dlg;
2806 pjsip_dlg_inc_lock(
dlg);
2809 pjsip_dlg_dec_lock(
dlg);
2815 pjsip_dlg_dec_lock(
dlg);
2819 sub->body_changed = 1;
2821 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2825 if (
sub->tree->notification_batch_interval) {
2836 sub->tree->root->resource);
2840 pjsip_dlg_dec_lock(
dlg);
2851 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR,
sub->uri,
buf, size);
2860 uri = pjsip_uri_get_uri(
dlg->remote.info->uri);
2862 if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri,
buf, size) < 0) {
2869 return sub->resource;
2874 return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2886 pj_list_init(&res_hdr);
2892 return pjsip_evsub_accept(sub_tree->
evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2992 ast_log(
LOG_ERROR,
"No event package specified for publish handler. Cannot register\n");
2999 ast_log(
LOG_ERROR,
"Could not allocate publications container for event '%s'\n",
3056 ast_log(
LOG_ERROR,
"No event package specified for subscription handler. Cannot register\n");
3063 "Unable to register subscription handler for event %s. A handler is already registered\n",
3134 size_t num_accept,
const char *
body_type)
3139 for (i = 0; i < num_accept; ++i) {
3142 ast_debug(3,
"Body generator %p found for accept type %s\n", generator, accept[i]);
3144 ast_log(
LOG_WARNING,
"Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
3151 ast_debug(3,
"No body generator found for accept type %s\n", accept[i]);
3179 if (
sub->handler->notifier->subscription_established(
sub)) {
3185 ast_debug(3,
"No notify data, not generating any body content\n");
3230 ast_log(
LOG_ERROR,
"Unable to create expiration timer of %d seconds for %s\n",
3243 pjsip_expires_hdr *expires_header;
3249 pjsip_uri *request_uri;
3250 size_t resource_size;
3253 pj_status_t dlg_status;
3254 const pj_str_t *
user;
3259 if (!endpoint->subscription.allow) {
3265 request_uri = rdata->msg_info.msg->line.req.uri;
3268 char uri_str[PJSIP_MAX_URL_SIZE];
3270 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str,
sizeof(uri_str));
3277 resource_size = pj_strlen(
user) + 1;
3287 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3288 if (expires_header) {
3289 if (expires_header->ivalue == 0) {
3290 ast_debug(1,
"Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3295 if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3296 ast_log(
LOG_WARNING,
"Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3315 memset(&tree, 0,
sizeof(tree));
3318 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3326 if (dlg_status != PJ_EEXISTS) {
3327 ast_debug(3,
"No dialog exists, rejecting\n");
3376 pjsip_generic_string_hdr *etag_hdr,
unsigned int *expires,
int *entity_id)
3378 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
3381 char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3385 if (sscanf(etag,
"%30d", entity_id) != 1) {
3394 }
else if (!etag_hdr && rdata->msg_info.msg->body) {
3396 }
else if (etag_hdr && !rdata->msg_info.msg->body) {
3398 }
else if (etag_hdr && rdata->msg_info.msg->body) {
3410 ast_debug(3,
"Destroying SIP publication\n");
3422 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
3444 dst = publication->
data;
3446 dst += resource_len;
3453 pjsip_rx_data *rdata)
3455 pjsip_tx_data *tdata;
3456 pjsip_transaction *tsx;
3462 if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3472 if (pjsip_tsx_create_uas(&
pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3473 pjsip_tx_data_dec_ref(tdata);
3477 pjsip_tsx_recv_msg(tsx, rdata);
3479 if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3480 pjsip_tx_data_dec_ref(tdata);
3491 char *resource_name;
3492 size_t resource_size;
3495 pjsip_uri *request_uri;
3497 const pj_str_t *
user;
3499 request_uri = rdata->msg_info.msg->line.req.uri;
3502 char uri_str[PJSIP_MAX_URL_SIZE];
3504 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str,
sizeof(uri_str));
3511 resource_size = pj_strlen(
user) + 1;
3523 ast_debug(1,
"No 'inbound-publication' defined for resource '%s'\n", resource_name);
3529 ast_debug(1,
"Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3535 for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->
next) {
3536 if (!strcmp(event_configuration_name->
name,
handler->event_name)) {
3541 if (!event_configuration_name) {
3542 ast_debug(1,
"Event '%s' is not configured for '%s'\n",
handler->event_name, resource_name);
3547 resp =
handler->new_publication(endpoint, resource_name, event_configuration_name->
value);
3549 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3564 ast_debug(3,
"Publication state change failed\n");
3579 if (publication->handler->publish_expire) {
3580 publication->handler->publish_expire(publication);
3602 pjsip_event_hdr *event_header;
3606 static const pj_str_t str_sip_if_match = {
"SIP-If-Match", 12 };
3607 pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match,
NULL);
3610 unsigned int expires = 0;
3611 int entity_id, response = 0;
3616 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str_event_name, rdata->msg_info.msg->hdr.next);
3617 if (!event_header) {
3638 static const pj_str_t str_conditional_request_failed = {
"Conditional Request Failed", 26 };
3649 publication->expires = expires;
3652 switch (publish_type) {
3658 if (
handler->publication_state_change(publication, rdata->msg_info.msg->body,
3666 handler->publication_state_change(publication, rdata->msg_info.msg->body,
3718 pj_size_t accept_len;
3732 accept_len = strlen(generator->
type) + strlen(generator->
subtype) + 1;
3735 pj_strset(&accept,
ast_alloca(accept_len + 1), accept_len);
3736 sprintf((
char *) pj_strbuf(&accept),
"%s/%s", generator->
type, generator->
subtype);
3739 PJSIP_H_ACCEPT,
NULL, 1, &accept);
3750 if (iter == generator) {
3774 if (iter == supplement) {
3785 return sub->body_generator->type;
3790 return sub->body_generator->subtype;
3809 ast_log(
LOG_WARNING,
"%s/%s body generator does not accept the type of data provided\n",
3828 if (!strcmp(generator->
type, supplement->
type) &&
3864 int found_counts = 0;
3871 memset(summary, 0,
sizeof(*summary));
3876 if (sscanf(line,
"voice-message: %d/%d (%d/%d)",
3885 return !found_counts;
3892 const char *endpoint_name;
3901 ast_debug(1,
"Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3907 ast_debug(1,
"Incoming MWI: Found endpoint: %s\n", endpoint_name);
3909 ast_debug(1,
"Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3911 "Endpoint: %s", endpoint_name);
3917 atsign = strchr(
mailbox,
'@');
3919 ast_debug(1,
"Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3920 endpoint_name, endpoint->incoming_mwi_mailbox);
3928 body =
ast_alloca(rdata->msg_info.msg->body->len + 1);
3929 rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3930 rdata->msg_info.msg->body->len + 1);
3933 ast_debug(1,
"Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3941 ast_log(
LOG_ERROR,
"Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
3942 "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3943 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3948 ast_debug(1,
"Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3949 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3955 "MessageAccount: %s\r\n"
3956 "VoiceMessagesNew: %d\r\n"
3957 "VoiceMessagesOld: %d\r\n"
3958 "VoiceMessagesUrgentNew: %d\r\n"
3959 "VoiceMessagesUrgentOld: %d",
3960 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3973 if (rdata->msg_info.msg->body &&
3975 "application",
"simple-message-summary")) {
3983 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3987 }
else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
4085 char task_name[256];
4088 ast_debug(3,
"Cancelling timer: %s\n", task_name);
4098#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
4099 pjsip_evsub_dec_ref(sub_tree->
evsub);
4116#if PJ_VERSION_NUM >= 0x020D0000
4117# define HAVE_PJSIP_EVSUB_PENDING_NOTIFY 1
4134 ast_debug(3,
"evsub %p state %s event %s sub_tree %p sub_tree state %s\n",
evsub,
4135 pjsip_evsub_get_state_name(
evsub), pjsip_event_str(
event->type), sub_tree,
4138 if (!sub_tree || pjsip_evsub_get_state(
evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
4150#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
4155 if (
event->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&
4156 !pjsip_method_cmp(&
event->body.tsx_state.tsx->method, &pjsip_subscribe_method) &&
4157 pjsip_evsub_get_expires(
evsub) == 0) {
4158 ast_debug(3,
"Subscription ending, do nothing.\n");
4170 pjsip_dialog *
dlg = sub_tree->
dlg;
4172 ast_debug(3,
"sub_tree %p sub_tree state %s\n", sub_tree,
4175 pjsip_dlg_inc_lock(
dlg);
4177 pjsip_dlg_dec_lock(
dlg);
4189 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
4190 pjsip_dlg_dec_lock(
dlg);
4198 "SUBSCRIPTION_TERMINATED" :
"SUBSCRIPTION_REFRESHED",
4201 pjsip_dlg_dec_lock(
dlg);
4210 ast_debug(3,
"sub_tree %p sub_tree state %s\n", sub_tree,
4231 return strcmp(s1, s2);
4283 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4289 ast_debug(3,
"evsub %p sub_tree %p sub_tree state %s\n",
evsub, sub_tree,
4297 char task_name[256];
4300 ast_debug(3,
"Cancelling timer: %s\n", task_name);
4310 if (pjsip_evsub_get_state(sub_tree->
evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
4336 memset(&tree, 0,
sizeof(tree));
4339 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
4345 sub_tree->
root = new_root;
4363 ast_log(
LOG_ERROR,
"Failed to push task to destroy old subscriptions for RLS '%s->%s'.\n",
4372 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
4381#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
4403 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4411 sub->handler->subscriber->state_change(
sub, rdata->msg_info.msg->body,
4412 pjsip_evsub_get_state(evsub));
4418 pjsip_tx_data *tdata;
4420 if (!sub_tree->
evsub) {
4425 if (pjsip_evsub_initiate(sub_tree->
evsub,
NULL, -1, &tdata) == PJ_SUCCESS) {
4426 pjsip_evsub_send_request(sub_tree->
evsub, tdata);
4428 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
4499 sub_tree, arg,
"InboundSubscriptionDetail") : 0;
4505 sub_tree, arg,
"OutboundSubscriptionDetail") : 0;
4571 astman_send_listack(s, m,
"A listing of resource lists follows, presented as ResourceListDetail events",
4581#define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
4582#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
4584#define MAX_REGEX_ERROR_LEN 128
4610 if (!sub_tree->
dlg) {
4614 callid = &sub_tree->
dlg->call_id->id;
4615 if (
cli->wordlen <= pj_strlen(callid)
4616 && !strncasecmp(
cli->a->word, pj_strbuf(callid),
cli->wordlen)
4617 && (++
cli->which >
cli->a->n)) {
4648 if (!strcasecmp(
a->argv[3],
"inbound")) {
4650 }
else if (!strcasecmp(
a->argv[3],
"outbound")) {
4660 cli.wordlen = strlen(
a->word);
4683 const char *
callid = (
const char *)
cli->buf;
4684 pj_str_t *sub_callid;
4692 int key_filler_width;
4695 if (!sub_tree->
dlg) {
4698 sub_callid = &sub_tree->
dlg->call_id->id;
4699 if (pj_strcmp2(sub_callid,
callid)) {
4710 "===========================================================================\n",
4711 "ParameterName",
"ParameterValue");
4738 value = strchr(key,
':');
4742 value_end = strchr(
value,
'\n');
4748 key_len =
value - key;
4749 key_filler_width = 20 - key_len;
4750 if (key_filler_width < 0) {
4751 key_filler_width = 0;
4753 value_len = value_end -
value;
4756 key_len, key, key_filler_width,
"",
4759 key = value_end + 1;
4787 e->
command =
"pjsip show subscription {inbound|outbound}";
4789 " pjsip show subscription inbound <call-id>\n"
4790 " pjsip show subscription outbound <call-id>\n"
4791 " Show active subscription with the dialog call-id\n";
4801 if (!strcasecmp(
a->argv[3],
"inbound")) {
4803 }
else if (!strcasecmp(
a->argv[3],
"outbound")) {
4814 cli.buf = (
void *)
a->argv[4];
4820#define CLI_SHOW_SUB_FORMAT_HEADER \
4821 "Endpoint: <Endpoint/Caller-ID.............................................>\n" \
4822 "Resource: <Resource/Event.................................................>\n" \
4823 " Expiry: <Expiry> <Call-id..............................................>\n" \
4824 "===========================================================================\n\n"
4825#define CLI_SHOW_SUB_FORMAT_ENTRY \
4826 "Endpoint: %s/%s\n" \
4827 "Resource: %s/%s\n" \
4828 " Expiry: %8d %s\n\n"
4832 char caller_id[256];
4843 if (sub_tree->
dlg) {
4888 e->
command =
"pjsip show subscriptions {inbound|outbound} [like]";
4890 " pjsip show subscriptions inbound [like <regex>]\n"
4891 " Show active inbound subscriptions\n"
4892 " pjsip show subscriptions outbound [like <regex>]\n"
4893 " Show active outbound subscriptions\n"
4895 " The regex selects a subscriptions output that matches.\n"
4896 " i.e., All output lines for a subscription are checked\n"
4897 " as a block by the regex.\n";
4903 if (
a->argc != 4 &&
a->argc != 6) {
4906 if (!strcasecmp(
a->argv[3],
"inbound")) {
4908 }
else if (!strcasecmp(
a->argv[3],
"outbound")) {
4918 if (strcasecmp(
a->argv[4],
"like")) {
4926 rc = regcomp(
cli.like,
regex, REG_EXTENDED | REG_NOSUB);
4931 ast_cli(
a->fd,
"Regular expression '%s' failed to compile: %s\n",
4953 ast_cli(
a->fd,
"%d active subscriptions%s%s%s\n",
4955 regex ?
" matched \"" :
"",
4967#define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n"
4968#define CLI_LIST_SUB_FORMAT_ENTRY "%-30.30s %-30.30s %6d %s\n"
4972 char ep_cid_buf[50];
4973 char res_evt_buf[50];
4977 snprintf(ep_cid_buf,
sizeof(ep_cid_buf),
"%s/%s",
4984 snprintf(res_evt_buf,
sizeof(res_evt_buf),
"%s/%s",
4989 if (sub_tree->
dlg) {
5035 e->
command =
"pjsip list subscriptions {inbound|outbound} [like]";
5037 " pjsip list subscriptions inbound [like <regex>]\n"
5038 " List active inbound subscriptions\n"
5039 " pjsip list subscriptions outbound [like <regex>]\n"
5040 " List active outbound subscriptions\n"
5042 " The regex selects output lines that match.\n";
5048 if (
a->argc != 4 &&
a->argc != 6) {
5051 if (!strcasecmp(
a->argv[3],
"inbound")) {
5053 }
else if (!strcasecmp(
a->argv[3],
"outbound")) {
5063 if (strcasecmp(
a->argv[4],
"like")) {
5071 rc = regcomp(
cli.like,
regex, REG_EXTENDED | REG_NOSUB);
5076 ast_cli(
a->fd,
"Regular expression '%s' failed to compile: %s\n",
5097 "Endpoint/CLI",
"Resource/Event",
"Expiry",
"Call-id");
5099 ast_cli(
a->fd,
"\n%d active subscriptions%s%s%s\n",
5101 regex ?
" matched \"" :
"",
5200#define RESOURCE_LIST_INIT_SIZE 4
5310 "pjsip.conf,criteria=type=resource_list");
5334#ifdef TEST_FRAMEWORK
5341const char *bad_resources[] = {
5353static int test_new_subscribe(
struct ast_sip_endpoint *endpoint,
const char *resource)
5357 for (i = 0; i <
ARRAY_LEN(bad_resources); ++i) {
5358 if (!strcmp(resource, bad_resources[i])) {
5380 .event_name =
"test",
5382 .notifier = &test_notifier,
5401 for (i = 0; i < num_resources; ++i) {
5415static void cleanup_resource_list(
struct resource_list *list)
5437 const char *list_name,
const char *
event,
const char **
resources,
size_t num_resources)
5455 cleanup_resource_list(list);
5476 const char **
resources,
size_t num_resources)
5486 for (i = 0; i < num_resources; ++i) {
5500static void test_resource_tree_destroy(
struct resource_tree *tree)
5506static int ineligible_configuration(
void)
5523 if (strcasecmp(
value,
"memory") && strcasecmp(
value,
"astdb")) {
5544 info->name =
"resource_tree";
5545 info->category =
"/res/res_pjsip_pubsub/";
5546 info->summary =
"Basic resource tree integrity check";
5548 "Create a resource list and ensure that our attempt to build a tree works as expected.";
5554 if (ineligible_configuration()) {
5556 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5589 const char *resources_1[] = {
5595 const char *resources_2[] = {
5609 info->name =
"complex_resource_tree";
5610 info->category =
"/res/res_pjsip_pubsub/";
5611 info->summary =
"Complex resource tree integrity check";
5613 "Create a complex resource list and ensure that our attempt to build a tree works as expected.";
5619 if (ineligible_configuration()) {
5621 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5625 list_1 = create_resource_list(
test,
"foo",
"test", resources_1,
ARRAY_LEN(resources_1));
5630 list_2 = create_resource_list(
test,
"dwarves",
"test", resources_2,
ARRAY_LEN(resources_2));
5675 info->name =
"bad_resource";
5676 info->category =
"/res/res_pjsip_pubsub/";
5677 info->summary =
"Ensure bad resources do not end up in the tree";
5679 "Create a resource list with a single bad resource. Ensure the bad resource does not end up in the tree.";
5685 if (ineligible_configuration()) {
5687 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5722 const char *resources_1[] = {
5729 const char *resources_2[] = {
5739 info->name =
"bad_branch";
5740 info->category =
"/res/res_pjsip_pubsub/";
5741 info->summary =
"Ensure bad branches are pruned from the tree";
5743 "Create a resource list that makes a tree with an entire branch of bad resources.\n"
5744 "Ensure the bad branch is pruned from the tree.";
5750 if (ineligible_configuration()) {
5752 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5756 list_1 = create_resource_list(
test,
"foo",
"test", resources_1,
ARRAY_LEN(resources_1));
5760 list_2 = create_resource_list(
test,
"gross",
"test", resources_2,
ARRAY_LEN(resources_2));
5780 if (check_node(
test, tree->root, resources_1,
ARRAY_LEN(resources_1) - 1)) {
5793 const char *resources_1[] = {
5799 const char *resources_2[] = {
5812 info->name =
"duplicate_resource";
5813 info->category =
"/res/res_pjsip_pubsub/";
5814 info->summary =
"Ensure duplicated resources do not end up in the tree";
5816 "Create a resource list with a single duplicated resource. Ensure the duplicated resource does not end up in the tree.";
5822 if (ineligible_configuration()) {
5824 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5828 list_1 = create_resource_list(
test,
"foo",
"test", resources_1,
ARRAY_LEN(resources_1));
5833 list_2 = create_resource_list(
test,
"ducks",
"test", resources_2,
ARRAY_LEN(resources_2));
5874 const char *resources_1[] = {
5877 const char *resources_2[] = {
5884 info->name =
"loop";
5885 info->category =
"/res/res_pjsip_pubsub/";
5886 info->summary =
"Test that loops are properly detected.";
5888 "Create two resource lists that refer to each other. Ensure that attempting to build a tree\n"
5889 "results in an empty tree.";
5895 if (ineligible_configuration()) {
5897 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5901 list_1 = create_resource_list(
test,
"herp",
"test", resources_1,
ARRAY_LEN(resources_1));
5905 list_2 = create_resource_list(
test,
"derp",
"test", resources_2,
ARRAY_LEN(resources_2));
5933 info->name =
"bad_event";
5934 info->category =
"/res/res_pjsip_pubsub/";
5935 info->summary =
"Ensure that list with wrong event specified is not retrieved";
5937 "Create a simple resource list for event 'tsetse'. Ensure that trying to retrieve the list for event 'test' fails.";
5943 if (ineligible_configuration()) {
5945 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5969 if (strcmp(tree->root->resource,
"foo")) {
5993 const char *
event =
var->name + 6;
6015 static const pj_str_t str_PUBLISH = {
"PUBLISH", 7 };
6021 ast_log(
LOG_ERROR,
"Could not create scheduler for publication expiration\n");
6026 ast_log(
LOG_ERROR,
"Could not start scheduler thread for publication expiration\n");
6035 ast_log(
LOG_ERROR,
"Could not register subscription persistence object support\n");
6074 ast_log(
LOG_ERROR,
"Could not register subscription persistence object support\n");
6166 .
requires =
"res_pjsip",
static struct ast_generator gen
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
int ast_shutdown_final(void)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
#define ao2_link(container, obj)
Add an object to a container.
@ AO2_ALLOC_OPT_LOCK_MUTEX
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_unlink(container, obj)
Remove an object from a container.
#define ao2_find(container, arg, flags)
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
#define ao2_alloc(data_size, destructor_fn)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
static const char config[]
#define AST_MAX_EXTENSION
Standard Command Line Interface.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
static struct ast_cli_entry cli[]
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define CHARFLDSET(type, field)
A helper macro to pass the appropriate arguments to aco_option_register for OPT_CHAR_ARRAY_T.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
Asterisk datastore objects.
void ast_datastores_remove(struct ao2_container *datastores, const char *name)
Remove a data store from a container.
struct ao2_container * ast_datastores_alloc(void)
Allocate a specialized data stores container.
int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore)
Add a data store to a container.
struct ast_datastore * ast_datastores_find(struct ao2_container *datastores, const char *name)
Find a data store in a container.
struct ast_datastore * ast_datastores_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Allocate a datastore for use with the datastores container.
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
void astman_append(struct mansession *s, const char *fmt,...)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
struct ast_flags ast_options
@ AST_OPT_FLAG_FULLY_BOOTED
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
struct ast_sip_sched_task * ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, const char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)
Schedule a task to run in the res_pjsip thread pool.
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
Gets the task name.
void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
Set a serializer on a SIP dialog so requests and responses are automatically serialized.
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
@ AST_SIP_SCHED_TASK_FIXED
@ AST_SIP_SCHED_TASK_DATA_AO2
#define ast_config_load(filename, flags)
Load a config file.
#define ast_variable_new(name, value, filename)
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
#define ast_debug(level,...)
Log a DEBUG message.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
A set of macros to manage forward-linked lists.
#define AST_RWLIST_REMOVE_CURRENT
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_RWLIST_TRAVERSE_SAFE_END
#define AST_RWLIST_TRAVERSE
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define AST_RWLIST_INSERT_TAIL
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
#define ast_module_unref(mod)
Release a reference to the module.
#define ast_module_ref(mod)
Hold a reference to the module.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODPRI_CHANNEL_DEPEND
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs)
Publish a MWI state update via stasis.
struct stasis_forward * sub
int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
const pj_str_t * ast_sip_pjsip_uri_get_username(pjsip_uri *uri)
Get the user portion of the pjsip_uri.
void ast_sip_unregister_service(pjsip_module *module)
struct ast_sip_contact * ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
Retrieve the first bound contact from a list of AORs.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
pjsip_dialog * ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user)
General purpose method for creating a UAC dialog with an endpoint.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
#define AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(_transport, _dest)
Fill a buffer with a pjsip transport's remote ip address and port.
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
int ast_sip_is_uri_sip_sips(pjsip_uri *uri)
Check whether a pjsip_uri is SIP/SIPS or not.
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
pjsip_dialog * ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
General purpose method for creating a UAS dialog with an endpoint.
#define ast_sip_mod_data_set(pool, mod_data, id, key, val)
Utilizing a mod_data array for a given id, set the value associated with the given key.
#define IP6ADDR_COLON_PORT_BUFLEN
#define ast_sip_mod_data_get(mod_data, id, key)
Using the dictionary stored in mod_data array at a given id, retrieve the value associated with the g...
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
#define PJSIP_EXPIRES_NOT_SPECIFIED
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
Checks if the given content type matches type/subtype.
void ast_sip_transport_monitor_unregister_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type, const char *local_name, int local_port, const char *contact_uri)
General purpose method for creating an rdata structure using specific information.
static struct ast_sorcery * sorcery
void ast_sip_sanitize_xml(const char *input, char *output, size_t len)
Replace offensive XML characters with XML entities.
#define AST_PJSIP_XML_PROLOG_LEN
Length of the XML prolog when printing presence or other XML in PJSIP.
pj_xml_node * ast_sip_presence_xml_create_node(pj_pool_t *pool, pj_xml_node *parent, const char *name)
Create XML node.
pj_xml_attr * ast_sip_presence_xml_create_attr(pj_pool_t *pool, pj_xml_node *node, const char *name, const char *value)
Create XML attribute.
#define CLI_SHOW_SUB_FORMAT_ENTRY
static void subscription_tree_destructor(void *obj)
static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
struct ast_sip_endpoint * ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
Get the endpoint that is associated with this subscription.
int(* on_subscription_t)(struct sip_subscription_tree *sub, void *arg)
void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
Retrive the remote URI for this subscription.
static int subscription_persistence_recreate(void *obj, void *arg, int flags)
Callback function to perform the actual recreation of a subscription.
static int subscription_persistence_load(void *data)
Function which loads and recreates persisted subscriptions upon startup when the system is fully boot...
static struct subscription_persistence * subscription_persistence_create(struct sip_subscription_tree *sub_tree)
Function which creates initial persistence information of a subscription in sorcery.
int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler)
Register a publish handler.
static struct sip_subscription_tree * create_subscription_tree(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree, pj_status_t *dlg_status, struct subscription_persistence *persistence)
Create a subscription tree based on a resource tree.
static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)
void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
Unregister a subscription handler.
static pjsip_generic_string_hdr * generate_content_id_hdr(pj_pool_t *pool, const struct ast_sip_subscription *sub)
Create a Content-ID header.
static struct ast_cli_entry cli_commands[]
const char * ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
Get the body type used for this subscription.
static int generate_initial_notify(struct ast_sip_subscription *sub)
static int allocate_tdata_buffer(pjsip_tx_data *tdata)
Pre-allocate a buffer for the transmission.
static int sip_publication_respond(struct ast_sip_publication *pub, int status_code, pjsip_rx_data *rdata)
static struct ast_sip_subscription_handler * find_sub_handler_for_event_name(const char *event_name)
static int ami_show_resource_lists(struct mansession *s, const struct message *m)
void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator)
Unregister a body generator with the pubsub core.
static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
Register a subscription handler.
static void pubsub_on_client_refresh(pjsip_evsub *sub)
static int publication_hash_fn(const void *obj, const int flags)
static int resource_list_apply_handler(const struct ast_sorcery *sorcery, void *obj)
void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
Unregister a body generator with the pubsub core.
static int sub_tree_subscription_terminate_cb(void *data)
#define CLI_SHOW_SUB_FORMAT_HEADER
static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *parts, unsigned int use_full_state)
Create a multipart body part for a subscribed resource.
static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler, const char *resource, struct resource_tree *tree, int has_eventlist_support, pjsip_rx_data *rdata)
Build a resource tree.
static int schedule_notification(struct sip_subscription_tree *sub_tree)
static int pubsub_on_refresh_timeout(void *userdata)
static int publication_cmp_fn(void *obj, void *arg, int flags)
static struct ast_sched_context * sched
Scheduler used for automatically expiring publications.
sip_persistence_update_type
@ SUBSCRIPTION_PERSISTENCE_CREATED
@ SUBSCRIPTION_PERSISTENCE_SEND_REQUEST
@ SUBSCRIPTION_PERSISTENCE_REFRESHED
@ SUBSCRIPTION_PERSISTENCE_RECREATED
static int exceptional_accept(const pj_str_t *accept)
Is the Accept header from the SUBSCRIBE in the list of exceptions?
static void pubsub_on_server_timeout(pjsip_evsub *sub)
sip_subscription_tree_state
The state of the subscription tree.
@ SIP_SUB_TREE_TERMINATE_PENDING
@ SIP_SUB_TREE_TERMINATED
@ SIP_SUB_TREE_TERMINATE_IN_PROGRESS
static int resource_event_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
void ast_sip_subscription_destroy(struct ast_sip_subscription *sub)
Alert the pubsub core that the subscription is ready for destruction.
static int serialized_pubsub_on_refresh_timeout(void *userdata)
void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
Remove a subscription datastore from the subscription.
static int serialized_send_notify(void *userdata)
static void clean_sub_tree(pjsip_evsub *evsub)
Callback sequence for subscription terminate:
sip_publish_type
The types of PUBLISH messages defined in RFC 3903.
@ SIP_PUBLISH_REMOVE
Remove.
@ SIP_PUBLISH_REFRESH
Refresh.
@ SIP_PUBLISH_UNKNOWN
Unknown.
@ SIP_PUBLISH_MODIFY
Modify.
@ SIP_PUBLISH_INITIAL
Initial.
static void * subscription_persistence_alloc(const char *name)
Allocator for subscription persistence.
static int serialized_pubsub_on_client_refresh(void *userdata)
static int sub_persistence_recreate(void *obj)
const struct ast_json * ast_sip_subscription_get_persistence_data(const struct ast_sip_subscription *subscription)
Retrieve persistence data for a subscription.
#define MAX_REGEX_ERROR_LEN
static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
static int esc_etag_counter
static char * cli_complete_subscription_callid(struct ast_cli_args *a)
static struct ast_sip_subscription * create_virtual_subscriptions(const struct ast_sip_subscription_handler *handler, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct sip_subscription_tree *tree, struct tree_node *current)
Create a tree of virtual subscriptions based on a resource tree node.
struct ast_datastore * ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
static const pj_str_t str_event_name
static int format_ami_resource_lists(void *obj, void *arg, int flags)
#define DEFAULT_PUBLISH_EXPIRES
Default expiration time for PUBLISH if one is not specified.
static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
static void shutdown_subscriptions(struct ast_sip_subscription *sub)
static void * rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
static int cli_show_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static void remove_subscription(struct sip_subscription_tree *obj)
static int persistence_endpoint_struct2str(const void *obj, const intptr_t *args, char **buf)
struct ast_taskprocessor * ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub)
Get the serializer for the subscription.
static pjsip_require_hdr * create_require_eventlist(pj_pool_t *pool)
Shortcut method to create a Require: eventlist header.
int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data, int terminate)
Notify a SIP subscription of a state change.
int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
Register a body generator with the pubsub core.
void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name)
Remove a publication datastore from the publication.
static void * publication_resource_alloc(const char *name)
Allocator for publication resource.
static int resource_endpoint_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler)
Unregister a publish handler.
static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
Add a datastore to a SIP subscription.
static int parse_simple_message_summary(char *body, struct simple_message_summary *summary)
static struct ast_sip_pubsub_body_generator * subscription_get_generator_from_rdata(pjsip_rx_data *rdata, const struct ast_sip_subscription_handler *handler)
Retrieve a body generator using the Accept header of an rdata message.
static char * sub_tree_state_description[]
#define AMI_SHOW_SUBSCRIPTIONS_INBOUND
#define NEW_SUBSCRIBE(notifier, endpoint, resource, rdata)
const char * ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub)
Get the body subtype used for this subscription.
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND
const char * ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
Get the name of the subscribed resource.
static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
static struct ast_sip_subscription * allocate_subscription(const struct ast_sip_subscription_handler *handler, const char *resource, const char *display_name, struct sip_subscription_tree *tree)
#define PUBLICATIONS_BUCKETS
Number of buckets for publications (on a per handler)
static int have_visited(const char *resource, struct resources *visited)
Determine if this resource has been visited already.
static pjsip_evsub_user pubsub_cb
static int sched_cb(const void *data)
#define RESOURCE_LIST_INIT_SIZE
static struct pjsip_module pubsub_module
static void sub_add_handler(struct ast_sip_subscription_handler *handler)
pjsip_sip_uri * ast_sip_subscription_get_sip_uri(struct ast_sip_subscription *sub)
Retrieve the local sip uri for this subscription.
void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, struct ast_json *persistence_data)
Set persistence data for a subscription.
static char * cli_show_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
const char * ast_sip_publication_get_event_configuration(const struct ast_sip_publication *pub)
Given a publication, get the configuration name for the event type in use.
static pjsip_msg_body * generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub, unsigned int force_full_state)
Create a resource list body for NOTIFY requests.
static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
Send a NOTIFY request to a subscriber.
static void destroy_subscriptions(struct ast_sip_subscription *root)
int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator)
Register a body generator with the pubsub core.
static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler, struct resource_list *list, struct tree_node *parent, struct resources *visited, pjsip_rx_data *rdata)
Build child nodes for a given parent.
static int persistence_generator_data_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
Opaque structure representing an RFC 3265 SIP subscription.
static void add_subscription(struct sip_subscription_tree *obj)
static void pubsub_on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
Called whenever an in-dialog SUBSCRIBE is received.
static void free_body_parts(struct body_part_list *parts)
Destroy a list of body parts.
static int subscription_unreference_dialog(void *obj)
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype_nolock(const char *type, const char *subtype)
static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static int publish_expire(const void *data)
static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
static pjsip_msg_body * create_multipart_body(pj_pool_t *pool)
Create and initialize the PJSIP multipart body structure for a resource list subscription.
static int ami_subscription_detail(struct sip_subscription_tree *sub_tree, struct ast_sip_ami *ami, const char *event)
static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata)
static int apply_list_configuration(struct ast_sorcery *sorcery)
static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
PJSIP callback when underlying SIP subscription changes state.
pjsip_dialog * ast_sip_subscription_get_dialog(struct ast_sip_subscription *sub)
Get the pjsip dialog that is associated with this subscription.
static int list_item_to_str(const void *obj, const intptr_t *args, char **buf)
static int list_item_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
int ast_sip_pubsub_generate_body_content(const char *type, const char *subtype, struct ast_sip_body_data *data, struct ast_str **str)
Generate body content for a PUBLISH or NOTIFY.
static struct ast_sip_pubsub_body_generator * find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64], size_t num_accept, const char *body_type)
static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
Check if the rdata has a Supported header containing 'eventlist'.
static struct ast_sip_publish_handler * find_pub_handler(const char *event)
static void tree_node_destroy(struct tree_node *node)
Destructor for a tree node.
static int persistence_tag_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
struct ast_datastore * ast_sip_publication_get_datastore(struct ast_sip_publication *publication, const char *name)
Retrieve a publication datastore.
static void subscription_persistence_remove(struct sip_subscription_tree *sub_tree)
Function which removes persistence of a subscription from sorcery.
static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int publish_expire_callback(void *data)
static void resource_list_destructor(void *obj)
static int cmp_strings(char *s1, char *s2)
Compare strings for equality checking for NULL.
static void subscription_persistence_update(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, enum sip_persistence_update_type type)
Function which updates persistence information of a subscription in sorcery.
struct ast_sip_endpoint * ast_sip_publication_get_endpoint(struct ast_sip_publication *pub)
Given a publication, get the associated endpoint.
static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata)
static int item_in_vector(const struct resource_list *list, const char *item)
static void destroy_subscription(struct ast_sip_subscription *sub)
static pjsip_msg_body * generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root, unsigned int force_full_state)
Create the body for a NOTIFY request.
#define CLI_LIST_SUB_FORMAT_HEADER
static void sub_tree_transport_cb(void *data)
int ast_sip_pubsub_is_body_generator_registered(const char *type, const char *subtype)
Is a body generator registered for the given type/subtype.
static int load_module(void)
static int persistence_tag_struct2str(const void *obj, const intptr_t *args, char **buf)
static void subscription_persistence_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Event callback which fires subscription persistence recreation when the system is fully booted.
static int for_each_subscription(on_subscription_t on_subscription, void *arg)
static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid, const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
Add a resource XML element to an RLMI body.
static void pubsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
static void resource_tree_destroy(struct resource_tree *tree)
Destroy a resource tree.
static int initial_notify_task(void *obj)
static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
static struct ast_sip_pubsub_body_generator * find_body_generator_accept(const char *accept)
static int unload_module(void)
static void * resource_list_alloc(const char *name)
static int cmp_subscription_childrens(struct ast_sip_subscription *s1, struct ast_sip_subscription *s2)
compares the childrens of two ast_sip_subscription s1 and s2
static int persistence_generator_data_struct2str(const void *obj, const intptr_t *args, char **buf)
static char * cli_list_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void publication_resource_destroy(void *obj)
Destructor for publication resource.
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype(const char *type, const char *subtype)
static enum sip_publish_type determine_sip_publish_type(pjsip_rx_data *rdata, pjsip_generic_string_hdr *etag_hdr, unsigned int *expires, int *entity_id)
static char * cli_show_subscription_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
const pjsip_method pjsip_publish_method
Defined method for PUBLISH.
static void set_state_terminated(struct ast_sip_subscription *sub)
#define MOD_DATA_PERSISTENCE
const char * ast_sip_publication_get_resource(const struct ast_sip_publication *pub)
Given a publication, get the resource the publication is to.
struct ao2_container * ast_sip_publication_get_datastores(const struct ast_sip_publication *publication)
Get the datastores container for a publication.
static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static void publish_add_handler(struct ast_sip_publish_handler *handler)
static struct ast_sip_publication * publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, struct ast_sip_publish_handler *handler)
static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree, struct ast_str **buf)
struct ast_sip_subscription * ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, const char *resource)
Create a new ast_sip_subscription structure.
static struct tree_node * tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state, const char *display_name)
Allocate a tree node.
#define CLI_LIST_SUB_FORMAT_ENTRY
static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
static pjsip_media_type rlmi_media_type
static void subscription_persistence_destroy(void *obj)
Destructor for subscription persistence.
int ast_sip_subscription_is_terminated(const struct ast_sip_subscription *sub)
Get whether the subscription has been terminated or not.
static pjsip_multipart_part * build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *body_parts, unsigned int full_state)
Create an RLMI body part for a multipart resource list body.
void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
Retrieve the local URI for this subscription.
static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
void * ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, const char *header)
Get a header value for a subscription.
int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore)
Add a datastore to a SIP publication.
static const char * sip_subscription_roles_map[]
static struct body_part * allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
Allocate and initialize a body part structure.
static struct ast_sip_publication * sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, const char *event_configuration_name)
static struct resource_list * retrieve_resource_list(const char *resource, const char *event)
Helper function for retrieving a resource list for a given event.
const char * accept_exceptions[]
Accept headers that are exceptions to the rule.
static void publication_destroy_fn(void *obj)
Internal destructor for publications.
static struct sip_subscription_tree * allocate_subscription_tree(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
static struct ast_sip_subscription_handler * subscription_get_handler_from_rdata(pjsip_rx_data *rdata, const char *endpoint)
Retrieve a handler using the Event header of an rdata message.
#define DEFAULT_EXPIRES
Default expiration for subscriptions.
static int destroy_subscriptions_task(void *obj)
struct ao2_container * ast_sip_subscription_get_datastores(const struct ast_sip_subscription *subscription)
Get the datastores container for a subscription.
struct ast_datastore * ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name)
Retrieve a subscription datastore.
@ AST_SIP_PUBLISH_STATE_ACTIVE
@ AST_SIP_PUBLISH_STATE_TERMINATED
@ AST_SIP_PUBLISH_STATE_INITIALIZED
#define AST_SIP_MAX_ACCEPT
#define AST_SIP_DEVICE_FEATURE_SYNC_DATA
ast_sip_subscription_role
Role for the subscription that is being created.
Scheduler Routines (derived from cheops)
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
#define AST_SCHED_REPLACE_UNREF(id, sched, when, callback, data, unrefcall, addfailcall, refcall)
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
Register a regex for multiple fields within an object.
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
#define ast_sorcery_apply_config(sorcery, name)
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
#define ast_sorcery_apply_default(sorcery, type, name, data)
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
#define stasis_subscribe_pool(topic, callback, data)
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
Parse a time (float) string.
descriptor for a cli entry.
Structure for a data store type.
Structure for a data store object.
Structure used to handle boolean flags.
JSON parsing error information.
Abstract JSON element (object, array, string, int, ...).
struct ast_party_name name
Subscriber name.
struct ast_party_number number
Subscriber phone number.
unsigned char valid
TRUE if the name information is valid/present.
char * str
Subscriber name (Malloced)
unsigned char valid
TRUE if the number information is valid/present.
char * str
Subscriber phone number (Malloced)
Data used to create bodies for NOTIFY/PUBLISH requests.
Party identification options for endpoints.
An entity with which Asterisk communicates.
struct ast_sip_endpoint_id_configuration id
const ast_string_field aors
int(* new_subscribe)(struct ast_sip_endpoint *endpoint, const char *resource)
Called when a SUBSCRIBE arrives attempting to establish a new subscription.
int(* refresh_subscribe)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata)
Called when a SUBSCRIBE arrives for an already active subscription.
int(* notify_created)(struct ast_sip_subscription *sub, pjsip_tx_data *tdata)
Optional callback to execute before sending outgoing NOTIFY requests. Because res_pjsip_pubsub create...
Structure representing a publication resource.
SORCERY_OBJECT(details)
Sorcery object details.
char * endpoint
Optional name of an endpoint that is only allowed to publish to this resource.
struct ast_variable * events
Mapping for event types to configuration.
Structure representing a SIP publication.
unsigned int expires
Expiration time of the publication.
struct ast_sip_publish_handler * handler
Handler for this publication.
struct ast_sip_endpoint * endpoint
The endpoint with which the subscription is communicating.
int sched_id
Scheduled item for expiration of publication.
char * event_configuration_name
The name of the event type configuration.
char data[0]
Data containing the above.
struct ao2_container * datastores
char * resource
The resource the publication is to.
int entity_tag
Entity tag for the publication.
Callbacks that publication handlers will define.
struct ast_sip_publish_handler * next
struct ao2_container * publications
Publications.
const char * event_name
The name of the event this handler deals with.
int(* publication_state_change)(struct ast_sip_publication *pub, pjsip_msg_body *body, enum ast_sip_publish_state state)
Published resource has changed states.
void(* to_string)(void *body, struct ast_str **str)
Convert the body to a string.
struct ast_sip_pubsub_body_generator::@263 list
void(* destroy_body)(void *body)
Deallocate resources created for the body.
const char * type
Content type In "plain/text", "plain" is the type.
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
void *(* allocate_body)(void *data)
allocate body structure.
int(* generate_body_content)(void *body, void *data)
Add content to the body of a SIP request.
int(* supplement_body)(void *body, void *data)
Add additional content to a SIP request body.
const char * type
Content type In "plain/text", "plain" is the type.
struct ast_sip_pubsub_body_supplement::@264 list
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
struct ast_sip_notifier * notifier
void(* to_ami)(struct ast_sip_subscription *sub, struct ast_str **buf)
Converts the subscriber to AMI.
struct ast_sip_subscription_handler * next
const char * accept[AST_SIP_MAX_ACCEPT]
Structure representing a "virtual" SIP subscription.
struct sip_subscription_tree * tree
struct ast_sip_pubsub_body_generator * body_generator
const struct ast_sip_subscription_handler * handler
struct ast_json * persistence_data
struct ast_str * body_text
struct ao2_container * datastores
pjsip_evsub_state subscription_state
struct ast_sip_subscription::@466 children
Full structure for sorcery.
Support for dynamic strings.
A ast_taskprocessor structure is a singleton by name.
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Type declaration for container of body part structures.
A multipart body part and meta-information.
const char * display_name
pjsip_generic_string_hdr * cid
pjsip_multipart_part * part
struct sip_subscription_tree * sub_tree
In case you didn't read that giant block of text above the mansession_session struct,...
struct subscription_persistence * persistence
Resource list configuration item.
unsigned int notification_batch_interval
unsigned int resource_display_name
unsigned int notification_batch_interval
A vector of strings commonly used throughout this module.
struct sched_id * sched_id
int voice_messages_urgent_old
char message_account[PJSIP_MAX_URL_SIZE]
int voice_messages_urgent_new
A tree of SIP subscriptions.
struct subscription_persistence * persistence
struct ast_sip_endpoint * endpoint
char transport_key[IP6ADDR_COLON_PORT_BUFLEN]
enum ast_sip_subscription_role role
struct sip_subscription_tree * next
unsigned int send_scheduled_notify
enum sip_subscription_tree_state state
unsigned int generate_initial_notify
struct ast_sip_subscription * root
struct ast_taskprocessor * serializer
unsigned int notification_batch_interval
struct ast_sip_sched_task * expiration_task
Structure used for persisting an inbound subscription.
struct ast_json * generator_data
char src_name[PJ_INET6_ADDRSTRLEN]
char contact_uri[PJSIP_MAX_URL_SIZE]
char packet[PJSIP_MAX_PKT_LEN]
char local_name[PJ_INET6_ADDRSTRLEN]
A node for a resource tree.
struct tree_node::@467 children
structure to hold users read from users.conf
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
#define ast_test_suite_event_notify(s, f,...)
#define AST_TEST_DEFINE(hdr)
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
static struct aco_type item
static void test_handler(void *data, const char *app_name, struct ast_json *message)
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
int error(const char *format,...)
#define ast_test_flag(p, flag)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Universally unique identifier support.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.