31 #include <pjsip_simple.h> 230 .name = {
"PubSub Module", 13 },
231 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
235 #define MOD_DATA_PERSISTENCE "sub_persistence" 236 #define MOD_DATA_MSG "sub_msg" 244 #define PUBLICATIONS_BUCKETS 37 247 #define DEFAULT_PUBLISH_EXPIRES 3600 250 #define DATASTORE_BUCKETS 53 253 #define DEFAULT_EXPIRES 3600 376 char packet[PJSIP_MAX_PKT_LEN];
378 char src_name[PJ_INET6_ADDRSTRLEN];
382 char transport_key[32];
384 char local_name[PJ_INET6_ADDRSTRLEN];
392 struct timeval expires;
394 char contact_uri[PJSIP_MAX_URL_SIZE];
418 "TerminateInProgress",
493 pjsip_evsub_state subscription_state;
543 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
545 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
576 if (!sub_tree->
evsub) {
582 ast_debug(3,
"Transport destroyed. Removing subscription '%s->%s' prune on boot: %d\n",
587 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
639 char tag[PJ_GUID_STRING_LENGTH + 1];
645 "subscription_persistence",
NULL);
647 pjsip_dialog *dlg = sub_tree->
dlg;
671 ast_debug(3,
"Updating persistence for '%s->%s' prune on boot: %s\n",
680 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
681 pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
NULL);
691 (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
695 ast_debug(3,
"adding transport monitor on %s for '%s->%s' prune on boot: %d\n",
696 rdata->tp_info.transport->obj_name,
699 sub_tree->
transport = rdata->tp_info.transport;
709 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
723 if (rdata->msg_info.msg_buf) {
752 ast_debug(3,
"Unregistering transport monitor on %s '%s->%s'\n",
755 sub_tree->
root ? sub_tree->
root->resource :
"Unknown");
768 size_t num_accept,
const char *
body_type);
773 pjsip_event_hdr *event_header;
777 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str_event_name, rdata->msg_info.msg->hdr.next);
780 endpoint ? endpoint :
"Unknown");
788 endpoint ? endpoint :
"Unknown");
808 "application/rlmi+xml",
834 pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
836 size_t num_accept_headers = 0;
838 while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
842 for (i = 0; i < accept_header->count && num_accept_headers <
AST_SIP_MAX_ACCEPT; ++i) {
844 ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i],
sizeof(accept[num_accept_headers]));
845 ++num_accept_headers;
850 if (num_accept_headers == 0) {
855 num_accept_headers = 1;
868 pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
870 while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
873 for (i = 0; i < supported_header->count; i++) {
874 if (!pj_stricmp2(&supported_header->values[i],
"eventlist")) {
911 if (strcmp(list->
event, event)) {
912 ast_log(
LOG_WARNING,
"Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
913 resource, list->
event, event);
938 node =
ast_calloc(1,
sizeof(*node) + strlen(resource) + 1);
943 strcpy(node->resource, resource);
987 static int have_visited(
const char *resource,
struct resources *visited)
1032 ast_debug(1,
"Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1039 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1043 "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1047 ast_debug(2,
"Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1048 resource, parent->resource);
1053 ast_debug(2,
"Subscription to leaf resource %s resulted in error response %d\n",
1057 ast_debug(2,
"Resource %s (child of %s) is a list\n", resource, parent->resource);
1060 ast_debug(1,
"Cannot build children of resource %s due to allocation failure\n", resource);
1065 ast_debug(1,
"List %s had no successful children.\n", resource);
1070 ast_debug(2,
"List %s had successful children. Adding to parent %s\n",
1071 resource, parent->resource);
1136 const char *resource,
struct resource_tree *tree,
int has_eventlist_support)
1139 struct resources visited;
1142 ast_debug(2,
"Subscription '%s->%s' is not to a list\n",
1151 ast_debug(2,
"Subscription '%s->%s' is a list\n",
1191 ast_debug(2,
"Removing subscription '%s->%s' from list of subscriptions\n",
1203 ast_debug(3,
"Destroying SIP subscription from '%s->%s'\n",
1237 pjsip_sip_uri *contact_uri;
1239 sub =
ast_calloc(1,
sizeof(*sub) + strlen(resource) + 1);
1243 strcpy(sub->resource, resource);
1252 if (!sub->body_text) {
1257 sub->uri = pjsip_sip_uri_create(tree->
dlg->pool, PJ_FALSE);
1258 contact_uri = pjsip_uri_get_uri(tree->
dlg->local.contact->uri);
1259 pjsip_sip_uri_assign(tree->
dlg->pool, sub->uri, contact_uri);
1260 pj_strdup2(tree->
dlg->pool, &sub->uri->user, resource);
1271 sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1298 sub->full_state = current->full_state;
1310 ast_debug(1,
"Child subscription to resource %s could not be created\n",
1311 child_node->resource);
1316 ast_debug(1,
"Child subscription to resource %s could not be appended\n",
1317 child_node->resource);
1371 ast_debug(3,
"Destroying subscription tree %p '%s->%s'\n",
1374 sub_tree->
root ? sub_tree->
root->resource :
"Unknown");
1378 if (sub_tree->
dlg) {
1391 ast_debug(3,
"Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1475 *dlg_status = PJ_ENOMEM;
1482 if (*dlg_status != PJ_EEXISTS) {
1493 pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
1494 pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->
tag);
1495 dlg->local.tag_hval = pj_hash_calc_tolower(0,
NULL, &dlg->local.info->tag);
1496 pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
1497 dlg->local.cseq = persistence->
cseq;
1500 pjsip_evsub_create_uas(dlg, &
pubsub_cb, rdata, 0, &sub_tree->
evsub);
1509 pjsip_dlg_dec_lock(dlg);
1511 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK 1512 pjsip_evsub_add_ref(sub_tree->
evsub);
1516 pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
1560 pjsip_rx_data *rdata = recreate_data->
rdata;
1566 pjsip_sip_uri *request_uri;
1567 size_t resource_size;
1570 pjsip_expires_hdr *expires_header;
1573 request_uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
1574 resource_size = pj_strlen(&request_uri->user) + 1;
1585 if (!handler || !handler->
notifier) {
1586 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not get subscription handler.\n",
1594 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Body generator not available.\n",
1607 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: The endpoint was not found\n",
1614 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1615 rdata->msg_info.msg->hdr.next);
1616 if (!expires_header) {
1617 expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1618 if (!expires_header) {
1619 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not update expires header.\n",
1625 pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1631 ast_debug(3,
"Expired subscription retrived from persistent store '%s' %s\n",
1637 expires_header->ivalue = expires;
1639 memset(&tree, 0,
sizeof(tree));
1642 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1643 pj_status_t dlg_status;
1646 &tree, &dlg_status, persistence);
1648 if (dlg_status != PJ_EEXISTS) {
1649 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not create subscription tree.\n",
1657 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
1662 ind->
expires = expires_header->ivalue;
1667 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
1687 pj_pool_t *
pool = arg;
1689 pjsip_rx_data rdata;
1694 ast_debug(3,
"Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1702 ast_debug(3,
"Expired subscription retrived from persistent store '%s' %s\n",
1708 memset(&rdata, 0,
sizeof(rdata));
1709 pj_pool_reset(pool);
1710 rdata.tp_info.pool =
pool;
1715 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: The message could not be parsed\n",
1721 if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1722 ast_log(
LOG_NOTICE,
"Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1731 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1740 ast_log(
LOG_WARNING,
"Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
1757 PJSIP_POOL_RDATA_INC);
1759 ast_log(
LOG_WARNING,
"Could not create a memory pool for recreating SIP subscriptions\n");
1767 ao2_ref(persisted_subscriptions, -1);
1787 if (strcmp(type,
"FullyBooted")) {
1805 if (!on_subscription) {
1811 if (on_subscription(i, arg)) {
1831 if (sub_tree->
dlg) {
1862 pj_cstr(&name, header);
1864 return pjsip_msg_find_hdr_by_name(msg, &name,
NULL);
1875 pjsip_tx_data *tdata;
1892 ast_log(
LOG_WARNING,
"No contacts configured for endpoint %s. Unable to create SIP subsription\n",
1908 pjsip_evsub_create_uac(dlg, &
pubsub_cb, &event, 0, &sub_tree->
evsub);
1911 evsub = sub_tree->
evsub;
1913 if (pjsip_evsub_initiate(evsub,
NULL, -1, &tdata) == PJ_SUCCESS) {
1914 pjsip_evsub_send_request(sub_tree->
evsub, tdata);
1920 pjsip_evsub_terminate(evsub, PJ_TRUE);
1973 for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
1974 buf = pj_pool_alloc(tdata->pool, buf_size);
1975 size = pjsip_msg_print(tdata->msg, buf, buf_size);
1982 tdata->buf.start =
buf;
1983 tdata->buf.cur = tdata->buf.start;
1984 tdata->buf.end = tdata->buf.start + buf_size;
1991 #ifdef TEST_FRAMEWORK 1993 pjsip_evsub *evsub = sub_tree->
evsub;
1999 pjsip_tx_data_dec_ref(tdata);
2003 res = pjsip_evsub_send_request(sub_tree->
evsub, tdata);
2010 pjsip_evsub_get_state_name(evsub),
2013 return (res == PJ_SUCCESS ? 0 : -1);
2030 const char *resource_name,
const pjsip_sip_uri *resource_uri, pjsip_evsub_state
state)
2032 static pj_str_t
cid_name = {
"cid", 3 };
2033 pj_xml_node *resource;
2035 pj_xml_node *instance;
2036 pj_xml_attr *cid_attr;
2038 char uri[PJSIP_MAX_URL_SIZE];
2041 const pj_str_t cid_stripped = {
2042 .ptr = cid->hvalue.ptr + 1,
2043 .slen = cid->hvalue.slen - 2,
2050 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri,
sizeof(uri));
2053 pj_strdup2(pool, &name->content, resource_name);
2059 state == PJSIP_EVSUB_STATE_TERMINATED ?
"terminated" :
"active");
2065 cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2066 pj_xml_add_attr(instance, cid_attr);
2082 pjsip_generic_string_hdr *
cid;
2110 static const pj_str_t
cid_name = {
"Content-ID", 10 };
2111 pjsip_generic_string_hdr *cid;
2117 alloc_size =
sizeof(
id) + pj_strlen(&sub->uri->host) + 3;
2118 cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2119 cid_value.slen = sprintf(cid_value.ptr,
"<%s@%.*s>",
2121 (
int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
2122 cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2130 pj_xml_node *rlmi = msg_body->data;
2132 num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
2142 const pj_xml_node *rlmi = data;
2144 return pj_xml_clone(pool, rlmi);
2163 struct body_part_list *body_parts,
unsigned int full_state)
2167 pjsip_multipart_part *rlmi_part;
2168 char version_str[32];
2169 char uri[PJSIP_MAX_URL_SIZE];
2170 pjsip_generic_string_hdr *cid;
2179 snprintf(version_str,
sizeof(version_str),
"%u", sub->version++);
2192 rlmi_part = pjsip_multipart_create_part(pool);
2194 rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2195 pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &
rlmi_media_type);
2197 rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2202 pj_list_insert_before(&rlmi_part->hdr, cid);
2208 unsigned int force_full_state);
2244 bp->
state = sub->subscription_state;
2259 struct body_part_list *parts,
unsigned int use_full_state)
2262 pjsip_msg_body *body;
2276 bp->
part = pjsip_multipart_create_part(pool);
2277 bp->
part->body = body;
2278 pj_list_insert_before(&bp->
part->hdr, bp->
cid);
2294 pjsip_param *media_type_param;
2296 pj_str_t pj_boundary;
2298 pjsip_media_type_init2(&media_type,
"multipart",
"related");
2300 media_type_param = pj_pool_alloc(pool,
sizeof(*media_type_param));
2301 pj_list_init(media_type_param);
2303 pj_strdup2(pool, &media_type_param->name,
"type");
2304 pj_strdup2(pool, &media_type_param->value,
"\"application/rlmi+xml\"");
2306 pj_list_insert_before(&media_type.param, media_type_param);
2309 return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2325 unsigned int force_full_state)
2328 pjsip_multipart_part *rlmi_part;
2329 pjsip_msg_body *multipart;
2330 struct body_part_list body_parts;
2331 unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
2354 pjsip_multipart_add_part(pool, multipart, rlmi_part);
2357 pjsip_multipart_add_part(pool, multipart,
AST_VECTOR_GET(&body_parts, i)->part);
2372 unsigned int force_full_state)
2374 pjsip_msg_body *body;
2377 if (force_full_state || root->body_changed) {
2389 body = pjsip_msg_body_create(pool, &type, &subtype, &text);
2390 root->body_changed = 0;
2406 pjsip_require_hdr *require;
2408 require = pjsip_require_hdr_create(pool);
2409 pj_strdup2(pool, &require->values[0],
"eventlist");
2427 pjsip_evsub *evsub = sub_tree->
evsub;
2428 pjsip_tx_data *tdata;
2431 && sub_tree->
root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED
2436 if (pjsip_evsub_notify(evsub, sub_tree->
root->subscription_state,
2437 NULL,
NULL, &tdata) != PJ_SUCCESS) {
2442 if (!tdata->msg->body) {
2443 pjsip_tx_data_dec_ref(tdata);
2449 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2465 pjsip_dialog *
dlg = sub_tree->
dlg;
2467 pjsip_dlg_inc_lock(dlg);
2478 pjsip_dlg_dec_lock(dlg);
2483 if (sub_tree->
root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) {
2491 ?
"SUBSCRIPTION_TERMINATED" :
"SUBSCRIPTION_STATE_CHANGED",
2492 "Resource: %s", sub_tree->
root->resource);
2495 pjsip_dlg_dec_lock(dlg);
2535 pjsip_dlg_inc_lock(dlg);
2538 pjsip_dlg_dec_lock(dlg);
2544 pjsip_dlg_dec_lock(dlg);
2548 sub->body_changed = 1;
2550 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2569 pjsip_dlg_dec_lock(dlg);
2580 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2589 uri = pjsip_uri_get_uri(dlg->remote.info->uri);
2591 if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
2598 return sub->resource;
2603 return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2615 pj_list_init(&res_hdr);
2621 return pjsip_evsub_accept(sub_tree->
evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2672 subscription->persistence_data = persistence_data;
2688 return subscription->persistence_data;
2721 ast_log(
LOG_ERROR,
"No event package specified for publish handler. Cannot register\n");
2728 ast_log(
LOG_ERROR,
"Could not allocate publications container for event '%s'\n",
2744 if (handler == iter) {
2785 ast_log(
LOG_ERROR,
"No event package specified for subscription handler. Cannot register\n");
2792 "Unable to register subscription handler for event %s. A handler is already registered\n",
2798 pj_cstr(&accept[i], handler->
accept[i]);
2816 if (handler == iter) {
2830 if (!strcmp(gen->
type, type)
2831 && !strcmp(gen->
subtype, subtype)) {
2863 size_t num_accept,
const char *
body_type)
2868 for (i = 0; i < num_accept; ++i) {
2871 ast_debug(3,
"Body generator %p found for accept type %s\n", generator, accept[i]);
2872 if (strcmp(generator->
body_type, body_type)) {
2873 ast_log(
LOG_WARNING,
"Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
2880 ast_debug(3,
"No body generator found for accept type %s\n", accept[i]);
2953 ast_debug(3,
"Scheduling timer: %s\n", name);
2958 ast_log(
LOG_ERROR,
"Unable to create expiration timer of %d seconds for %s\n",
2971 pjsip_expires_hdr *expires_header;
2977 pjsip_uri *request_uri;
2978 pjsip_sip_uri *request_uri_sip;
2979 size_t resource_size;
2982 pj_status_t dlg_status;
2987 if (!endpoint->subscription.allow) {
2993 request_uri = rdata->msg_info.msg->line.req.uri;
2995 if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
2996 char uri_str[PJSIP_MAX_URL_SIZE];
2998 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str,
sizeof(uri_str));
3004 request_uri_sip = pjsip_uri_get_uri(request_uri);
3005 resource_size = pj_strlen(&request_uri_sip->user) + 1;
3015 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3016 if (expires_header) {
3017 if (expires_header->ivalue == 0) {
3018 ast_debug(1,
"Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3023 if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3024 ast_log(
LOG_WARNING,
"Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3043 memset(&tree, 0,
sizeof(tree));
3046 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3054 if (dlg_status != PJ_EEXISTS) {
3061 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
3074 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
3103 pjsip_generic_string_hdr *etag_hdr,
unsigned int *expires,
int *entity_id)
3105 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
3108 char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3112 if (sscanf(etag,
"%30d", entity_id) != 1) {
3121 }
else if (!etag_hdr && rdata->msg_info.msg->body) {
3123 }
else if (etag_hdr && !rdata->msg_info.msg->body) {
3125 }
else if (etag_hdr && rdata->msg_info.msg->body) {
3137 ast_debug(3,
"Destroying SIP publication\n");
3149 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL);
3150 size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
3171 dst = publication->
data;
3172 publication->
resource = strcpy(dst, resource);
3173 dst += resource_len;
3180 pjsip_rx_data *rdata)
3182 pjsip_tx_data *tdata;
3183 pjsip_transaction *tsx;
3189 if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3192 snprintf(buf,
sizeof(buf),
"%d", pub->
entity_tag);
3195 snprintf(buf,
sizeof(buf),
"%d", pub->
expires);
3199 if (pjsip_tsx_create_uas(&
pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3200 pjsip_tx_data_dec_ref(tdata);
3204 pjsip_tsx_recv_msg(tsx, rdata);
3206 if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3207 pjsip_tx_data_dec_ref(tdata);
3218 char *resource_name;
3219 size_t resource_size;
3222 pjsip_uri *request_uri;
3223 pjsip_sip_uri *request_uri_sip;
3226 request_uri = rdata->msg_info.msg->line.req.uri;
3228 if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
3229 char uri_str[PJSIP_MAX_URL_SIZE];
3231 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str,
sizeof(uri_str));
3237 request_uri_sip = pjsip_uri_get_uri(request_uri);
3238 resource_size = pj_strlen(&request_uri_sip->user) + 1;
3240 ast_copy_pj_str(resource_name, &request_uri_sip->user, resource_size);
3250 ast_debug(1,
"No 'inbound-publication' defined for resource '%s'\n", resource_name);
3256 ast_debug(1,
"Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3262 for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->
next) {
3263 if (!strcmp(event_configuration_name->
name, handler->
event_name)) {
3268 if (!event_configuration_name) {
3269 ast_debug(1,
"Event '%s' is not configured for '%s'\n", handler->
event_name, resource_name);
3276 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3305 if (publication->handler->publish_expire) {
3306 publication->handler->publish_expire(publication);
3328 pjsip_event_hdr *event_header;
3332 static const pj_str_t str_sip_if_match = {
"SIP-If-Match", 12 };
3333 pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match,
NULL);
3336 unsigned int expires = 0;
3337 int entity_id, response = 0;
3342 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str_event_name, rdata->msg_info.msg->hdr.next);
3343 if (!event_header) {
3364 static const pj_str_t str_conditional_request_failed = {
"Conditional Request Failed", 26 };
3375 publication->expires = expires;
3378 switch (publish_type) {
3444 pj_size_t accept_len;
3458 accept_len = strlen(generator->
type) + strlen(generator->
subtype) + 1;
3461 pj_strset(&accept,
ast_alloca(accept_len + 1), accept_len);
3462 sprintf((
char *) pj_strbuf(&accept),
"%s/%s", generator->
type, generator->
subtype);
3465 PJSIP_H_ACCEPT,
NULL, 1, &accept);
3476 if (iter == generator) {
3500 if (iter == supplement) {
3535 ast_log(
LOG_WARNING,
"%s/%s body generator does not accept the type of data provided\n",
3554 if (!strcmp(generator->
type, supplement->
type) &&
3582 char message_account[PJSIP_MAX_URL_SIZE];
3590 int found_counts = 0;
3597 memset(summary, 0,
sizeof(*summary));
3602 if (sscanf(line,
"voice-message: %d/%d (%d/%d)",
3611 return !found_counts;
3618 const char *endpoint_name;
3627 ast_debug(1,
"Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3633 ast_debug(1,
"Incoming MWI: Found endpoint: %s\n", endpoint_name);
3635 ast_debug(1,
"Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3637 "Endpoint: %s", endpoint_name);
3642 mailbox =
ast_strdupa(endpoint->incoming_mwi_mailbox);
3643 atsign = strchr(mailbox,
'@');
3645 ast_debug(1,
"Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3646 endpoint_name, endpoint->incoming_mwi_mailbox);
3652 context = atsign + 1;
3654 body =
ast_alloca(rdata->msg_info.msg->body->len + 1);
3655 rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3656 rdata->msg_info.msg->body->len + 1);
3659 ast_debug(1,
"Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3667 ast_log(
LOG_ERROR,
"Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. " 3668 "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3669 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3674 ast_debug(1,
"Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3675 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3681 "MessageAccount: %s\r\n" 3682 "VoiceMessagesNew: %d\r\n" 3683 "VoiceMessagesOld: %d\r\n" 3684 "VoiceMessagesUrgentNew: %d\r\n" 3685 "VoiceMessagesUrgentOld: %d",
3686 endpoint_name, endpoint->incoming_mwi_mailbox, summary.
message_account,
3699 if (rdata->msg_info.msg->body &&
3701 "application",
"simple-message-summary")) {
3709 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3713 }
else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
3724 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
3812 ast_debug(3,
"evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub,
3813 pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree,
3816 if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
3829 char task_name[256];
3832 ast_debug(3,
"Cancelling timer: %s\n", task_name);
3842 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK 3843 pjsip_evsub_dec_ref(sub_tree->
evsub);
3862 pjsip_dialog *
dlg = sub_tree->
dlg;
3864 ast_debug(3,
"sub_tree %p sub_tree state %s\n", sub_tree,
3867 pjsip_dlg_inc_lock(dlg);
3869 pjsip_dlg_dec_lock(dlg);
3881 "SUBSCRIPTION_TERMINATED" :
"SUBSCRIPTION_REFRESHED",
3882 "Resource: %s", sub_tree->
root->resource);
3884 pjsip_dlg_dec_lock(dlg);
3893 ast_debug(3,
"sub_tree %p sub_tree state %s\n", sub_tree,
3912 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
3916 sub_tree = pjsip_evsub_get_mod_data(evsub,
pubsub_module.id);
3917 ast_debug(3,
"evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree,
3925 char task_name[256];
3928 ast_debug(3,
"Cancelling timer: %s\n", task_name);
3938 if (pjsip_evsub_get_state(sub_tree->
evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
3957 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
3961 if (!(sub = pjsip_evsub_get_mod_data(evsub,
pubsub_module.id))) {
3966 pjsip_evsub_get_state(evsub));
3972 pjsip_tx_data *tdata;
3974 if (!sub_tree->
evsub) {
3979 if (pjsip_evsub_initiate(sub_tree->
evsub,
NULL, -1, &tdata) == PJ_SUCCESS) {
3980 pjsip_evsub_send_request(sub_tree->
evsub, tdata);
3982 pjsip_evsub_terminate(sub_tree->
evsub, PJ_TRUE);
3993 if (!(sub_tree = pjsip_evsub_get_mod_data(evsub,
pubsub_module.id))) {
4019 sub_tree = pjsip_evsub_get_mod_data(evsub,
pubsub_module.id);
4053 sub_tree, arg,
"InboundSubscriptionDetail") : 0;
4059 sub_tree, arg,
"OutboundSubscriptionDetail") : 0;
4125 astman_send_listack(s, m,
"A listing of resource lists follows, presented as ResourceListDetail events",
4135 #define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound" 4136 #define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound" 4138 #define MAX_REGEX_ERROR_LEN 128 4164 if (!sub_tree->
dlg) {
4168 callid = &sub_tree->
dlg->call_id->id;
4169 if (cli->
wordlen <= pj_strlen(callid)
4170 && !strncasecmp(cli->
a->
word, pj_strbuf(callid), cli->
wordlen)
4171 && (++cli->
which > cli->
a->
n)) {
4202 if (!strcasecmp(a->
argv[3],
"inbound")) {
4204 }
else if (!strcasecmp(a->
argv[3],
"outbound")) {
4237 const char *
callid = (
const char *) cli->
buf;
4238 pj_str_t *sub_callid;
4246 int key_filler_width;
4249 if (!sub_tree->
dlg) {
4252 sub_callid = &sub_tree->
dlg->call_id->id;
4253 if (pj_strcmp2(sub_callid, callid)) {
4264 "===========================================================================\n",
4265 "ParameterName",
"ParameterValue");
4292 value = strchr(key,
':');
4296 value_end = strchr(
value,
'\n');
4302 key_len =
value - key;
4303 key_filler_width = 20 - key_len;
4304 if (key_filler_width < 0) {
4305 key_filler_width = 0;
4307 value_len = value_end -
value;
4310 key_len, key, key_filler_width,
"",
4313 key = value_end + 1;
4341 e->
command =
"pjsip show subscription {inbound|outbound}";
4342 e->
usage =
"Usage:\n" 4343 " pjsip show subscription inbound <call-id>\n" 4344 " pjsip show subscription outbound <call-id>\n" 4345 " Show active subscription with the dialog call-id\n";
4355 if (!strcasecmp(a->
argv[3],
"inbound")) {
4357 }
else if (!strcasecmp(a->
argv[3],
"outbound")) {
4368 cli.
buf = (
void *) a->
argv[4];
4374 #define CLI_SHOW_SUB_FORMAT_HEADER \ 4375 "Endpoint: <Endpoint/Caller-ID.............................................>\n" \ 4376 "Resource: <Resource/Event.................................................>\n" \ 4377 " Expiry: <Expiry> <Call-id..............................................>\n" \ 4378 "===========================================================================\n\n" 4379 #define CLI_SHOW_SUB_FORMAT_ENTRY \ 4380 "Endpoint: %s/%s\n" \ 4381 "Resource: %s/%s\n" \ 4382 " Expiry: %8d %s\n\n" 4386 char caller_id[256];
4397 if (sub_tree->
dlg) {
4442 e->
command =
"pjsip show subscriptions {inbound|outbound} [like]";
4443 e->
usage =
"Usage:\n" 4444 " pjsip show subscriptions inbound [like <regex>]\n" 4445 " Show active inbound subscriptions\n" 4446 " pjsip show subscriptions outbound [like <regex>]\n" 4447 " Show active outbound subscriptions\n" 4449 " The regex selects a subscriptions output that matches.\n" 4450 " i.e., All output lines for a subscription are checked\n" 4451 " as a block by the regex.\n";
4457 if (a->
argc != 4 && a->
argc != 6) {
4460 if (!strcasecmp(a->
argv[3],
"inbound")) {
4462 }
else if (!strcasecmp(a->
argv[3],
"outbound")) {
4472 if (strcasecmp(a->
argv[4],
"like")) {
4477 memset(&like, 0,
sizeof(like));
4480 rc = regcomp(cli.
like, regex, REG_EXTENDED | REG_NOSUB);
4485 ast_cli(a->
fd,
"Regular expression '%s' failed to compile: %s\n",
4507 ast_cli(a->
fd,
"%d active subscriptions%s%s%s\n",
4509 regex ?
" matched \"" :
"",
4521 #define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n" 4522 #define CLI_LIST_SUB_FORMAT_ENTRY "%-30.30s %-30.30s %6d %s\n" 4526 char ep_cid_buf[50];
4527 char res_evt_buf[50];
4531 snprintf(ep_cid_buf,
sizeof(ep_cid_buf),
"%s/%s",
4538 snprintf(res_evt_buf,
sizeof(res_evt_buf),
"%s/%s",
4539 sub_tree->
root->resource,
4543 if (sub_tree->
dlg) {
4589 e->
command =
"pjsip list subscriptions {inbound|outbound} [like]";
4590 e->
usage =
"Usage:\n" 4591 " pjsip list subscriptions inbound [like <regex>]\n" 4592 " List active inbound subscriptions\n" 4593 " pjsip list subscriptions outbound [like <regex>]\n" 4594 " List active outbound subscriptions\n" 4596 " The regex selects output lines that match.\n";
4602 if (a->
argc != 4 && a->
argc != 6) {
4605 if (!strcasecmp(a->
argv[3],
"inbound")) {
4607 }
else if (!strcasecmp(a->
argv[3],
"outbound")) {
4617 if (strcasecmp(a->
argv[4],
"like")) {
4622 memset(&like, 0,
sizeof(like));
4625 rc = regcomp(cli.
like, regex, REG_EXTENDED | REG_NOSUB);
4630 ast_cli(a->
fd,
"Regular expression '%s' failed to compile: %s\n",
4651 "Endpoint/CLI",
"Resource/Event",
"Expiry",
"Call-id");
4653 ast_cli(a->
fd,
"\n%d active subscriptions%s%s%s\n",
4655 regex ?
" matched \"" :
"",
4750 #define RESOURCE_LIST_INIT_SIZE 4 4860 "pjsip.conf,criteria=type=resource_list");
4882 #ifdef TEST_FRAMEWORK 4948 for (i = 0; i < num_resources; ++i) {
4984 const char *list_name,
const char *
event,
const char **resources,
size_t num_resources)
5023 const char **resources,
size_t num_resources)
5033 for (i = 0; i < num_resources; ++i) {
5034 if (strcmp(resources[i],
AST_VECTOR_GET(&node->children, i)->resource)) {
5070 if (strcasecmp(value,
"memory") && strcasecmp(value,
"astdb")) {
5082 const char *resources[] = {
5091 info->name =
"resource_tree";
5092 info->category =
"/res/res_pjsip_pubsub/";
5093 info->summary =
"Basic resource tree integrity check";
5095 "Create a resource list and ensure that our attempt to build a tree works as expected.";
5103 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5136 const char *resources_1[] = {
5142 const char *resources_2[] = {
5156 info->name =
"complex_resource_tree";
5157 info->category =
"/res/res_pjsip_pubsub/";
5158 info->summary =
"Complex resource tree integrity check";
5160 "Create a complex resource list and ensure that our attempt to build a tree works as expected.";
5168 "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");