2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Mark Michelson <mmichelson@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 * \brief Opaque structure representing an RFC 3265 SIP subscription
23 <depend>pjproject</depend>
24 <depend>res_pjsip</depend>
25 <support_level>core</support_level>
31 #include <pjsip_simple.h>
34 #include "asterisk/res_pjsip_pubsub.h"
35 #include "asterisk/module.h"
36 #include "asterisk/linkedlists.h"
37 #include "asterisk/astobj2.h"
38 #include "asterisk/datastore.h"
39 #include "asterisk/uuid.h"
40 #include "asterisk/taskprocessor.h"
41 #include "asterisk/sched.h"
42 #include "asterisk/res_pjsip.h"
43 #include "asterisk/callerid.h"
44 #include "asterisk/manager.h"
45 #include "asterisk/test.h"
46 #include "res_pjsip/include/res_pjsip_private.h"
47 #include "asterisk/res_pjsip_presence_xml.h"
50 <manager name="PJSIPShowSubscriptionsInbound" language="en_US">
57 Provides a listing of all inbound subscriptions. An event <literal>InboundSubscriptionDetail</literal>
58 is issued for each subscription object. Once all detail events are completed an
59 <literal>InboundSubscriptionDetailComplete</literal> event is issued.
63 <manager name="PJSIPShowSubscriptionsOutbound" language="en_US">
70 Provides a listing of all outbound subscriptions. An event <literal>OutboundSubscriptionDetail</literal>
71 is issued for each subscription object. Once all detail events are completed an
72 <literal>OutboundSubscriptionDetailComplete</literal> event is issued.
76 <manager name="PJSIPShowResourceLists" language="en_US">
78 Displays settings for configured resource lists.
83 Provides a listing of all resource lists. An event <literal>ResourceListDetail</literal>
84 is issued for each resource list object. Once all detail events are completed a
85 <literal>ResourceListDetailComplete</literal> event is issued.
90 <configInfo name="res_pjsip_pubsub" language="en_US">
91 <synopsis>Module that implements publish and subscribe support.</synopsis>
92 <configFile name="pjsip.conf">
93 <configObject name="subscription_persistence">
94 <synopsis>Persists SIP subscriptions so they survive restarts.</synopsis>
95 <configOption name="packet">
96 <synopsis>Entire SIP SUBSCRIBE packet that created the subscription</synopsis>
98 <configOption name="src_name">
99 <synopsis>The source address of the subscription</synopsis>
101 <configOption name="src_port">
102 <synopsis>The source port of the subscription</synopsis>
104 <configOption name="transport_key">
105 <synopsis>The type of transport the subscription was received on</synopsis>
107 <configOption name="local_name">
108 <synopsis>The local address the subscription was received on</synopsis>
110 <configOption name="local_port">
111 <synopsis>The local port the subscription was received on</synopsis>
113 <configOption name="cseq">
114 <synopsis>The sequence number of the next NOTIFY to be sent</synopsis>
116 <configOption name="tag">
117 <synopsis>The local tag of the dialog for the subscription</synopsis>
119 <configOption name="endpoint">
120 <synopsis>The name of the endpoint that subscribed</synopsis>
122 <configOption name="expires">
123 <synopsis>The time at which the subscription expires</synopsis>
126 <configObject name="resource_list">
127 <synopsis>Resource list configuration parameters.</synopsis>
128 <configOption name="type">
129 <synopsis>Must be of type 'resource_list'</synopsis>
131 <configOption name="event">
132 <synopsis>The SIP event package that the list resource belong to.</synopsis>
134 The SIP event package describes the types of resources that Asterisk reports
138 <enum name="presence"><para>
139 Device state and presence reporting.
141 <enum name="message-summary"><para>
142 Message-waiting indication (MWI) reporting.
147 <configOption name="list_item">
148 <synopsis>The name of a resource to report state on</synopsis>
150 <para>In general Asterisk looks up list items in the following way:</para>
151 <para>1. Check if the list item refers to another configured resource list.</para>
152 <para>2. Pass the name of the resource off to event-package-specific handlers
153 to find the specified resource.</para>
154 <para>The second part means that the way the list item is specified depends
155 on what type of list this is. For instance, if you have the <replaceable>event</replaceable>
156 set to <literal>presence</literal>, then list items should be in the form of
157 dialplan_extension@dialplan_context. For <literal>message-summary</literal> mailbox
158 names should be listed.</para>
161 <configOption name="full_state" default="no">
162 <synopsis>Indicates if the entire list's state should be sent out.</synopsis>
164 <para>If this option is enabled, and a resource changes state, then Asterisk will construct
165 a notification that contains the state of all resources in the list. If the option is
166 disabled, Asterisk will construct a notification that only contains the states of
167 resources that have changed.</para>
169 <para>Even with this option disabled, there are certain situations where Asterisk is forced
170 to send a notification with the states of all resources in the list. When a subscriber
171 renews or terminates its subscription to the list, Asterisk MUST send a full state
176 <configOption name="notification_batch_interval" default="0">
177 <synopsis>Time Asterisk should wait, in milliseconds, before sending notifications.</synopsis>
179 <para>When a resource's state changes, it may be desired to wait a certain amount before Asterisk
180 sends a notification to subscribers. This allows for other state changes to accumulate, so that
181 Asterisk can communicate multiple state changes in a single notification instead of rapidly sending
182 many notifications.</para>
186 <configObject name="inbound-publication">
187 <synopsis>The configuration for inbound publications</synopsis>
188 <configOption name="endpoint" default="">
189 <synopsis>Optional name of an endpoint that is only allowed to publish to this resource</synopsis>
191 <configOption name="type">
192 <synopsis>Must be of type 'inbound-publication'.</synopsis>
199 static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata);
201 static struct pjsip_module pubsub_module = {
202 .name = { "PubSub Module", 13 },
203 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
204 .on_rx_request = pubsub_on_rx_request,
207 #define MOD_DATA_PERSISTENCE "sub_persistence"
208 #define MOD_DATA_MSG "sub_msg"
210 static const pj_str_t str_event_name = { "Event", 5 };
212 /*! \brief Scheduler used for automatically expiring publications */
213 static struct ast_sched_context *sched;
215 /*! \brief Number of buckets for publications (on a per handler) */
216 #define PUBLICATIONS_BUCKETS 37
218 /*! \brief Default expiration time for PUBLISH if one is not specified */
219 #define DEFAULT_PUBLISH_EXPIRES 3600
221 /*! \brief Number of buckets for subscription datastore */
222 #define DATASTORE_BUCKETS 53
224 /*! \brief Default expiration for subscriptions */
225 #define DEFAULT_EXPIRES 3600
227 /*! \brief Defined method for PUBLISH */
228 const pjsip_method pjsip_publish_method =
235 * \brief The types of PUBLISH messages defined in RFC 3903
237 enum sip_publish_type {
242 * This actually is not defined in RFC 3903. We use this as a constant
243 * to indicate that an incoming PUBLISH does not fit into any of the
244 * other categories and is thus invalid.
252 * The first PUBLISH sent. This will contain a non-zero Expires header
253 * as well as a body that indicates the current state of the endpoint
254 * that has sent the message. The initial PUBLISH is the only type
255 * of PUBLISH to not contain a Sip-If-Match header in it.
263 * Used to keep a published state from expiring. This will contain a
264 * non-zero Expires header but no body since its purpose is not to
273 * Used to change state from its previous value. This will contain
274 * a body updating the published state. May or may not contain an
283 * Used to remove published state from an ESC. This will contain
284 * an Expires header set to 0 and likely no body.
290 * \brief A vector of strings commonly used throughout this module
292 AST_VECTOR(resources, const char *);
295 * \brief Resource list configuration item
297 struct resource_list {
298 SORCERY_OBJECT(details);
299 /*! SIP event package the list uses. */
301 /*! Strings representing resources in the list. */
302 struct resources items;
303 /*! Indicates if Asterisk sends full or partial state on notifications. */
304 unsigned int full_state;
305 /*! Time, in milliseconds Asterisk waits before sending a batched notification.*/
306 unsigned int notification_batch_interval;
310 * Used to create new entity IDs by ESCs.
312 static int esc_etag_counter;
315 * \brief Structure representing a SIP publication
317 struct ast_sip_publication {
318 /*! Publication datastores set up by handlers */
319 struct ao2_container *datastores;
320 /*! \brief Entity tag for the publication */
322 /*! \brief Handler for this publication */
323 struct ast_sip_publish_handler *handler;
324 /*! \brief The endpoint with which the subscription is communicating */
325 struct ast_sip_endpoint *endpoint;
326 /*! \brief Expiration time of the publication */
328 /*! \brief Scheduled item for expiration of publication */
330 /*! \brief The resource the publication is to */
332 /*! \brief The name of the event type configuration */
333 char *event_configuration_name;
334 /*! \brief Data containing the above */
340 * \brief Structure used for persisting an inbound subscription
342 struct subscription_persistence {
343 /*! Sorcery object details */
344 SORCERY_OBJECT(details);
345 /*! The name of the endpoint involved in the subscrption */
347 /*! SIP message that creates the subscription */
348 char packet[PJSIP_MAX_PKT_LEN];
349 /*! Source address of the message */
350 char src_name[PJ_INET6_ADDRSTRLEN];
351 /*! Source port of the message */
353 /*! Local transport key type */
354 char transport_key[32];
355 /*! Local transport address */
356 char local_name[PJ_INET6_ADDRSTRLEN];
357 /*! Local transport port */
359 /*! Next CSeq to use for message */
361 /*! Local tag of the dialog */
363 /*! When this subscription expires */
364 struct timeval expires;
368 * \brief A tree of SIP subscriptions
370 * Because of the ability to subscribe to resource lists, a SIP
371 * subscription can result in a tree of subscriptions being created.
372 * This structure represents the information relevant to the subscription
373 * as a whole, to include the underlying PJSIP structure for the
376 struct sip_subscription_tree {
377 /*! The endpoint with which the subscription is communicating */
378 struct ast_sip_endpoint *endpoint;
379 /*! Serializer on which to place operations for this subscription */
380 struct ast_taskprocessor *serializer;
381 /*! The role for this subscription */
382 enum ast_sip_subscription_role role;
383 /*! Persistence information */
384 struct subscription_persistence *persistence;
385 /*! The underlying PJSIP event subscription structure */
387 /*! The underlying PJSIP dialog */
389 /*! Interval to use for batching notifications */
390 unsigned int notification_batch_interval;
391 /*! Scheduler ID for batched notification */
393 /*! Indicator if scheduled batched notification should be sent */
394 unsigned int send_scheduled_notify;
395 /*! The root of the subscription tree */
396 struct ast_sip_subscription *root;
397 /*! Is this subscription to a list? */
399 /*! Next item in the list */
400 AST_LIST_ENTRY(sip_subscription_tree) next;
404 * \brief Structure representing a "virtual" SIP subscription.
406 * This structure serves a dual purpose. Structurally, it is
407 * the constructed tree of subscriptions based on the resources
408 * being subscribed to. API-wise, this serves as the handle that
409 * subscription handlers use in order to interact with the pubsub API.
411 struct ast_sip_subscription {
412 /*! Subscription datastores set up by handlers */
413 struct ao2_container *datastores;
414 /*! The handler for this subscription */
415 const struct ast_sip_subscription_handler *handler;
416 /*! Pointer to the base of the tree */
417 struct sip_subscription_tree *tree;
418 /*! Body generaator for NOTIFYs */
419 struct ast_sip_pubsub_body_generator *body_generator;
420 /*! Vector of child subscriptions */
421 AST_VECTOR(, struct ast_sip_subscription *) children;
422 /*! Saved NOTIFY body text for this subscription */
423 struct ast_str *body_text;
424 /*! Indicator that the body text has changed since the last notification */
426 /*! The current state of the subscription */
427 pjsip_evsub_state subscription_state;
428 /*! For lists, the current version to place in the RLMI body */
429 unsigned int version;
430 /*! For lists, indicates if full state should always be communicated. */
431 unsigned int full_state;
432 /*! URI associated with the subscription */
434 /*! Name of resource being subscribed to */
439 * \brief Structure representing a publication resource
441 struct ast_sip_publication_resource {
442 /*! \brief Sorcery object details */
443 SORCERY_OBJECT(details);
444 /*! \brief Optional name of an endpoint that is only allowed to publish to this resource */
446 /*! \brief Mapping for event types to configuration */
447 struct ast_variable *events;
450 static const char *sip_subscription_roles_map[] = {
451 [AST_SIP_SUBSCRIBER] = "Subscriber",
452 [AST_SIP_NOTIFIER] = "Notifier"
455 AST_RWLIST_HEAD_STATIC(subscriptions, sip_subscription_tree);
457 AST_RWLIST_HEAD_STATIC(body_generators, ast_sip_pubsub_body_generator);
458 AST_RWLIST_HEAD_STATIC(body_supplements, ast_sip_pubsub_body_supplement);
460 static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event);
461 static void pubsub_on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata,
462 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
463 static void pubsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
464 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
465 static void pubsub_on_client_refresh(pjsip_evsub *sub);
466 static void pubsub_on_server_timeout(pjsip_evsub *sub);
468 static pjsip_evsub_user pubsub_cb = {
469 .on_evsub_state = pubsub_on_evsub_state,
470 .on_rx_refresh = pubsub_on_rx_refresh,
471 .on_rx_notify = pubsub_on_rx_notify,
472 .on_client_refresh = pubsub_on_client_refresh,
473 .on_server_timeout = pubsub_on_server_timeout,
476 /*! \brief Destructor for publication resource */
477 static void publication_resource_destroy(void *obj)
479 struct ast_sip_publication_resource *resource = obj;
481 ast_free(resource->endpoint);
482 ast_variables_destroy(resource->events);
485 /*! \brief Allocator for publication resource */
486 static void *publication_resource_alloc(const char *name)
488 return ast_sorcery_generic_alloc(sizeof(struct ast_sip_publication_resource), publication_resource_destroy);
491 /*! \brief Destructor for subscription persistence */
492 static void subscription_persistence_destroy(void *obj)
494 struct subscription_persistence *persistence = obj;
496 ast_free(persistence->endpoint);
497 ast_free(persistence->tag);
500 /*! \brief Allocator for subscription persistence */
501 static void *subscription_persistence_alloc(const char *name)
503 return ast_sorcery_generic_alloc(sizeof(struct subscription_persistence), subscription_persistence_destroy);
506 /*! \brief Function which creates initial persistence information of a subscription in sorcery */
507 static struct subscription_persistence *subscription_persistence_create(struct sip_subscription_tree *sub_tree)
509 char tag[PJ_GUID_STRING_LENGTH + 1];
511 /* The id of this persistence object doesn't matter as we keep it on the subscription and don't need to
512 * look it up by id at all.
514 struct subscription_persistence *persistence = ast_sorcery_alloc(ast_sip_get_sorcery(),
515 "subscription_persistence", NULL);
517 pjsip_dialog *dlg = sub_tree->dlg;
523 persistence->endpoint = ast_strdup(ast_sorcery_object_get_id(sub_tree->endpoint));
524 ast_copy_pj_str(tag, &dlg->local.info->tag, sizeof(tag));
525 persistence->tag = ast_strdup(tag);
527 ast_sorcery_create(ast_sip_get_sorcery(), persistence);
531 /*! \brief Function which updates persistence information of a subscription in sorcery */
532 static void subscription_persistence_update(struct sip_subscription_tree *sub_tree,
533 pjsip_rx_data *rdata)
537 if (!sub_tree->persistence) {
542 sub_tree->persistence->cseq = dlg->local.cseq;
546 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
548 expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
549 sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1));
551 ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
552 sizeof(sub_tree->persistence->packet));
553 ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
554 sizeof(sub_tree->persistence->src_name));
555 sub_tree->persistence->src_port = rdata->pkt_info.src_port;
556 ast_copy_string(sub_tree->persistence->transport_key, rdata->tp_info.transport->type_name,
557 sizeof(sub_tree->persistence->transport_key));
558 ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host,
559 sizeof(sub_tree->persistence->local_name));
560 sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port;
563 ast_sorcery_update(ast_sip_get_sorcery(), sub_tree->persistence);
566 /*! \brief Function which removes persistence of a subscription from sorcery */
567 static void subscription_persistence_remove(struct sip_subscription_tree *sub_tree)
569 if (!sub_tree->persistence) {
573 ast_sorcery_delete(ast_sip_get_sorcery(), sub_tree->persistence);
574 ao2_ref(sub_tree->persistence, -1);
578 static struct ast_sip_subscription_handler *find_sub_handler_for_event_name(const char *event_name);
579 static struct ast_sip_pubsub_body_generator *find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64],
582 /*! \brief Retrieve a handler using the Event header of an rdata message */
583 static struct ast_sip_subscription_handler *subscription_get_handler_from_rdata(pjsip_rx_data *rdata)
585 pjsip_event_hdr *event_header;
587 struct ast_sip_subscription_handler *handler;
589 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
591 ast_log(LOG_WARNING, "Incoming SUBSCRIBE request with no Event header\n");
594 ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
596 handler = find_sub_handler_for_event_name(event);
598 ast_log(LOG_WARNING, "No registered subscribe handler for event %s\n", event);
605 * \brief Accept headers that are exceptions to the rule
607 * Typically, when a SUBSCRIBE arrives, we attempt to find a
608 * body generator that matches one of the Accept headers in
609 * the request. When subscribing to a single resource, this works
610 * great. However, when subscribing to a list, things work
611 * differently. Most Accept header values are fine, but there
612 * are a couple that are endemic to resource lists that need
613 * to be ignored when searching for a body generator to use
614 * for the individual resources of the subscription.
616 const char *accept_exceptions[] = {
618 "application/rlmi+xml",
622 * \brief Is the Accept header from the SUBSCRIBE in the list of exceptions?
624 * \retval 1 This Accept header value is an exception to the rule.
625 * \retval 0 This Accept header is not an exception to the rule.
627 static int exceptional_accept(const pj_str_t *accept)
631 for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
632 if (!pj_strcmp2(accept, accept_exceptions[i])) {
640 /*! \brief Retrieve a body generator using the Accept header of an rdata message */
641 static struct ast_sip_pubsub_body_generator *subscription_get_generator_from_rdata(pjsip_rx_data *rdata,
642 const struct ast_sip_subscription_handler *handler)
644 pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
645 char accept[AST_SIP_MAX_ACCEPT][64];
646 size_t num_accept_headers = 0;
648 while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next))) {
651 for (i = 0; i < accept_header->count; ++i) {
652 if (!exceptional_accept(&accept_header->values[i])) {
653 ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
654 ++num_accept_headers;
659 if (num_accept_headers == 0) {
660 /* If a SUBSCRIBE contains no Accept headers, then we must assume that
661 * the default accept type for the event package is to be used.
663 ast_copy_string(accept[0], handler->notifier->default_accept, sizeof(accept[0]));
664 num_accept_headers = 1;
667 return find_body_generator(accept, num_accept_headers);
670 struct resource_tree;
673 * \brief A node for a resource tree.
676 AST_VECTOR(, struct tree_node *) children;
677 unsigned int full_state;
682 * \brief Helper function for retrieving a resource list for a given event.
684 * This will retrieve a resource list that corresponds to the resource and event provided.
686 * \param resource The name of the resource list to retrieve
687 * \param event The expected event name on the resource list
689 static struct resource_list *retrieve_resource_list(const char *resource, const char *event)
691 struct resource_list *list;
693 list = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
698 if (strcmp(list->event, event)) {
699 ast_log(LOG_WARNING, "Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
700 resource, list->event, event);
709 * \brief Allocate a tree node
711 * In addition to allocating and initializing the tree node, the node is also added
712 * to the vector of visited resources. See \ref build_resource_tree for more information
713 * on the visited resources.
715 * \param resource The name of the resource for this tree node.
716 * \param visited The vector of resources that have been visited.
717 * \param if allocating a list, indicate whether full state is requested in notifications.
718 * \retval NULL Allocation failure.
719 * \retval non-NULL The newly-allocated tree_node
721 static struct tree_node *tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state)
723 struct tree_node *node;
725 node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
730 strcpy(node->resource, resource);
731 if (AST_VECTOR_INIT(&node->children, 4)) {
735 node->full_state = full_state;
738 AST_VECTOR_APPEND(visited, resource);
744 * \brief Destructor for a tree node
746 * This function calls recursively in order to destroy
747 * all nodes lower in the tree from the given node in
748 * addition to the node itself.
750 * \param node The node to destroy.
752 static void tree_node_destroy(struct tree_node *node)
759 for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
760 tree_node_destroy(AST_VECTOR_GET(&node->children, i));
762 AST_VECTOR_FREE(&node->children);
767 * \brief Determine if this resource has been visited already
769 * See \ref build_resource_tree for more information
771 * \param resource The resource currently being visited
772 * \param visited The resources that have previously been visited
774 static int have_visited(const char *resource, struct resources *visited)
778 for (i = 0; i < AST_VECTOR_SIZE(visited); ++i) {
779 if (!strcmp(resource, AST_VECTOR_GET(visited, i))) {
788 * \brief Build child nodes for a given parent.
790 * This iterates through the items on a resource list and creates tree nodes for each one. The
791 * tree nodes created are children of the supplied parent node. If an item in the resource
792 * list is itself a list, then this function is called recursively to provide children for
795 * If an item in a resource list is not a list, then the supplied subscription handler is
796 * called into as if a new SUBSCRIBE for the list item were presented. The handler's response
797 * is used to determine if the node can be added to the tree or not.
799 * If a parent node ends up having no child nodes added under it, then the parent node is
800 * pruned from the tree.
802 * \param endpoint The endpoint that sent the inbound SUBSCRIBE.
803 * \param handler The subscription handler for leaf nodes in the tree.
804 * \param list The configured resource list from which the child node is being built.
805 * \param parent The parent node for these children.
806 * \param visited The resources that have already been visited.
808 static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
809 struct resource_list *list, struct tree_node *parent, struct resources *visited)
813 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
814 struct tree_node *current;
815 struct resource_list *child_list;
816 const char *resource = AST_VECTOR_GET(&list->items, i);
818 if (have_visited(resource, visited)) {
819 ast_debug(1, "Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
823 child_list = retrieve_resource_list(resource, list->event);
825 int resp = handler->notifier->new_subscribe(endpoint, resource);
826 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
827 current = tree_node_alloc(resource, visited, 0);
829 ast_debug(1, "Subscription to leaf resource %s was successful, but encountered"
830 "allocation error afterwards\n", resource);
833 ast_debug(1, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
834 resource, parent->resource);
835 AST_VECTOR_APPEND(&parent->children, current);
837 ast_debug(1, "Subscription to leaf resource %s resulted in error response %d\n",
841 ast_debug(1, "Resource %s (child of %s) is a list\n", resource, parent->resource);
842 current = tree_node_alloc(resource, visited, child_list->full_state);
844 ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
847 build_node_children(endpoint, handler, child_list, current, visited);
848 if (AST_VECTOR_SIZE(¤t->children) > 0) {
849 ast_debug(1, "List %s had no successful children.\n", resource);
850 AST_VECTOR_APPEND(&parent->children, current);
852 ast_debug(1, "List %s had successful children. Adding to parent %s\n",
853 resource, parent->resource);
854 tree_node_destroy(current);
856 ao2_cleanup(child_list);
862 * \brief A resource tree
864 * When an inbound SUBSCRIBE arrives, the resource being subscribed to may
865 * be a resource list. If this is the case, the resource list may contain resources
866 * that are themselves lists. The structure needed to hold the resources is
869 * Upon receipt of the SUBSCRIBE, the tree is built by determining if subscriptions
870 * to the individual resources in the tree would be successful or not. Any successful
871 * subscriptions result in a node in the tree being created. Any unsuccessful subscriptions
872 * result in no node being created.
874 * This tree can be seen as a bare-bones analog of the tree of ast_sip_subscriptions that
875 * will end up being created to actually carry out the duties of a SIP SUBSCRIBE dialog.
877 struct resource_tree {
878 struct tree_node *root;
879 unsigned int notification_batch_interval;
883 * \brief Destroy a resource tree.
885 * This function makes no assumptions about how the tree itself was
886 * allocated and does not attempt to free the tree itself. Callers
887 * of this function are responsible for freeing the tree.
889 * \param tree The tree to destroy.
891 static void resource_tree_destroy(struct resource_tree *tree)
894 tree_node_destroy(tree->root);
899 * \brief Build a resource tree
901 * This function builds a resource tree based on the requested resource in a SUBSCRIBE request.
903 * This function also creates a container that has all resources that have been visited during
904 * creation of the tree, whether those resources resulted in a tree node being created or not.
905 * Keeping this container of visited resources allows for misconfigurations such as loops in
906 * the tree or duplicated resources to be detected.
908 * \param endpoint The endpoint that sent the SUBSCRIBE request.
909 * \param handler The subscription handler for leaf nodes in the tree.
910 * \param resource The resource requested in the SUBSCRIBE request.
911 * \param tree The tree that is to be built.
913 * \retval 200-299 Successfully subscribed to at least one resource.
914 * \retval 300-699 Failure to subscribe to requested resource.
916 static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
917 const char *resource, struct resource_tree *tree)
919 struct resource_list *list;
920 struct resources visited;
922 list = retrieve_resource_list(resource, handler->event_name);
924 ast_debug(1, "Subscription to resource %s is not to a list\n", resource);
925 tree->root = tree_node_alloc(resource, NULL, 0);
929 return handler->notifier->new_subscribe(endpoint, resource);
932 ast_debug(1, "Subscription to resource %s is a list\n", resource);
933 if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
937 tree->root = tree_node_alloc(resource, &visited, list->full_state);
942 tree->notification_batch_interval = list->notification_batch_interval;
944 build_node_children(endpoint, handler, list, tree->root, &visited);
945 AST_VECTOR_FREE(&visited);
948 if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
955 static int datastore_hash(const void *obj, int flags)
957 const struct ast_datastore *datastore = obj;
958 const char *uid = flags & OBJ_KEY ? obj : datastore->uid;
960 ast_assert(uid != NULL);
962 return ast_str_hash(uid);
965 static int datastore_cmp(void *obj, void *arg, int flags)
967 const struct ast_datastore *datastore1 = obj;
968 const struct ast_datastore *datastore2 = arg;
969 const char *uid2 = flags & OBJ_KEY ? arg : datastore2->uid;
971 ast_assert(datastore1->uid != NULL);
972 ast_assert(uid2 != NULL);
974 return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
977 static int subscription_remove_serializer(void *obj)
979 struct sip_subscription_tree *sub_tree = obj;
981 /* This is why we keep the dialog on the subscription. When the subscription
982 * is destroyed, there is no guarantee that the underlying dialog is ready
983 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
984 * either. The dialog could be destroyed before our subscription is. We fix
985 * this problem by keeping a reference to the dialog until it is time to
986 * destroy the subscription. We need to have the dialog available when the
987 * subscription is destroyed so that we can guarantee that our attempt to
988 * remove the serializer will be successful.
990 ast_sip_dialog_set_serializer(sub_tree->dlg, NULL);
991 pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
996 static void add_subscription(struct sip_subscription_tree *obj)
998 SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
999 AST_RWLIST_INSERT_TAIL(&subscriptions, obj, next);
1002 static void remove_subscription(struct sip_subscription_tree *obj)
1004 struct sip_subscription_tree *i;
1005 SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
1006 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscriptions, i, next) {
1008 AST_RWLIST_REMOVE_CURRENT(next);
1009 ast_debug(1, "Removing subscription to resource %s from list of subscriptions\n",
1010 ast_sip_subscription_get_resource_name(i->root));
1014 AST_RWLIST_TRAVERSE_SAFE_END;
1017 static void subscription_destructor(void *obj)
1019 struct ast_sip_subscription *sub = obj;
1021 ast_debug(3, "Destroying SIP subscription to resource %s\n", sub->resource);
1022 ast_free(sub->body_text);
1024 ao2_cleanup(sub->datastores);
1027 static struct ast_sip_subscription *allocate_subscription(const struct ast_sip_subscription_handler *handler,
1028 const char *resource, struct sip_subscription_tree *tree)
1030 struct ast_sip_subscription *sub;
1031 pjsip_sip_uri *contact_uri;
1033 sub = ao2_alloc(sizeof(*sub) + strlen(resource) + 1, subscription_destructor);
1037 strcpy(sub->resource, resource); /* Safe */
1039 sub->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp);
1040 if (!sub->datastores) {
1045 sub->body_text = ast_str_create(128);
1046 if (!sub->body_text) {
1051 sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
1052 contact_uri = pjsip_uri_get_uri(tree->dlg->local.contact->uri);
1053 pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, contact_uri);
1054 pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
1056 sub->handler = handler;
1057 sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1064 * \brief Create a tree of virtual subscriptions based on a resource tree node.
1066 * \param handler The handler to supply to leaf subscriptions.
1067 * \param resource The requested resource for this subscription.
1068 * \param generator Body generator to use for leaf subscriptions.
1069 * \param tree The root of the subscription tree.
1070 * \param current The tree node that corresponds to the subscription being created.
1072 static struct ast_sip_subscription *create_virtual_subscriptions(const struct ast_sip_subscription_handler *handler,
1073 const char *resource, struct ast_sip_pubsub_body_generator *generator,
1074 struct sip_subscription_tree *tree, struct tree_node *current)
1077 struct ast_sip_subscription *sub;
1079 sub = allocate_subscription(handler, resource, tree);
1084 sub->full_state = current->full_state;
1085 sub->body_generator = generator;
1087 for (i = 0; i < AST_VECTOR_SIZE(¤t->children); ++i) {
1088 struct ast_sip_subscription *child;
1089 struct tree_node *child_node = AST_VECTOR_GET(¤t->children, i);
1091 child = create_virtual_subscriptions(handler, child_node->resource, generator,
1095 ast_debug(1, "Child subscription to resource %s could not be created\n",
1096 child_node->resource);
1100 if (AST_VECTOR_APPEND(&sub->children, child)) {
1101 ast_debug(1, "Child subscription to resource %s could not be appended\n",
1102 child_node->resource);
1109 static void shutdown_subscriptions(struct ast_sip_subscription *sub)
1113 if (AST_VECTOR_SIZE(&sub->children) > 0) {
1114 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
1115 shutdown_subscriptions(AST_VECTOR_GET(&sub->children, i));
1116 ao2_cleanup(AST_VECTOR_GET(&sub->children, i));
1121 if (sub->handler->subscription_shutdown) {
1122 sub->handler->subscription_shutdown(sub);
1126 static void subscription_tree_destructor(void *obj)
1128 struct sip_subscription_tree *sub_tree = obj;
1130 remove_subscription(sub_tree);
1132 subscription_persistence_remove(sub_tree);
1133 ao2_cleanup(sub_tree->endpoint);
1135 if (sub_tree->dlg) {
1136 ast_sip_push_task_synchronous(NULL, subscription_remove_serializer, sub_tree);
1139 shutdown_subscriptions(sub_tree->root);
1140 ao2_cleanup(sub_tree->root);
1142 ast_taskprocessor_unreference(sub_tree->serializer);
1143 ast_module_unref(ast_module_info->self);
1146 static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
1148 /* We keep a reference to the dialog until our subscription is destroyed. See
1149 * the subscription_destructor for more details
1151 pjsip_dlg_inc_session(dlg, &pubsub_module);
1152 sub_tree->dlg = dlg;
1153 ast_sip_dialog_set_serializer(dlg, sub_tree->serializer);
1154 pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
1157 static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_endpoint *endpoint)
1159 struct sip_subscription_tree *sub_tree;
1161 sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
1166 ast_module_ref(ast_module_info->self);
1168 sub_tree->serializer = ast_sip_create_serializer();
1169 if (!sub_tree->serializer) {
1170 ao2_ref(sub_tree, -1);
1174 sub_tree->endpoint = ao2_bump(endpoint);
1175 sub_tree->notify_sched_id = -1;
1177 add_subscription(sub_tree);
1182 * \brief Create a subscription tree based on a resource tree.
1184 * Using the previously-determined valid resources in the provided resource tree,
1185 * a corresponding tree of ast_sip_subscriptions are created. The root of the
1186 * subscription tree is a real subscription, and the rest in the tree are
1187 * virtual subscriptions.
1189 * \param handler The handler to use for leaf subscriptions
1190 * \param endpoint The endpoint that sent the SUBSCRIBE request
1191 * \param rdata The SUBSCRIBE content
1192 * \param resource The requested resource in the SUBSCRIBE request
1193 * \param generator The body generator to use in leaf subscriptions
1194 * \param tree The resource tree on which the subscription tree is based
1196 * \retval NULL Could not create the subscription tree
1197 * \retval non-NULL The root of the created subscription tree
1200 static struct sip_subscription_tree *create_subscription_tree(const struct ast_sip_subscription_handler *handler,
1201 struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
1202 struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree)
1204 struct sip_subscription_tree *sub_tree;
1206 struct subscription_persistence *persistence;
1208 sub_tree = allocate_subscription_tree(endpoint);
1213 dlg = ast_sip_create_dialog_uas(endpoint, rdata);
1215 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1216 ao2_ref(sub_tree, -1);
1220 persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
1221 pubsub_module.id, MOD_DATA_PERSISTENCE);
1223 /* Update the created dialog with the persisted information */
1224 pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
1225 pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->tag);
1226 dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
1227 pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
1228 dlg->local.cseq = persistence->cseq;
1229 dlg->remote.cseq = persistence->cseq;
1232 pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
1233 subscription_setup_dialog(sub_tree, dlg);
1235 ast_sip_mod_data_set(dlg->pool, dlg->mod_data, pubsub_module.id, MOD_DATA_MSG,
1236 pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
1238 sub_tree->notification_batch_interval = tree->notification_batch_interval;
1240 sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
1241 if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
1242 sub_tree->is_list = 1;
1248 /*! \brief Callback function to perform the actual recreation of a subscription */
1249 static int subscription_persistence_recreate(void *obj, void *arg, int flags)
1251 struct subscription_persistence *persistence = obj;
1252 pj_pool_t *pool = arg;
1253 pjsip_rx_data rdata = { { 0, }, };
1254 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1255 struct sip_subscription_tree *sub_tree;
1256 struct ast_sip_pubsub_body_generator *generator;
1259 size_t resource_size;
1260 pjsip_sip_uri *request_uri;
1261 struct resource_tree tree;
1262 pjsip_expires_hdr *expires_header;
1263 struct ast_sip_subscription_handler *handler;
1265 /* If this subscription has already expired remove it */
1266 if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) {
1267 ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1271 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", persistence->endpoint);
1273 ast_log(LOG_WARNING, "A subscription for '%s' could not be recreated as the endpoint was not found\n",
1274 persistence->endpoint);
1275 ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1279 pj_pool_reset(pool);
1280 rdata.tp_info.pool = pool;
1282 if (ast_sip_create_rdata(&rdata, persistence->packet, persistence->src_name, persistence->src_port,
1283 persistence->transport_key, persistence->local_name, persistence->local_port)) {
1284 ast_log(LOG_WARNING, "A subscription for '%s' could not be recreated as the message could not be parsed\n",
1285 persistence->endpoint);
1286 ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1290 request_uri = pjsip_uri_get_uri(rdata.msg_info.msg->line.req.uri);
1291 resource_size = pj_strlen(&request_uri->user) + 1;
1292 resource = alloca(resource_size);
1293 ast_copy_pj_str(resource, &request_uri->user, resource_size);
1295 /* Update the expiration header with the new expiration */
1296 expires_header = pjsip_msg_find_hdr(rdata.msg_info.msg, PJSIP_H_EXPIRES, rdata.msg_info.msg->hdr.next);
1297 if (!expires_header) {
1298 expires_header = pjsip_expires_hdr_create(pool, 0);
1299 if (!expires_header) {
1300 ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1303 pjsip_msg_add_hdr(rdata.msg_info.msg, (pjsip_hdr*)expires_header);
1305 expires_header->ivalue = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
1307 handler = subscription_get_handler_from_rdata(&rdata);
1308 if (!handler || !handler->notifier) {
1309 ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1313 generator = subscription_get_generator_from_rdata(&rdata, handler);
1315 ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1319 ast_sip_mod_data_set(rdata.tp_info.pool, rdata.endpt_info.mod_data,
1320 pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
1322 memset(&tree, 0, sizeof(tree));
1323 resp = build_resource_tree(endpoint, handler, resource, &tree);
1324 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1325 sub_tree = create_subscription_tree(handler, endpoint, &rdata, resource, generator, &tree);
1326 sub_tree->persistence = ao2_bump(persistence);
1327 subscription_persistence_update(sub_tree, &rdata);
1329 ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1331 resource_tree_destroy(&tree);
1336 /*! \brief Function which loads and recreates persisted subscriptions upon startup when the system is fully booted */
1337 static int subscription_persistence_load(void *data)
1339 struct ao2_container *persisted_subscriptions = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
1340 "subscription_persistence", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1343 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "rtd%p", PJSIP_POOL_RDATA_LEN,
1344 PJSIP_POOL_RDATA_INC);
1346 ast_log(LOG_WARNING, "Could not create a memory pool for recreating SIP subscriptions\n");
1350 ao2_callback(persisted_subscriptions, OBJ_NODATA, subscription_persistence_recreate, pool);
1352 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1354 ao2_ref(persisted_subscriptions, -1);
1358 /*! \brief Event callback which fires subscription persistence recreation when the system is fully booted */
1359 static void subscription_persistence_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
1361 struct ast_json_payload *payload;
1364 if (stasis_message_type(message) != ast_manager_get_generic_type()) {
1368 payload = stasis_message_data(message);
1369 type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1371 /* This subscription only responds to the FullyBooted event so that all modules have been loaded when we
1372 * recreate SIP subscriptions.
1374 if (strcmp(type, "FullyBooted")) {
1378 /* This has to be here so the subscription is recreated when the body generator is available */
1379 ast_sip_push_task(NULL, subscription_persistence_load, NULL);
1381 /* Once the system is fully booted we don't care anymore */
1382 stasis_unsubscribe(sub);
1385 typedef int (*on_subscription_t)(struct sip_subscription_tree *sub, void *arg);
1387 static int for_each_subscription(on_subscription_t on_subscription, void *arg)
1390 struct sip_subscription_tree *i;
1391 SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
1393 if (!on_subscription) {
1397 AST_RWLIST_TRAVERSE(&subscriptions, i, next) {
1398 if (on_subscription(i, arg)) {
1406 static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree,
1407 struct ast_str **buf)
1410 struct ast_sip_endpoint_id_configuration *id = &sub_tree->endpoint->id;
1412 ast_str_append(buf, 0, "Role: %s\r\n",
1413 sip_subscription_roles_map[sub_tree->role]);
1414 ast_str_append(buf, 0, "Endpoint: %s\r\n",
1415 ast_sorcery_object_get_id(sub_tree->endpoint));
1417 ast_copy_pj_str(str, &sub_tree->dlg->call_id->id, sizeof(str));
1418 ast_str_append(buf, 0, "Callid: %s\r\n", str);
1420 ast_str_append(buf, 0, "State: %s\r\n", pjsip_evsub_get_state_name(sub_tree->evsub));
1422 ast_callerid_merge(str, sizeof(str),
1423 S_COR(id->self.name.valid, id->self.name.str, NULL),
1424 S_COR(id->self.number.valid, id->self.number.str, NULL),
1427 ast_str_append(buf, 0, "Callerid: %s\r\n", str);
1429 /* XXX This needs to be done recursively for lists */
1430 if (sub_tree->root->handler->to_ami) {
1431 sub_tree->root->handler->to_ami(sub_tree->root, buf);
1436 void *ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, const char *header)
1438 pjsip_dialog *dlg = sub->tree->dlg;
1439 pjsip_msg *msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1442 pj_cstr(&name, header);
1444 return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
1447 struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
1448 struct ast_sip_endpoint *endpoint, const char *resource)
1450 struct ast_sip_subscription *sub;
1452 struct ast_sip_contact *contact;
1454 pjsip_tx_data *tdata;
1456 struct sip_subscription_tree *sub_tree = NULL;
1458 sub_tree = allocate_subscription_tree(endpoint);
1463 sub = allocate_subscription(handler, resource, sub_tree);
1465 ao2_cleanup(sub_tree);
1469 contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
1470 if (!contact || ast_strlen_zero(contact->uri)) {
1471 ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
1472 ast_sorcery_object_get_id(endpoint));
1473 ao2_ref(sub_tree, -1);
1474 ao2_cleanup(contact);
1478 dlg = ast_sip_create_dialog_uac(endpoint, contact->uri, NULL);
1479 ao2_cleanup(contact);
1481 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1482 ao2_ref(sub_tree, -1);
1486 pj_cstr(&event, handler->event_name);
1487 pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub_tree->evsub);
1488 subscription_setup_dialog(sub_tree, dlg);
1490 evsub = sub_tree->evsub;
1492 if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
1493 pjsip_evsub_send_request(evsub, tdata);
1495 /* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
1496 * being called and terminating the subscription. Therefore, we don't
1497 * need to decrease the reference count of sub here.
1499 pjsip_evsub_terminate(evsub, PJ_TRUE);
1500 ao2_ref(sub_tree, -1);
1507 struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
1509 ast_assert(sub->tree->endpoint != NULL);
1510 return ao2_bump(sub->tree->endpoint);
1513 struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub)
1515 ast_assert(sub->tree->serializer != NULL);
1516 return sub->tree->serializer;
1519 static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
1521 #ifdef TEST_FRAMEWORK
1522 struct ast_sip_endpoint *endpoint = sub_tree->endpoint;
1526 res = pjsip_evsub_send_request(sub_tree->evsub, tdata) == PJ_SUCCESS ? 0 : -1;
1527 subscription_persistence_update(sub_tree, NULL);
1529 ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
1532 pjsip_evsub_get_state_name(sub_tree->evsub),
1533 ast_sorcery_object_get_id(endpoint));
1539 * \brief Add a resource XML element to an RLMI body
1541 * Each resource element represents a subscribed resource in the list. This function currently
1542 * will unconditionally add an instance element to each created resource element. Instance
1543 * elements refer to later parts in the multipart body.
1545 * \param pool PJLIB allocation pool
1546 * \param cid Content-ID header of the resource
1547 * \param resource_name Name of the resource
1548 * \param resource_uri URI of the resource
1549 * \param state State of the subscribed resource
1551 static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid,
1552 const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
1554 static pj_str_t cid_name = { "cid", 3 };
1555 pj_xml_node *resource;
1557 pj_xml_node *instance;
1558 pj_xml_attr *cid_attr;
1560 char uri[PJSIP_MAX_URL_SIZE];
1562 /* This creates a string representing the Content-ID without the enclosing < > */
1563 const pj_str_t cid_stripped = {
1564 .ptr = cid->hvalue.ptr + 1,
1565 .slen = cid->hvalue.slen - 2,
1568 resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
1569 name = ast_sip_presence_xml_create_node(pool, resource, "name");
1570 instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
1572 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
1573 ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
1575 pj_strdup2(pool, &name->content, resource_name);
1577 ast_generate_random_string(id, sizeof(id));
1579 ast_sip_presence_xml_create_attr(pool, instance, "id", id);
1580 ast_sip_presence_xml_create_attr(pool, instance, "state",
1581 state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
1583 /* Use the PJLIB-util XML library directly here since we are using a
1587 cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
1588 pj_xml_add_attr(instance, cid_attr);
1592 * \brief A multipart body part and meta-information
1594 * When creating a multipart body part, the end result (the
1595 * pjsip_multipart_part) is hard to inspect without undoing
1596 * a lot of what was done to create it. Therefore, we use this
1597 * structure to store meta-information about the body part.
1599 * The main consumer of this is the creator of the RLMI body
1600 * part of a multipart resource list body.
1603 /*! Content-ID header for the body part */
1604 pjsip_generic_string_hdr *cid;
1605 /*! Subscribed resource represented in the body part */
1606 const char *resource;
1607 /*! URI for the subscribed body part */
1609 /*! Subscription state of the resource represented in the body part */
1610 pjsip_evsub_state state;
1611 /*! The actual body part that will be present in the multipart body */
1612 pjsip_multipart_part *part;
1616 * \brief Type declaration for container of body part structures
1618 AST_VECTOR(body_part_list, struct body_part *);
1621 * \brief Create a Content-ID header
1623 * Content-ID headers are required by RFC2387 for multipart/related
1624 * bodies. They serve as identifiers for each part of the multipart body.
1626 * \param pool PJLIB allocation pool
1627 * \param sub Subscription to a resource
1629 static pjsip_generic_string_hdr *generate_content_id_hdr(pj_pool_t *pool,
1630 const struct ast_sip_subscription *sub)
1632 static const pj_str_t cid_name = { "Content-ID", 10 };
1633 pjsip_generic_string_hdr *cid;
1638 /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
1639 alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
1640 cid_value.ptr = pj_pool_alloc(pool, alloc_size);
1641 cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
1642 ast_generate_random_string(id, sizeof(id)),
1643 (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
1644 cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
1649 static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
1652 pj_xml_node *rlmi = msg_body->data;
1654 num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
1655 if (num_printed == AST_PJSIP_XML_PROLOG_LEN) {
1662 static void *rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
1664 const pj_xml_node *rlmi = data;
1666 return pj_xml_clone(pool, rlmi);
1670 * \brief Create an RLMI body part for a multipart resource list body
1672 * RLMI (Resource list meta information) is a special body type that lists
1673 * the subscribed resources and tells subscribers the number of subscribed
1674 * resources and what other body parts are in the multipart body. The
1675 * RLMI body also has a version number that a subscriber can use to ensure
1676 * that the locally-stored state corresponds to server state.
1678 * \param pool The allocation pool
1679 * \param sub The subscription representing the subscribed resource list
1680 * \param body_parts A container of body parts that RLMI will refer to
1681 * \param full_state Indicates whether this is a full or partial state notification
1682 * \return The multipart part representing the RLMI body
1684 static pjsip_multipart_part *build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
1685 struct body_part_list *body_parts, unsigned int full_state)
1687 static const pj_str_t rlmi_type = { "application", 11 };
1688 static const pj_str_t rlmi_subtype = { "rlmi+xml", 8 };
1691 pjsip_multipart_part *rlmi_part;
1692 char version_str[32];
1693 char uri[PJSIP_MAX_URL_SIZE];
1694 pjsip_generic_string_hdr *cid;
1697 rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
1698 ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
1700 ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
1701 ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
1703 snprintf(version_str, sizeof(version_str), "%u", sub->version++);
1704 ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
1705 ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
1707 name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
1708 pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
1710 for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
1711 const struct body_part *part = AST_VECTOR_GET(body_parts, i);
1713 add_rlmi_resource(pool, rlmi, part->cid, part->resource, part->uri, part->state);
1716 rlmi_part = pjsip_multipart_create_part(pool);
1718 rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
1719 pj_strdup(pool, &rlmi_part->body->content_type.type, &rlmi_type);
1720 pj_strdup(pool, &rlmi_part->body->content_type.subtype, &rlmi_subtype);
1721 pj_list_init(&rlmi_part->body->content_type.param);
1723 rlmi_part->body->data = pj_xml_clone(pool, rlmi);
1724 rlmi_part->body->clone_data = rlmi_clone_data;
1725 rlmi_part->body->print_body = rlmi_print_body;
1727 cid = generate_content_id_hdr(pool, sub);
1728 pj_list_insert_before(&rlmi_part->hdr, cid);
1733 static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
1734 unsigned int force_full_state);
1737 * \brief Destroy a list of body parts
1739 * \param parts The container of parts to destroy
1741 static void free_body_parts(struct body_part_list *parts)
1745 for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
1746 struct body_part *part = AST_VECTOR_GET(parts, i);
1750 AST_VECTOR_FREE(parts);
1754 * \brief Allocate and initialize a body part structure
1756 * \param pool PJLIB allocation pool
1757 * \param sub Subscription representing a subscribed resource
1759 static struct body_part *allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
1761 struct body_part *bp;
1763 bp = ast_calloc(1, sizeof(*bp));
1768 bp->cid = generate_content_id_hdr(pool, sub);
1769 bp->resource = sub->resource;
1770 bp->state = sub->subscription_state;
1777 * \brief Create a multipart body part for a subscribed resource
1779 * \param pool PJLIB allocation pool
1780 * \param sub The subscription representing a subscribed resource
1781 * \param parts A vector of parts to append the created part to.
1782 * \param use_full_state Unused locally, but may be passed to other functions
1784 static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub,
1785 struct body_part_list *parts, unsigned int use_full_state)
1787 struct body_part *bp;
1788 pjsip_msg_body *body;
1790 bp = allocate_body_part(pool, sub);
1795 body = generate_notify_body(pool, sub, use_full_state);
1797 /* Partial state was requested and the resource has not changed state */
1802 bp->part = pjsip_multipart_create_part(pool);
1803 bp->part->body = body;
1804 pj_list_insert_before(&bp->part->hdr, bp->cid);
1806 AST_VECTOR_APPEND(parts, bp);
1810 * \brief Create and initialize the PJSIP multipart body structure for a resource list subscription
1813 * \return The multipart message body
1815 static pjsip_msg_body *create_multipart_body(pj_pool_t *pool)
1817 pjsip_media_type media_type;
1818 pjsip_param *media_type_param;
1820 pj_str_t pj_boundary;
1822 pjsip_media_type_init2(&media_type, "multipart", "related");
1824 media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
1825 pj_list_init(media_type_param);
1827 pj_strdup2(pool, &media_type_param->name, "type");
1828 pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
1830 pj_list_insert_before(&media_type.param, media_type_param);
1832 pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
1833 return pjsip_multipart_create(pool, &media_type, &pj_boundary);
1837 * \brief Create a resource list body for NOTIFY requests
1839 * Resource list bodies are multipart/related bodies. The first part of the multipart body
1840 * is an RLMI body that describes the rest of the parts to come. The other parts of the body
1841 * convey state of individual subscribed resources.
1843 * \param pool PJLIB allocation pool
1844 * \param sub Subscription details from which to generate body
1845 * \param force_full_state If true, ignore resource list settings and send a full state notification
1846 * \return The generated multipart/related body
1848 static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
1849 unsigned int force_full_state)
1852 pjsip_multipart_part *rlmi_part;
1853 pjsip_msg_body *multipart;
1854 struct body_part_list body_parts;
1855 unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
1857 if (AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children))) {
1861 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
1862 build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
1865 /* This can happen if issuing partial state and no children of the list have changed state */
1866 if (AST_VECTOR_SIZE(&body_parts) == 0) {
1870 multipart = create_multipart_body(pool);
1872 rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
1876 pjsip_multipart_add_part(pool, multipart, rlmi_part);
1878 for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
1879 pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
1882 free_body_parts(&body_parts);
1887 * \brief Create the body for a NOTIFY request.
1889 * \param pool The pool used for allocations
1890 * \param root The root of the subscription tree
1891 * \param force_full_state If true, ignore resource list settings and send a full state notification
1893 static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
1894 unsigned int force_full_state)
1896 pjsip_msg_body *body;
1898 if (AST_VECTOR_SIZE(&root->children) == 0) {
1899 if (force_full_state || root->body_changed) {
1900 /* Not a list. We've already generated the body and saved it on the subscription.
1901 * Use that directly.
1907 pj_cstr(&type, ast_sip_subscription_get_body_type(root));
1908 pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
1909 pj_cstr(&text, ast_str_buffer(root->body_text));
1911 body = pjsip_msg_body_create(pool, &type, &subtype, &text);
1912 root->body_changed = 0;
1917 body = generate_list_body(pool, root, force_full_state);
1924 * \brief Shortcut method to create a Require: eventlist header
1926 static pjsip_require_hdr *create_require_eventlist(pj_pool_t *pool)
1928 pjsip_require_hdr *require;
1930 require = pjsip_require_hdr_create(pool);
1931 pj_strdup2(pool, &require->values[0], "eventlist");
1938 * \brief Send a NOTIFY request to a subscriber
1940 * \param sub_tree The subscription tree representing the subscription
1941 * \param force_full_state If true, ignore resource list settings and send full resource list state.
1943 * \retval non-zero Failure
1945 static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
1947 pjsip_evsub *evsub = sub_tree->evsub;
1948 pjsip_tx_data *tdata;
1950 if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
1951 NULL, NULL, &tdata) != PJ_SUCCESS) {
1955 tdata->msg->body = generate_notify_body(tdata->pool, sub_tree->root, force_full_state);
1956 if (!tdata->msg->body) {
1957 pjsip_tx_data_dec_ref(tdata);
1961 if (sub_tree->is_list) {
1962 pjsip_require_hdr *require = create_require_eventlist(tdata->pool);
1963 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
1966 if (sip_subscription_send_request(sub_tree, tdata)) {
1970 sub_tree->send_scheduled_notify = 0;
1975 static int serialized_send_notify(void *userdata)
1977 struct sip_subscription_tree *sub_tree = userdata;
1979 /* It's possible that between when the notification was scheduled
1980 * and now, that a new SUBSCRIBE arrived, requiring full state to be
1981 * sent out in an immediate NOTIFY. If that has happened, we need to
1982 * bail out here instead of sending the batched NOTIFY.
1984 if (!sub_tree->send_scheduled_notify) {
1985 ao2_cleanup(sub_tree);
1989 send_notify(sub_tree, 0);
1990 ao2_cleanup(sub_tree);
1994 static int sched_cb(const void *data)
1996 struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
1998 /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
1999 ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree);
2003 static int schedule_notification(struct sip_subscription_tree *sub_tree)
2005 /* There's already a notification scheduled */
2006 if (sub_tree->notify_sched_id > -1) {
2010 sub_tree->notify_sched_id = ast_sched_add(sched, sub_tree->notification_batch_interval, sched_cb, ao2_bump(sub_tree));
2011 if (sub_tree->notify_sched_id < 0) {
2015 sub_tree->send_scheduled_notify = 1;
2019 int ast_sip_subscription_notify(struct ast_sip_subscription *sub, void *notify_data,
2022 if (ast_sip_pubsub_generate_body_content(ast_sip_subscription_get_body_type(sub),
2023 ast_sip_subscription_get_body_subtype(sub), notify_data, &sub->body_text)) {
2027 sub->body_changed = 1;
2029 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2032 if (sub->tree->notification_batch_interval) {
2033 return schedule_notification(sub->tree);
2035 return send_notify(sub->tree, 0);
2039 void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
2041 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2044 void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
2046 pjsip_dialog *dlg = sub->tree->dlg;
2047 ast_copy_pj_str(buf, &dlg->remote.info_str, size);
2050 const char *ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
2052 return sub->resource;
2055 static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
2059 /* If this is a persistence recreation the subscription has already been accepted */
2060 if (ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_PERSISTENCE)) {
2064 pj_list_init(&res_hdr);
2065 if (sub_tree->is_list) {
2066 /* If subscribing to a list, our response has to have a Require: eventlist header in it */
2067 pj_list_insert_before(&res_hdr, create_require_eventlist(rdata->tp_info.pool));
2070 return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2073 static void subscription_datastore_destroy(void *obj)
2075 struct ast_datastore *datastore = obj;
2077 /* Using the destroy function (if present) destroy the data */
2078 if (datastore->info->destroy != NULL && datastore->data != NULL) {
2079 datastore->info->destroy(datastore->data);
2080 datastore->data = NULL;
2083 ast_free((void *) datastore->uid);
2084 datastore->uid = NULL;
2087 struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
2089 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
2090 const char *uid_ptr = uid;
2096 datastore = ao2_alloc(sizeof(*datastore), subscription_datastore_destroy);
2101 datastore->info = info;
2102 if (ast_strlen_zero(uid)) {
2103 /* They didn't provide an ID so we'll provide one ourself */
2104 struct ast_uuid *uuid = ast_uuid_generate();
2105 char uuid_buf[AST_UUID_STR_LEN];
2109 uid_ptr = ast_uuid_to_str(uuid, uuid_buf, sizeof(uuid_buf));
2113 datastore->uid = ast_strdup(uid_ptr);
2114 if (!datastore->uid) {
2118 ao2_ref(datastore, +1);
2122 int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
2124 ast_assert(datastore != NULL);
2125 ast_assert(datastore->info != NULL);
2126 ast_assert(!ast_strlen_zero(datastore->uid));
2128 if (!ao2_link(subscription->datastores, datastore)) {
2134 struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name)
2136 return ao2_find(subscription->datastores, name, OBJ_KEY);
2139 void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
2141 ao2_find(subscription->datastores, name, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
2144 int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore)
2146 ast_assert(datastore != NULL);
2147 ast_assert(datastore->info != NULL);
2148 ast_assert(!ast_strlen_zero(datastore->uid));
2150 if (!ao2_link(publication->datastores, datastore)) {
2156 struct ast_datastore *ast_sip_publication_get_datastore(struct ast_sip_publication *publication, const char *name)
2158 return ao2_find(publication->datastores, name, OBJ_KEY);
2161 void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name)
2163 ao2_callback(publication->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
2166 AST_RWLIST_HEAD_STATIC(publish_handlers, ast_sip_publish_handler);
2168 static int publication_hash_fn(const void *obj, const int flags)
2170 const struct ast_sip_publication *publication = obj;
2171 const int *entity_tag = obj;
2173 return flags & OBJ_KEY ? *entity_tag : publication->entity_tag;
2176 static int publication_cmp_fn(void *obj, void *arg, int flags)
2178 const struct ast_sip_publication *publication1 = obj;
2179 const struct ast_sip_publication *publication2 = arg;
2180 const int *entity_tag = arg;
2182 return (publication1->entity_tag == (flags & OBJ_KEY ? *entity_tag : publication2->entity_tag) ?
2183 CMP_MATCH | CMP_STOP : 0);
2186 static void publish_add_handler(struct ast_sip_publish_handler *handler)
2188 SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
2189 AST_RWLIST_INSERT_TAIL(&publish_handlers, handler, next);
2192 int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler)
2194 if (ast_strlen_zero(handler->event_name)) {
2195 ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
2199 if (!(handler->publications = ao2_container_alloc(PUBLICATIONS_BUCKETS,
2200 publication_hash_fn, publication_cmp_fn))) {
2201 ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
2202 handler->event_name);
2206 publish_add_handler(handler);
2208 ast_module_ref(ast_module_info->self);
2213 void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler)
2215 struct ast_sip_publish_handler *iter;
2216 SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
2217 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&publish_handlers, iter, next) {
2218 if (handler == iter) {
2219 AST_RWLIST_REMOVE_CURRENT(next);
2220 ao2_cleanup(handler->publications);
2221 ast_module_unref(ast_module_info->self);
2225 AST_RWLIST_TRAVERSE_SAFE_END;
2228 AST_RWLIST_HEAD_STATIC(subscription_handlers, ast_sip_subscription_handler);
2230 static void sub_add_handler(struct ast_sip_subscription_handler *handler)
2232 SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
2233 AST_RWLIST_INSERT_TAIL(&subscription_handlers, handler, next);
2234 ast_module_ref(ast_module_info->self);
2237 static struct ast_sip_subscription_handler *find_sub_handler_for_event_name(const char *event_name)
2239 struct ast_sip_subscription_handler *iter;
2240 SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
2242 AST_RWLIST_TRAVERSE(&subscription_handlers, iter, next) {
2243 if (!strcmp(iter->event_name, event_name)) {
2250 int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
2253 pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
2254 struct ast_sip_subscription_handler *existing;
2257 if (ast_strlen_zero(handler->event_name)) {
2258 ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
2262 existing = find_sub_handler_for_event_name(handler->event_name);
2264 ast_log(LOG_ERROR, "Unable to register subscription handler for event %s."
2265 "A handler is already registered\n", handler->event_name);
2269 for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
2270 pj_cstr(&accept[i], handler->accept[i]);
2273 pj_cstr(&event, handler->event_name);
2275 pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
2277 sub_add_handler(handler);
2282 void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
2284 struct ast_sip_subscription_handler *iter;
2285 SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
2286 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscription_handlers, iter, next) {
2287 if (handler == iter) {
2288 AST_RWLIST_REMOVE_CURRENT(next);
2289 ast_module_unref(ast_module_info->self);
2293 AST_RWLIST_TRAVERSE_SAFE_END;
2296 static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype(const char *content_type,
2297 const char *content_subtype)
2299 struct ast_sip_pubsub_body_generator *iter;
2300 SCOPED_LOCK(lock, &body_generators, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
2302 AST_LIST_TRAVERSE(&body_generators, iter, list) {
2303 if (!strcmp(iter->type, content_type) &&
2304 !strcmp(iter->subtype, content_subtype)) {
2312 static struct ast_sip_pubsub_body_generator *find_body_generator_accept(const char *accept)
2314 char *accept_copy = ast_strdupa(accept);
2315 char *subtype = accept_copy;
2316 char *type = strsep(&subtype, "/");
2318 if (ast_strlen_zero(type) || ast_strlen_zero(subtype)) {
2322 return find_body_generator_type_subtype(type, subtype);
2325 static struct ast_sip_pubsub_body_generator *find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64],
2329 struct ast_sip_pubsub_body_generator *generator = NULL;
2331 for (i = 0; i < num_accept; ++i) {
2332 generator = find_body_generator_accept(accept[i]);
2334 ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
2337 ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
2344 static int generate_initial_notify(struct ast_sip_subscription *sub)
2349 if (AST_VECTOR_SIZE(&sub->children) > 0) {
2352 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2353 if (generate_initial_notify(AST_VECTOR_GET(&sub->children, i))) {
2361 if (sub->handler->notifier->subscription_established(sub)) {
2365 notify_data = sub->handler->notifier->get_notify_data(sub);
2370 res = ast_sip_pubsub_generate_body_content(ast_sip_subscription_get_body_type(sub),
2371 ast_sip_subscription_get_body_subtype(sub), notify_data, &sub->body_text);
2373 ao2_cleanup(notify_data);
2378 static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
2380 pjsip_expires_hdr *expires_header;
2381 struct ast_sip_subscription_handler *handler;
2382 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2383 struct sip_subscription_tree *sub_tree;
2384 struct ast_sip_pubsub_body_generator *generator;
2386 pjsip_uri *request_uri;
2387 pjsip_sip_uri *request_uri_sip;
2388 size_t resource_size;
2390 struct resource_tree tree;
2392 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
2393 ast_assert(endpoint != NULL);
2395 if (!endpoint->subscription.allow) {
2396 ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
2397 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
2401 request_uri = rdata->msg_info.msg->line.req.uri;
2403 if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
2404 char uri_str[PJSIP_MAX_URL_SIZE];
2406 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
2407 ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
2408 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
2412 request_uri_sip = pjsip_uri_get_uri(request_uri);
2413 resource_size = pj_strlen(&request_uri_sip->user) + 1;
2414 resource = alloca(resource_size);
2415 ast_copy_pj_str(resource, &request_uri_sip->user, resource_size);
2417 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
2419 if (expires_header) {
2420 if (expires_header->ivalue == 0) {
2421 ast_log(LOG_WARNING, "Susbscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
2422 ast_sorcery_object_get_id(endpoint));
2423 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
2426 if (expires_header->ivalue < endpoint->subscription.minexpiry) {
2427 ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
2428 expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subscription.minexpiry);
2429 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
2434 handler = subscription_get_handler_from_rdata(rdata);
2436 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
2440 generator = subscription_get_generator_from_rdata(rdata, handler);
2442 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
2446 memset(&tree, 0, sizeof(tree));
2447 resp = build_resource_tree(endpoint, handler, resource, &tree);
2448 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
2449 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
2450 resource_tree_destroy(&tree);
2454 sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree);
2456 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
2458 sub_tree->persistence = subscription_persistence_create(sub_tree);
2459 subscription_persistence_update(sub_tree, rdata);
2460 sip_subscription_accept(sub_tree, rdata, resp);
2461 if (generate_initial_notify(sub_tree->root)) {
2462 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
2464 send_notify(sub_tree, 1);
2467 resource_tree_destroy(&tree);
2471 static struct ast_sip_publish_handler *find_pub_handler(const char *event)
2473 struct ast_sip_publish_handler *iter = NULL;
2474 SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
2476 AST_RWLIST_TRAVERSE(&publish_handlers, iter, next) {
2477 if (strcmp(event, iter->event_name)) {
2478 ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
2481 ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
2488 static enum sip_publish_type determine_sip_publish_type(pjsip_rx_data *rdata,
2489 pjsip_generic_string_hdr *etag_hdr, int *expires, int *entity_id)
2491 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
2494 char etag[pj_strlen(&etag_hdr->hvalue) + 1];
2496 ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
2498 if (sscanf(etag, "%30d", entity_id) != 1) {
2499 return SIP_PUBLISH_UNKNOWN;
2503 *expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
2506 return SIP_PUBLISH_REMOVE;
2507 } else if (!etag_hdr && rdata->msg_info.msg->body) {
2508 return SIP_PUBLISH_INITIAL;
2509 } else if (etag_hdr && !rdata->msg_info.msg->body) {
2510 return SIP_PUBLISH_REFRESH;
2511 } else if (etag_hdr && rdata->msg_info.msg->body) {
2512 return SIP_PUBLISH_MODIFY;
2515 return SIP_PUBLISH_UNKNOWN;
2518 /*! \brief Internal destructor for publications */
2519 static void publication_destroy_fn(void *obj)
2521 struct ast_sip_publication *publication = obj;
2523 ast_debug(3, "Destroying SIP publication\n");
2525 ao2_cleanup(publication->datastores);
2526 ao2_cleanup(publication->endpoint);
2529 static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
2530 const char *resource, const char *event_configuration_name)
2532 struct ast_sip_publication *publication;
2533 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
2534 size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
2537 ast_assert(endpoint != NULL);
2539 if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
2543 if (!(publication->datastores = ao2_container_alloc(DATASTORE_BUCKETS, datastore_hash, datastore_cmp))) {
2544 ao2_ref(publication, -1);
2548 publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
2549 ao2_ref(endpoint, +1);
2550 publication->endpoint = endpoint;
2551 publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
2552 publication->sched_id = -1;
2553 dst = publication->data;
2554 publication->resource = strcpy(dst, resource);
2555 dst += resource_len;
2556 publication->event_configuration_name = strcpy(dst, event_configuration_name);
2561 static int sip_publication_respond(struct ast_sip_publication *pub, int status_code,
2562 pjsip_rx_data *rdata)
2565 pjsip_tx_data *tdata;
2566 pjsip_transaction *tsx;
2568 if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, status_code, NULL, &tdata) != PJ_SUCCESS) {
2572 if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
2573 RAII_VAR(char *, entity_tag, NULL, ast_free_ptr);
2574 RAII_VAR(char *, expires, NULL, ast_free_ptr);
2576 if ((ast_asprintf(&entity_tag, "%d", pub->entity_tag) < 0) ||
2577 (ast_asprintf(&expires, "%d", pub->expires) < 0)) {
2578 pjsip_tx_data_dec_ref(tdata);
2582 ast_sip_add_header(tdata, "SIP-ETag", entity_tag);
2583 ast_sip_add_header(tdata, "Expires", expires);
2586 if ((status = pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx)) != PJ_SUCCESS) {
2590 pjsip_tsx_recv_msg(tsx, rdata);
2592 if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
2599 static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
2600 struct ast_sip_publish_handler *handler)
2602 struct ast_sip_publication *publication;
2603 char *resource_name;
2604 size_t resource_size;
2605 RAII_VAR(struct ast_sip_publication_resource *, resource, NULL, ao2_cleanup);
2606 struct ast_variable *event_configuration_name = NULL;
2607 pjsip_uri *request_uri;
2608 pjsip_sip_uri *request_uri_sip;
2611 request_uri = rdata->msg_info.msg->line.req.uri;
2613 if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
2614 char uri_str[PJSIP_MAX_URL_SIZE];
2616 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
2617 ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
2618 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
2622 request_uri_sip = pjsip_uri_get_uri(request_uri);
2623 resource_size = pj_strlen(&request_uri_sip->user) + 1;
2624 resource_name = alloca(resource_size);
2625 ast_copy_pj_str(resource_name, &request_uri_sip->user, resource_size);
2627 resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
2629 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
2633 if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
2634 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
2638 for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
2639 if (!strcmp(event_configuration_name->name, handler->event_name)) {
2644 if (!event_configuration_name) {
2645 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
2649 resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
2651 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
2652 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
2656 publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
2659 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
2663 publication->handler = handler;
2664 if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
2665 AST_SIP_PUBLISH_STATE_INITIALIZED)) {
2666 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
2667 ao2_cleanup(publication);
2671 sip_publication_respond(publication, resp, rdata);
2676 static int publish_expire_callback(void *data)
2678 RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
2680 if (publication->handler->publish_expire) {
2681 publication->handler->publish_expire(publication);
2687 static int publish_expire(const void *data)
2689 struct ast_sip_publication *publication = (struct ast_sip_publication*)data;
2691 ao2_unlink(publication->handler->publications, publication);
2692 publication->sched_id = -1;
2694 if (ast_sip_push_task(NULL, publish_expire_callback, publication)) {
2695 ao2_cleanup(publication);
2701 static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
2703 pjsip_event_hdr *event_header;
2704 struct ast_sip_publish_handler *handler;
2705 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2707 static const pj_str_t str_sip_if_match = { "SIP-If-Match", 12 };
2708 pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
2709 enum sip_publish_type publish_type;
2710 RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
2711 int expires = 0, entity_id, response = 0;
2713 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
2714 ast_assert(endpoint != NULL);
2716 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
2717 if (!event_header) {
2718 ast_log(LOG_WARNING, "Incoming PUBLISH request with no Event header\n");
2719 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
2722 ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
2724 handler = find_pub_handler(event);
2726 ast_log(LOG_WARNING, "No registered publish handler for event %s\n", event);
2727 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
2731 publish_type = determine_sip_publish_type(rdata, etag_hdr, &expires, &entity_id);
2733 /* If this is not an initial publish ensure that a publication is present */
2734 if ((publish_type != SIP_PUBLISH_INITIAL) && (publish_type != SIP_PUBLISH_UNKNOWN)) {
2735 if (!(publication = ao2_find(handler->publications, &entity_id, OBJ_KEY | OBJ_UNLINK))) {
2736 static const pj_str_t str_conditional_request_failed = { "Conditional Request Failed", 26 };
2738 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 412, &str_conditional_request_failed,
2743 /* Per the RFC every response has to have a new entity tag */
2744 publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
2746 /* Update the expires here so that the created responses will contain the correct value */
2747 publication->expires = expires;
2750 switch (publish_type) {
2751 case SIP_PUBLISH_INITIAL:
2752 publication = publish_request_initial(endpoint, rdata, handler);
2754 case SIP_PUBLISH_REFRESH:
2755 case SIP_PUBLISH_MODIFY:
2756 if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
2757 AST_SIP_PUBLISH_STATE_ACTIVE)) {
2758 /* If an error occurs we want to terminate the publication */
2763 case SIP_PUBLISH_REMOVE:
2764 handler->publication_state_change(publication, rdata->msg_info.msg->body,
2765 AST_SIP_PUBLISH_STATE_TERMINATED);
2768 case SIP_PUBLISH_UNKNOWN:
2770 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
2776 ao2_link(handler->publications, publication);
2778 AST_SCHED_REPLACE_UNREF(publication->sched_id, sched, expires * 1000, publish_expire, publication,
2779 ao2_ref(publication, -1), ao2_ref(publication, -1), ao2_ref(publication, +1));
2781 AST_SCHED_DEL_UNREF(sched, publication->sched_id, ao2_ref(publication, -1));
2786 sip_publication_respond(publication, response, rdata);
2792 struct ast_sip_endpoint *ast_sip_publication_get_endpoint(struct ast_sip_publication *pub)
2794 return pub->endpoint;
2797 const char *ast_sip_publication_get_resource(const struct ast_sip_publication *pub)
2799 return pub->resource;
2802 const char *ast_sip_publication_get_event_configuration(const struct ast_sip_publication *pub)
2804 return pub->event_configuration_name;
2807 int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator)
2809 struct ast_sip_pubsub_body_generator *existing;
2811 pj_size_t accept_len;
2813 existing = find_body_generator_type_subtype(generator->type, generator->subtype);
2815 ast_log(LOG_WARNING, "Cannot register body generator of %s/%s."
2816 "One is already registered.\n", generator->type, generator->subtype);
2820 AST_RWLIST_WRLOCK(&body_generators);
2821 AST_LIST_INSERT_HEAD(&body_generators, generator, list);
2822 AST_RWLIST_UNLOCK(&body_generators);
2824 /* Lengths of type and subtype plus space for a slash. pj_str_t is not
2825 * null-terminated, so there is no need to allocate for the extra null
2828 accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
2830 accept.ptr = alloca(accept_len);
2831 accept.slen = accept_len;
2832 /* Safe use of sprintf */
2833 sprintf(accept.ptr, "%s/%s", generator->type, generator->subtype);
2834 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
2835 PJSIP_H_ACCEPT, NULL, 1, &accept);
2840 void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator)
2842 struct ast_sip_pubsub_body_generator *iter;
2843 SCOPED_LOCK(lock, &body_generators, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
2845 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_generators, iter, list) {
2846 if (iter == generator) {
2847 AST_LIST_REMOVE_CURRENT(list);
2851 AST_RWLIST_TRAVERSE_SAFE_END;
2854 int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
2856 AST_RWLIST_WRLOCK(&body_supplements);
2857 AST_RWLIST_INSERT_TAIL(&body_supplements, supplement, list);
2858 AST_RWLIST_UNLOCK(&body_supplements);
2863 void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
2865 struct ast_sip_pubsub_body_supplement *iter;
2866 SCOPED_LOCK(lock, &body_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
2868 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_supplements, iter, list) {
2869 if (iter == supplement) {
2870 AST_LIST_REMOVE_CURRENT(list);
2874 AST_RWLIST_TRAVERSE_SAFE_END;
2877 const char *ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
2879 return sub->body_generator->type;
2882 const char *ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub)
2884 return sub->body_generator->subtype;
2887 int ast_sip_pubsub_generate_body_content(const char *type, const char *subtype,
2888 void *data, struct ast_str **str)
2890 struct ast_sip_pubsub_body_supplement *supplement;
2891 struct ast_sip_pubsub_body_generator *generator;
2895 generator = find_body_generator_type_subtype(type, subtype);
2897 ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
2902 body = generator->allocate_body(data);
2904 ast_log(LOG_WARNING, "Unable to allocate a NOTIFY body of type %s/%s\n",
2909 if (generator->generate_body_content(body, data)) {
2914 AST_RWLIST_RDLOCK(&body_supplements);
2915 AST_RWLIST_TRAVERSE(&body_supplements, supplement, list) {
2916 if (!strcmp(generator->type, supplement->type) &&
2917 !strcmp(generator->subtype, supplement->subtype)) {
2918 res = supplement->supplement_body(body, data);
2924 AST_RWLIST_UNLOCK(&body_supplements);
2927 generator->to_string(body, str);
2931 if (generator->destroy_body) {
2932 generator->destroy_body(body);
2938 static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
2940 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
2941 return pubsub_on_rx_subscribe_request(rdata);
2942 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
2943 return pubsub_on_rx_publish_request(rdata);
2949 static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
2951 struct sip_subscription_tree *sub_tree;
2953 if (pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
2957 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
2962 ao2_cleanup(sub_tree);
2964 pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
2967 static void set_state_terminated(struct ast_sip_subscription *sub)
2971 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2972 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2973 set_state_terminated(AST_VECTOR_GET(&sub->children, i));
2977 static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata,
2978 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
2980 struct sip_subscription_tree *sub_tree;
2982 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
2987 /* If sending a NOTIFY to terminate a subscription, then pubsub_on_evsub_state()
2988 * will be called when we send the NOTIFY, and that will result in dropping the
2989 * refcount of sub_tree by one, and possibly destroying the sub_tree. We need to
2990 * hold a reference to the sub_tree until this function returns so that we don't
2991 * try to read from or write to freed memory by accident
2993 ao2_ref(sub_tree, +1);
2995 if (pjsip_evsub_get_state(evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
2996 set_state_terminated(sub_tree->root);
2999 if (send_notify(sub_tree, 1)) {
3003 if (sub_tree->is_list) {
3004 pj_list_insert_before(res_hdr, create_require_eventlist(rdata->tp_info.pool));
3007 ao2_ref(sub_tree, -1);
3010 static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code,
3011 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
3013 struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3019 sub->handler->subscriber->state_change(sub, rdata->msg_info.msg->body,
3020 pjsip_evsub_get_state(evsub));
3023 static int serialized_pubsub_on_client_refresh(void *userdata)
3025 struct sip_subscription_tree *sub_tree = userdata;
3026 pjsip_tx_data *tdata;
3028 if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
3029 pjsip_evsub_send_request(sub_tree->evsub, tdata);
3031 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3034 ao2_cleanup(sub_tree);
3038 static void pubsub_on_client_refresh(pjsip_evsub *evsub)
3040 struct sip_subscription_tree *sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3042 ao2_ref(sub_tree, +1);
3043 ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_client_refresh, sub_tree);
3046 static int serialized_pubsub_on_server_timeout(void *userdata)
3048 struct sip_subscription_tree *sub_tree = userdata;
3050 set_state_terminated(sub_tree->root);
3051 send_notify(sub_tree, 1);
3053 ao2_cleanup(sub_tree);
3057 static void pubsub_on_server_timeout(pjsip_evsub *evsub)
3059 struct sip_subscription_tree *sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3062 /* if a subscription has been terminated and the subscription
3063 timeout/expires is less than the time it takes for all pending
3064 transactions to end then the subscription timer will not have
3065 been canceled yet and sub will be null, so do nothing since
3066 the subscription has already been terminated. */
3070 ao2_ref(sub_tree, +1);
3071 ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_server_timeout, sub_tree);
3074 static int ami_subscription_detail(struct sip_subscription_tree *sub_tree,
3075 struct ast_sip_ami *ami,
3078 RAII_VAR(struct ast_str *, buf,
3079 ast_sip_create_ami_event(event, ami), ast_free);
3085 sip_subscription_to_ami(sub_tree, &buf);
3086 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
3090 static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
3092 return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
3093 sub_tree, arg, "InboundSubscriptionDetail") : 0;
3096 static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)
3098 return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
3099 sub_tree, arg, "OutboundSubscriptionDetail") : 0;
3102 static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
3104 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
3107 astman_send_listack(s, m, "Following are Events for "
3108 "each inbound Subscription", "start");
3110 num = for_each_subscription(ami_subscription_detail_inbound, &ami);
3112 astman_append(s, "Event: InboundSubscriptionDetailComplete\r\n");
3113 if (!ast_strlen_zero(ami.action_id)) {
3114 astman_append(s, "ActionID: %s\r\n", ami.action_id);
3116 astman_append(s, "EventList: Complete\r\n"
3117 "ListItems: %d\r\n\r\n", num);
3121 static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
3123 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
3126 astman_send_listack(s, m, "Following are Events for "
3127 "each outbound Subscription", "start");
3129 num = for_each_subscription(ami_subscription_detail_outbound, &ami);
3131 astman_append(s, "Event: OutboundSubscriptionDetailComplete\r\n");
3132 if (!ast_strlen_zero(ami.action_id)) {
3133 astman_append(s, "ActionID: %s\r\n", ami.action_id);
3135 astman_append(s, "EventList: Complete\r\n"
3136 "ListItems: %d\r\n\r\n", num);
3140 static int format_ami_resource_lists(void *obj, void *arg, int flags)
3142 struct resource_list *list = obj;
3143 struct ast_sip_ami *ami = arg;
3144 struct ast_str *buf;
3146 buf = ast_sip_create_ami_event("ResourceListDetail", ami);
3151 if (ast_sip_sorcery_object_to_ami(list, &buf)) {
3155 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
3161 static int ami_show_resource_lists(struct mansession *s, const struct message *m)
3163 struct ast_sip_ami ami = { .s = s, .m = m };
3165 struct ao2_container *lists;
3167 lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
3168 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
3170 if (!lists || !(num = ao2_container_count(lists))) {
3171 astman_send_error(s, m, "No resource lists found\n");
3175 astman_send_listack(s, m, "A listing of resource lists follows, "
3176 "presented as ResourceListDetail events", "start");
3178 ao2_callback(lists, OBJ_NODATA, format_ami_resource_lists, &ami);
3181 "Event: ResourceListDetailComplete\r\n"
3182 "EventList: Complete\r\n"
3183 "ListItems: %d\r\n\r\n", num);
3187 #define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
3188 #define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
3190 static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
3192 struct subscription_persistence *persistence = obj;
3194 persistence->endpoint = ast_strdup(var->value);
3198 static int persistence_endpoint_struct2str(const void *obj, const intptr_t *args, char **buf)
3200 const struct subscription_persistence *persistence = obj;
3202 *buf = ast_strdup(persistence->endpoint);
3206 static int persistence_tag_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
3208 struct subscription_persistence *persistence = obj;
3210 persistence->tag = ast_strdup(var->value);
3214 static int persistence_tag_struct2str(const void *obj, const intptr_t *args, char **buf)
3216 const struct subscription_persistence *persistence = obj;
3218 *buf = ast_strdup(persistence->tag);
3222 static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
3224 struct subscription_persistence *persistence = obj;
3225 return ast_get_timeval(var->value, &persistence->expires, ast_tv(0, 0), NULL);
3228 static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
3230 const struct subscription_persistence *persistence = obj;
3231 return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0;
3234 #define RESOURCE_LIST_INIT_SIZE 4
3236 static void resource_list_destructor(void *obj)
3238 struct resource_list *list = obj;
3241 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
3242 ast_free((char *) AST_VECTOR_GET(&list->items, i));
3245 AST_VECTOR_FREE(&list->items);
3248 static void *resource_list_alloc(const char *name)
3250 struct resource_list *list;
3252 list = ast_sorcery_generic_alloc(sizeof(*list), resource_list_destructor);
3257 if (AST_VECTOR_INIT(&list->items, RESOURCE_LIST_INIT_SIZE)) {
3265 static int item_in_vector(const struct resource_list *list, const char *item)
3269 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
3270 if (!strcmp(item, AST_VECTOR_GET(&list->items, i))) {
3278 static int list_item_handler(const struct aco_option *opt,
3279 struct ast_variable *var, void *obj)
3281 struct resource_list *list = obj;
3282 char *items = ast_strdupa(var->value);
3285 while ((item = strsep(&items, ","))) {
3286 if (item_in_vector(list, item)) {
3287 ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);