Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
res_pjsip_pubsub.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Mark Michelson <mmichelson@digium.com>
7 *
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.
13 *
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.
17 */
18/*!
19 * \brief Opaque structure representing an RFC 3265 SIP subscription
20 */
21
22/*** MODULEINFO
23 <depend>pjproject</depend>
24 <depend>res_pjsip</depend>
25 <support_level>core</support_level>
26 ***/
27
28#include "asterisk.h"
29
30#include <pjsip.h>
31#include <pjsip_simple.h>
32#include <pjlib.h>
33
34#include "asterisk/mwi.h"
36#include "asterisk/module.h"
38#include "asterisk/astobj2.h"
39#include "asterisk/datastore.h"
40#include "asterisk/uuid.h"
42#include "asterisk/sched.h"
43#include "asterisk/res_pjsip.h"
44#include "asterisk/callerid.h"
45#include "asterisk/manager.h"
46#include "asterisk/cli.h"
47#include "asterisk/test.h"
50
51/*** DOCUMENTATION
52 <manager name="PJSIPShowSubscriptionsInbound" language="en_US">
53 <synopsis>
54 Lists subscriptions.
55 </synopsis>
56 <syntax />
57 <description>
58 <para>
59 Provides a listing of all inbound subscriptions. An event <literal>InboundSubscriptionDetail</literal>
60 is issued for each subscription object. Once all detail events are completed an
61 <literal>InboundSubscriptionDetailComplete</literal> event is issued.
62 </para>
63 </description>
64 </manager>
65 <manager name="PJSIPShowSubscriptionsOutbound" language="en_US">
66 <synopsis>
67 Lists subscriptions.
68 </synopsis>
69 <syntax />
70 <description>
71 <para>
72 Provides a listing of all outbound subscriptions. An event <literal>OutboundSubscriptionDetail</literal>
73 is issued for each subscription object. Once all detail events are completed an
74 <literal>OutboundSubscriptionDetailComplete</literal> event is issued.
75 </para>
76 </description>
77 </manager>
78 <manager name="PJSIPShowResourceLists" language="en_US">
79 <synopsis>
80 Displays settings for configured resource lists.
81 </synopsis>
82 <syntax />
83 <description>
84 <para>
85 Provides a listing of all resource lists. An event <literal>ResourceListDetail</literal>
86 is issued for each resource list object. Once all detail events are completed a
87 <literal>ResourceListDetailComplete</literal> event is issued.
88 </para>
89 </description>
90 </manager>
91
92 <configInfo name="res_pjsip_pubsub" language="en_US">
93 <synopsis>Module that implements publish and subscribe support.</synopsis>
94 <configFile name="pjsip.conf">
95 <configObject name="subscription_persistence">
96 <synopsis>Persists SIP subscriptions so they survive restarts.</synopsis>
97 <configOption name="packet">
98 <synopsis>Entire SIP SUBSCRIBE packet that created the subscription</synopsis>
99 </configOption>
100 <configOption name="src_name">
101 <synopsis>The source address of the subscription</synopsis>
102 </configOption>
103 <configOption name="src_port">
104 <synopsis>The source port of the subscription</synopsis>
105 </configOption>
106 <configOption name="transport_key">
107 <synopsis>The type of transport the subscription was received on</synopsis>
108 </configOption>
109 <configOption name="local_name">
110 <synopsis>The local address the subscription was received on</synopsis>
111 </configOption>
112 <configOption name="local_port">
113 <synopsis>The local port the subscription was received on</synopsis>
114 </configOption>
115 <configOption name="cseq">
116 <synopsis>The sequence number of the next NOTIFY to be sent</synopsis>
117 </configOption>
118 <configOption name="tag">
119 <synopsis>The local tag of the dialog for the subscription</synopsis>
120 </configOption>
121 <configOption name="endpoint">
122 <synopsis>The name of the endpoint that subscribed</synopsis>
123 </configOption>
124 <configOption name="expires">
125 <synopsis>The time at which the subscription expires</synopsis>
126 </configOption>
127 <configOption name="contact_uri">
128 <synopsis>The Contact URI of the dialog for the subscription</synopsis>
129 </configOption>
130 <configOption name="prune_on_boot">
131 <synopsis>If set, indicates that the contact used a reliable transport
132 and therefore the subscription must be deleted after an asterisk restart.
133 </synopsis>
134 </configOption>
135 <configOption name="generator_data">
136 <synopsis>If set, contains persistence data for all generators of content
137 for the subscription.
138 </synopsis>
139 </configOption>
140 </configObject>
141 <configObject name="resource_list">
142 <synopsis>Resource list configuration parameters.</synopsis>
143 <description>
144 <para>This configuration object allows for RFC 4662 resource list subscriptions
145 to be specified. This can be useful to decrease the amount of subscription traffic
146 that a server has to process.</para>
147 <note>
148 <para>Current limitations limit the size of SIP NOTIFY requests that Asterisk sends
149 to double that of the PJSIP maximum packet length. If your resource list notifications
150 are larger than this maximum, you will need to make adjustments.</para>
151 </note>
152 </description>
153 <configOption name="type">
154 <synopsis>Must be of type 'resource_list'</synopsis>
155 </configOption>
156 <configOption name="event">
157 <synopsis>The SIP event package that the list resource belong to.</synopsis>
158 <description><para>
159 The SIP event package describes the types of resources that Asterisk reports
160 the state of.
161 </para>
162 <enumlist>
163 <enum name="presence"><para>
164 Device state and presence reporting.
165 </para></enum>
166 <enum name="dialog"><para>
167 This is identical to <replaceable>presence</replaceable>.
168 </para></enum>
169 <enum name="message-summary"><para>
170 Message-waiting indication (MWI) reporting.
171 </para></enum>
172 </enumlist>
173 </description>
174 </configOption>
175 <configOption name="list_item">
176 <synopsis>The name of a resource to report state on</synopsis>
177 <description>
178 <para>In general Asterisk looks up list items in the following way:</para>
179 <para>1. Check if the list item refers to another configured resource list.</para>
180 <para>2. Pass the name of the resource off to event-package-specific handlers
181 to find the specified resource.</para>
182 <para>The second part means that the way the list item is specified depends
183 on what type of list this is. For instance, if you have the <replaceable>event</replaceable>
184 set to <literal>presence</literal>, then list items should be in the form of
185 dialplan_extension@dialplan_context. For <literal>message-summary</literal> mailbox
186 names should be listed.</para>
187 </description>
188 </configOption>
189 <configOption name="full_state" default="no">
190 <synopsis>Indicates if the entire list's state should be sent out.</synopsis>
191 <description>
192 <para>If this option is enabled, and a resource changes state, then Asterisk will construct
193 a notification that contains the state of all resources in the list. If the option is
194 disabled, Asterisk will construct a notification that only contains the states of
195 resources that have changed.</para>
196 <note>
197 <para>Even with this option disabled, there are certain situations where Asterisk is forced
198 to send a notification with the states of all resources in the list. When a subscriber
199 renews or terminates its subscription to the list, Asterisk MUST send a full state
200 notification.</para>
201 </note>
202 </description>
203 </configOption>
204 <configOption name="notification_batch_interval" default="0">
205 <synopsis>Time Asterisk should wait, in milliseconds, before sending notifications.</synopsis>
206 <description>
207 <para>When a resource's state changes, it may be desired to wait a certain amount before Asterisk
208 sends a notification to subscribers. This allows for other state changes to accumulate, so that
209 Asterisk can communicate multiple state changes in a single notification instead of rapidly sending
210 many notifications.</para>
211 </description>
212 </configOption>
213 <configOption name="resource_display_name" default="no">
214 <synopsis>Indicates whether display name of resource or the resource name being reported.</synopsis>
215 <description>
216 <para>If this option is enabled, the Display Name will be reported as resource name.
217 If the <replaceable>event</replaceable> set to <literal>presence</literal> or <literal>dialog</literal>,
218 the non-empty HINT name will be set as the Display Name.
219 The <literal>message-summary</literal> is not supported yet.</para>
220 </description>
221 </configOption>
222 </configObject>
223 <configObject name="inbound-publication">
224 <synopsis>The configuration for inbound publications</synopsis>
225 <configOption name="endpoint" default="">
226 <synopsis>Optional name of an endpoint that is only allowed to publish to this resource</synopsis>
227 </configOption>
228 <configOption name="type">
229 <synopsis>Must be of type 'inbound-publication'.</synopsis>
230 </configOption>
231 </configObject>
232 </configFile>
233 </configInfo>
234 ***/
235
236static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata);
237
238static struct pjsip_module pubsub_module = {
239 .name = { "PubSub Module", 13 },
240 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
241 .on_rx_request = pubsub_on_rx_request,
242};
243
244#define MOD_DATA_PERSISTENCE "sub_persistence"
245#define MOD_DATA_MSG "sub_msg"
246
247static const pj_str_t str_event_name = { "Event", 5 };
248
249/*! \brief Scheduler used for automatically expiring publications */
251
252/*! \brief Number of buckets for publications (on a per handler) */
253#define PUBLICATIONS_BUCKETS 37
254
255/*! \brief Default expiration time for PUBLISH if one is not specified */
256#define DEFAULT_PUBLISH_EXPIRES 3600
257
258/*! \brief Number of buckets for subscription datastore */
259#define DATASTORE_BUCKETS 53
260
261/*! \brief Default expiration for subscriptions */
262#define DEFAULT_EXPIRES 3600
263
264/*! \brief Defined method for PUBLISH */
265const pjsip_method pjsip_publish_method =
266{
267 PJSIP_OTHER_METHOD,
268 { "PUBLISH", 7 }
269};
270
271/*!
272 * \brief The types of PUBLISH messages defined in RFC 3903
273 */
275 /*!
276 * \brief Unknown
277 *
278 * \details
279 * This actually is not defined in RFC 3903. We use this as a constant
280 * to indicate that an incoming PUBLISH does not fit into any of the
281 * other categories and is thus invalid.
282 */
284
285 /*!
286 * \brief Initial
287 *
288 * \details
289 * The first PUBLISH sent. This will contain a non-zero Expires header
290 * as well as a body that indicates the current state of the endpoint
291 * that has sent the message. The initial PUBLISH is the only type
292 * of PUBLISH to not contain a Sip-If-Match header in it.
293 */
295
296 /*!
297 * \brief Refresh
298 *
299 * \details
300 * Used to keep a published state from expiring. This will contain a
301 * non-zero Expires header but no body since its purpose is not to
302 * update state.
303 */
305
306 /*!
307 * \brief Modify
308 *
309 * \details
310 * Used to change state from its previous value. This will contain
311 * a body updating the published state. May or may not contain an
312 * Expires header.
313 */
315
316 /*!
317 * \brief Remove
318 *
319 * \details
320 * Used to remove published state from an ESC. This will contain
321 * an Expires header set to 0 and likely no body.
322 */
324};
325
326/*!
327 * \brief A vector of strings commonly used throughout this module
328 */
329AST_VECTOR(resources, const char *);
330
331/*!
332 * \brief Resource list configuration item
333 */
336 /*! SIP event package the list uses. */
337 char event[32];
338 /*! Strings representing resources in the list. */
340 /*! Indicates if Asterisk sends full or partial state on notifications. */
341 unsigned int full_state;
342 /*! Time, in milliseconds Asterisk waits before sending a batched notification.*/
344 /*! Indicates whether display name of resource or the resource name being reported.*/
346};
347
348/*!
349 * Used to create new entity IDs by ESCs.
350 */
352
353/*!
354 * \brief Structure representing a SIP publication
355 */
357 /*! Publication datastores set up by handlers */
359 /*! \brief Entity tag for the publication */
361 /*! \brief Handler for this publication */
363 /*! \brief The endpoint with which the subscription is communicating */
365 /*! \brief Expiration time of the publication */
366 unsigned int expires;
367 /*! \brief Scheduled item for expiration of publication */
369 /*! \brief The resource the publication is to */
370 char *resource;
371 /*! \brief The name of the event type configuration */
373 /*! \brief Data containing the above */
374 char data[0];
375};
376
377
378/*!
379 * \brief Structure used for persisting an inbound subscription
380 */
382 /*! Sorcery object details */
384 /*! The name of the endpoint involved in the subscription */
385 char *endpoint;
386 /*! SIP message that creates the subscription */
387 char packet[PJSIP_MAX_PKT_LEN];
388 /*! Source address of the message */
389 char src_name[PJ_INET6_ADDRSTRLEN];
390 /*! Source port of the message */
392 /*! Local transport type (UDP,TCP,TLS)*/
394 /*! Local transport address */
395 char local_name[PJ_INET6_ADDRSTRLEN];
396 /*! Local transport port */
398 /*! Next CSeq to use for message */
399 unsigned int cseq;
400 /*! Local tag of the dialog */
401 char *tag;
402 /*! When this subscription expires */
403 struct timeval expires;
404 /*! Contact URI */
405 char contact_uri[PJSIP_MAX_URL_SIZE];
406 /*! Prune subscription on restart */
408 /*! Body generator specific persistence data */
410};
411
412/*!
413 * \brief The state of the subscription tree
414 */
416 /*! Normal operation */
418 /*! A terminate has been requested by Asterisk, the client, or pjproject */
420 /*! The terminate is in progress */
422 /*! The terminate process has finished and the subscription tree is no longer valid */
424};
425
427 "Normal",
428 "TerminatePending",
429 "TerminateInProgress",
430 "Terminated"
431};
432
433/*!
434 * \brief A tree of SIP subscriptions
435 *
436 * Because of the ability to subscribe to resource lists, a SIP
437 * subscription can result in a tree of subscriptions being created.
438 * This structure represents the information relevant to the subscription
439 * as a whole, to include the underlying PJSIP structure for the
440 * subscription.
441 */
443 /*! The endpoint with which the subscription is communicating */
445 /*! Serializer on which to place operations for this subscription */
447 /*! The role for this subscription */
449 /*! Persistence information */
451 /*! The underlying PJSIP event subscription structure */
452 pjsip_evsub *evsub;
453 /*! The underlying PJSIP dialog */
454 pjsip_dialog *dlg;
455 /*! Interval to use for batching notifications */
457 /*! Scheduler ID for batched notification */
459 /*! Indicator if scheduled batched notification should be sent */
461 /*! The root of the subscription tree */
463 /*! Is this subscription to a list? */
465 /*! Next item in the list */
467 /*! Subscription tree state */
469 /*! On asterisk restart, this is the task data used
470 * to restart the expiration timer if pjproject isn't
471 * capable of restarting the timer.
472 */
474 /*! The transport the subscription was received on.
475 * Only used for reliable transports.
476 */
478 /*! Indicator if initial notify should be generated.
479 * Used to refresh modified RLS.
480 */
482};
483
484/*!
485 * \brief Structure representing a "virtual" SIP subscription.
486 *
487 * This structure serves a dual purpose. Structurally, it is
488 * the constructed tree of subscriptions based on the resources
489 * being subscribed to. API-wise, this serves as the handle that
490 * subscription handlers use in order to interact with the pubsub API.
491 */
493 /*! Subscription datastores set up by handlers */
495 /*! The handler for this subscription */
497 /*! Pointer to the base of the tree */
499 /*! Body generator for NOTIFYs */
501 /*! Vector of child subscriptions */
503 /*! Saved NOTIFY body text for this subscription */
505 /*! Indicator that the body text has changed since the last notification */
507 /*! The current state of the subscription */
508 pjsip_evsub_state subscription_state;
509 /*! For lists, the current version to place in the RLMI body */
510 unsigned int version;
511 /*! For lists, indicates if full state should always be communicated. */
512 unsigned int full_state;
513 /*! URI associated with the subscription */
514 pjsip_sip_uri *uri;
515 /*! Data to be persisted with the subscription */
517 /*! Display Name of resource */
519 /*! Name of resource being subscribed to */
520 char resource[0];
521};
522
523/*!
524 * \brief Structure representing a publication resource
525 */
527 /*! \brief Sorcery object details */
529 /*! \brief Optional name of an endpoint that is only allowed to publish to this resource */
530 char *endpoint;
531 /*! \brief Mapping for event types to configuration */
533};
534
535static const char *sip_subscription_roles_map[] = {
536 [AST_SIP_SUBSCRIBER] = "Subscriber",
537 [AST_SIP_NOTIFIER] = "Notifier"
538};
539
541 /*! Called from send request */
543 /*! Subscription created from initial client request */
545 /*! Subscription recreated by asterisk on startup */
547 /*! Subscription created from client refresh */
549};
550
552
555
556static pjsip_media_type rlmi_media_type;
557
558static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event);
559static void pubsub_on_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata,
560 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
561static void pubsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
562 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
563static void pubsub_on_client_refresh(pjsip_evsub *sub);
564static void pubsub_on_server_timeout(pjsip_evsub *sub);
565
566static pjsip_evsub_user pubsub_cb = {
567 .on_evsub_state = pubsub_on_evsub_state,
568 .on_rx_refresh = pubsub_on_rx_refresh,
569 .on_rx_notify = pubsub_on_rx_notify,
570 .on_client_refresh = pubsub_on_client_refresh,
571 .on_server_timeout = pubsub_on_server_timeout,
572};
573
574/*! \brief Destructor for publication resource */
575static void publication_resource_destroy(void *obj)
576{
577 struct ast_sip_publication_resource *resource = obj;
578
579 ast_free(resource->endpoint);
580 ast_variables_destroy(resource->events);
581}
582
583/*! \brief Allocator for publication resource */
584static void *publication_resource_alloc(const char *name)
585{
587}
588
590{
591 struct sip_subscription_tree *sub_tree = data;
592
593 if (!sub_tree->evsub) {
594 /* Something else already terminated the subscription. */
595 ao2_ref(sub_tree, -1);
596 return 0;
597 }
598
599 ast_debug(3, "Transport destroyed. Removing subscription '%s->%s' prune on boot: %d\n",
600 sub_tree->persistence->endpoint, sub_tree->root->resource,
601 sub_tree->persistence->prune_on_boot);
602
604 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
605
606 ao2_ref(sub_tree, -1);
607 return 0;
608}
609
610/*!
611 * \internal
612 * \brief The reliable transport we used as a subscription contact has shutdown.
613 *
614 * \param data What subscription needs to be terminated.
615 *
616 * \note Normally executed by the pjsip monitor thread.
617 */
618static void sub_tree_transport_cb(void *data)
619{
620 struct sip_subscription_tree *sub_tree = data;
621
622 /*
623 * Push off the subscription termination to the serializer to
624 * avoid deadlock. Another thread could be trying to send a
625 * message on the subscription that can deadlock with this
626 * thread.
627 */
628 ao2_ref(sub_tree, +1);
630 sub_tree)) {
631 ao2_ref(sub_tree, -1);
632 }
633}
634
635/*! \brief Destructor for subscription persistence */
637{
638 struct subscription_persistence *persistence = obj;
639
640 ast_free(persistence->endpoint);
641 ast_free(persistence->tag);
642 ast_json_unref(persistence->generator_data);
643}
644
645/*! \brief Allocator for subscription persistence */
646static void *subscription_persistence_alloc(const char *name)
647{
649}
650
651/*! \brief Function which creates initial persistence information of a subscription in sorcery */
653{
654 char tag[PJ_GUID_STRING_LENGTH + 1];
655
656 /* The id of this persistence object doesn't matter as we keep it on the subscription and don't need to
657 * look it up by id at all.
658 */
660 "subscription_persistence", NULL);
661
662 pjsip_dialog *dlg = sub_tree->dlg;
663
664 if (!persistence) {
665 return NULL;
666 }
667
668 persistence->endpoint = ast_strdup(ast_sorcery_object_get_id(sub_tree->endpoint));
669 ast_copy_pj_str(tag, &dlg->local.info->tag, sizeof(tag));
670 persistence->tag = ast_strdup(tag);
671
673 return persistence;
674}
675
676/*! \brief Function which updates persistence information of a subscription in sorcery */
678 pjsip_rx_data *rdata, enum sip_persistence_update_type type)
679{
680 pjsip_dialog *dlg;
681
682 if (!sub_tree->persistence) {
683 return;
684 }
685
686 ast_debug(3, "Updating persistence for '%s->%s' prune on boot: %s\n",
687 sub_tree->persistence->endpoint, sub_tree->root->resource,
688 sub_tree->persistence->prune_on_boot ? "yes" : "no");
689
690 dlg = sub_tree->dlg;
691 sub_tree->persistence->cseq = dlg->local.cseq;
692
693 if (rdata) {
694 unsigned int expires;
695 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
696 pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
697
698 expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
700
701 if (contact_hdr) {
702 if (contact_hdr) {
704 sub_tree->persistence->prune_on_boot =
706 (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
707 sub_tree->endpoint, rdata);
708
709 if (sub_tree->persistence->prune_on_boot) {
710 ast_debug(3, "adding transport monitor on %s for '%s->%s' prune on boot: %d\n",
711 rdata->tp_info.transport->obj_name,
712 sub_tree->persistence->endpoint, sub_tree->root->resource,
713 sub_tree->persistence->prune_on_boot);
714 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(rdata->tp_info.transport,
715 sub_tree->transport_key);
717 sub_tree_transport_cb, sub_tree);
718 /*
719 * FYI: ast_sip_transport_monitor_register holds a reference to the sub_tree
720 */
721 }
722 }
723 }
724
725 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
726 sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri));
727 } else {
728 ast_log(LOG_WARNING, "Contact not updated due to missing contact header\n");
729 }
730
731 /* When receiving a packet on an streaming transport, it's possible to receive more than one SIP
732 * message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf
733 * will always point to the proper SIP message that is to be processed. When updating subscription
734 * persistence that is pulled from persistent storage, though, the rdata->pkt_info.packet will
735 * only ever have a single SIP message on it, and so we base persistence on that.
736 */
739 if (rdata->msg_info.msg_buf) {
740 ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf,
741 MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len + 1));
742 } else {
743 ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
744 sizeof(sub_tree->persistence->packet));
745 }
746 }
747 ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
748 sizeof(sub_tree->persistence->src_name));
749 sub_tree->persistence->src_port = rdata->pkt_info.src_port;
750 ast_copy_string(sub_tree->persistence->transport_type, rdata->tp_info.transport->type_name,
751 sizeof(sub_tree->persistence->transport_type));
752 ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host,
753 sizeof(sub_tree->persistence->local_name));
754 sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port;
755 }
756
758}
759
760/*! \brief Function which removes persistence of a subscription from sorcery */
762{
763 if (!sub_tree->persistence) {
764 return;
765 }
766
767 if (sub_tree->persistence->prune_on_boot && !ast_strlen_zero(sub_tree->transport_key)) {
768 ast_debug(3, "Unregistering transport monitor on %s '%s->%s'\n",
769 sub_tree->transport_key,
770 sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
771 sub_tree->root ? sub_tree->root->resource : "Unknown");
773 sub_tree_transport_cb, sub_tree, NULL);
774 }
775
777 ao2_ref(sub_tree->persistence, -1);
778 sub_tree->persistence = NULL;
779}
780
781
784 size_t num_accept, const char *body_type);
785
786/*! \brief Retrieve a handler using the Event header of an rdata message */
787static struct ast_sip_subscription_handler *subscription_get_handler_from_rdata(pjsip_rx_data *rdata, const char *endpoint)
788{
789 pjsip_event_hdr *event_header;
790 char event[32];
792
793 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
794 if (!event_header) {
795 ast_log(LOG_WARNING, "Incoming SUBSCRIBE request from %s with no Event header\n",
796 endpoint ? endpoint : "Unknown");
797 return NULL;
798 }
799 ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
800
802 if (!handler) {
803 ast_log(LOG_WARNING, "No registered subscribe handler for event %s from %s\n", event,
804 endpoint ? endpoint : "Unknown");
805 }
806
807 return handler;
808}
809
810/*!
811 * \brief Accept headers that are exceptions to the rule
812 *
813 * Typically, when a SUBSCRIBE arrives, we attempt to find a
814 * body generator that matches one of the Accept headers in
815 * the request. When subscribing to a single resource, this works
816 * great. However, when subscribing to a list, things work
817 * differently. Most Accept header values are fine, but there
818 * are a couple that are endemic to resource lists that need
819 * to be ignored when searching for a body generator to use
820 * for the individual resources of the subscription.
821 */
822const char *accept_exceptions[] = {
823 "multipart/related",
824 "application/rlmi+xml",
825};
826
827/*!
828 * \brief Is the Accept header from the SUBSCRIBE in the list of exceptions?
829 *
830 * \retval 1 This Accept header value is an exception to the rule.
831 * \retval 0 This Accept header is not an exception to the rule.
832 */
833static int exceptional_accept(const pj_str_t *accept)
834{
835 int i;
836
837 for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
838 if (!pj_strcmp2(accept, accept_exceptions[i])) {
839 return 1;
840 }
841 }
842
843 return 0;
844}
845
846/*! \brief Retrieve a body generator using the Accept header of an rdata message */
849{
850 pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
851 char accept[AST_SIP_MAX_ACCEPT][64];
852 size_t num_accept_headers = 0;
853
854 while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
855 (num_accept_headers < AST_SIP_MAX_ACCEPT)) {
856 int i;
857
858 for (i = 0; i < accept_header->count && num_accept_headers < AST_SIP_MAX_ACCEPT; ++i) {
859 if (!exceptional_accept(&accept_header->values[i])) {
860 ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
861 ++num_accept_headers;
862 }
863 }
864 }
865
866 if (num_accept_headers == 0) {
867 /* If a SUBSCRIBE contains no Accept headers, then we must assume that
868 * the default accept type for the event package is to be used.
869 */
870 ast_copy_string(accept[0], handler->notifier->default_accept, sizeof(accept[0]));
871 num_accept_headers = 1;
872 }
873
874 return find_body_generator(accept, num_accept_headers, handler->body_type);
875}
876
877/*! \brief Check if the rdata has a Supported header containing 'eventlist'
878 *
879 * \retval 1 rdata has an eventlist containing supported header
880 * \retval 0 rdata doesn't have an eventlist containing supported header
881 */
882static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
883{
884 pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
885
886 while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
887 int i;
888
889 for (i = 0; i < supported_header->count; i++) {
890 if (!pj_stricmp2(&supported_header->values[i], "eventlist")) {
891 return 1;
892 }
893 }
894 }
895
896 return 0;
897}
898
899struct resource_tree;
900
901/*!
902 * \brief A node for a resource tree.
903 */
904struct tree_node {
906 unsigned int full_state;
908 char resource[0];
909};
910
911/*!
912 * \brief Helper function for retrieving a resource list for a given event.
913 *
914 * This will retrieve a resource list that corresponds to the resource and event provided.
915 *
916 * \param resource The name of the resource list to retrieve
917 * \param event The expected event name on the resource list
918 */
919static struct resource_list *retrieve_resource_list(const char *resource, const char *event)
920{
921 struct resource_list *list;
922
923 list = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
924 if (!list) {
925 return NULL;
926 }
927
928 if (strcmp(list->event, event)) {
929 ast_log(LOG_WARNING, "Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
930 resource, list->event, event);
931 ao2_cleanup(list);
932 return NULL;
933 }
934
935 return list;
936}
937
938/*!
939 * \brief Allocate a tree node
940 *
941 * In addition to allocating and initializing the tree node, the node is also added
942 * to the vector of visited resources. See \ref build_resource_tree for more information
943 * on the visited resources.
944 *
945 * \param resource The name of the resource for this tree node.
946 * \param visited The vector of resources that have been visited.
947 * \param full_state if allocating a list, indicate whether full state is requested in notifications.
948 * \param display_name the display name to include with this tree node.
949 *
950 * \retval NULL Allocation failure.
951 * \retval non-NULL The newly-allocated tree_node
952 */
953static struct tree_node *tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state, const char *display_name)
954{
955 struct tree_node *node;
956
957 node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
958 if (!node) {
959 return NULL;
960 }
961
962 strcpy(node->resource, resource);
963 if (AST_VECTOR_INIT(&node->children, 4)) {
964 ast_free(node);
965 return NULL;
966 }
967 node->full_state = full_state;
968 node->display_name = ast_strdup(display_name);
969
970 if (visited) {
971 AST_VECTOR_APPEND(visited, resource);
972 }
973 return node;
974}
975
976/*!
977 * \brief Destructor for a tree node
978 *
979 * This function calls recursively in order to destroy
980 * all nodes lower in the tree from the given node in
981 * addition to the node itself.
982 *
983 * \param node The node to destroy.
984 */
985static void tree_node_destroy(struct tree_node *node)
986{
987 int i;
988 if (!node) {
989 return;
990 }
991
992 for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
993 tree_node_destroy(AST_VECTOR_GET(&node->children, i));
994 }
995 AST_VECTOR_FREE(&node->children);
996 ast_free(node->display_name);
997 ast_free(node);
998}
999
1000/*!
1001 * \brief Determine if this resource has been visited already
1002 *
1003 * See \ref build_resource_tree for more information
1004 *
1005 * \param resource The resource currently being visited
1006 * \param visited The resources that have previously been visited
1007 */
1008static int have_visited(const char *resource, struct resources *visited)
1009{
1010 int i;
1011
1012 for (i = 0; i < AST_VECTOR_SIZE(visited); ++i) {
1013 if (!strcmp(resource, AST_VECTOR_GET(visited, i))) {
1014 return 1;
1015 }
1016 }
1017
1018 return 0;
1019}
1020
1021#define NEW_SUBSCRIBE(notifier, endpoint, resource, rdata) notifier->new_subscribe_with_rdata ? notifier->new_subscribe_with_rdata(endpoint, resource, rdata) : notifier->new_subscribe(endpoint, resource)
1022
1023/*!
1024 * \brief Build child nodes for a given parent.
1025 *
1026 * This iterates through the items on a resource list and creates tree nodes for each one. The
1027 * tree nodes created are children of the supplied parent node. If an item in the resource
1028 * list is itself a list, then this function is called recursively to provide children for
1029 * the new node.
1030 *
1031 * If an item in a resource list is not a list, then the supplied subscription handler is
1032 * called into as if a new SUBSCRIBE for the list item were presented. The handler's response
1033 * is used to determine if the node can be added to the tree or not.
1034 *
1035 * If a parent node ends up having no child nodes added under it, then the parent node is
1036 * pruned from the tree.
1037 *
1038 * \param endpoint The endpoint that sent the inbound SUBSCRIBE.
1039 * \param handler The subscription handler for leaf nodes in the tree.
1040 * \param list The configured resource list from which the child node is being built.
1041 * \param parent The parent node for these children.
1042 * \param visited The resources that have already been visited.
1043 */
1045 struct resource_list *list, struct tree_node *parent, struct resources *visited, pjsip_rx_data *rdata)
1046{
1047 int i;
1048
1049 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
1050 struct tree_node *current;
1051 struct resource_list *child_list;
1052 const char *resource = AST_VECTOR_GET(&list->items, i);
1053
1054 if (have_visited(resource, visited)) {
1055 ast_debug(1, "Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1056 continue;
1057 }
1058
1059 child_list = retrieve_resource_list(resource, list->event);
1060 if (!child_list) {
1061 int resp = NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
1062 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1063 char display_name[AST_MAX_EXTENSION] = "";
1064 if (list->resource_display_name && handler->notifier->get_resource_display_name) {
1065 handler->notifier->get_resource_display_name(endpoint, resource, display_name, sizeof(display_name));
1066 }
1067 current = tree_node_alloc(resource, visited, 0, ast_strlen_zero(display_name) ? NULL : display_name);
1068 if (!current) {
1069 ast_debug(1,
1070 "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1071 resource);
1072 continue;
1073 }
1074 ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1075 resource, parent->resource);
1076 if (AST_VECTOR_APPEND(&parent->children, current)) {
1078 }
1079 } else {
1080 ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n",
1081 resource, resp);
1082 }
1083 } else {
1084 ast_debug(2, "Resource %s (child of %s) is a list\n", resource, parent->resource);
1085 current = tree_node_alloc(resource, visited, child_list->full_state, NULL);
1086 if (!current) {
1087 ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
1088 continue;
1089 }
1090 build_node_children(endpoint, handler, child_list, current, visited, rdata);
1091 if (AST_VECTOR_SIZE(&current->children) > 0) {
1092 ast_debug(1, "List %s had no successful children.\n", resource);
1093 if (AST_VECTOR_APPEND(&parent->children, current)) {
1095 }
1096 } else {
1097 ast_debug(2, "List %s had successful children. Adding to parent %s\n",
1098 resource, parent->resource);
1100 }
1101 ao2_cleanup(child_list);
1102 }
1103 }
1104}
1105
1106/*!
1107 * \brief A resource tree
1108 *
1109 * When an inbound SUBSCRIBE arrives, the resource being subscribed to may
1110 * be a resource list. If this is the case, the resource list may contain resources
1111 * that are themselves lists. The structure needed to hold the resources is
1112 * a tree.
1113 *
1114 * Upon receipt of the SUBSCRIBE, the tree is built by determining if subscriptions
1115 * to the individual resources in the tree would be successful or not. Any successful
1116 * subscriptions result in a node in the tree being created. Any unsuccessful subscriptions
1117 * result in no node being created.
1118 *
1119 * This tree can be seen as a bare-bones analog of the tree of ast_sip_subscriptions that
1120 * will end up being created to actually carry out the duties of a SIP SUBSCRIBE dialog.
1121 */
1125};
1126
1127/*!
1128 * \brief Destroy a resource tree.
1129 *
1130 * This function makes no assumptions about how the tree itself was
1131 * allocated and does not attempt to free the tree itself. Callers
1132 * of this function are responsible for freeing the tree.
1133 *
1134 * \param tree The tree to destroy.
1135 */
1136static void resource_tree_destroy(struct resource_tree *tree)
1137{
1138 if (tree) {
1139 tree_node_destroy(tree->root);
1140 }
1141}
1142
1143/*!
1144 * \brief Build a resource tree
1145 *
1146 * This function builds a resource tree based on the requested resource in a SUBSCRIBE request.
1147 *
1148 * This function also creates a container that has all resources that have been visited during
1149 * creation of the tree, whether those resources resulted in a tree node being created or not.
1150 * Keeping this container of visited resources allows for misconfigurations such as loops in
1151 * the tree or duplicated resources to be detected.
1152 *
1153 * \param endpoint The endpoint that sent the SUBSCRIBE request.
1154 * \param handler The subscription handler for leaf nodes in the tree.
1155 * \param resource The resource requested in the SUBSCRIBE request.
1156 * \param tree The tree that is to be built.
1157 * \param has_eventlist_support
1158 *
1159 * \retval 200-299 Successfully subscribed to at least one resource.
1160 * \retval 300-699 Failure to subscribe to requested resource.
1161 */
1163 const char *resource, struct resource_tree *tree, int has_eventlist_support, pjsip_rx_data *rdata)
1164{
1165 RAII_VAR(struct resource_list *, list, NULL, ao2_cleanup);
1166 struct resources visited;
1167
1168 int not_eventlist_but_needs_children = !strcmp(handler->body_type, AST_SIP_DEVICE_FEATURE_SYNC_DATA);
1169
1170 if ((!has_eventlist_support && !not_eventlist_but_needs_children) || !(list = retrieve_resource_list(resource, handler->event_name))) {
1171 ast_debug(2, "Subscription '%s->%s' is not to a list\n",
1172 ast_sorcery_object_get_id(endpoint), resource);
1173 tree->root = tree_node_alloc(resource, NULL, 0, NULL);
1174 if (!tree->root) {
1175 return 500;
1176 }
1177 return NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
1178 }
1179
1180 ast_debug(2, "Subscription '%s->%s' is a list\n",
1181 ast_sorcery_object_get_id(endpoint), resource);
1182 if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
1183 return 500;
1184 }
1185
1186 tree->root = tree_node_alloc(resource, &visited, list->full_state, NULL);
1187 if (!tree->root) {
1188 AST_VECTOR_FREE(&visited);
1189 return 500;
1190 }
1191
1192 tree->notification_batch_interval = list->notification_batch_interval;
1193
1194 build_node_children(endpoint, handler, list, tree->root, &visited, rdata);
1195 AST_VECTOR_FREE(&visited);
1196
1197 if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
1198 return 200;
1199 } else {
1200 return 500;
1201 }
1202}
1203
1205{
1209}
1210
1212{
1213 struct sip_subscription_tree *i;
1214
1217 if (i == obj) {
1219 if (i->root) {
1220 ast_debug(2, "Removing subscription '%s->%s' from list of subscriptions\n",
1222 }
1223 break;
1224 }
1225 }
1228}
1229
1231{
1232 ast_debug(3, "Destroying SIP subscription from '%s->%s'\n",
1233 sub->tree && sub->tree->endpoint ? ast_sorcery_object_get_id(sub->tree->endpoint) : "Unknown",
1234 sub->resource);
1235
1236 ast_free(sub->body_text);
1237
1238 AST_VECTOR_FREE(&sub->children);
1239 ao2_cleanup(sub->datastores);
1240 ast_json_unref(sub->persistence_data);
1241 ast_free(sub->display_name);
1242 ast_free(sub);
1243}
1244
1246{
1247 int i;
1248
1249 if (!root) {
1250 return;
1251 }
1252
1253 for (i = 0; i < AST_VECTOR_SIZE(&root->children); ++i) {
1254 struct ast_sip_subscription *child;
1255
1256 child = AST_VECTOR_GET(&root->children, i);
1257 destroy_subscriptions(child);
1258 }
1259
1261}
1262
1264 const char *resource, const char *display_name, struct sip_subscription_tree *tree)
1265{
1266 struct ast_sip_subscription *sub;
1267 pjsip_msg *msg;
1268 pjsip_sip_uri *request_uri;
1269
1271 if (!msg) {
1272 ast_log(LOG_ERROR, "No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n", resource);
1273 return NULL;
1274 }
1275
1276 sub = ast_calloc(1, sizeof(*sub) + strlen(resource) + 1);
1277 if (!sub) {
1278 return NULL;
1279 }
1280 strcpy(sub->resource, resource); /* Safe */
1281
1282 sub->display_name = ast_strdup(display_name);
1283
1284 sub->datastores = ast_datastores_alloc();
1285 if (!sub->datastores) {
1287 return NULL;
1288 }
1289
1290 sub->body_text = ast_str_create(128);
1291 if (!sub->body_text) {
1293 return NULL;
1294 }
1295
1296 sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
1297 request_uri = pjsip_uri_get_uri(msg->line.req.uri);
1298 pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, request_uri);
1299 pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
1300
1301 /* If there is any persistence information available for this subscription that was persisted
1302 * then make it available so that the NOTIFY has the correct state.
1303 */
1304
1307 }
1308
1309 sub->handler = handler;
1310 sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1311 sub->tree = ao2_bump(tree);
1312
1313 return sub;
1314}
1315
1316/*!
1317 * \brief Create a tree of virtual subscriptions based on a resource tree node.
1318 *
1319 * \param handler The handler to supply to leaf subscriptions.
1320 * \param resource The requested resource for this subscription.
1321 * \param generator Body generator to use for leaf subscriptions.
1322 * \param tree The root of the subscription tree.
1323 * \param current The tree node that corresponds to the subscription being created.
1324 */
1326 const char *resource, struct ast_sip_pubsub_body_generator *generator,
1328{
1329 int i;
1330 struct ast_sip_subscription *sub;
1331
1333 if (!sub) {
1334 return NULL;
1335 }
1336
1337 sub->full_state = current->full_state;
1338 sub->body_generator = generator;
1339 AST_VECTOR_INIT(&sub->children, AST_VECTOR_SIZE(&current->children));
1340
1341 for (i = 0; i < AST_VECTOR_SIZE(&current->children); ++i) {
1342 struct ast_sip_subscription *child;
1343 struct tree_node *child_node = AST_VECTOR_GET(&current->children, i);
1344
1345 child = create_virtual_subscriptions(handler, child_node->resource, generator,
1346 tree, child_node);
1347
1348 if (!child) {
1349 ast_debug(1, "Child subscription to resource %s could not be created\n",
1350 child_node->resource);
1351 continue;
1352 }
1353
1354 if (AST_VECTOR_APPEND(&sub->children, child)) {
1355 ast_debug(1, "Child subscription to resource %s could not be appended\n",
1356 child_node->resource);
1357 destroy_subscription(child);
1358 /* Have to release tree here too because a ref was added
1359 * to child that destroy_subscription() doesn't release. */
1360 ao2_cleanup(tree);
1361 }
1362 }
1363
1364 return sub;
1365}
1366
1368{
1369 int i;
1370
1371 if (!sub) {
1372 return;
1373 }
1374
1375 if (AST_VECTOR_SIZE(&sub->children) > 0) {
1376 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
1378 }
1379 return;
1380 }
1381
1382 /* We notify subscription shutdown only on the tree leaves. */
1383 if (sub->handler->subscription_shutdown) {
1384 sub->handler->subscription_shutdown(sub);
1385 }
1386}
1387
1389{
1390 struct sip_subscription_tree *sub_tree = obj;
1391
1392 /* This is why we keep the dialog on the subscription. When the subscription
1393 * is destroyed, there is no guarantee that the underlying dialog is ready
1394 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1395 * either. The dialog could be destroyed before our subscription is. We fix
1396 * this problem by keeping a reference to the dialog until it is time to
1397 * destroy the subscription. We need to have the dialog available when the
1398 * subscription is destroyed so that we can guarantee that our attempt to
1399 * remove the serializer will be successful.
1400 */
1401 pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
1402 sub_tree->dlg = NULL;
1403
1404 return 0;
1405}
1406
1407static void subscription_tree_destructor(void *obj)
1408{
1409 struct sip_subscription_tree *sub_tree = obj;
1410
1411 ast_debug(3, "Destroying subscription tree %p '%s->%s'\n",
1412 sub_tree,
1413 sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
1414 sub_tree->root ? sub_tree->root->resource : "Unknown");
1415
1416 destroy_subscriptions(sub_tree->root);
1417
1418 if (sub_tree->dlg) {
1421 }
1422
1423 ao2_cleanup(sub_tree->endpoint);
1424
1427}
1428
1430{
1431 ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1432 sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree);
1433 ao2_cleanup(sub->tree);
1434}
1435
1436static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
1437{
1438 sub_tree->dlg = dlg;
1441 pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
1442 pjsip_dlg_inc_session(dlg, &pubsub_module);
1443}
1444
1446{
1447 struct sip_subscription_tree *sub_tree;
1448
1449 sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
1450 if (!sub_tree) {
1451 return NULL;
1452 }
1453
1455
1456 if (rdata) {
1457 /*
1458 * We must continue using the serializer that the original
1459 * SUBSCRIBE came in on for the dialog. There may be
1460 * retransmissions already enqueued in the original
1461 * serializer that can result in reentrancy and message
1462 * sequencing problems.
1463 */
1465 } else {
1466 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1467
1468 /* Create name with seq number appended. */
1469 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s",
1471
1472 sub_tree->serializer = ast_sip_create_serializer(tps_name);
1473 }
1474 if (!sub_tree->serializer) {
1475 ao2_ref(sub_tree, -1);
1476 return NULL;
1477 }
1478
1479 sub_tree->endpoint = ao2_bump(endpoint);
1480 sub_tree->notify_sched_id = -1;
1481
1482 return sub_tree;
1483}
1484
1485/*!
1486 * \brief Create a subscription tree based on a resource tree.
1487 *
1488 * Using the previously-determined valid resources in the provided resource tree,
1489 * a corresponding tree of ast_sip_subscriptions are created. The root of the
1490 * subscription tree is a real subscription, and the rest in the tree are
1491 * virtual subscriptions.
1492 *
1493 * \param handler The handler to use for leaf subscriptions
1494 * \param endpoint The endpoint that sent the SUBSCRIBE request
1495 * \param rdata The SUBSCRIBE content
1496 * \param resource The requested resource in the SUBSCRIBE request
1497 * \param generator The body generator to use in leaf subscriptions
1498 * \param tree The resource tree on which the subscription tree is based
1499 * \param[out] dlg_status The result of attempting to create a dialog
1500 * \param persistence
1501 *
1502 * \retval NULL Could not create the subscription tree
1503 * \retval non-NULL The root of the created subscription tree
1504 */
1505
1507 struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
1508 struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree,
1509 pj_status_t *dlg_status, struct subscription_persistence *persistence)
1510{
1511 struct sip_subscription_tree *sub_tree;
1512 pjsip_dialog *dlg;
1513
1514 sub_tree = allocate_subscription_tree(endpoint, rdata);
1515 if (!sub_tree) {
1516 *dlg_status = PJ_ENOMEM;
1517 return NULL;
1518 }
1519 sub_tree->role = AST_SIP_NOTIFIER;
1520
1521 dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, dlg_status);
1522 if (!dlg) {
1523 if (*dlg_status != PJ_EEXISTS) {
1524 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1525 }
1526 ao2_ref(sub_tree, -1);
1527 return NULL;
1528 }
1529
1530 persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
1532 if (persistence) {
1533 /* Update the created dialog with the persisted information */
1534 pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
1535 pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->tag);
1536 dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
1537 pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
1538 dlg->local.cseq = persistence->cseq;
1539 }
1540
1541 pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
1542
1543 subscription_setup_dialog(sub_tree, dlg);
1544
1545 /*
1546 * The evsub and subscription setup both add dialog refs, so the dialog ref that
1547 * was added when the dialog was created (see ast_sip_create_dialog_uas_lock) can
1548 * now be removed. The lock should no longer be needed so can be removed too.
1549 */
1550 pjsip_dlg_dec_lock(dlg);
1551
1552#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
1553 pjsip_evsub_add_ref(sub_tree->evsub);
1554#endif
1555
1557 pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
1558
1560
1561 /* Persistence information needs to be available for all the subscriptions */
1562 sub_tree->persistence = ao2_bump(persistence);
1563
1564 sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
1565 if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
1566 sub_tree->is_list = 1;
1567 }
1568
1569 add_subscription(sub_tree);
1570
1571 return sub_tree;
1572}
1573
1574/*! Wrapper structure for initial_notify_task */
1577 unsigned int expires;
1578};
1579
1580static int initial_notify_task(void *obj);
1581static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state);
1582
1583/*! Persistent subscription recreation continuation under distributor serializer data */
1586 pjsip_rx_data *rdata;
1587};
1588
1589/*!
1590 * \internal
1591 * \brief subscription_persistence_recreate continuation under distributor serializer.
1592 * \since 13.10.0
1593 *
1594 * \retval 0 on success.
1595 * \retval -1 on error.
1596 */
1597static int sub_persistence_recreate(void *obj)
1598{
1599 struct persistence_recreate_data *recreate_data = obj;
1600 struct subscription_persistence *persistence = recreate_data->persistence;
1601 pjsip_rx_data *rdata = recreate_data->rdata;
1602 struct ast_sip_endpoint *endpoint;
1603 struct sip_subscription_tree *sub_tree;
1604 struct ast_sip_pubsub_body_generator *generator;
1606 char *resource;
1607 size_t resource_size;
1608 int resp;
1609 struct resource_tree tree;
1610 pjsip_expires_hdr *expires_header;
1611 int64_t expires;
1612 const pj_str_t *user;
1613
1614 user = ast_sip_pjsip_uri_get_username(rdata->msg_info.msg->line.req.uri);
1615 resource_size = pj_strlen(user) + 1;
1616 resource = ast_alloca(resource_size);
1617 ast_copy_pj_str(resource, user, resource_size);
1618
1619 /*
1620 * We may want to match without any user options getting
1621 * in the way.
1622 */
1624
1626 if (!handler || !handler->notifier) {
1627 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get subscription handler.\n",
1628 persistence->endpoint);
1630 return 0;
1631 }
1632
1634 if (!generator) {
1635 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Body generator not available.\n",
1636 persistence->endpoint);
1638 return 0;
1639 }
1640
1641 ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data,
1642 pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
1643
1644 /* Getting the endpoint may take some time that can affect the expiration. */
1645 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1646 persistence->endpoint);
1647 if (!endpoint) {
1648 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The endpoint was not found\n",
1649 persistence->endpoint);
1651 return 0;
1652 }
1653
1654 /* Update the expiration header with the new expiration */
1655 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1656 rdata->msg_info.msg->hdr.next);
1657 if (!expires_header) {
1658 expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1659 if (!expires_header) {
1660 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not update expires header.\n",
1661 persistence->endpoint);
1663 ao2_ref(endpoint, -1);
1664 return 0;
1665 }
1666 pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1667 }
1668
1669 expires = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
1670 if (expires <= 0) {
1671 /* The subscription expired since we started recreating the subscription. */
1672 ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1673 persistence->endpoint, persistence->tag);
1675 ao2_ref(endpoint, -1);
1676 return 0;
1677 }
1678 expires_header->ivalue = expires;
1679
1680 memset(&tree, 0, sizeof(tree));
1681 resp = build_resource_tree(endpoint, handler, resource, &tree,
1683 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1684 pj_status_t dlg_status;
1685
1686 sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,
1687 &tree, &dlg_status, persistence);
1688 if (!sub_tree) {
1689 if (dlg_status != PJ_EEXISTS) {
1690 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",
1691 persistence->endpoint);
1693 }
1694 } else {
1695 struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
1696
1697 if (!ind) {
1698 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1699 goto error;
1700 }
1701
1702 ind->sub_tree = ao2_bump(sub_tree);
1703 ind->expires = expires_header->ivalue;
1704
1707 /* Could not send initial subscribe NOTIFY */
1708 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1709 ao2_ref(sub_tree, -1);
1710 ast_free(ind);
1711 }
1712 }
1713 } else {
1715 }
1716
1717error:
1718 resource_tree_destroy(&tree);
1719 ao2_ref(endpoint, -1);
1720
1721 return 0;
1722}
1723
1724/*! \brief Callback function to perform the actual recreation of a subscription */
1725static int subscription_persistence_recreate(void *obj, void *arg, int flags)
1726{
1727 struct subscription_persistence *persistence = obj;
1728 pj_pool_t *pool = arg;
1730 pjsip_rx_data rdata;
1731 struct persistence_recreate_data recreate_data;
1732
1733 /* If this subscription used a reliable transport it can't be reestablished so remove it */
1735 ast_debug(3, "Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1738 return 0;
1739 }
1740
1741 /* If this subscription has already expired remove it */
1743 ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1746 return 0;
1747 }
1748
1749 memset(&rdata, 0, sizeof(rdata));
1750 pj_pool_reset(pool);
1751 rdata.tp_info.pool = pool;
1752
1756 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n",
1759 return 0;
1760 }
1761
1762 if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1763 ast_log(LOG_NOTICE, "Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1766 return 0;
1767 }
1768
1769 /* Continue the remainder in the distributor serializer */
1771 if (!serializer) {
1772 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1775 return 0;
1776 }
1777 recreate_data.persistence = persistence;
1778 recreate_data.rdata = &rdata;
1780 &recreate_data)) {
1781 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
1784 }
1786
1787 return 0;
1788}
1789
1790/*! \brief Function which loads and recreates persisted subscriptions upon startup when the system is fully booted */
1791static int subscription_persistence_load(void *data)
1792{
1793 struct ao2_container *persisted_subscriptions = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
1794 "subscription_persistence", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1795 pj_pool_t *pool;
1796
1797 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "rtd%p", PJSIP_POOL_RDATA_LEN,
1798 PJSIP_POOL_RDATA_INC);
1799 if (!pool) {
1800 ast_log(LOG_WARNING, "Could not create a memory pool for recreating SIP subscriptions\n");
1801 return 0;
1802 }
1803
1804 ao2_callback(persisted_subscriptions, OBJ_NODATA, subscription_persistence_recreate, pool);
1805
1806 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1807
1808 ao2_ref(persisted_subscriptions, -1);
1809 return 0;
1810}
1811
1812/*! \brief Event callback which fires subscription persistence recreation when the system is fully booted */
1814{
1815 struct ast_json_payload *payload;
1816 const char *type;
1817
1819 return;
1820 }
1821
1822 payload = stasis_message_data(message);
1823 type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1824
1825 /* This subscription only responds to the FullyBooted event so that all modules have been loaded when we
1826 * recreate SIP subscriptions.
1827 */
1828 if (strcmp(type, "FullyBooted")) {
1829 return;
1830 }
1831
1832 /* This has to be here so the subscription is recreated when the body generator is available */
1834
1835 /* Once the system is fully booted we don't care anymore */
1837}
1838
1839typedef int (*on_subscription_t)(struct sip_subscription_tree *sub, void *arg);
1840
1841static int for_each_subscription(on_subscription_t on_subscription, void *arg)
1842{
1843 int num = 0;
1844 struct sip_subscription_tree *i;
1845
1846 if (!on_subscription) {
1847 return num;
1848 }
1849
1852 if (on_subscription(i, arg)) {
1853 break;
1854 }
1855 ++num;
1856 }
1858 return num;
1859}
1860
1862 struct ast_str **buf)
1863{
1864 char str[256];
1865 struct ast_sip_endpoint_id_configuration *id = &sub_tree->endpoint->id;
1866
1867 ast_str_append(buf, 0, "Role: %s\r\n",
1868 sip_subscription_roles_map[sub_tree->role]);
1869 ast_str_append(buf, 0, "Endpoint: %s\r\n",
1871
1872 if (sub_tree->dlg) {
1873 ast_copy_pj_str(str, &sub_tree->dlg->call_id->id, sizeof(str));
1874 } else {
1875 ast_copy_string(str, "<unknown>", sizeof(str));
1876 }
1877 ast_str_append(buf, 0, "Callid: %s\r\n", str);
1878
1879 ast_str_append(buf, 0, "State: %s\r\n", pjsip_evsub_get_state_name(sub_tree->evsub));
1880
1881 ast_callerid_merge(str, sizeof(str),
1882 S_COR(id->self.name.valid, id->self.name.str, NULL),
1883 S_COR(id->self.number.valid, id->self.number.str, NULL),
1884 "Unknown");
1885
1886 ast_str_append(buf, 0, "Callerid: %s\r\n", str);
1887
1888 /* XXX This needs to be done recursively for lists */
1889 if (sub_tree->root->handler->to_ami) {
1890 sub_tree->root->handler->to_ami(sub_tree->root, buf);
1891 }
1892}
1893
1894
1896{
1897 pjsip_dialog *dlg;
1898 pjsip_msg *msg;
1899 pj_str_t name;
1900
1901 dlg = sub->tree->dlg;
1902 msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1903 pj_cstr(&name, header);
1904
1905 return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
1906}
1907
1908/* XXX This function is not used. */
1910 struct ast_sip_endpoint *endpoint, const char *resource)
1911{
1912 struct ast_sip_subscription *sub;
1913 pjsip_dialog *dlg;
1914 struct ast_sip_contact *contact;
1915 pj_str_t event;
1916 pjsip_tx_data *tdata;
1917 pjsip_evsub *evsub;
1918 struct sip_subscription_tree *sub_tree = NULL;
1919
1921 if (!sub_tree) {
1922 return NULL;
1923 }
1924
1925 sub = allocate_subscription(handler, resource, NULL, sub_tree);
1926 if (!sub) {
1927 ao2_cleanup(sub_tree);
1928 return NULL;
1929 }
1930
1932 if (!contact || ast_strlen_zero(contact->uri)) {
1933 ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
1935 ao2_ref(sub_tree, -1);
1936 ao2_cleanup(contact);
1937 return NULL;
1938 }
1939
1941 ao2_cleanup(contact);
1942 if (!dlg) {
1943 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1944 ao2_ref(sub_tree, -1);
1945 return NULL;
1946 }
1947
1948 pj_cstr(&event, handler->event_name);
1949 pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub_tree->evsub);
1950 subscription_setup_dialog(sub_tree, dlg);
1951
1952 evsub = sub_tree->evsub;
1953
1954 if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
1955 pjsip_evsub_send_request(sub_tree->evsub, tdata);
1956 } else {
1957 /* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
1958 * being called and terminating the subscription. Therefore, we don't
1959 * need to decrease the reference count of sub here.
1960 */
1961 pjsip_evsub_terminate(evsub, PJ_TRUE);
1962 ao2_ref(sub_tree, -1);
1963 return NULL;
1964 }
1965
1966 add_subscription(sub_tree);
1967
1968 return sub;
1969}
1970
1972{
1973 ast_assert(sub->tree->dlg != NULL);
1974 return sub->tree->dlg;
1975}
1976
1978{
1979 ast_assert(sub->tree->endpoint != NULL);
1980 return ao2_bump(sub->tree->endpoint);
1981}
1982
1984{
1985 ast_assert(sub->tree->serializer != NULL);
1986 return sub->tree->serializer;
1987}
1988
1989/*!
1990 * \brief Pre-allocate a buffer for the transmission
1991 *
1992 * Typically, we let PJSIP do this step for us when we send a request. PJSIP's buffer
1993 * allocation algorithm is to allocate a buffer of PJSIP_MAX_PKT_LEN bytes and attempt
1994 * to write the packet to the allocated buffer. If the buffer is too small to hold the
1995 * packet, then we get told the message is too long to be sent.
1996 *
1997 * When dealing with SIP NOTIFY, especially with RLS, it is possible to exceed
1998 * PJSIP_MAX_PKT_LEN. Rather than accepting the limitation imposed on us by default,
1999 * we instead take the strategy of pre-allocating the buffer, testing for ourselves
2000 * if the message will fit, and resizing the buffer as required.
2001 *
2002 * The limit we impose is double that of the maximum packet length.
2003 *
2004 * \param tdata The tdata onto which to allocate a buffer
2005 * \retval 0 Success
2006 * \retval -1 The message is too large
2007 */
2008static int allocate_tdata_buffer(pjsip_tx_data *tdata)
2009{
2010 int buf_size;
2011 int size = -1;
2012 char *buf;
2013
2014 for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
2015 buf = pj_pool_alloc(tdata->pool, buf_size);
2016 size = pjsip_msg_print(tdata->msg, buf, buf_size);
2017 }
2018
2019 if (size == -1) {
2020 return -1;
2021 }
2022
2023 tdata->buf.start = buf;
2024 tdata->buf.cur = tdata->buf.start;
2025 tdata->buf.end = tdata->buf.start + buf_size;
2026
2027 return 0;
2028}
2029
2030static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
2031{
2032#ifdef TEST_FRAMEWORK
2033 struct ast_sip_endpoint *endpoint = sub_tree->endpoint;
2034 pjsip_evsub *evsub = sub_tree->evsub;
2035#endif
2036 int res;
2037
2038 if (allocate_tdata_buffer(tdata)) {
2039 ast_log(LOG_ERROR, "SIP request %s is too large to send.\n", tdata->info);
2040 pjsip_tx_data_dec_ref(tdata);
2041 return -1;
2042 }
2043
2044 res = pjsip_evsub_send_request(sub_tree->evsub, tdata);
2045
2047
2048 ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
2049 "StateText: %s\r\n"
2050 "Endpoint: %s\r\n",
2051 pjsip_evsub_get_state_name(evsub),
2052 ast_sorcery_object_get_id(endpoint));
2053
2054 return (res == PJ_SUCCESS ? 0 : -1);
2055}
2056
2057/*!
2058 * \brief Add a resource XML element to an RLMI body
2059 *
2060 * Each resource element represents a subscribed resource in the list. This function currently
2061 * will unconditionally add an instance element to each created resource element. Instance
2062 * elements refer to later parts in the multipart body.
2063 *
2064 * \param pool PJLIB allocation pool
2065 * \param rlmi
2066 * \param cid Content-ID header of the resource
2067 * \param resource_name Name of the resource
2068 * \param resource_uri URI of the resource
2069 * \param state State of the subscribed resource
2070 */
2071static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid,
2072 const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
2073{
2074 static pj_str_t cid_name = { "cid", 3 };
2075 pj_xml_node *resource;
2076 pj_xml_node *name;
2077 pj_xml_node *instance;
2078 pj_xml_attr *cid_attr;
2079 char id[6];
2080 char uri[PJSIP_MAX_URL_SIZE];
2081 char name_sanitized[PJSIP_MAX_URL_SIZE];
2082
2083 /* This creates a string representing the Content-ID without the enclosing < > */
2084 const pj_str_t cid_stripped = {
2085 .ptr = cid->hvalue.ptr + 1,
2086 .slen = cid->hvalue.slen - 2,
2087 };
2088
2089 resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
2090 name = ast_sip_presence_xml_create_node(pool, resource, "name");
2091 instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
2092
2093 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
2094 ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
2095
2096 ast_sip_sanitize_xml(resource_name, name_sanitized, sizeof(name_sanitized));
2097 pj_strdup2(pool, &name->content, name_sanitized);
2098
2099 ast_generate_random_string(id, sizeof(id));
2100
2101 ast_sip_presence_xml_create_attr(pool, instance, "id", id);
2102 ast_sip_presence_xml_create_attr(pool, instance, "state",
2103 state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
2104
2105 /* Use the PJLIB-util XML library directly here since we are using a
2106 * pj_str_t
2107 */
2108
2109 cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2110 pj_xml_add_attr(instance, cid_attr);
2111}
2112
2113/*!
2114 * \brief A multipart body part and meta-information
2115 *
2116 * When creating a multipart body part, the end result (the
2117 * pjsip_multipart_part) is hard to inspect without undoing
2118 * a lot of what was done to create it. Therefore, we use this
2119 * structure to store meta-information about the body part.
2120 *
2121 * The main consumer of this is the creator of the RLMI body
2122 * part of a multipart resource list body.
2123 */
2125 /*! Content-ID header for the body part */
2126 pjsip_generic_string_hdr *cid;
2127 /*! Subscribed resource represented in the body part */
2128 const char *resource;
2129 /*! URI for the subscribed body part */
2130 pjsip_sip_uri *uri;
2131 /*! Subscription state of the resource represented in the body part */
2132 pjsip_evsub_state state;
2133 /*! The actual body part that will be present in the multipart body */
2134 pjsip_multipart_part *part;
2135 /*! Display name for the resource */
2136 const char *display_name;
2137};
2138
2139/*!
2140 * \brief Type declaration for container of body part structures
2141 */
2143
2144/*!
2145 * \brief Create a Content-ID header
2146 *
2147 * Content-ID headers are required by RFC2387 for multipart/related
2148 * bodies. They serve as identifiers for each part of the multipart body.
2149 *
2150 * \param pool PJLIB allocation pool
2151 * \param sub Subscription to a resource
2152 */
2153static pjsip_generic_string_hdr *generate_content_id_hdr(pj_pool_t *pool,
2154 const struct ast_sip_subscription *sub)
2155{
2156 static const pj_str_t cid_name = { "Content-ID", 10 };
2157 pjsip_generic_string_hdr *cid;
2158 char id[6];
2159 size_t alloc_size;
2160 pj_str_t cid_value;
2161
2162 /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
2163 alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
2164 cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2165 cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
2166 ast_generate_random_string(id, sizeof(id)),
2167 (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
2168 cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2169
2170 return cid;
2171}
2172
2173static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
2174{
2175 int num_printed;
2176 pj_xml_node *rlmi = msg_body->data;
2177
2178 num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
2179 if (num_printed <= AST_PJSIP_XML_PROLOG_LEN) {
2180 return -1;
2181 }
2182
2183 return num_printed;
2184}
2185
2186static void *rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
2187{
2188 const pj_xml_node *rlmi = data;
2189
2190 return pj_xml_clone(pool, rlmi);
2191}
2192
2193/*!
2194 * \brief Create an RLMI body part for a multipart resource list body
2195 *
2196 * RLMI (Resource list meta information) is a special body type that lists
2197 * the subscribed resources and tells subscribers the number of subscribed
2198 * resources and what other body parts are in the multipart body. The
2199 * RLMI body also has a version number that a subscriber can use to ensure
2200 * that the locally-stored state corresponds to server state.
2201 *
2202 * \param pool The allocation pool
2203 * \param sub The subscription representing the subscribed resource list
2204 * \param body_parts A container of body parts that RLMI will refer to
2205 * \param full_state Indicates whether this is a full or partial state notification
2206 * \return The multipart part representing the RLMI body
2207 */
2208static pjsip_multipart_part *build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
2209 struct body_part_list *body_parts, unsigned int full_state)
2210{
2211 pj_xml_node *rlmi;
2212 pj_xml_node *name;
2213 pjsip_multipart_part *rlmi_part;
2214 char version_str[32];
2215 char uri[PJSIP_MAX_URL_SIZE];
2216 pjsip_generic_string_hdr *cid;
2217 int i;
2218
2219 rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
2220 ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
2221
2222 ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
2223 ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
2224
2225 snprintf(version_str, sizeof(version_str), "%u", sub->version++);
2226 ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
2227 ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
2228
2229 name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
2230 pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
2231
2232 for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
2233 const struct body_part *part = AST_VECTOR_GET(body_parts, i);
2234
2235 add_rlmi_resource(pool, rlmi, part->cid, S_OR(part->display_name, part->resource), part->uri, part->state);
2236 }
2237
2238 rlmi_part = pjsip_multipart_create_part(pool);
2239
2240 rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2241 pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &rlmi_media_type);
2242
2243 rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2244 rlmi_part->body->clone_data = rlmi_clone_data;
2245 rlmi_part->body->print_body = rlmi_print_body;
2246
2248 pj_list_insert_before(&rlmi_part->hdr, cid);
2249
2250 return rlmi_part;
2251}
2252
2253static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
2254 unsigned int force_full_state);
2255
2256/*!
2257 * \brief Destroy a list of body parts
2258 *
2259 * \param parts The container of parts to destroy
2260 */
2261static void free_body_parts(struct body_part_list *parts)
2262{
2263 int i;
2264
2265 for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
2266 struct body_part *part = AST_VECTOR_GET(parts, i);
2267 ast_free(part);
2268 }
2269
2270 AST_VECTOR_FREE(parts);
2271}
2272
2273/*!
2274 * \brief Allocate and initialize a body part structure
2275 *
2276 * \param pool PJLIB allocation pool
2277 * \param sub Subscription representing a subscribed resource
2278 */
2279static struct body_part *allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
2280{
2281 struct body_part *bp;
2282
2283 bp = ast_calloc(1, sizeof(*bp));
2284 if (!bp) {
2285 return NULL;
2286 }
2287
2288 bp->cid = generate_content_id_hdr(pool, sub);
2289 bp->resource = sub->resource;
2290 bp->state = sub->subscription_state;
2291 bp->uri = sub->uri;
2292 bp->display_name = sub->display_name;
2293
2294 return bp;
2295}
2296
2297/*!
2298 * \brief Create a multipart body part for a subscribed resource
2299 *
2300 * \param pool PJLIB allocation pool
2301 * \param sub The subscription representing a subscribed resource
2302 * \param parts A vector of parts to append the created part to.
2303 * \param use_full_state Unused locally, but may be passed to other functions
2304 */
2305static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub,
2306 struct body_part_list *parts, unsigned int use_full_state)
2307{
2308 struct body_part *bp;
2309 pjsip_msg_body *body;
2310
2311 bp = allocate_body_part(pool, sub);
2312 if (!bp) {
2313 return;
2314 }
2315
2316 body = generate_notify_body(pool, sub, use_full_state);
2317 if (!body) {
2318 /* Partial state was requested and the resource has not changed state */
2319 ast_free(bp);
2320 return;
2321 }
2322
2323 bp->part = pjsip_multipart_create_part(pool);
2324 bp->part->body = body;
2325 pj_list_insert_before(&bp->part->hdr, bp->cid);
2326
2327 if (AST_VECTOR_APPEND(parts, bp)) {
2328 ast_free(bp);
2329 }
2330}
2331
2332/*!
2333 * \brief Create and initialize the PJSIP multipart body structure for a resource list subscription
2334 *
2335 * \param pool
2336 * \return The multipart message body
2337 */
2338static pjsip_msg_body *create_multipart_body(pj_pool_t *pool)
2339{
2340 pjsip_media_type media_type;
2341 pjsip_param *media_type_param;
2342 char boundary[6];
2343 pj_str_t pj_boundary;
2344
2345 pjsip_media_type_init2(&media_type, "multipart", "related");
2346
2347 media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
2348 pj_list_init(media_type_param);
2349
2350 pj_strdup2(pool, &media_type_param->name, "type");
2351 pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
2352
2353 pj_list_insert_before(&media_type.param, media_type_param);
2354
2355 pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
2356 return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2357}
2358
2359/*!
2360 * \brief Create a resource list body for NOTIFY requests
2361 *
2362 * Resource list bodies are multipart/related bodies. The first part of the multipart body
2363 * is an RLMI body that describes the rest of the parts to come. The other parts of the body
2364 * convey state of individual subscribed resources.
2365 *
2366 * \param pool PJLIB allocation pool
2367 * \param sub Subscription details from which to generate body
2368 * \param force_full_state If true, ignore resource list settings and send a full state notification
2369 * \return The generated multipart/related body
2370 */
2371static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
2372 unsigned int force_full_state)
2373{
2374 int i;
2375 pjsip_multipart_part *rlmi_part;
2376 pjsip_msg_body *multipart;
2377 struct body_part_list body_parts;
2378 unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
2379
2380 if (AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children))) {
2381 return NULL;
2382 }
2383
2384 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2385 build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
2386 }
2387
2388 /* This can happen if issuing partial state and no children of the list have changed state */
2389 if (AST_VECTOR_SIZE(&body_parts) == 0) {
2390 free_body_parts(&body_parts);
2391 return NULL;
2392 }
2393
2394 multipart = create_multipart_body(pool);
2395
2396 rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
2397 if (!rlmi_part) {
2398 free_body_parts(&body_parts);
2399 return NULL;
2400 }
2401 pjsip_multipart_add_part(pool, multipart, rlmi_part);
2402
2403 for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
2404 pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
2405 }
2406
2407 free_body_parts(&body_parts);
2408 return multipart;
2409}
2410
2411/*!
2412 * \brief Create the body for a NOTIFY request.
2413 *
2414 * \param pool The pool used for allocations
2415 * \param root The root of the subscription tree
2416 * \param force_full_state If true, ignore resource list settings and send a full state notification
2417 */
2418static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
2419 unsigned int force_full_state)
2420{
2421 pjsip_msg_body *body;
2422
2423 if (AST_VECTOR_SIZE(&root->children) == 0) {
2424 if (force_full_state || root->body_changed) {
2425 /* Not a list. We've already generated the body and saved it on the subscription.
2426 * Use that directly.
2427 */
2428 pj_str_t type;
2429 pj_str_t subtype;
2430 pj_str_t text;
2431
2433 pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
2434 pj_cstr(&text, ast_str_buffer(root->body_text));
2435
2436 body = pjsip_msg_body_create(pool, &type, &subtype, &text);
2437 root->body_changed = 0;
2438 } else {
2439 body = NULL;
2440 }
2441 } else {
2442 body = generate_list_body(pool, root, force_full_state);
2443 }
2444
2445 return body;
2446}
2447
2448/*!
2449 * \brief Shortcut method to create a Require: eventlist header
2450 */
2451static pjsip_require_hdr *create_require_eventlist(pj_pool_t *pool)
2452{
2453 pjsip_require_hdr *require;
2454
2455 require = pjsip_require_hdr_create(pool);
2456 pj_strdup2(pool, &require->values[0], "eventlist");
2457 require->count = 1;
2458
2459 return require;
2460}
2461
2463{
2464 int i;
2465
2466 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2467 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2468 set_state_terminated(AST_VECTOR_GET(&sub->children, i));
2469 }
2470}
2471
2472/*!
2473 * \brief Send a NOTIFY request to a subscriber
2474 *
2475 * \pre sub_tree->dlg is locked
2476 *
2477 * \param sub_tree The subscription tree representing the subscription
2478 * \param force_full_state If true, ignore resource list settings and send full resource list state.
2479 * \retval 0 Success
2480 * \retval non-zero Failure
2481 */
2482static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
2483{
2484 pjsip_evsub *evsub = sub_tree->evsub;
2485 pjsip_tx_data *tdata;
2486
2487 if (ast_shutdown_final()
2488 && sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED
2489 && sub_tree->persistence) {
2490 return 0;
2491 }
2492
2493 if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
2494 NULL, NULL, &tdata) != PJ_SUCCESS) {
2495 return -1;
2496 }
2497
2498 tdata->msg->body = generate_notify_body(tdata->pool, sub_tree->root, force_full_state);
2499 if (!tdata->msg->body) {
2500 pjsip_tx_data_dec_ref(tdata);
2501 return -1;
2502 }
2503
2504 if (sub_tree->is_list) {
2505 pjsip_require_hdr *require = create_require_eventlist(tdata->pool);
2506 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2507 }
2508
2509 if (sub_tree->root->handler->notifier->notify_created) {
2510 /* The module for this event wants a callback to the pjsip_tx_data,
2511 * e.g. so it can add custom headers or do something custom to the response. */
2512 sub_tree->root->handler->notifier->notify_created(sub_tree->root, tdata);
2513 }
2514
2515 if (sip_subscription_send_request(sub_tree, tdata)) {
2516 /* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */
2517 return -1;
2518 }
2519
2520 sub_tree->send_scheduled_notify = 0;
2521
2522 return 0;
2523}
2524
2525static int serialized_send_notify(void *userdata)
2526{
2527 struct sip_subscription_tree *sub_tree = userdata;
2528 pjsip_dialog *dlg = sub_tree->dlg;
2529
2530 pjsip_dlg_inc_lock(dlg);
2531
2532 sub_tree->notify_sched_id = -1;
2533
2534 /* It's possible that between when the notification was scheduled
2535 * and now a new SUBSCRIBE arrived requiring full state to be
2536 * sent out in an immediate NOTIFY. It's also possible that we're
2537 * already processing a terminate. If that has happened, we need to
2538 * bail out here instead of sending the batched NOTIFY.
2539 */
2540
2542 || !sub_tree->send_scheduled_notify) {
2543 pjsip_dlg_dec_lock(dlg);
2544 ao2_cleanup(sub_tree);
2545 return 0;
2546 }
2547
2548 if (sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) {
2550 }
2551
2552 send_notify(sub_tree, 0);
2553
2555 sub_tree->state == SIP_SUB_TREE_TERMINATED
2556 ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2557 "Resource: %s", sub_tree->root->resource);
2558
2559 pjsip_dlg_dec_lock(dlg);
2560 ao2_cleanup(sub_tree);
2561 return 0;
2562}
2563
2564static int sched_cb(const void *data)
2565{
2566 struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
2567
2568 /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
2569 if (ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree)) {
2570 ao2_cleanup(sub_tree);
2571 }
2572
2573 return 0;
2574}
2575
2577{
2578 /* There's already a notification scheduled */
2579 if (sub_tree->notify_sched_id > -1) {
2580 return 0;
2581 }
2582
2583 sub_tree->send_scheduled_notify = 1;
2585 if (sub_tree->notify_sched_id < 0) {
2586 ao2_cleanup(sub_tree);
2587 return -1;
2588 }
2589
2590 return 0;
2591}
2592
2594 int terminate)
2595{
2596 int res;
2597 pjsip_dialog *dlg = sub->tree->dlg;
2598
2599 pjsip_dlg_inc_lock(dlg);
2600
2601 if (sub->tree->state != SIP_SUB_TREE_NORMAL) {
2602 pjsip_dlg_dec_lock(dlg);
2603 return 0;
2604 }
2605
2608 pjsip_dlg_dec_lock(dlg);
2609 return -1;
2610 }
2611
2612 sub->body_changed = 1;
2613 if (terminate) {
2614 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2615 sub->tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
2616 }
2617
2618 if (sub->tree->notification_batch_interval) {
2619 res = schedule_notification(sub->tree);
2620 } else {
2621 /* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */
2622 ao2_ref(sub->tree, +1);
2623 if (terminate) {
2625 }
2626 res = send_notify(sub->tree, 0);
2627 ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2628 "Resource: %s",
2629 sub->tree->root->resource);
2630 ao2_ref(sub->tree, -1);
2631 }
2632
2633 pjsip_dlg_dec_lock(dlg);
2634 return res;
2635}
2636
2638{
2639 return sub->uri;
2640}
2641
2643{
2644 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2645}
2646
2648{
2649 pjsip_dialog *dlg;
2650 pjsip_sip_uri *uri;
2651
2652 dlg = sub->tree->dlg;
2653 uri = pjsip_uri_get_uri(dlg->remote.info->uri);
2654
2655 if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
2656 *buf = '\0';
2657 }
2658}
2659
2661{
2662 return sub->resource;
2663}
2664
2666{
2667 return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2668}
2669
2670static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
2671{
2672 pjsip_hdr res_hdr;
2673
2674 /* If this is a persistence recreation the subscription has already been accepted */
2675 if (ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_PERSISTENCE)) {
2676 return 0;
2677 }
2678
2679 pj_list_init(&res_hdr);
2680 if (sub_tree->is_list) {
2681 /* If subscribing to a list, our response has to have a Require: eventlist header in it */
2682 pj_list_insert_before(&res_hdr, create_require_eventlist(rdata->tp_info.pool));
2683 }
2684
2685 return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2686}
2687
2689{
2691}
2692
2694{
2695 return ast_datastores_add(subscription->datastores, datastore);
2696}
2697
2699{
2700 return ast_datastores_find(subscription->datastores, name);
2701}
2702
2704{
2705 ast_datastores_remove(subscription->datastores, name);
2706}
2707
2709{
2710 return subscription->datastores;
2711}
2712
2714{
2715 return ast_datastores_add(publication->datastores, datastore);
2716}
2717
2719{
2720 return ast_datastores_find(publication->datastores, name);
2721}
2722
2724{
2725 ast_datastores_remove(publication->datastores, name);
2726}
2727
2729{
2730 return publication->datastores;
2731}
2732
2733void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, struct ast_json *persistence_data)
2734{
2735 ast_json_unref(subscription->persistence_data);
2736 subscription->persistence_data = persistence_data;
2737
2738 if (subscription->tree->persistence) {
2739 if (!subscription->tree->persistence->generator_data) {
2741 if (!subscription->tree->persistence->generator_data) {
2742 return;
2743 }
2744 }
2745 ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
2746 ast_json_ref(persistence_data));
2747 }
2748}
2749
2751{
2752 return subscription->persistence_data;
2753}
2754
2756
2757static int publication_hash_fn(const void *obj, const int flags)
2758{
2759 const struct ast_sip_publication *publication = obj;
2760 const int *entity_tag = obj;
2761
2762 return flags & OBJ_KEY ? *entity_tag : publication->entity_tag;
2763}
2764
2765static int publication_cmp_fn(void *obj, void *arg, int flags)
2766{
2767 const struct ast_sip_publication *publication1 = obj;
2768 const struct ast_sip_publication *publication2 = arg;
2769 const int *entity_tag = arg;
2770
2771 return (publication1->entity_tag == (flags & OBJ_KEY ? *entity_tag : publication2->entity_tag) ?
2772 CMP_MATCH | CMP_STOP : 0);
2773}
2774
2776{
2780}
2781
2783{
2784 if (ast_strlen_zero(handler->event_name)) {
2785 ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
2786 return -1;
2787 }
2788
2791 if (!handler->publications) {
2792 ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
2793 handler->event_name);
2794 return -1;
2795 }
2796
2798
2799 return 0;
2800}
2801
2803{
2804 struct ast_sip_publish_handler *iter;
2805
2808 if (handler == iter) {
2810 ao2_cleanup(handler->publications);
2811 break;
2812 }
2813 }
2816}
2817
2819
2821{
2825}
2826
2828{
2829 struct ast_sip_subscription_handler *iter;
2830
2833 if (!strcmp(iter->event_name, event_name)) {
2834 break;
2835 }
2836 }
2838 return iter;
2839}
2840
2842{
2843 pj_str_t event;
2844 pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
2845 struct ast_sip_subscription_handler *existing;
2846 int i = 0;
2847
2848 if (ast_strlen_zero(handler->event_name)) {
2849 ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
2850 return -1;
2851 }
2852
2853 existing = find_sub_handler_for_event_name(handler->event_name);
2854 if (existing) {
2856 "Unable to register subscription handler for event %s. A handler is already registered\n",
2857 handler->event_name);
2858 return -1;
2859 }
2860
2861 for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
2862 pj_cstr(&accept[i], handler->accept[i]);
2863 }
2864
2865 pj_cstr(&event, handler->event_name);
2866
2867 pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
2868
2870
2871 return 0;
2872}
2873
2875{
2876 struct ast_sip_subscription_handler *iter;
2877
2880 if (handler == iter) {
2882 break;
2883 }
2884 }
2887}
2888
2890{
2892
2894 if (!strcmp(gen->type, type)
2895 && !strcmp(gen->subtype, subtype)) {
2896 break;
2897 }
2898 }
2899
2900 return gen;
2901}
2902
2904{
2906
2910 return gen;
2911}
2912
2914{
2915 char *accept_copy = ast_strdupa(accept);
2916 char *subtype = accept_copy;
2917 char *type = strsep(&subtype, "/");
2918
2920 return NULL;
2921 }
2922
2924}
2925
2927 size_t num_accept, const char *body_type)
2928{
2929 int i;
2930 struct ast_sip_pubsub_body_generator *generator = NULL;
2931
2932 for (i = 0; i < num_accept; ++i) {
2933 generator = find_body_generator_accept(accept[i]);
2934 if (generator) {
2935 ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
2936 if (strcmp(generator->body_type, body_type)) {
2937 ast_log(LOG_WARNING, "Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
2938 generator->type, generator->subtype, generator);
2939 generator = NULL;
2940 continue;
2941 }
2942 break;
2943 } else {
2944 ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
2945 }
2946 }
2947
2948 return generator;
2949}
2950
2952{
2953 void *notify_data;
2954 int res;
2955 struct ast_sip_body_data data = {
2956 .body_type = sub->handler->body_type,
2957 };
2958
2959 if (AST_VECTOR_SIZE(&sub->children) > 0) {
2960 int i;
2961
2962 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2963 if (generate_initial_notify(AST_VECTOR_GET(&sub->children, i))) {
2964 return -1;
2965 }
2966 }
2967
2968 return 0;
2969 }
2970
2971 /* We notify subscription establishment only on the tree leaves. */
2972 if (sub->handler->notifier->subscription_established(sub)) {
2973 return -1;
2974 }
2975
2976 notify_data = sub->handler->notifier->get_notify_data(sub);
2977 if (!notify_data) {
2978 ast_debug(3, "No notify data, not generating any body content\n");
2979 return -1;
2980 }
2981
2982 data.body_data = notify_data;
2983
2985 ast_sip_subscription_get_body_subtype(sub), &data, &sub->body_text);
2986
2988
2989 return res;
2990}
2991
2992static int pubsub_on_refresh_timeout(void *userdata);
2993
2994static int initial_notify_task(void * obj)
2995{
2996 struct initial_notify_data *ind = obj;
2997
2999 pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE);
3000 } else {
3001 send_notify(ind->sub_tree, 1);
3002 ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
3003 "Resource: %s",
3004 ind->sub_tree->root->resource);
3005 }
3006
3008 char *name = ast_alloca(strlen("->/ ") +
3009 strlen(ind->sub_tree->persistence->endpoint) +
3010 strlen(ind->sub_tree->root->resource) +
3011 strlen(ind->sub_tree->root->handler->event_name) +
3012 ind->sub_tree->dlg->call_id->id.slen + 1);
3013
3014 sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint,
3016 (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr);
3017
3018 ast_debug(3, "Scheduling timer: %s\n", name);
3022 if (!ind->sub_tree->expiration_task) {
3023 ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n",
3024 ind->expires, name);
3025 }
3026 }
3027
3028 ao2_ref(ind->sub_tree, -1);
3029 ast_free(ind);
3030
3031 return 0;
3032}
3033
3034static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
3035{
3036 pjsip_expires_hdr *expires_header;
3038 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3039 struct sip_subscription_tree *sub_tree;
3040 struct ast_sip_pubsub_body_generator *generator;
3041 char *resource;
3042 pjsip_uri *request_uri;
3043 size_t resource_size;
3044 int resp;
3045 struct resource_tree tree;
3046 pj_status_t dlg_status;
3047 const pj_str_t *user;
3048
3049 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3050 ast_assert(endpoint != NULL);
3051
3052 if (!endpoint->subscription.allow) {
3053 ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
3054 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
3055 return PJ_TRUE;
3056 }
3057
3058 request_uri = rdata->msg_info.msg->line.req.uri;
3059
3060 if (!ast_sip_is_uri_sip_sips(request_uri)) {
3061 char uri_str[PJSIP_MAX_URL_SIZE];
3062
3063 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3064 ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3065 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3066 return PJ_TRUE;
3067 }
3068
3069 user = ast_sip_pjsip_uri_get_username(request_uri);
3070 resource_size = pj_strlen(user) + 1;
3071 resource = ast_alloca(resource_size);
3072 ast_copy_pj_str(resource, user, resource_size);
3073
3074 /*
3075 * We may want to match without any user options getting
3076 * in the way.
3077 */
3079
3080 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3081 if (expires_header) {
3082 if (expires_header->ivalue == 0) {
3083 ast_debug(1, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3084 ast_sorcery_object_get_id(endpoint));
3085 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3086 return PJ_TRUE;
3087 }
3088 if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3089 ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3090 expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subscription.minexpiry);
3091 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
3092 return PJ_TRUE;
3093 }
3094 }
3095
3097 if (!handler) {
3098 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3099 return PJ_TRUE;
3100 }
3101
3103 if (!generator) {
3104 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3105 return PJ_TRUE;
3106 }
3107
3108 memset(&tree, 0, sizeof(tree));
3109 resp = build_resource_tree(endpoint, handler, resource, &tree,
3111 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3112 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3113 resource_tree_destroy(&tree);
3114 return PJ_TRUE;
3115 }
3116
3117 sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
3118 if (!sub_tree) {
3119 if (dlg_status != PJ_EEXISTS) {
3120 ast_debug(3, "No dialog exists, rejecting\n");
3121 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3122 }
3123 } else {
3124 struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
3125
3126 if (!ind) {
3127 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3128 resource_tree_destroy(&tree);
3129 return PJ_TRUE;
3130 }
3131
3132 ind->sub_tree = ao2_bump(sub_tree);
3133 /* Since this is a normal subscribe, pjproject takes care of the timer */
3135
3138 sip_subscription_accept(sub_tree, rdata, resp);
3140 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3141 ao2_ref(sub_tree, -1);
3142 ast_free(ind);
3143 }
3144 }
3145
3146 resource_tree_destroy(&tree);
3147 return PJ_TRUE;
3148}
3149
3151{
3152 struct ast_sip_publish_handler *iter = NULL;
3153
3156 if (strcmp(event, iter->event_name)) {
3157 ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
3158 continue;
3159 }
3160 ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
3161 break;
3162 }
3164
3165 return iter;
3166}
3167
3168static enum sip_publish_type determine_sip_publish_type(pjsip_rx_data *rdata,
3169 pjsip_generic_string_hdr *etag_hdr, unsigned int *expires, int *entity_id)
3170{
3171 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3172
3173 if (etag_hdr) {
3174 char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3175
3176 ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
3177
3178 if (sscanf(etag, "%30d", entity_id) != 1) {
3179 return SIP_PUBLISH_UNKNOWN;
3180 }
3181 }
3182
3183 *expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3184
3185 if (!(*expires)) {
3186 return SIP_PUBLISH_REMOVE;
3187 } else if (!etag_hdr && rdata->msg_info.msg->body) {
3188 return SIP_PUBLISH_INITIAL;
3189 } else if (etag_hdr && !rdata->msg_info.msg->body) {
3190 return SIP_PUBLISH_REFRESH;
3191 } else if (etag_hdr && rdata->msg_info.msg->body) {
3192 return SIP_PUBLISH_MODIFY;
3193 }
3194
3195 return SIP_PUBLISH_UNKNOWN;
3196}
3197
3198/*! \brief Internal destructor for publications */
3199static void publication_destroy_fn(void *obj)
3200{
3201 struct ast_sip_publication *publication = obj;
3202
3203 ast_debug(3, "Destroying SIP publication\n");
3204
3205 ao2_cleanup(publication->datastores);
3206 ao2_cleanup(publication->endpoint);
3207
3209}
3210
3211static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
3212 const char *resource, const char *event_configuration_name)
3213{
3214 struct ast_sip_publication *publication;
3215 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3216 size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
3217 char *dst;
3218
3220
3221 if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
3222 return NULL;
3223 }
3224
3226
3227 if (!(publication->datastores = ast_datastores_alloc())) {
3228 ao2_ref(publication, -1);
3229 return NULL;
3230 }
3231
3233 ao2_ref(endpoint, +1);
3234 publication->endpoint = endpoint;
3235 publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3236 publication->sched_id = -1;
3237 dst = publication->data;
3238 publication->resource = strcpy(dst, resource);
3239 dst += resource_len;
3240 publication->event_configuration_name = strcpy(dst, event_configuration_name);
3241
3242 return publication;
3243}
3244
3245static int sip_publication_respond(struct ast_sip_publication *pub, int status_code,
3246 pjsip_rx_data *rdata)
3247{
3248 pjsip_tx_data *tdata;
3249 pjsip_transaction *tsx;
3250
3251 if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, status_code, NULL, &tdata) != PJ_SUCCESS) {
3252 return -1;
3253 }
3254
3255 if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3256 char buf[30];
3257
3258 snprintf(buf, sizeof(buf), "%d", pub->entity_tag);
3259 ast_sip_add_header(tdata, "SIP-ETag", buf);
3260
3261 snprintf(buf, sizeof(buf), "%d", pub->expires);
3262 ast_sip_add_header(tdata, "Expires", buf);
3263 }
3264
3265 if (pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3266 pjsip_tx_data_dec_ref(tdata);
3267 return -1;
3268 }
3269
3270 pjsip_tsx_recv_msg(tsx, rdata);
3271
3272 if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3273 pjsip_tx_data_dec_ref(tdata);
3274 return -1;
3275 }
3276
3277 return 0;
3278}
3279
3280static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
3282{
3283 struct ast_sip_publication *publication;
3284 char *resource_name;
3285 size_t resource_size;
3287 struct ast_variable *event_configuration_name = NULL;
3288 pjsip_uri *request_uri;
3289 int resp;
3290 const pj_str_t *user;
3291
3292 request_uri = rdata->msg_info.msg->line.req.uri;
3293
3294 if (!ast_sip_is_uri_sip_sips(request_uri)) {
3295 char uri_str[PJSIP_MAX_URL_SIZE];
3296
3297 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3298 ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3299 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3300 return NULL;
3301 }
3302
3303 user = ast_sip_pjsip_uri_get_username(request_uri);
3304 resource_size = pj_strlen(user) + 1;
3305 resource_name = ast_alloca(resource_size);
3306 ast_copy_pj_str(resource_name, user, resource_size);
3307
3308 /*
3309 * We may want to match without any user options getting
3310 * in the way.
3311 */
3313
3314 resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
3315 if (!resource) {
3316 ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name);
3317 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3318 return NULL;
3319 }
3320
3321 if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
3322 ast_debug(1, "Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3323 resource_name, resource->endpoint, ast_sorcery_object_get_id(endpoint));
3324 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
3325 return NULL;
3326 }
3327
3328 for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
3329 if (!strcmp(event_configuration_name->name, handler->event_name)) {
3330 break;
3331 }
3332 }
3333
3334 if (!event_configuration_name) {
3335 ast_debug(1, "Event '%s' is not configured for '%s'\n", handler->event_name, resource_name);
3336 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3337 return NULL;
3338 }
3339
3340 resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
3341
3342 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3343 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3344 return NULL;
3345 }
3346
3347 publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
3348
3349 if (!publication) {
3350 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
3351 return NULL;
3352 }
3353
3354 publication->handler = handler;
3355 if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
3357 ast_debug(3, "Publication state change failed\n");
3358 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3359 ao2_cleanup(publication);
3360 return NULL;
3361 }
3362
3363 sip_publication_respond(publication, resp, rdata);
3364
3365 return publication;
3366}
3367
3368static int publish_expire_callback(void *data)
3369{
3370 RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
3371
3372 if (publication->handler->publish_expire) {
3373 publication->handler->publish_expire(publication);
3374 }
3375
3376 return 0;
3377}
3378
3379static int publish_expire(const void *data)
3380{
3381 struct ast_sip_publication *publication = (struct ast_sip_publication*)data;
3382
3383 ao2_unlink(publication->handler->publications, publication);
3384 publication->sched_id = -1;
3385
3386 if (ast_sip_push_task(NULL, publish_expire_callback, publication)) {
3387 ao2_cleanup(publication);
3388 }
3389
3390 return 0;
3391}
3392
3393static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
3394{
3395 pjsip_event_hdr *event_header;
3397 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3398 char event[32];
3399 static const pj_str_t str_sip_if_match = { "SIP-If-Match", 12 };
3400 pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
3401 enum sip_publish_type publish_type;
3402 RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
3403 unsigned int expires = 0;
3404 int entity_id, response = 0;
3405
3406 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3407 ast_assert(endpoint != NULL);
3408
3409 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
3410 if (!event_header) {
3411 ast_log(LOG_WARNING, "Incoming PUBLISH request from %s with no Event header\n",
3412 ast_sorcery_object_get_id(endpoint));
3413 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3414 return PJ_TRUE;
3415 }
3416 ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
3417
3419 if (!handler) {
3420 ast_log(LOG_WARNING, "No registered publish handler for event %s from %s\n", event,
3421 ast_sorcery_object_get_id(endpoint));
3422 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3423 return PJ_TRUE;
3424 }
3425
3426 publish_type = determine_sip_publish_type(rdata, etag_hdr, &expires, &entity_id);
3427
3428 /* If this is not an initial publish ensure that a publication is present */
3429 if ((publish_type != SIP_PUBLISH_INITIAL) && (publish_type != SIP_PUBLISH_UNKNOWN)) {
3430 if (!(publication = ao2_find(handler->publications, &entity_id, OBJ_KEY | OBJ_UNLINK))) {
3431 static const pj_str_t str_conditional_request_failed = { "Conditional Request Failed", 26 };
3432
3433 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 412, &str_conditional_request_failed,
3434 NULL, NULL);
3435 return PJ_TRUE;
3436 }
3437
3438 /* Per the RFC every response has to have a new entity tag */
3439 publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
3440
3441 /* Update the expires here so that the created responses will contain the correct value */
3442 publication->expires = expires;
3443 }
3444
3445 switch (publish_type) {
3447 publication = publish_request_initial(endpoint, rdata, handler);
3448 break;
3450 case SIP_PUBLISH_MODIFY:
3451 if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
3453 /* If an error occurs we want to terminate the publication */
3454 expires = 0;
3455 }
3456 response = 200;
3457 break;
3458 case SIP_PUBLISH_REMOVE:
3459 handler->publication_state_change(publication, rdata->msg_info.msg->body,
3461 response = 200;
3462 break;
3464 default:
3465 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3466 break;
3467 }
3468
3469 if (publication) {
3470 if (expires) {
3471 ao2_link(handler->publications, publication);
3472
3473 AST_SCHED_REPLACE_UNREF(publication->sched_id, sched, expires * 1000, publish_expire, publication,
3474 ao2_ref(_data, -1), ao2_ref(publication, -1), ao2_ref(publication, +1));
3475 } else {
3476 AST_SCHED_DEL_UNREF(sched, publication->sched_id, ao2_ref(publication, -1));
3477 }
3478 }
3479
3480 if (response) {
3481 sip_publication_respond(publication, response, rdata);
3482 }
3483
3484 return PJ_TRUE;
3485}
3486
3488{
3489 return pub->endpoint;
3490}
3491
3493{
3494 return pub->resource;
3495}
3496
3498{
3499 return pub->event_configuration_name;
3500}
3501
3502int ast_sip_pubsub_is_body_generator_registered(const char *type, const char *subtype)
3503{
3504 return !!find_body_generator_type_subtype(type, subtype);
3505}
3506
3508{
3509 struct ast_sip_pubsub_body_generator *existing;
3510 pj_str_t accept;
3511 pj_size_t accept_len;
3512
3514 existing = find_body_generator_type_subtype_nolock(generator->type, generator->subtype);
3515 if (existing) {
3517 ast_log(LOG_WARNING, "A body generator for %s/%s is already registered.\n",
3518 generator->type, generator->subtype);
3519 return -1;
3520 }
3523
3524 /* Lengths of type and subtype plus a slash. */
3525 accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
3526
3527 /* Add room for null terminator that sprintf() will set. */
3528 pj_strset(&accept, ast_alloca(accept_len + 1), accept_len);
3529 sprintf((char *) pj_strbuf(&accept), "%s/%s", generator->type, generator->subtype);/* Safe */
3530
3531 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
3532 PJSIP_H_ACCEPT, NULL, 1, &accept);
3533
3534 return 0;
3535}
3536
3538{
3539 struct ast_sip_pubsub_body_generator *iter;
3540
3543 if (iter == generator) {
3545 break;
3546 }
3547 }
3550}
3551
3553{
3557
3558 return 0;
3559}
3560
3562{
3563 struct ast_sip_pubsub_body_supplement *iter;
3564
3567 if (iter == supplement) {
3569 break;
3570 }
3571 }
3574}
3575
3577{
3578 return sub->body_generator->type;
3579}
3580
3582{
3583 return sub->body_generator->subtype;
3584}
3585
3587 struct ast_sip_body_data *data, struct ast_str **str)
3588{
3589 struct ast_sip_pubsub_body_supplement *supplement;
3590 struct ast_sip_pubsub_body_generator *generator;
3591 int res = 0;
3592 void *body;
3593
3595 if (!generator) {
3596 ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
3597 type, subtype);
3598 return -1;
3599 }
3600
3601 if (strcmp(data->body_type, generator->body_type)) {
3602 ast_log(LOG_WARNING, "%s/%s body generator does not accept the type of data provided\n",
3603 type, subtype);
3604 return -1;
3605 }
3606
3607 body = generator->allocate_body(data->body_data);
3608 if (!body) {
3609 ast_log(LOG_WARNING, "%s/%s body generator could not to allocate a body\n",
3610 type, subtype);
3611 return -1;
3612 }
3613
3614 if (generator->generate_body_content(body, data->body_data)) {
3615 res = -1;
3616 goto end;
3617 }
3618
3621 if (!strcmp(generator->type, supplement->type) &&
3622 !strcmp(generator->subtype, supplement->subtype)) {
3623 res = supplement->supplement_body(body, data->body_data);
3624 if (res) {
3625 break;
3626 }
3627 }
3628 }
3630
3631 if (!res) {
3632 generator->to_string(body, str);
3633 }
3634
3635end:
3636 if (generator->destroy_body) {
3637 generator->destroy_body(body);
3638 }
3639
3640 return res;
3641}
3642
3649 char message_account[PJSIP_MAX_URL_SIZE];
3650};
3651
3652static int parse_simple_message_summary(char *body,
3653 struct simple_message_summary *summary)
3654{
3655 char *line;
3656 char *buffer;
3657 int found_counts = 0;
3658
3659 if (ast_strlen_zero(body) || !summary) {
3660 return -1;
3661 }
3662
3663 buffer = ast_strdupa(body);
3664 memset(summary, 0, sizeof(*summary));
3665
3666 while ((line = ast_read_line_from_buffer(&buffer))) {
3667 line = ast_str_to_lower(line);
3668
3669 if (sscanf(line, "voice-message: %d/%d (%d/%d)",
3670 &summary->voice_messages_new, &summary->voice_messages_old,
3672 found_counts = 1;
3673 } else {
3674 sscanf(line, "message-account: %s", summary->message_account);
3675 }
3676 }
3677
3678 return !found_counts;
3679}
3680
3681static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata)
3682{
3683 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3684 struct simple_message_summary summary;
3685 const char *endpoint_name;
3686 char *atsign;
3687 char *context;
3688 char *body;
3689 char *mailbox;
3690 int rc;
3691
3692 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3693 if (!endpoint) {
3694 ast_debug(1, "Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3695 rc = 404;
3696 goto error;
3697 }
3698
3699 endpoint_name = ast_sorcery_object_get_id(endpoint);
3700 ast_debug(1, "Incoming MWI: Found endpoint: %s\n", endpoint_name);
3701 if (ast_strlen_zero(endpoint->incoming_mwi_mailbox)) {
3702 ast_debug(1, "Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3703 ast_test_suite_event_notify("PUBSUB_NO_INCOMING_MWI_MAILBOX",
3704 "Endpoint: %s", endpoint_name);
3705 rc = 404;
3706 goto error;
3707 }
3708
3709 mailbox = ast_strdupa(endpoint->incoming_mwi_mailbox);
3710 atsign = strchr(mailbox, '@');
3711 if (!atsign) {
3712 ast_debug(1, "Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3713 endpoint_name, endpoint->incoming_mwi_mailbox);
3714 rc = 404;
3715 goto error;
3716 }
3717
3718 *atsign = '\0';
3719 context = atsign + 1;
3720
3721 body = ast_alloca(rdata->msg_info.msg->body->len + 1);
3722 rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3723 rdata->msg_info.msg->body->len + 1);
3724
3725 if (parse_simple_message_summary(body, &summary) != 0) {
3726 ast_debug(1, "Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3727 ast_sorcery_object_get_id(endpoint), body);
3728 rc = 404;
3729 goto error;
3730 }
3731
3733 summary.voice_messages_new, summary.voice_messages_old)) {
3734 ast_log(LOG_ERROR, "Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
3735 "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3736 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3737 summary.voice_messages_new, summary.voice_messages_old,
3739 rc = 404;
3740 } else {
3741 ast_debug(1, "Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3742 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3743 summary.voice_messages_new, summary.voice_messages_old,
3745 ast_test_suite_event_notify("PUBSUB_INCOMING_MWI_PUBLISH",
3746 "Endpoint: %s\r\n"
3747 "Mailbox: %s\r\n"
3748 "MessageAccount: %s\r\n"
3749 "VoiceMessagesNew: %d\r\n"
3750 "VoiceMessagesOld: %d\r\n"
3751 "VoiceMessagesUrgentNew: %d\r\n"
3752 "VoiceMessagesUrgentOld: %d",
3753 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3754 summary.voice_messages_new, summary.voice_messages_old,
3756 rc = 200;
3757 }
3758
3759error:
3760 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, rc, NULL, NULL, NULL);
3761 return PJ_TRUE;
3762}
3763
3764static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata)
3765{
3766 if (rdata->msg_info.msg->body &&
3767 ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type,
3768 "application", "simple-message-summary")) {
3769 return pubsub_on_rx_mwi_notify_request(rdata);
3770 }
3771 return PJ_FALSE;
3772}
3773
3774static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
3775{
3776 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3777 return pubsub_on_rx_subscribe_request(rdata);
3778 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
3779 return pubsub_on_rx_publish_request(rdata);
3780 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
3781 return pubsub_on_rx_notify_request(rdata);
3782 }
3783
3784 return PJ_FALSE;
3785}
3786
3787/*!
3788 * \brief Callback sequence for subscription terminate:
3789 *
3790 * * Please note that the descriptions below represent pjproject behavior on versions
3791 * >= 2.13.
3792 * * Client initiated:
3793 * pjproject receives SUBSCRIBE on the subscription's serializer thread
3794 * calls pubsub_evsub_set_state with state = TERMINATED
3795 * pubsub_on_evsub_state checks the event and finds it is due to a received
3796 * SUBSCRIBE with an expires of 0 and so does nothing.
3797 * calls pubsub_on_rx_refresh with dialog locked
3798 * pubsub_on_rx_refresh sets TERMINATE_PENDING
3799 * calls pubsub_on_refresh_timeout to push final NOTIFY to pjproject
3800 * checks state == TERMINATE_PENDING
3801 * sets TERMINATE_IN_PROGRESS
3802 * calls send_notify (2)
3803 * send_notify ultimately calls pjsip_evsub_send_request
3804 * pjsip_evsub_send_request calls evsub's set_state
3805 * set_state calls pubsub_evsub_set_state
3806 * pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS
3807 * removes the subscriptions
3808 * cleans up references to evsub
3809 * sets state = TERMINATED
3810 * pubsub_on_refresh_timeout unlocks dialog
3811 * returns to pjproject
3812 * pjproject unlocks dialog
3813 *
3814 * * Subscription timer expires:
3815 * pjproject timer expires
3816 * locks dialog
3817 * calls pubsub_on_server_timeout
3818 * pubsub_on_server_timeout checks state == NORMAL
3819 * sets TERMINATE_PENDING
3820 * pushes serialized_pubsub_on_refresh_timeout
3821 * returns to pjproject
3822 * pjproject unlocks dialog
3823 * serialized_pubsub_on_refresh_timeout starts (1)
3824 * locks dialog
3825 * checks state == TERMINATE_PENDING
3826 * sets TERMINATE_IN_PROGRESS
3827 * calls send_notify (2)
3828 * send_notify ultimately calls pjsip_evsub_send_request
3829 * pjsip_evsub_send_request calls evsub's set_state
3830 * set_state calls pubsub_evsub_set_state
3831 * pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS
3832 * checks that the event is not due to un-SUBSCRIBE
3833 * removes the subscriptions
3834 * cleans up references to evsub
3835 * sets state = TERMINATED
3836 * serialized_pubsub_on_refresh_timeout unlocks dialog
3837 *
3838 * * Transmission failure sending NOTIFY or error response from client
3839 * pjproject transaction timer expires or non OK response
3840 * pjproject locks dialog
3841 * calls pubsub_on_evsub_state with event TSX_STATE
3842 * pubsub_on_evsub_state checks event == TSX_STATE
3843 * removes the subscriptions
3844 * cleans up references to evsub
3845 * sets state = TERMINATED
3846 * pjproject unlocks dialog
3847 *
3848 * * ast_sip_subscription_notify is called
3849 * checks state == NORMAL
3850 * if not batched...
3851 * sets TERMINATE_IN_PROGRESS (if terminate is requested)
3852 * calls send_notify
3853 * See (2) Above
3854 * if batched...
3855 * sets TERMINATE_PENDING
3856 * schedules task
3857 * scheduler runs sched_task
3858 * sched_task pushes serialized_send_notify
3859 * serialized_send_notify starts
3860 * checks state <= TERMINATE_PENDING
3861 * if state == TERMINATE_PENDING set state = TERMINATE_IN_PROGRESS
3862 * call send_notify
3863 * See (2) Above
3864 *
3865 */
3866
3867
3868/* The code in this function was previously in pubsub_on_evsub_state. */
3869static void clean_sub_tree(pjsip_evsub *evsub)
3870{
3871
3872 struct sip_subscription_tree *sub_tree;
3873 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3874
3875 ast_debug(3, "Cleaning subscription %p\n", evsub);
3876
3877 if (sub_tree->expiration_task) {
3878 char task_name[256];
3879
3880 ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
3881 ast_debug(3, "Cancelling timer: %s\n", task_name);
3883 ao2_cleanup(sub_tree->expiration_task);
3884 sub_tree->expiration_task = NULL;
3885 }
3886
3887 remove_subscription(sub_tree);
3888
3889 pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
3890
3891#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
3892 pjsip_evsub_dec_ref(sub_tree->evsub);
3893#endif
3894
3895 sub_tree->evsub = NULL;
3896
3899
3901 shutdown_subscriptions(sub_tree->root);
3902
3903 sub_tree->state = SIP_SUB_TREE_TERMINATED;
3904 /* Remove evsub's reference to the sub_tree */
3905 ao2_ref(sub_tree, -1);
3906}
3907
3908/* This functionality appeared in pjsip 2.13 */
3909#if PJ_VERSION_NUM >= 0x020D0000
3910# define HAVE_PJSIP_EVSUB_PENDING_NOTIFY 1
3911#endif
3912
3913/*!
3914 * \brief PJSIP callback when underlying SIP subscription changes state
3915 *
3916 * Although this function is called for every state change, we only care
3917 * about the TERMINATED state, and only when we're actually processing the final
3918 * notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS) OR when a transmission failure
3919 * occurs (PJSIP_EVENT_TSX_STATE). In this case, we do all the subscription tree
3920 * cleanup tasks and decrement the evsub reference.
3921 */
3922static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
3923{
3924 struct sip_subscription_tree *sub_tree =
3925 pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3926
3927 ast_debug(3, "evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub,
3928 pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree,
3929 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3930
3931 if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
3932 return;
3933 }
3934
3935 /* It's easier to write this as what we WANT to process, then negate it. */
3936 if (!(sub_tree->state == SIP_SUB_TREE_TERMINATE_IN_PROGRESS
3937 || (event->type == PJSIP_EVENT_TSX_STATE && sub_tree->state == SIP_SUB_TREE_NORMAL)
3938 )) {
3939 ast_debug(3, "Do nothing.\n");
3940 return;
3941 }
3942
3943#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
3944 /* This check looks for re-subscribes with an expires of 0. If we receive one of those,
3945 we don't want to clean the evsub because we still need it to send the final NOTIFY.
3946 This was previously handled by pubsub_on_rx_refresh setting:
3947 'sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING' */
3948 if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&
3949 !pjsip_method_cmp(&event->body.tsx_state.tsx->method, &pjsip_subscribe_method) &&
3950 pjsip_evsub_get_expires(evsub) == 0) {
3951 ast_debug(3, "Subscription ending, do nothing.\n");
3952 return;
3953 }
3954#endif
3955 /* If we made it this far, we want to clean the sub tree. For pjproject <2.13, the sub_tree
3956 state check makes sure the evsub is not cleaned at the wrong time */
3958}
3959
3960static int pubsub_on_refresh_timeout(void *userdata)
3961{
3962 struct sip_subscription_tree *sub_tree = userdata;
3963 pjsip_dialog *dlg = sub_tree->dlg;
3964
3965 ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
3966 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3967
3968 pjsip_dlg_inc_lock(dlg);
3969 if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) {
3970 pjsip_dlg_dec_lock(dlg);
3971 return 0;
3972 }
3973
3974 if (sub_tree->state == SIP_SUB_TREE_TERMINATE_PENDING) {
3976 set_state_terminated(sub_tree->root);
3977 }
3978
3979 if (sub_tree->generate_initial_notify) {
3980 sub_tree->generate_initial_notify = 0;
3981 if (generate_initial_notify(sub_tree->root)) {
3982 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3983 pjsip_dlg_dec_lock(dlg);
3984 return 0;
3985 }
3986 }
3987
3988 send_notify(sub_tree, 1);
3989
3990 ast_test_suite_event_notify(sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ?
3991 "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED",
3992 "Resource: %s", sub_tree->root->resource);
3993
3994 pjsip_dlg_dec_lock(dlg);
3995
3996 return 0;
3997}
3998
4000{
4001 struct sip_subscription_tree *sub_tree = userdata;
4002
4003 ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
4004 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4005
4006 pubsub_on_refresh_timeout(userdata);
4007 ao2_cleanup(sub_tree);
4008
4009 return 0;
4010}
4011
4012/*!
4013 * \brief Compare strings for equality checking for NULL.
4014 *
4015 * This function considers NULL values as empty strings.
4016 * This means NULL or empty strings are equal.
4017 *
4018 * \retval 0 The strings are equal
4019 * \retval 1 The strings are not equal
4020 */
4021static int cmp_strings(char *s1, char *s2)
4022{
4023 if (!ast_strlen_zero(s1) && !ast_strlen_zero(s2)) {
4024 return strcmp(s1, s2);
4025 }
4026
4027 return ast_strlen_zero(s1) == ast_strlen_zero(s2) ? 0 : 1;
4028}
4029
4030/*!
4031 * \brief compares the childrens of two ast_sip_subscription s1 and s2
4032 *
4033 * \retval 0 The s1 childrens match the s2 childrens
4034 * \retval 1 The s1 childrens do not match the s2 childrens
4035 */
4037{
4038 int i;
4039
4040 if (AST_VECTOR_SIZE(&s1->children) != AST_VECTOR_SIZE(&s2->children)) {
4041 return 1;
4042 }
4043
4044 for (i = 0; i < AST_VECTOR_SIZE(&s1->children); ++i) {
4045 struct ast_sip_subscription *c1 = AST_VECTOR_GET(&s1->children, i);
4046 struct ast_sip_subscription *c2 = AST_VECTOR_GET(&s2->children, i);
4047
4048 if (cmp_strings(c1->resource, c2->resource)
4049 || cmp_strings(c1->display_name, c2->display_name)) {
4050
4051 return 1;
4052 }
4053 }
4054
4055 return 0;
4056}
4057
4058static int destroy_subscriptions_task(void *obj)
4059{
4060 struct ast_sip_subscription *sub = (struct ast_sip_subscription *) obj;
4061
4063
4064 return 0;
4065}
4066
4067/*!
4068 * \brief Called whenever an in-dialog SUBSCRIBE is received
4069 *
4070 * This includes both SUBSCRIBE requests that actually refresh the subscription
4071 * as well as SUBSCRIBE requests that end the subscription.
4072 *
4073 * In either case we push an appropriate NOTIFY via pubsub_on_refresh_timeout.
4074 */
4075static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata,
4076 int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4077{
4078 struct sip_subscription_tree *sub_tree;
4080
4081 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4082 ast_debug(3, "evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree,
4083 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4084
4085 if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4086 return;
4087 }
4088
4089 if (sub_tree->expiration_task) {
4090 char task_name[256];
4091
4092 ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
4093 ast_debug(3, "Cancelling timer: %s\n", task_name);
4095 ao2_cleanup(sub_tree->expiration_task);
4096 sub_tree->expiration_task = NULL;
4097 }
4098
4099 /* PJSIP will set the evsub's state to terminated before calling into this function
4100 * if the Expires value of the incoming SUBSCRIBE is 0.
4101 */
4102
4103 if (pjsip_evsub_get_state(sub_tree->evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
4105 }
4106
4108
4109 /* If the handler wants a callback on refresh, then do it (some protocols require this). */
4110 if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->root->handler->notifier->refresh_subscribe) {
4111 if (!sub_tree->root->handler->notifier->refresh_subscribe(sub_tree->root, rdata)) {
4112 return; /* If the callback handled it, we're done. */
4113 }
4114 }
4115
4116 if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->is_list) {
4117 /* update RLS */
4118 const char *resource = sub_tree->root->resource;
4119 struct ast_sip_subscription *old_root = sub_tree->root;
4120 struct ast_sip_subscription *new_root = NULL;
4121
4122 struct ast_sip_pubsub_body_generator *generator = NULL;
4123
4124 if (endpoint && (generator = subscription_get_generator_from_rdata(rdata, sub_tree->root->handler))) {
4125
4126 struct resource_tree tree;
4127 int resp;
4128
4129 memset(&tree, 0, sizeof(tree));
4130 resp = build_resource_tree(endpoint, sub_tree->root->handler, resource, &tree,
4132 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
4133 new_root = create_virtual_subscriptions(sub_tree->root->handler, resource, generator, sub_tree, tree.root);
4134 if (new_root) {
4135 if (cmp_subscription_childrens(old_root, new_root)) {
4136 ast_debug(1, "RLS '%s->%s' was modified, regenerate it\n", ast_sorcery_object_get_id(endpoint), old_root->resource);
4137 new_root->version = old_root->version;
4138 sub_tree->root = new_root;
4139 sub_tree->generate_initial_notify = 1;
4140
4141 /* If there is scheduled notification need to delete it to avoid use old subscriptions */
4142 if (sub_tree->notify_sched_id > -1) {
4143 AST_SCHED_DEL_UNREF(sched, sub_tree->notify_sched_id, ao2_ref(sub_tree, -1));
4144 sub_tree->send_scheduled_notify = 0;
4145 }
4146
4147 /* Terminate old subscriptions to stop sending NOTIFY messages on exten/device state changes */
4148 set_state_terminated(old_root);
4149
4150 /* Shutdown old subscriptions to remove exten/device state change callbacks
4151 that can queue tasks for old subscriptions */
4152 shutdown_subscriptions(old_root);
4153
4154 /* Postpone destruction until all already queued tasks that may be using old subscriptions have completed */
4155 if (ast_sip_push_task(sub_tree->serializer, destroy_subscriptions_task, old_root)) {
4156 ast_log(LOG_ERROR, "Failed to push task to destroy old subscriptions for RLS '%s->%s'.\n",
4157 ast_sorcery_object_get_id(endpoint), old_root->resource);
4158 }
4159 } else {
4160 destroy_subscriptions(new_root);
4161 }
4162 }
4163 } else {
4165 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4166 }
4167
4168 resource_tree_destroy(&tree);
4169 }
4170 }
4171
4173
4174#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
4175 /* As of pjsip 2.13, the NOTIFY has to be sent within this function as pjproject now
4176 requires it. Previously this would have caused an early NOTIFY to go out before the
4177 SUBSCRIBE's 200 OK. The previous solution was to push the NOTIFY, but now pjproject
4178 looks for the NOTIFY to be sent from this function and caches it to send after it
4179 auto-replies to the SUBSCRIBE. */
4180 pubsub_on_refresh_timeout(sub_tree);
4181#else
4183 /* If we can't push the NOTIFY refreshing task...we'll just go with it. */
4184 ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n");
4185 sub_tree->state = SIP_SUB_TREE_NORMAL;
4186 ao2_ref(sub_tree, -1);
4187 }
4188#endif
4189
4190 if (sub_tree->is_list) {
4191 pj_list_insert_before(res_hdr, create_require_eventlist(rdata->tp_info.pool));
4192 }
4193}
4194
4195static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code,
4196 pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4197{
4198 struct ast_sip_subscription *sub;
4199
4200 if (!(sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4201 return;
4202 }
4203
4204 sub->handler->subscriber->state_change(sub, rdata->msg_info.msg->body,
4205 pjsip_evsub_get_state(evsub));
4206}
4207
4208static int serialized_pubsub_on_client_refresh(void *userdata)
4209{
4210 struct sip_subscription_tree *sub_tree = userdata;
4211 pjsip_tx_data *tdata;
4212
4213 if (!sub_tree->evsub) {
4214 ao2_cleanup(sub_tree);
4215 return 0;
4216 }
4217
4218 if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
4219 pjsip_evsub_send_request(sub_tree->evsub, tdata);
4220 } else {
4221 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4222 }
4223
4224 ao2_cleanup(sub_tree);
4225 return 0;
4226}
4227
4228static void pubsub_on_client_refresh(pjsip_evsub *evsub)
4229{
4230 struct sip_subscription_tree *sub_tree;
4231
4232 if (!(sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4233 return;
4234 }
4235
4237 ao2_cleanup(sub_tree);
4238 }
4239}
4240
4241static void pubsub_on_server_timeout(pjsip_evsub *evsub)
4242{
4243 struct sip_subscription_tree *sub_tree;
4244
4245 /* PJSIP does not terminate the server timeout timer when a SUBSCRIBE
4246 * with Expires: 0 arrives to end a subscription, nor does it terminate
4247 * this timer when we send a NOTIFY request in response to receiving such
4248 * a SUBSCRIBE. PJSIP does not stop the server timeout timer until the
4249 * NOTIFY transaction has finished (either through receiving a response
4250 * or through a transaction timeout).
4251 *
4252 * Therefore, it is possible that we can be told that a server timeout
4253 * occurred after we already thought that the subscription had been
4254 * terminated. In such a case, we will have already removed the sub_tree
4255 * from the evsub's mod_data array.
4256 */
4257
4258 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4259 if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4260 return;
4261 }
4262
4265 sub_tree->state = SIP_SUB_TREE_NORMAL;
4266 ao2_cleanup(sub_tree);
4267 }
4268}
4269
4271 struct ast_sip_ami *ami,
4272 const char *event)
4273{
4274 struct ast_str *buf;
4275
4277 if (!buf) {
4278 return -1;
4279 }
4280
4281 sip_subscription_to_ami(sub_tree, &buf);
4282 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4283 ast_free(buf);
4284
4285 ++ami->count;
4286 return 0;
4287}
4288
4289static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4290{
4291 return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
4292 sub_tree, arg, "InboundSubscriptionDetail") : 0;
4293}
4294
4295static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4296{
4297 return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
4298 sub_tree, arg, "OutboundSubscriptionDetail") : 0;
4299}
4300
4301static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
4302{
4303 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4304
4305 astman_send_listack(s, m, "Following are Events for each inbound Subscription",
4306 "start");
4307
4309
4310 astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count);
4312 return 0;
4313}
4314
4315static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
4316{
4317 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4318
4319 astman_send_listack(s, m, "Following are Events for each outbound Subscription",
4320 "start");
4321
4323
4324 astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count);
4326 return 0;
4327}
4328
4329static int format_ami_resource_lists(void *obj, void *arg, int flags)
4330{
4331 struct resource_list *list = obj;
4332 struct ast_sip_ami *ami = arg;
4333 struct ast_str *buf;
4334
4335 buf = ast_sip_create_ami_event("ResourceListDetail", ami);
4336 if (!buf) {
4337 return CMP_STOP;
4338 }
4339
4340 if (ast_sip_sorcery_object_to_ami(list, &buf)) {
4341 ast_free(buf);
4342 return CMP_STOP;
4343 }
4344 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4345 ast_free(buf);
4346
4347 ++ami->count;
4348 return 0;
4349}
4350
4351static int ami_show_resource_lists(struct mansession *s, const struct message *m)
4352{
4353 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4354 struct ao2_container *lists;
4355
4356 lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
4358
4359 if (!lists || !ao2_container_count(lists)) {
4360 astman_send_error(s, m, "No resource lists found\n");
4361 return 0;
4362 }
4363
4364 astman_send_listack(s, m, "A listing of resource lists follows, presented as ResourceListDetail events",
4365 "start");
4366
4368
4369 astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count);
4371 return 0;
4372}
4373
4374#define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
4375#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
4376
4377#define MAX_REGEX_ERROR_LEN 128
4378
4380 /*! CLI handler entry e parameter */
4382 /*! CLI handler entry a parameter */
4384 /*! CLI subscription entry output line(s) */
4385 struct ast_str *buf;
4386 /*! Compiled regular expression to select if buf is written to CLI when not NULL. */
4387 regex_t *like;
4389};
4390
4393 /*! Found callid for search position */
4394 char *callid;
4397};
4398
4400{
4401 pj_str_t *callid;
4402
4403 if (!sub_tree->dlg) {
4404 return 0;
4405 }
4406
4407 callid = &sub_tree->dlg->call_id->id;
4408 if (cli->wordlen <= pj_strlen(callid)
4409 && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
4410 && (++cli->which > cli->a->n)) {
4411 cli->callid = ast_malloc(pj_strlen(callid) + 1);
4412 if (cli->callid) {
4413 ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
4414 }
4415 return -1;
4416 }
4417 return 0;
4418}
4419
4420static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4421{
4422 return sub_tree->role == AST_SIP_NOTIFIER
4423 ? cli_complete_subscription_common(sub_tree, arg) : 0;
4424}
4425
4426static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4427{
4428 return sub_tree->role == AST_SIP_SUBSCRIBER
4429 ? cli_complete_subscription_common(sub_tree, arg) : 0;
4430}
4431
4433{
4435 on_subscription_t on_subscription;
4436
4437 if (a->pos != 4) {
4438 return NULL;
4439 }
4440
4441 if (!strcasecmp(a->argv[3], "inbound")) {
4442 on_subscription = cli_complete_subscription_inbound;
4443 } else if (!strcasecmp(a->argv[3], "outbound")) {
4444 on_subscription = cli_complete_subscription_outbound;
4445 } else {
4446 /* Should never get here */
4447 ast_assert(0);
4448 return NULL;
4449 }
4450
4451 cli.a = a;
4452 cli.callid = NULL;
4453 cli.wordlen = strlen(a->word);
4454 cli.which = 0;
4455 for_each_subscription(on_subscription, &cli);
4456
4457 return cli.callid;
4458}
4459
4460static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
4461{
4462 int expiry;
4463
4464 expiry = sub_tree->persistence
4465 ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
4466 : 0;
4467 if (expiry < 0) {
4468 /* Subscription expired */
4469 expiry = 0;
4470 }
4471 return expiry;
4472}
4473
4475{
4476 const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
4477 pj_str_t *sub_callid;
4478 struct ast_str *buf;
4479 char *src;
4480 char *dest;
4481 char *key;
4482 char *value;
4483 char *value_end;
4484 int key_len;
4485 int key_filler_width;
4486 int value_len;
4487
4488 if (!sub_tree->dlg) {
4489 return 0;
4490 }
4491 sub_callid = &sub_tree->dlg->call_id->id;
4492 if (pj_strcmp2(sub_callid, callid)) {
4493 return 0;
4494 }
4495
4496 buf = ast_str_create(512);
4497 if (!buf) {
4498 return -1;
4499 }
4500
4501 ast_cli(cli->a->fd,
4502 "%-20s: %s\n"
4503 "===========================================================================\n",
4504 "ParameterName", "ParameterValue");
4505
4506 ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
4507 ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
4508 ast_str_append(&buf, 0, "Expiry: %u\n", cli_subscription_expiry(sub_tree));
4509
4510 sip_subscription_to_ami(sub_tree, &buf);
4511
4512 /* Convert AMI \r\n to \n line terminators. */
4513 src = strchr(ast_str_buffer(buf), '\r');
4514 if (src) {
4515 dest = src;
4516 ++src;
4517 while (*src) {
4518 if (*src == '\r') {
4519 ++src;
4520 continue;
4521 }
4522 *dest++ = *src++;
4523 }
4524 *dest = '\0';
4526 }
4527
4528 /* Reformat AMI key value pairs to pretty columns */
4529 key = ast_str_buffer(buf);
4530 do {
4531 value = strchr(key, ':');
4532 if (!value) {
4533 break;
4534 }
4535 value_end = strchr(value, '\n');
4536 if (!value_end) {
4537 break;
4538 }
4539
4540 /* Calculate field lengths */
4541 key_len = value - key;
4542 key_filler_width = 20 - key_len;
4543 if (key_filler_width < 0) {
4544 key_filler_width = 0;
4545 }
4546 value_len = value_end - value;
4547
4548 ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
4549 key_len, key, key_filler_width, "",
4550 value_len, value);
4551
4552 key = value_end + 1;
4553 } while (*key);
4554 ast_cli(cli->a->fd, "\n");
4555
4556 ast_free(buf);
4557
4558 return -1;
4559}
4560