Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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"
37 #include "asterisk/linkedlists.h"
38 #include "asterisk/astobj2.h"
39 #include "asterisk/datastore.h"
40 #include "asterisk/uuid.h"
41 #include "asterisk/taskprocessor.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 
236 static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata);
237 
238 static 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 
247 static const pj_str_t str_event_name = { "Event", 5 };
248 
249 /*! \brief Scheduler used for automatically expiring publications */
250 static struct ast_sched_context *sched;
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 */
265 const 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  */
329 AST_VECTOR(resources, const char *);
330 
331 /*!
332  * \brief Resource list configuration item
333  */
335  SORCERY_OBJECT(details);
336  /*! SIP event package the list uses. */
337  char event[32];
338  /*! Strings representing resources in the list. */
339  struct resources items;
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.*/
345  unsigned int resource_display_name;
346 };
347 
348 /*!
349  * Used to create new entity IDs by ESCs.
350  */
351 static int esc_etag_counter;
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 */
368  int sched_id;
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 */
383  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 */
391  int src_port;
392  /*! Local transport key type */
393  char transport_key[32];
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 
426 static char *sub_tree_state_description[] = {
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 */
460  unsigned int send_scheduled_notify;
461  /*! The root of the subscription tree */
463  /*! Is this subscription to a list? */
464  int is_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  */
477  pjsip_transport *transport;
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 */
528  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 
535 static 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 
556 static pjsip_media_type rlmi_media_type;
557 
558 static void pubsub_on_evsub_state(pjsip_evsub *sub, pjsip_event *event);
559 static 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);
561 static 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);
563 static void pubsub_on_client_refresh(pjsip_evsub *sub);
564 static void pubsub_on_server_timeout(pjsip_evsub *sub);
565 
566 static 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 */
575 static 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 */
584 static 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  */
618 static 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 */
636 static void subscription_persistence_destroy(void *obj)
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 */
646 static 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 
672  ast_sorcery_create(ast_sip_get_sorcery(), persistence);
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  sub_tree->transport = rdata->tp_info.transport;
715  ast_sip_transport_monitor_register(rdata->tp_info.transport,
716  sub_tree_transport_cb, sub_tree);
717  /*
718  * FYI: ast_sip_transport_monitor_register holds a reference to the sub_tree
719  */
720  }
721  }
722  }
723 
724  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
725  sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri));
726  } else {
727  ast_log(LOG_WARNING, "Contact not updated due to missing contact header\n");
728  }
729 
730  /* When receiving a packet on an streaming transport, it's possible to receive more than one SIP
731  * message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf
732  * will always point to the proper SIP message that is to be processed. When updating subscription
733  * persistence that is pulled from persistent storage, though, the rdata->pkt_info.packet will
734  * only ever have a single SIP message on it, and so we base persistence on that.
735  */
738  if (rdata->msg_info.msg_buf) {
739  ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf,
740  MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len + 1));
741  } else {
742  ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
743  sizeof(sub_tree->persistence->packet));
744  }
745  }
746  ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
747  sizeof(sub_tree->persistence->src_name));
748  sub_tree->persistence->src_port = rdata->pkt_info.src_port;
749  ast_copy_string(sub_tree->persistence->transport_key, rdata->tp_info.transport->type_name,
750  sizeof(sub_tree->persistence->transport_key));
751  ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host,
752  sizeof(sub_tree->persistence->local_name));
753  sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port;
754  }
755 
757 }
758 
759 /*! \brief Function which removes persistence of a subscription from sorcery */
761 {
762  if (!sub_tree->persistence) {
763  return;
764  }
765 
766  if (sub_tree->persistence->prune_on_boot && sub_tree->transport) {
767  ast_debug(3, "Unregistering transport monitor on %s '%s->%s'\n",
768  sub_tree->transport->obj_name,
769  sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
770  sub_tree->root ? sub_tree->root->resource : "Unknown");
772  sub_tree_transport_cb, sub_tree, NULL);
773  }
774 
776  ao2_ref(sub_tree->persistence, -1);
777  sub_tree->persistence = NULL;
778 }
779 
780 
783  size_t num_accept, const char *body_type);
784 
785 /*! \brief Retrieve a handler using the Event header of an rdata message */
786 static struct ast_sip_subscription_handler *subscription_get_handler_from_rdata(pjsip_rx_data *rdata, const char *endpoint)
787 {
788  pjsip_event_hdr *event_header;
789  char event[32];
791 
792  event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
793  if (!event_header) {
794  ast_log(LOG_WARNING, "Incoming SUBSCRIBE request from %s with no Event header\n",
795  endpoint ? endpoint : "Unknown");
796  return NULL;
797  }
798  ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
799 
801  if (!handler) {
802  ast_log(LOG_WARNING, "No registered subscribe handler for event %s from %s\n", event,
803  endpoint ? endpoint : "Unknown");
804  }
805 
806  return handler;
807 }
808 
809 /*!
810  * \brief Accept headers that are exceptions to the rule
811  *
812  * Typically, when a SUBSCRIBE arrives, we attempt to find a
813  * body generator that matches one of the Accept headers in
814  * the request. When subscribing to a single resource, this works
815  * great. However, when subscribing to a list, things work
816  * differently. Most Accept header values are fine, but there
817  * are a couple that are endemic to resource lists that need
818  * to be ignored when searching for a body generator to use
819  * for the individual resources of the subscription.
820  */
821 const char *accept_exceptions[] = {
822  "multipart/related",
823  "application/rlmi+xml",
824 };
825 
826 /*!
827  * \brief Is the Accept header from the SUBSCRIBE in the list of exceptions?
828  *
829  * \retval 1 This Accept header value is an exception to the rule.
830  * \retval 0 This Accept header is not an exception to the rule.
831  */
832 static int exceptional_accept(const pj_str_t *accept)
833 {
834  int i;
835 
836  for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
837  if (!pj_strcmp2(accept, accept_exceptions[i])) {
838  return 1;
839  }
840  }
841 
842  return 0;
843 }
844 
845 /*! \brief Retrieve a body generator using the Accept header of an rdata message */
848 {
849  pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
850  char accept[AST_SIP_MAX_ACCEPT][64];
851  size_t num_accept_headers = 0;
852 
853  while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
854  (num_accept_headers < AST_SIP_MAX_ACCEPT)) {
855  int i;
856 
857  for (i = 0; i < accept_header->count && num_accept_headers < AST_SIP_MAX_ACCEPT; ++i) {
858  if (!exceptional_accept(&accept_header->values[i])) {
859  ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
860  ++num_accept_headers;
861  }
862  }
863  }
864 
865  if (num_accept_headers == 0) {
866  /* If a SUBSCRIBE contains no Accept headers, then we must assume that
867  * the default accept type for the event package is to be used.
868  */
869  ast_copy_string(accept[0], handler->notifier->default_accept, sizeof(accept[0]));
870  num_accept_headers = 1;
871  }
872 
873  return find_body_generator(accept, num_accept_headers, handler->body_type);
874 }
875 
876 /*! \brief Check if the rdata has a Supported header containing 'eventlist'
877  *
878  * \retval 1 rdata has an eventlist containing supported header
879  * \retval 0 rdata doesn't have an eventlist containing supported header
880  */
881 static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
882 {
883  pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
884 
885  while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
886  int i;
887 
888  for (i = 0; i < supported_header->count; i++) {
889  if (!pj_stricmp2(&supported_header->values[i], "eventlist")) {
890  return 1;
891  }
892  }
893  }
894 
895  return 0;
896 }
897 
898 struct resource_tree;
899 
900 /*!
901  * \brief A node for a resource tree.
902  */
903 struct tree_node {
905  unsigned int full_state;
907  char resource[0];
908 };
909 
910 /*!
911  * \brief Helper function for retrieving a resource list for a given event.
912  *
913  * This will retrieve a resource list that corresponds to the resource and event provided.
914  *
915  * \param resource The name of the resource list to retrieve
916  * \param event The expected event name on the resource list
917  */
918 static struct resource_list *retrieve_resource_list(const char *resource, const char *event)
919 {
920  struct resource_list *list;
921 
922  list = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
923  if (!list) {
924  return NULL;
925  }
926 
927  if (strcmp(list->event, event)) {
928  ast_log(LOG_WARNING, "Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
929  resource, list->event, event);
930  ao2_cleanup(list);
931  return NULL;
932  }
933 
934  return list;
935 }
936 
937 /*!
938  * \brief Allocate a tree node
939  *
940  * In addition to allocating and initializing the tree node, the node is also added
941  * to the vector of visited resources. See \ref build_resource_tree for more information
942  * on the visited resources.
943  *
944  * \param resource The name of the resource for this tree node.
945  * \param visited The vector of resources that have been visited.
946  * \param full_state if allocating a list, indicate whether full state is requested in notifications.
947  * \retval NULL Allocation failure.
948  * \retval non-NULL The newly-allocated tree_node
949  */
950 static struct tree_node *tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state, const char *display_name)
951 {
952  struct tree_node *node;
953 
954  node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
955  if (!node) {
956  return NULL;
957  }
958 
959  strcpy(node->resource, resource);
960  if (AST_VECTOR_INIT(&node->children, 4)) {
961  ast_free(node);
962  return NULL;
963  }
964  node->full_state = full_state;
965  node->display_name = ast_strdup(display_name);
966 
967  if (visited) {
968  AST_VECTOR_APPEND(visited, resource);
969  }
970  return node;
971 }
972 
973 /*!
974  * \brief Destructor for a tree node
975  *
976  * This function calls recursively in order to destroy
977  * all nodes lower in the tree from the given node in
978  * addition to the node itself.
979  *
980  * \param node The node to destroy.
981  */
982 static void tree_node_destroy(struct tree_node *node)
983 {
984  int i;
985  if (!node) {
986  return;
987  }
988 
989  for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
990  tree_node_destroy(AST_VECTOR_GET(&node->children, i));
991  }
992  AST_VECTOR_FREE(&node->children);
993  ast_free(node->display_name);
994  ast_free(node);
995 }
996 
997 /*!
998  * \brief Determine if this resource has been visited already
999  *
1000  * See \ref build_resource_tree for more information
1001  *
1002  * \param resource The resource currently being visited
1003  * \param visited The resources that have previously been visited
1004  */
1005 static int have_visited(const char *resource, struct resources *visited)
1006 {
1007  int i;
1008 
1009  for (i = 0; i < AST_VECTOR_SIZE(visited); ++i) {
1010  if (!strcmp(resource, AST_VECTOR_GET(visited, i))) {
1011  return 1;
1012  }
1013  }
1014 
1015  return 0;
1016 }
1017 
1018 /*!
1019  * \brief Build child nodes for a given parent.
1020  *
1021  * This iterates through the items on a resource list and creates tree nodes for each one. The
1022  * tree nodes created are children of the supplied parent node. If an item in the resource
1023  * list is itself a list, then this function is called recursively to provide children for
1024  * the new node.
1025  *
1026  * If an item in a resource list is not a list, then the supplied subscription handler is
1027  * called into as if a new SUBSCRIBE for the list item were presented. The handler's response
1028  * is used to determine if the node can be added to the tree or not.
1029  *
1030  * If a parent node ends up having no child nodes added under it, then the parent node is
1031  * pruned from the tree.
1032  *
1033  * \param endpoint The endpoint that sent the inbound SUBSCRIBE.
1034  * \param handler The subscription handler for leaf nodes in the tree.
1035  * \param list The configured resource list from which the child node is being built.
1036  * \param parent The parent node for these children.
1037  * \param visited The resources that have already been visited.
1038  */
1039 static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
1040  struct resource_list *list, struct tree_node *parent, struct resources *visited)
1041 {
1042  int i;
1043 
1044  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
1045  struct tree_node *current;
1046  struct resource_list *child_list;
1047  const char *resource = AST_VECTOR_GET(&list->items, i);
1048 
1049  if (have_visited(resource, visited)) {
1050  ast_debug(1, "Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1051  continue;
1052  }
1053 
1054  child_list = retrieve_resource_list(resource, list->event);
1055  if (!child_list) {
1056  int resp = handler->notifier->new_subscribe(endpoint, resource);
1057  if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1058  char display_name[AST_MAX_EXTENSION] = "";
1059  if (list->resource_display_name && handler->notifier->get_resource_display_name) {
1060  handler->notifier->get_resource_display_name(endpoint, resource, display_name, sizeof(display_name));
1061  }
1062  current = tree_node_alloc(resource, visited, 0, ast_strlen_zero(display_name) ? NULL : display_name);
1063  if (!current) {
1064  ast_debug(1,
1065  "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1066  resource);
1067  continue;
1068  }
1069  ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1070  resource, parent->resource);
1071  if (AST_VECTOR_APPEND(&parent->children, current)) {
1073  }
1074  } else {
1075  ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n",
1076  resource, resp);
1077  }
1078  } else {
1079  ast_debug(2, "Resource %s (child of %s) is a list\n", resource, parent->resource);
1080  current = tree_node_alloc(resource, visited, child_list->full_state, NULL);
1081  if (!current) {
1082  ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
1083  continue;
1084  }
1085  build_node_children(endpoint, handler, child_list, current, visited);
1086  if (AST_VECTOR_SIZE(&current->children) > 0) {
1087  ast_debug(1, "List %s had no successful children.\n", resource);
1088  if (AST_VECTOR_APPEND(&parent->children, current)) {
1090  }
1091  } else {
1092  ast_debug(2, "List %s had successful children. Adding to parent %s\n",
1093  resource, parent->resource);
1095  }
1096  ao2_cleanup(child_list);
1097  }
1098  }
1099 }
1100 
1101 /*!
1102  * \brief A resource tree
1103  *
1104  * When an inbound SUBSCRIBE arrives, the resource being subscribed to may
1105  * be a resource list. If this is the case, the resource list may contain resources
1106  * that are themselves lists. The structure needed to hold the resources is
1107  * a tree.
1108  *
1109  * Upon receipt of the SUBSCRIBE, the tree is built by determining if subscriptions
1110  * to the individual resources in the tree would be successful or not. Any successful
1111  * subscriptions result in a node in the tree being created. Any unsuccessful subscriptions
1112  * result in no node being created.
1113  *
1114  * This tree can be seen as a bare-bones analog of the tree of ast_sip_subscriptions that
1115  * will end up being created to actually carry out the duties of a SIP SUBSCRIBE dialog.
1116  */
1118  struct tree_node *root;
1120 };
1121 
1122 /*!
1123  * \brief Destroy a resource tree.
1124  *
1125  * This function makes no assumptions about how the tree itself was
1126  * allocated and does not attempt to free the tree itself. Callers
1127  * of this function are responsible for freeing the tree.
1128  *
1129  * \param tree The tree to destroy.
1130  */
1131 static void resource_tree_destroy(struct resource_tree *tree)
1132 {
1133  if (tree) {
1134  tree_node_destroy(tree->root);
1135  }
1136 }
1137 
1138 /*!
1139  * \brief Build a resource tree
1140  *
1141  * This function builds a resource tree based on the requested resource in a SUBSCRIBE request.
1142  *
1143  * This function also creates a container that has all resources that have been visited during
1144  * creation of the tree, whether those resources resulted in a tree node being created or not.
1145  * Keeping this container of visited resources allows for misconfigurations such as loops in
1146  * the tree or duplicated resources to be detected.
1147  *
1148  * \param endpoint The endpoint that sent the SUBSCRIBE request.
1149  * \param handler The subscription handler for leaf nodes in the tree.
1150  * \param resource The resource requested in the SUBSCRIBE request.
1151  * \param tree The tree that is to be built.
1152  * \param has_eventlist_support
1153  *
1154  * \retval 200-299 Successfully subscribed to at least one resource.
1155  * \retval 300-699 Failure to subscribe to requested resource.
1156  */
1158  const char *resource, struct resource_tree *tree, int has_eventlist_support)
1159 {
1160  RAII_VAR(struct resource_list *, list, NULL, ao2_cleanup);
1161  struct resources visited;
1162 
1163  if (!has_eventlist_support || !(list = retrieve_resource_list(resource, handler->event_name))) {
1164  ast_debug(2, "Subscription '%s->%s' is not to a list\n",
1165  ast_sorcery_object_get_id(endpoint), resource);
1166  tree->root = tree_node_alloc(resource, NULL, 0, NULL);
1167  if (!tree->root) {
1168  return 500;
1169  }
1170  return handler->notifier->new_subscribe(endpoint, resource);
1171  }
1172 
1173  ast_debug(2, "Subscription '%s->%s' is a list\n",
1174  ast_sorcery_object_get_id(endpoint), resource);
1175  if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
1176  return 500;
1177  }
1178 
1179  tree->root = tree_node_alloc(resource, &visited, list->full_state, NULL);
1180  if (!tree->root) {
1181  AST_VECTOR_FREE(&visited);
1182  return 500;
1183  }
1184 
1185  tree->notification_batch_interval = list->notification_batch_interval;
1186 
1187  build_node_children(endpoint, handler, list, tree->root, &visited);
1188  AST_VECTOR_FREE(&visited);
1189 
1190  if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
1191  return 200;
1192  } else {
1193  return 500;
1194  }
1195 }
1196 
1197 static void add_subscription(struct sip_subscription_tree *obj)
1198 {
1202 }
1203 
1205 {
1206  struct sip_subscription_tree *i;
1207 
1210  if (i == obj) {
1212  if (i->root) {
1213  ast_debug(2, "Removing subscription '%s->%s' from list of subscriptions\n",
1215  }
1216  break;
1217  }
1218  }
1221 }
1222 
1224 {
1225  ast_debug(3, "Destroying SIP subscription from '%s->%s'\n",
1226  sub->tree && sub->tree->endpoint ? ast_sorcery_object_get_id(sub->tree->endpoint) : "Unknown",
1227  sub->resource);
1228 
1229  ast_free(sub->body_text);
1230 
1231  AST_VECTOR_FREE(&sub->children);
1232  ao2_cleanup(sub->datastores);
1233  ast_json_unref(sub->persistence_data);
1234  ast_free(sub->display_name);
1235  ast_free(sub);
1236 }
1237 
1239 {
1240  int i;
1241 
1242  if (!root) {
1243  return;
1244  }
1245 
1246  for (i = 0; i < AST_VECTOR_SIZE(&root->children); ++i) {
1247  struct ast_sip_subscription *child;
1248 
1249  child = AST_VECTOR_GET(&root->children, i);
1250  destroy_subscriptions(child);
1251  }
1252 
1253  destroy_subscription(root);
1254 }
1255 
1257  const char *resource, const char *display_name, struct sip_subscription_tree *tree)
1258 {
1259  struct ast_sip_subscription *sub;
1260  pjsip_msg *msg;
1261  pjsip_sip_uri *request_uri;
1262 
1263  msg = ast_sip_mod_data_get(tree->dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1264  if (!msg) {
1265  ast_log(LOG_ERROR, "No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n", resource);
1266  return NULL;
1267  }
1268 
1269  sub = ast_calloc(1, sizeof(*sub) + strlen(resource) + 1);
1270  if (!sub) {
1271  return NULL;
1272  }
1273  strcpy(sub->resource, resource); /* Safe */
1274 
1275  sub->display_name = ast_strdup(display_name);
1276 
1277  sub->datastores = ast_datastores_alloc();
1278  if (!sub->datastores) {
1280  return NULL;
1281  }
1282 
1283  sub->body_text = ast_str_create(128);
1284  if (!sub->body_text) {
1286  return NULL;
1287  }
1288 
1289  sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
1290  request_uri = pjsip_uri_get_uri(msg->line.req.uri);
1291  pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, request_uri);
1292  pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
1293 
1294  /* If there is any persistence information available for this subscription that was persisted
1295  * then make it available so that the NOTIFY has the correct state.
1296  */
1297 
1300  }
1301 
1302  sub->handler = handler;
1303  sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1304  sub->tree = ao2_bump(tree);
1305 
1306  return sub;
1307 }
1308 
1309 /*!
1310  * \brief Create a tree of virtual subscriptions based on a resource tree node.
1311  *
1312  * \param handler The handler to supply to leaf subscriptions.
1313  * \param resource The requested resource for this subscription.
1314  * \param generator Body generator to use for leaf subscriptions.
1315  * \param tree The root of the subscription tree.
1316  * \param current The tree node that corresponds to the subscription being created.
1317  */
1319  const char *resource, struct ast_sip_pubsub_body_generator *generator,
1320  struct sip_subscription_tree *tree, struct tree_node *current)
1321 {
1322  int i;
1323  struct ast_sip_subscription *sub;
1324 
1325  sub = allocate_subscription(handler, resource, current->display_name, tree);
1326  if (!sub) {
1327  return NULL;
1328  }
1329 
1330  sub->full_state = current->full_state;
1331  sub->body_generator = generator;
1332  AST_VECTOR_INIT(&sub->children, AST_VECTOR_SIZE(&current->children));
1333 
1334  for (i = 0; i < AST_VECTOR_SIZE(&current->children); ++i) {
1335  struct ast_sip_subscription *child;
1336  struct tree_node *child_node = AST_VECTOR_GET(&current->children, i);
1337 
1338  child = create_virtual_subscriptions(handler, child_node->resource, generator,
1339  tree, child_node);
1340 
1341  if (!child) {
1342  ast_debug(1, "Child subscription to resource %s could not be created\n",
1343  child_node->resource);
1344  continue;
1345  }
1346 
1347  if (AST_VECTOR_APPEND(&sub->children, child)) {
1348  ast_debug(1, "Child subscription to resource %s could not be appended\n",
1349  child_node->resource);
1350  destroy_subscription(child);
1351  /* Have to release tree here too because a ref was added
1352  * to child that destroy_subscription() doesn't release. */
1353  ao2_cleanup(tree);
1354  }
1355  }
1356 
1357  return sub;
1358 }
1359 
1361 {
1362  int i;
1363 
1364  if (!sub) {
1365  return;
1366  }
1367 
1368  if (AST_VECTOR_SIZE(&sub->children) > 0) {
1369  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
1370  shutdown_subscriptions(AST_VECTOR_GET(&sub->children, i));
1371  }
1372  return;
1373  }
1374 
1375  /* We notify subscription shutdown only on the tree leaves. */
1376  if (sub->handler->subscription_shutdown) {
1377  sub->handler->subscription_shutdown(sub);
1378  }
1379 }
1380 static int subscription_unreference_dialog(void *obj)
1381 {
1382  struct sip_subscription_tree *sub_tree = obj;
1383 
1384  /* This is why we keep the dialog on the subscription. When the subscription
1385  * is destroyed, there is no guarantee that the underlying dialog is ready
1386  * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1387  * either. The dialog could be destroyed before our subscription is. We fix
1388  * this problem by keeping a reference to the dialog until it is time to
1389  * destroy the subscription. We need to have the dialog available when the
1390  * subscription is destroyed so that we can guarantee that our attempt to
1391  * remove the serializer will be successful.
1392  */
1393  pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
1394  sub_tree->dlg = NULL;
1395 
1396  return 0;
1397 }
1398 
1399 static void subscription_tree_destructor(void *obj)
1400 {
1401  struct sip_subscription_tree *sub_tree = obj;
1402 
1403  ast_debug(3, "Destroying subscription tree %p '%s->%s'\n",
1404  sub_tree,
1405  sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
1406  sub_tree->root ? sub_tree->root->resource : "Unknown");
1407 
1408  destroy_subscriptions(sub_tree->root);
1409 
1410  if (sub_tree->dlg) {
1413  }
1414 
1415  ao2_cleanup(sub_tree->endpoint);
1416 
1419 }
1420 
1422 {
1423  ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1424  sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree);
1425  ao2_cleanup(sub->tree);
1426 }
1427 
1428 static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
1429 {
1430  sub_tree->dlg = dlg;
1433  pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
1434  pjsip_dlg_inc_session(dlg, &pubsub_module);
1435 }
1436 
1437 static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
1438 {
1439  struct sip_subscription_tree *sub_tree;
1440 
1441  sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
1442  if (!sub_tree) {
1443  return NULL;
1444  }
1445 
1447 
1448  if (rdata) {
1449  /*
1450  * We must continue using the serializer that the original
1451  * SUBSCRIBE came in on for the dialog. There may be
1452  * retransmissions already enqueued in the original
1453  * serializer that can result in reentrancy and message
1454  * sequencing problems.
1455  */
1457  } else {
1458  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1459 
1460  /* Create name with seq number appended. */
1461  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s",
1463 
1464  sub_tree->serializer = ast_sip_create_serializer(tps_name);
1465  }
1466  if (!sub_tree->serializer) {
1467  ao2_ref(sub_tree, -1);
1468  return NULL;
1469  }
1470 
1471  sub_tree->endpoint = ao2_bump(endpoint);
1472  sub_tree->notify_sched_id = -1;
1473 
1474  return sub_tree;
1475 }
1476 
1477 /*!
1478  * \brief Create a subscription tree based on a resource tree.
1479  *
1480  * Using the previously-determined valid resources in the provided resource tree,
1481  * a corresponding tree of ast_sip_subscriptions are created. The root of the
1482  * subscription tree is a real subscription, and the rest in the tree are
1483  * virtual subscriptions.
1484  *
1485  * \param handler The handler to use for leaf subscriptions
1486  * \param endpoint The endpoint that sent the SUBSCRIBE request
1487  * \param rdata The SUBSCRIBE content
1488  * \param resource The requested resource in the SUBSCRIBE request
1489  * \param generator The body generator to use in leaf subscriptions
1490  * \param tree The resource tree on which the subscription tree is based
1491  * \param[out] dlg_status The result of attempting to create a dialog
1492  * \param persistence
1493  *
1494  * \retval NULL Could not create the subscription tree
1495  * \retval non-NULL The root of the created subscription tree
1496  */
1497 
1499  struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
1500  struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree,
1501  pj_status_t *dlg_status, struct subscription_persistence *persistence)
1502 {
1503  struct sip_subscription_tree *sub_tree;
1504  pjsip_dialog *dlg;
1505 
1506  sub_tree = allocate_subscription_tree(endpoint, rdata);
1507  if (!sub_tree) {
1508  *dlg_status = PJ_ENOMEM;
1509  return NULL;
1510  }
1511  sub_tree->role = AST_SIP_NOTIFIER;
1512 
1513  dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, dlg_status);
1514  if (!dlg) {
1515  if (*dlg_status != PJ_EEXISTS) {
1516  ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1517  }
1518  ao2_ref(sub_tree, -1);
1519  return NULL;
1520  }
1521 
1522  persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
1524  if (persistence) {
1525  /* Update the created dialog with the persisted information */
1526  pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
1527  pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->tag);
1528  dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
1529  pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
1530  dlg->local.cseq = persistence->cseq;
1531  }
1532 
1533  pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
1534 
1535  subscription_setup_dialog(sub_tree, dlg);
1536 
1537  /*
1538  * The evsub and subscription setup both add dialog refs, so the dialog ref that
1539  * was added when the dialog was created (see ast_sip_create_dialog_uas_lock) can
1540  * now be removed. The lock should no longer be needed so can be removed too.
1541  */
1542  pjsip_dlg_dec_lock(dlg);
1543 
1544 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
1545  pjsip_evsub_add_ref(sub_tree->evsub);
1546 #endif
1547 
1548  ast_sip_mod_data_set(dlg->pool, dlg->mod_data, pubsub_module.id, MOD_DATA_MSG,
1549  pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
1550 
1552 
1553  /* Persistence information needs to be available for all the subscriptions */
1554  sub_tree->persistence = ao2_bump(persistence);
1555 
1556  sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
1557  if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
1558  sub_tree->is_list = 1;
1559  }
1560 
1561  add_subscription(sub_tree);
1562 
1563  return sub_tree;
1564 }
1565 
1566 /*! Wrapper structure for initial_notify_task */
1569  unsigned int expires;
1570 };
1571 
1572 static int initial_notify_task(void *obj);
1573 static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state);
1574 
1575 /*! Persistent subscription recreation continuation under distributor serializer data */
1578  pjsip_rx_data *rdata;
1579 };
1580 
1581 /*!
1582  * \internal
1583  * \brief subscription_persistence_recreate continuation under distributor serializer.
1584  * \since 13.10.0
1585  *
1586  * \retval 0 on success.
1587  * \retval -1 on error.
1588  */
1589 static int sub_persistence_recreate(void *obj)
1590 {
1591  struct persistence_recreate_data *recreate_data = obj;
1592  struct subscription_persistence *persistence = recreate_data->persistence;
1593  pjsip_rx_data *rdata = recreate_data->rdata;
1594  struct ast_sip_endpoint *endpoint;
1595  struct sip_subscription_tree *sub_tree;
1596  struct ast_sip_pubsub_body_generator *generator;
1598  char *resource;
1599  pjsip_sip_uri *request_uri;
1600  size_t resource_size;
1601  int resp;
1602  struct resource_tree tree;
1603  pjsip_expires_hdr *expires_header;
1604  int64_t expires;
1605 
1606  request_uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
1607  resource_size = pj_strlen(&request_uri->user) + 1;
1608  resource = ast_alloca(resource_size);
1609  ast_copy_pj_str(resource, &request_uri->user, resource_size);
1610 
1611  /*
1612  * We may want to match without any user options getting
1613  * in the way.
1614  */
1616 
1617  handler = subscription_get_handler_from_rdata(rdata, persistence->endpoint);
1618  if (!handler || !handler->notifier) {
1619  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get subscription handler.\n",
1620  persistence->endpoint);
1621  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1622  return 0;
1623  }
1624 
1625  generator = subscription_get_generator_from_rdata(rdata, handler);
1626  if (!generator) {
1627  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Body generator not available.\n",
1628  persistence->endpoint);
1629  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1630  return 0;
1631  }
1632 
1633  ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data,
1634  pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
1635 
1636  /* Getting the endpoint may take some time that can affect the expiration. */
1637  endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1638  persistence->endpoint);
1639  if (!endpoint) {
1640  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The endpoint was not found\n",
1641  persistence->endpoint);
1642  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1643  return 0;
1644  }
1645 
1646  /* Update the expiration header with the new expiration */
1647  expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1648  rdata->msg_info.msg->hdr.next);
1649  if (!expires_header) {
1650  expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1651  if (!expires_header) {
1652  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not update expires header.\n",
1653  persistence->endpoint);
1654  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1655  ao2_ref(endpoint, -1);
1656  return 0;
1657  }
1658  pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1659  }
1660 
1661  expires = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
1662  if (expires <= 0) {
1663  /* The subscription expired since we started recreating the subscription. */
1664  ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1665  persistence->endpoint, persistence->tag);
1666  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1667  ao2_ref(endpoint, -1);
1668  return 0;
1669  }
1670  expires_header->ivalue = expires;
1671 
1672  memset(&tree, 0, sizeof(tree));
1673  resp = build_resource_tree(endpoint, handler, resource, &tree,
1675  if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1676  pj_status_t dlg_status;
1677 
1678  sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,
1679  &tree, &dlg_status, persistence);
1680  if (!sub_tree) {
1681  if (dlg_status != PJ_EEXISTS) {
1682  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",
1683  persistence->endpoint);
1684  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1685  }
1686  } else {
1687  struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
1688 
1689  if (!ind) {
1690  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1691  goto error;
1692  }
1693 
1694  ind->sub_tree = ao2_bump(sub_tree);
1695  ind->expires = expires_header->ivalue;
1696 
1699  /* Could not send initial subscribe NOTIFY */
1700  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1701  ao2_ref(sub_tree, -1);
1702  ast_free(ind);
1703  }
1704  }
1705  } else {
1706  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1707  }
1708 
1709 error:
1710  resource_tree_destroy(&tree);
1711  ao2_ref(endpoint, -1);
1712 
1713  return 0;
1714 }
1715 
1716 /*! \brief Callback function to perform the actual recreation of a subscription */
1717 static int subscription_persistence_recreate(void *obj, void *arg, int flags)
1718 {
1719  struct subscription_persistence *persistence = obj;
1720  pj_pool_t *pool = arg;
1721  struct ast_taskprocessor *serializer;
1722  pjsip_rx_data rdata;
1723  struct persistence_recreate_data recreate_data;
1724 
1725  /* If this subscription used a reliable transport it can't be reestablished so remove it */
1726  if (persistence->prune_on_boot) {
1727  ast_debug(3, "Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1730  return 0;
1731  }
1732 
1733  /* If this subscription has already expired remove it */
1734  if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) {
1735  ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1738  return 0;
1739  }
1740 
1741  memset(&rdata, 0, sizeof(rdata));
1742  pj_pool_reset(pool);
1743  rdata.tp_info.pool = pool;
1744 
1748  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n",
1751  return 0;
1752  }
1753 
1754  if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1755  ast_log(LOG_NOTICE, "Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1758  return 0;
1759  }
1760 
1761  /* Continue the remainder in the distributor serializer */
1763  if (!serializer) {
1764  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1767  return 0;
1768  }
1769  recreate_data.persistence = persistence;
1770  recreate_data.rdata = &rdata;
1772  &recreate_data)) {
1773  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
1776  }
1778 
1779  return 0;
1780 }
1781 
1782 /*! \brief Function which loads and recreates persisted subscriptions upon startup when the system is fully booted */
1783 static int subscription_persistence_load(void *data)
1784 {
1785  struct ao2_container *persisted_subscriptions = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
1786  "subscription_persistence", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1787  pj_pool_t *pool;
1788 
1789  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "rtd%p", PJSIP_POOL_RDATA_LEN,
1790  PJSIP_POOL_RDATA_INC);
1791  if (!pool) {
1792  ast_log(LOG_WARNING, "Could not create a memory pool for recreating SIP subscriptions\n");
1793  return 0;
1794  }
1795 
1796  ao2_callback(persisted_subscriptions, OBJ_NODATA, subscription_persistence_recreate, pool);
1797 
1798  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1799 
1800  ao2_ref(persisted_subscriptions, -1);
1801  return 0;
1802 }
1803 
1804 /*! \brief Event callback which fires subscription persistence recreation when the system is fully booted */
1806 {
1807  struct ast_json_payload *payload;
1808  const char *type;
1809 
1811  return;
1812  }
1813 
1814  payload = stasis_message_data(message);
1815  type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1816 
1817  /* This subscription only responds to the FullyBooted event so that all modules have been loaded when we
1818  * recreate SIP subscriptions.
1819  */
1820  if (strcmp(type, "FullyBooted")) {
1821  return;
1822  }
1823 
1824  /* This has to be here so the subscription is recreated when the body generator is available */
1826 
1827  /* Once the system is fully booted we don't care anymore */
1829 }
1830 
1831 typedef int (*on_subscription_t)(struct sip_subscription_tree *sub, void *arg);
1832 
1833 static int for_each_subscription(on_subscription_t on_subscription, void *arg)
1834 {
1835  int num = 0;
1836  struct sip_subscription_tree *i;
1837 
1838  if (!on_subscription) {
1839  return num;
1840  }
1841 
1844  if (on_subscription(i, arg)) {
1845  break;
1846  }
1847  ++num;
1848  }
1850  return num;
1851 }
1852 
1853 static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree,
1854  struct ast_str **buf)
1855 {
1856  char str[256];
1857  struct ast_sip_endpoint_id_configuration *id = &sub_tree->endpoint->id;
1858 
1859  ast_str_append(buf, 0, "Role: %s\r\n",
1860  sip_subscription_roles_map[sub_tree->role]);
1861  ast_str_append(buf, 0, "Endpoint: %s\r\n",
1862  ast_sorcery_object_get_id(sub_tree->endpoint));
1863 
1864  if (sub_tree->dlg) {
1865  ast_copy_pj_str(str, &sub_tree->dlg->call_id->id, sizeof(str));
1866  } else {
1867  ast_copy_string(str, "<unknown>", sizeof(str));
1868  }
1869  ast_str_append(buf, 0, "Callid: %s\r\n", str);
1870 
1871  ast_str_append(buf, 0, "State: %s\r\n", pjsip_evsub_get_state_name(sub_tree->evsub));
1872 
1873  ast_callerid_merge(str, sizeof(str),
1874  S_COR(id->self.name.valid, id->self.name.str, NULL),
1875  S_COR(id->self.number.valid, id->self.number.str, NULL),
1876  "Unknown");
1877 
1878  ast_str_append(buf, 0, "Callerid: %s\r\n", str);
1879 
1880  /* XXX This needs to be done recursively for lists */
1881  if (sub_tree->root->handler->to_ami) {
1882  sub_tree->root->handler->to_ami(sub_tree->root, buf);
1883  }
1884 }
1885 
1886 
1888 {
1889  pjsip_dialog *dlg;
1890  pjsip_msg *msg;
1891  pj_str_t name;
1892 
1893  dlg = sub->tree->dlg;
1894  msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1895  pj_cstr(&name, header);
1896 
1897  return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
1898 }
1899 
1900 /* XXX This function is not used. */
1902  struct ast_sip_endpoint *endpoint, const char *resource)
1903 {
1904  struct ast_sip_subscription *sub;
1905  pjsip_dialog *dlg;
1906  struct ast_sip_contact *contact;
1907  pj_str_t event;
1908  pjsip_tx_data *tdata;
1909  pjsip_evsub *evsub;
1910  struct sip_subscription_tree *sub_tree = NULL;
1911 
1913  if (!sub_tree) {
1914  return NULL;
1915  }
1916 
1917  sub = allocate_subscription(handler, resource, NULL, sub_tree);
1918  if (!sub) {
1919  ao2_cleanup(sub_tree);
1920  return NULL;
1921  }
1922 
1924  if (!contact || ast_strlen_zero(contact->uri)) {
1925  ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
1927  ao2_ref(sub_tree, -1);
1929  return NULL;
1930  }
1931 
1934  if (!dlg) {
1935  ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1936  ao2_ref(sub_tree, -1);
1937  return NULL;
1938  }
1939 
1940  pj_cstr(&event, handler->event_name);
1941  pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub_tree->evsub);
1942  subscription_setup_dialog(sub_tree, dlg);
1943 
1944  evsub = sub_tree->evsub;
1945 
1946  if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
1947  pjsip_evsub_send_request(sub_tree->evsub, tdata);
1948  } else {
1949  /* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
1950  * being called and terminating the subscription. Therefore, we don't
1951  * need to decrease the reference count of sub here.
1952  */
1953  pjsip_evsub_terminate(evsub, PJ_TRUE);
1954  ao2_ref(sub_tree, -1);
1955  return NULL;
1956  }
1957 
1958  add_subscription(sub_tree);
1959 
1960  return sub;
1961 }
1962 
1964 {
1965  ast_assert(sub->tree->dlg != NULL);
1966  return sub->tree->dlg;
1967 }
1968 
1970 {
1971  ast_assert(sub->tree->endpoint != NULL);
1972  return ao2_bump(sub->tree->endpoint);
1973 }
1974 
1976 {
1977  ast_assert(sub->tree->serializer != NULL);
1978  return sub->tree->serializer;
1979 }
1980 
1981 /*!
1982  * \brief Pre-allocate a buffer for the transmission
1983  *
1984  * Typically, we let PJSIP do this step for us when we send a request. PJSIP's buffer
1985  * allocation algorithm is to allocate a buffer of PJSIP_MAX_PKT_LEN bytes and attempt
1986  * to write the packet to the allocated buffer. If the buffer is too small to hold the
1987  * packet, then we get told the message is too long to be sent.
1988  *
1989  * When dealing with SIP NOTIFY, especially with RLS, it is possible to exceed
1990  * PJSIP_MAX_PKT_LEN. Rather than accepting the limitation imposed on us by default,
1991  * we instead take the strategy of pre-allocating the buffer, testing for ourselves
1992  * if the message will fit, and resizing the buffer as required.
1993  *
1994  * The limit we impose is double that of the maximum packet length.
1995  *
1996  * \param tdata The tdata onto which to allocate a buffer
1997  * \retval 0 Success
1998  * \retval -1 The message is too large
1999  */
2000 static int allocate_tdata_buffer(pjsip_tx_data *tdata)
2001 {
2002  int buf_size;
2003  int size = -1;
2004  char *buf;
2005 
2006  for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
2007  buf = pj_pool_alloc(tdata->pool, buf_size);
2008  size = pjsip_msg_print(tdata->msg, buf, buf_size);
2009  }
2010 
2011  if (size == -1) {
2012  return -1;
2013  }
2014 
2015  tdata->buf.start = buf;
2016  tdata->buf.cur = tdata->buf.start;
2017  tdata->buf.end = tdata->buf.start + buf_size;
2018 
2019  return 0;
2020 }
2021 
2022 static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
2023 {
2024 #ifdef TEST_FRAMEWORK
2025  struct ast_sip_endpoint *endpoint = sub_tree->endpoint;
2026  pjsip_evsub *evsub = sub_tree->evsub;
2027 #endif
2028  int res;
2029 
2030  if (allocate_tdata_buffer(tdata)) {
2031  ast_log(LOG_ERROR, "SIP request %s is too large to send.\n", tdata->info);
2032  pjsip_tx_data_dec_ref(tdata);
2033  return -1;
2034  }
2035 
2036  res = pjsip_evsub_send_request(sub_tree->evsub, tdata);
2037 
2039 
2040  ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
2041  "StateText: %s\r\n"
2042  "Endpoint: %s\r\n",
2043  pjsip_evsub_get_state_name(evsub),
2044  ast_sorcery_object_get_id(endpoint));
2045 
2046  return (res == PJ_SUCCESS ? 0 : -1);
2047 }
2048 
2049 /*!
2050  * \brief Add a resource XML element to an RLMI body
2051  *
2052  * Each resource element represents a subscribed resource in the list. This function currently
2053  * will unconditionally add an instance element to each created resource element. Instance
2054  * elements refer to later parts in the multipart body.
2055  *
2056  * \param pool PJLIB allocation pool
2057  * \param rlmi
2058  * \param cid Content-ID header of the resource
2059  * \param resource_name Name of the resource
2060  * \param resource_uri URI of the resource
2061  * \param state State of the subscribed resource
2062  */
2063 static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid,
2064  const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
2065 {
2066  static pj_str_t cid_name = { "cid", 3 };
2067  pj_xml_node *resource;
2068  pj_xml_node *name;
2069  pj_xml_node *instance;
2070  pj_xml_attr *cid_attr;
2071  char id[6];
2072  char uri[PJSIP_MAX_URL_SIZE];
2073 
2074  /* This creates a string representing the Content-ID without the enclosing < > */
2075  const pj_str_t cid_stripped = {
2076  .ptr = cid->hvalue.ptr + 1,
2077  .slen = cid->hvalue.slen - 2,
2078  };
2079 
2080  resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
2081  name = ast_sip_presence_xml_create_node(pool, resource, "name");
2082  instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
2083 
2084  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
2085  ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
2086 
2087  pj_strdup2(pool, &name->content, resource_name);
2088 
2089  ast_generate_random_string(id, sizeof(id));
2090 
2091  ast_sip_presence_xml_create_attr(pool, instance, "id", id);
2092  ast_sip_presence_xml_create_attr(pool, instance, "state",
2093  state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
2094 
2095  /* Use the PJLIB-util XML library directly here since we are using a
2096  * pj_str_t
2097  */
2098 
2099  cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2100  pj_xml_add_attr(instance, cid_attr);
2101 }
2102 
2103 /*!
2104  * \brief A multipart body part and meta-information
2105  *
2106  * When creating a multipart body part, the end result (the
2107  * pjsip_multipart_part) is hard to inspect without undoing
2108  * a lot of what was done to create it. Therefore, we use this
2109  * structure to store meta-information about the body part.
2110  *
2111  * The main consumer of this is the creator of the RLMI body
2112  * part of a multipart resource list body.
2113  */
2114 struct body_part {
2115  /*! Content-ID header for the body part */
2116  pjsip_generic_string_hdr *cid;
2117  /*! Subscribed resource represented in the body part */
2118  const char *resource;
2119  /*! URI for the subscribed body part */
2120  pjsip_sip_uri *uri;
2121  /*! Subscription state of the resource represented in the body part */
2122  pjsip_evsub_state state;
2123  /*! The actual body part that will be present in the multipart body */
2124  pjsip_multipart_part *part;
2125  /*! Display name for the resource */
2126  const char *display_name;
2127 };
2128 
2129 /*!
2130  * \brief Type declaration for container of body part structures
2131  */
2133 
2134 /*!
2135  * \brief Create a Content-ID header
2136  *
2137  * Content-ID headers are required by RFC2387 for multipart/related
2138  * bodies. They serve as identifiers for each part of the multipart body.
2139  *
2140  * \param pool PJLIB allocation pool
2141  * \param sub Subscription to a resource
2142  */
2143 static pjsip_generic_string_hdr *generate_content_id_hdr(pj_pool_t *pool,
2144  const struct ast_sip_subscription *sub)
2145 {
2146  static const pj_str_t cid_name = { "Content-ID", 10 };
2147  pjsip_generic_string_hdr *cid;
2148  char id[6];
2149  size_t alloc_size;
2150  pj_str_t cid_value;
2151 
2152  /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
2153  alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
2154  cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2155  cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
2156  ast_generate_random_string(id, sizeof(id)),
2157  (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
2158  cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2159 
2160  return cid;
2161 }
2162 
2163 static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
2164 {
2165  int num_printed;
2166  pj_xml_node *rlmi = msg_body->data;
2167 
2168  num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
2169  if (num_printed <= AST_PJSIP_XML_PROLOG_LEN) {
2170  return -1;
2171  }
2172 
2173  return num_printed;
2174 }
2175 
2176 static void *rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
2177 {
2178  const pj_xml_node *rlmi = data;
2179 
2180  return pj_xml_clone(pool, rlmi);
2181 }
2182 
2183 /*!
2184  * \brief Create an RLMI body part for a multipart resource list body
2185  *
2186  * RLMI (Resource list meta information) is a special body type that lists
2187  * the subscribed resources and tells subscribers the number of subscribed
2188  * resources and what other body parts are in the multipart body. The
2189  * RLMI body also has a version number that a subscriber can use to ensure
2190  * that the locally-stored state corresponds to server state.
2191  *
2192  * \param pool The allocation pool
2193  * \param sub The subscription representing the subscribed resource list
2194  * \param body_parts A container of body parts that RLMI will refer to
2195  * \param full_state Indicates whether this is a full or partial state notification
2196  * \return The multipart part representing the RLMI body
2197  */
2198 static pjsip_multipart_part *build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
2199  struct body_part_list *body_parts, unsigned int full_state)
2200 {
2201  pj_xml_node *rlmi;
2202  pj_xml_node *name;
2203  pjsip_multipart_part *rlmi_part;
2204  char version_str[32];
2205  char uri[PJSIP_MAX_URL_SIZE];
2206  pjsip_generic_string_hdr *cid;
2207  int i;
2208 
2209  rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
2210  ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
2211 
2212  ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
2213  ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
2214 
2215  snprintf(version_str, sizeof(version_str), "%u", sub->version++);
2216  ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
2217  ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
2218 
2219  name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
2220  pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
2221 
2222  for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
2223  const struct body_part *part = AST_VECTOR_GET(body_parts, i);
2224 
2225  add_rlmi_resource(pool, rlmi, part->cid, S_OR(part->display_name, part->resource), part->uri, part->state);
2226  }
2227 
2228  rlmi_part = pjsip_multipart_create_part(pool);
2229 
2230  rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2231  pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &rlmi_media_type);
2232 
2233  rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2234  rlmi_part->body->clone_data = rlmi_clone_data;
2235  rlmi_part->body->print_body = rlmi_print_body;
2236 
2237  cid = generate_content_id_hdr(pool, sub);
2238  pj_list_insert_before(&rlmi_part->hdr, cid);
2239 
2240  return rlmi_part;
2241 }
2242 
2243 static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
2244  unsigned int force_full_state);
2245 
2246 /*!
2247  * \brief Destroy a list of body parts
2248  *
2249  * \param parts The container of parts to destroy
2250  */
2251 static void free_body_parts(struct body_part_list *parts)
2252 {
2253  int i;
2254 
2255  for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
2256  struct body_part *part = AST_VECTOR_GET(parts, i);
2257  ast_free(part);
2258  }
2259 
2260  AST_VECTOR_FREE(parts);
2261 }
2262 
2263 /*!
2264  * \brief Allocate and initialize a body part structure
2265  *
2266  * \param pool PJLIB allocation pool
2267  * \param sub Subscription representing a subscribed resource
2268  */
2269 static struct body_part *allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
2270 {
2271  struct body_part *bp;
2272 
2273  bp = ast_calloc(1, sizeof(*bp));
2274  if (!bp) {
2275  return NULL;
2276  }
2277 
2278  bp->cid = generate_content_id_hdr(pool, sub);
2279  bp->resource = sub->resource;
2280  bp->state = sub->subscription_state;
2281  bp->uri = sub->uri;
2282  bp->display_name = sub->display_name;
2283 
2284  return bp;
2285 }
2286 
2287 /*!
2288  * \brief Create a multipart body part for a subscribed resource
2289  *
2290  * \param pool PJLIB allocation pool
2291  * \param sub The subscription representing a subscribed resource
2292  * \param parts A vector of parts to append the created part to.
2293  * \param use_full_state Unused locally, but may be passed to other functions
2294  */
2295 static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub,
2296  struct body_part_list *parts, unsigned int use_full_state)
2297 {
2298  struct body_part *bp;
2299  pjsip_msg_body *body;
2300 
2301  bp = allocate_body_part(pool, sub);
2302  if (!bp) {
2303  return;
2304  }
2305 
2306  body = generate_notify_body(pool, sub, use_full_state);
2307  if (!body) {
2308  /* Partial state was requested and the resource has not changed state */
2309  ast_free(bp);
2310  return;
2311  }
2312 
2313  bp->part = pjsip_multipart_create_part(pool);
2314  bp->part->body = body;
2315  pj_list_insert_before(&bp->part->hdr, bp->cid);
2316 
2317  if (AST_VECTOR_APPEND(parts, bp)) {
2318  ast_free(bp);
2319  }
2320 }
2321 
2322 /*!
2323  * \brief Create and initialize the PJSIP multipart body structure for a resource list subscription
2324  *
2325  * \param pool
2326  * \return The multipart message body
2327  */
2328 static pjsip_msg_body *create_multipart_body(pj_pool_t *pool)
2329 {
2330  pjsip_media_type media_type;
2331  pjsip_param *media_type_param;
2332  char boundary[6];
2333  pj_str_t pj_boundary;
2334 
2335  pjsip_media_type_init2(&media_type, "multipart", "related");
2336 
2337  media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
2338  pj_list_init(media_type_param);
2339 
2340  pj_strdup2(pool, &media_type_param->name, "type");
2341  pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
2342 
2343  pj_list_insert_before(&media_type.param, media_type_param);
2344 
2345  pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
2346  return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2347 }
2348 
2349 /*!
2350  * \brief Create a resource list body for NOTIFY requests
2351  *
2352  * Resource list bodies are multipart/related bodies. The first part of the multipart body
2353  * is an RLMI body that describes the rest of the parts to come. The other parts of the body
2354  * convey state of individual subscribed resources.
2355  *
2356  * \param pool PJLIB allocation pool
2357  * \param sub Subscription details from which to generate body
2358  * \param force_full_state If true, ignore resource list settings and send a full state notification
2359  * \return The generated multipart/related body
2360  */
2361 static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
2362  unsigned int force_full_state)
2363 {
2364  int i;
2365  pjsip_multipart_part *rlmi_part;
2366  pjsip_msg_body *multipart;
2367  struct body_part_list body_parts;
2368  unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
2369 
2370  if (AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children))) {
2371  return NULL;
2372  }
2373 
2374  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2375  build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
2376  }
2377 
2378  /* This can happen if issuing partial state and no children of the list have changed state */
2379  if (AST_VECTOR_SIZE(&body_parts) == 0) {
2380  free_body_parts(&body_parts);
2381  return NULL;
2382  }
2383 
2384  multipart = create_multipart_body(pool);
2385 
2386  rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
2387  if (!rlmi_part) {
2388  free_body_parts(&body_parts);
2389  return NULL;
2390  }
2391  pjsip_multipart_add_part(pool, multipart, rlmi_part);
2392 
2393  for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
2394  pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
2395  }
2396 
2397  free_body_parts(&body_parts);
2398  return multipart;
2399 }
2400 
2401 /*!
2402  * \brief Create the body for a NOTIFY request.
2403  *
2404  * \param pool The pool used for allocations
2405  * \param root The root of the subscription tree
2406  * \param force_full_state If true, ignore resource list settings and send a full state notification
2407  */
2408 static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
2409  unsigned int force_full_state)
2410 {
2411  pjsip_msg_body *body;
2412 
2413  if (AST_VECTOR_SIZE(&root->children) == 0) {
2414  if (force_full_state || root->body_changed) {
2415  /* Not a list. We've already generated the body and saved it on the subscription.
2416  * Use that directly.
2417  */
2418  pj_str_t type;
2419  pj_str_t subtype;
2420  pj_str_t text;
2421 
2422  pj_cstr(&type, ast_sip_subscription_get_body_type(root));
2423  pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
2424  pj_cstr(&text, ast_str_buffer(root->body_text));
2425 
2426  body = pjsip_msg_body_create(pool, &type, &subtype, &text);
2427  root->body_changed = 0;
2428  } else {
2429  body = NULL;
2430  }
2431  } else {
2432  body = generate_list_body(pool, root, force_full_state);
2433  }
2434 
2435  return body;
2436 }
2437 
2438 /*!
2439  * \brief Shortcut method to create a Require: eventlist header
2440  */
2441 static pjsip_require_hdr *create_require_eventlist(pj_pool_t *pool)
2442 {
2443  pjsip_require_hdr *require;
2444 
2445  require = pjsip_require_hdr_create(pool);
2446  pj_strdup2(pool, &require->values[0], "eventlist");
2447  require->count = 1;
2448 
2449  return require;
2450 }
2451 
2452 /*!
2453  * \brief Send a NOTIFY request to a subscriber
2454  *
2455  * \pre sub_tree->dlg is locked
2456  *
2457  * \param sub_tree The subscription tree representing the subscription
2458  * \param force_full_state If true, ignore resource list settings and send full resource list state.
2459  * \retval 0 Success
2460  * \retval non-zero Failure
2461  */
2462 static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
2463 {
2464  pjsip_evsub *evsub = sub_tree->evsub;
2465  pjsip_tx_data *tdata;
2466 
2467  if (ast_shutdown_final()
2468  && sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED
2469  && sub_tree->persistence) {
2470  return 0;
2471  }
2472 
2473  if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
2474  NULL, NULL, &tdata) != PJ_SUCCESS) {
2475  return -1;
2476  }
2477 
2478  tdata->msg->body = generate_notify_body(tdata->pool, sub_tree->root, force_full_state);
2479  if (!tdata->msg->body) {
2480  pjsip_tx_data_dec_ref(tdata);
2481  return -1;
2482  }
2483 
2484  if (sub_tree->is_list) {
2485  pjsip_require_hdr *require = create_require_eventlist(tdata->pool);
2486  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2487  }
2488 
2489  if (sip_subscription_send_request(sub_tree, tdata)) {
2490  /* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */
2491  return -1;
2492  }
2493 
2494  sub_tree->send_scheduled_notify = 0;
2495 
2496  return 0;
2497 }
2498 
2499 static int serialized_send_notify(void *userdata)
2500 {
2501  struct sip_subscription_tree *sub_tree = userdata;
2502  pjsip_dialog *dlg = sub_tree->dlg;
2503 
2504  pjsip_dlg_inc_lock(dlg);
2505 
2506  sub_tree->notify_sched_id = -1;
2507 
2508  /* It's possible that between when the notification was scheduled
2509  * and now a new SUBSCRIBE arrived requiring full state to be
2510  * sent out in an immediate NOTIFY. It's also possible that we're
2511  * already processing a terminate. If that has happened, we need to
2512  * bail out here instead of sending the batched NOTIFY.
2513  */
2514 
2515  if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS
2516  || !sub_tree->send_scheduled_notify) {
2517  pjsip_dlg_dec_lock(dlg);
2518  ao2_cleanup(sub_tree);
2519  return 0;
2520  }
2521 
2522  if (sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) {
2524  }
2525 
2526  send_notify(sub_tree, 0);
2527 
2529  sub_tree->state == SIP_SUB_TREE_TERMINATED
2530  ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2531  "Resource: %s", sub_tree->root->resource);
2532 
2533  pjsip_dlg_dec_lock(dlg);
2534  ao2_cleanup(sub_tree);
2535  return 0;
2536 }
2537 
2538 static int sched_cb(const void *data)
2539 {
2540  struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
2541 
2542  /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
2543  if (ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree)) {
2544  ao2_cleanup(sub_tree);
2545  }
2546 
2547  return 0;
2548 }
2549 
2550 static int schedule_notification(struct sip_subscription_tree *sub_tree)
2551 {
2552  /* There's already a notification scheduled */
2553  if (sub_tree->notify_sched_id > -1) {
2554  return 0;
2555  }
2556 
2557  sub_tree->send_scheduled_notify = 1;
2559  if (sub_tree->notify_sched_id < 0) {
2560  ao2_cleanup(sub_tree);
2561  return -1;
2562  }
2563 
2564  return 0;
2565 }
2566 
2568  int terminate)
2569 {
2570  int res;
2571  pjsip_dialog *dlg = sub->tree->dlg;
2572 
2573  pjsip_dlg_inc_lock(dlg);
2574 
2575  if (sub->tree->state != SIP_SUB_TREE_NORMAL) {
2576  pjsip_dlg_dec_lock(dlg);
2577  return 0;
2578  }
2579 
2582  pjsip_dlg_dec_lock(dlg);
2583  return -1;
2584  }
2585 
2586  sub->body_changed = 1;
2587  if (terminate) {
2588  sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2589  sub->tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
2590  }
2591 
2592  if (sub->tree->notification_batch_interval) {
2593  res = schedule_notification(sub->tree);
2594  } else {
2595  /* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */
2596  ao2_ref(sub->tree, +1);
2597  if (terminate) {
2598  sub->tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS;
2599  }
2600  res = send_notify(sub->tree, 0);
2601  ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2602  "Resource: %s",
2603  sub->tree->root->resource);
2604  ao2_ref(sub->tree, -1);
2605  }
2606 
2607  pjsip_dlg_dec_lock(dlg);
2608  return res;
2609 }
2610 
2612 {
2613  return sub->uri;
2614 }
2615 
2617 {
2618  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2619 }
2620 
2622 {
2623  pjsip_dialog *dlg;
2624  pjsip_sip_uri *uri;
2625 
2626  dlg = sub->tree->dlg;
2627  uri = pjsip_uri_get_uri(dlg->remote.info->uri);
2628 
2629  if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
2630  *buf = '\0';
2631  }
2632 }
2633 
2635 {
2636  return sub->resource;
2637 }
2638 
2640 {
2641  return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2642 }
2643 
2644 static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
2645 {
2646  pjsip_hdr res_hdr;
2647 
2648  /* If this is a persistence recreation the subscription has already been accepted */
2649  if (ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_PERSISTENCE)) {
2650  return 0;
2651  }
2652 
2653  pj_list_init(&res_hdr);
2654  if (sub_tree->is_list) {
2655  /* If subscribing to a list, our response has to have a Require: eventlist header in it */
2656  pj_list_insert_before(&res_hdr, create_require_eventlist(rdata->tp_info.pool));
2657  }
2658 
2659  return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2660 }
2661 
2663 {
2665 }
2666 
2667 int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
2668 {
2669  return ast_datastores_add(subscription->datastores, datastore);
2670 }
2671 
2673 {
2674  return ast_datastores_find(subscription->datastores, name);
2675 }
2676 
2677 void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
2678 {
2679  ast_datastores_remove(subscription->datastores, name);
2680 }
2681 
2683 {
2684  return subscription->datastores;
2685 }
2686 
2687 int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore)
2688 {
2689  return ast_datastores_add(publication->datastores, datastore);
2690 }
2691 
2693 {
2694  return ast_datastores_find(publication->datastores, name);
2695 }
2696 
2697 void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name)
2698 {
2699  ast_datastores_remove(publication->datastores, name);
2700 }
2701 
2703 {
2704  return publication->datastores;
2705 }
2706 
2707 void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, struct ast_json *persistence_data)
2708 {
2709  ast_json_unref(subscription->persistence_data);
2710  subscription->persistence_data = persistence_data;
2711 
2712  if (subscription->tree->persistence) {
2713  if (!subscription->tree->persistence->generator_data) {
2715  if (!subscription->tree->persistence->generator_data) {
2716  return;
2717  }
2718  }
2719  ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
2720  ast_json_ref(persistence_data));
2721  }
2722 }
2723 
2725 {
2726  return subscription->persistence_data;
2727 }
2728 
2730 
2731 static int publication_hash_fn(const void *obj, const int flags)
2732 {
2733  const struct ast_sip_publication *publication = obj;
2734  const int *entity_tag = obj;
2735 
2736  return flags & OBJ_KEY ? *entity_tag : publication->entity_tag;
2737 }
2738 
2739 static int publication_cmp_fn(void *obj, void *arg, int flags)
2740 {
2741  const struct ast_sip_publication *publication1 = obj;
2742  const struct ast_sip_publication *publication2 = arg;
2743  const int *entity_tag = arg;
2744 
2745  return (publication1->entity_tag == (flags & OBJ_KEY ? *entity_tag : publication2->entity_tag) ?
2746  CMP_MATCH | CMP_STOP : 0);
2747 }
2748 
2750 {
2754 }
2755 
2757 {
2758  if (ast_strlen_zero(handler->event_name)) {
2759  ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
2760  return -1;
2761  }
2762 
2765  if (!handler->publications) {
2766  ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
2767  handler->event_name);
2768  return -1;
2769  }
2770 
2772 
2773  return 0;
2774 }
2775 
2777 {
2778  struct ast_sip_publish_handler *iter;
2779 
2782  if (handler == iter) {
2784  ao2_cleanup(handler->publications);
2785  break;
2786  }
2787  }
2790 }
2791 
2793 
2795 {
2799 }
2800 
2802 {
2803  struct ast_sip_subscription_handler *iter;
2804 
2807  if (!strcmp(iter->event_name, event_name)) {
2808  break;
2809  }
2810  }
2812  return iter;
2813 }
2814 
2816 {
2817  pj_str_t event;
2818  pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
2819  struct ast_sip_subscription_handler *existing;
2820  int i = 0;
2821 
2822  if (ast_strlen_zero(handler->event_name)) {
2823  ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
2824  return -1;
2825  }
2826 
2827  existing = find_sub_handler_for_event_name(handler->event_name);
2828  if (existing) {
2830  "Unable to register subscription handler for event %s. A handler is already registered\n",
2831  handler->event_name);
2832  return -1;
2833  }
2834 
2835  for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
2836  pj_cstr(&accept[i], handler->accept[i]);
2837  }
2838 
2839  pj_cstr(&event, handler->event_name);
2840 
2841  pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
2842 
2844 
2845  return 0;
2846 }
2847 
2849 {
2850  struct ast_sip_subscription_handler *iter;
2851 
2854  if (handler == iter) {
2856  break;
2857  }
2858  }
2861 }
2862 
2864 {
2866 
2868  if (!strcmp(gen->type, type)
2869  && !strcmp(gen->subtype, subtype)) {
2870  break;
2871  }
2872  }
2873 
2874  return gen;
2875 }
2876 
2878 {
2880 
2884  return gen;
2885 }
2886 
2888 {
2889  char *accept_copy = ast_strdupa(accept);
2890  char *subtype = accept_copy;
2891  char *type = strsep(&subtype, "/");
2892 
2894  return NULL;
2895  }
2896 
2898 }
2899 
2901  size_t num_accept, const char *body_type)
2902 {
2903  int i;
2904  struct ast_sip_pubsub_body_generator *generator = NULL;
2905 
2906  for (i = 0; i < num_accept; ++i) {
2907  generator = find_body_generator_accept(accept[i]);
2908  if (generator) {
2909  ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
2910  if (strcmp(generator->body_type, body_type)) {
2911  ast_log(LOG_WARNING, "Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
2912  generator->type, generator->subtype, generator);
2913  generator = NULL;
2914  continue;
2915  }
2916  break;
2917  } else {
2918  ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
2919  }
2920  }
2921 
2922  return generator;
2923 }
2924 
2926 {
2927  void *notify_data;
2928  int res;
2929  struct ast_sip_body_data data = {
2930  .body_type = sub->handler->body_type,
2931  };
2932 
2933  if (AST_VECTOR_SIZE(&sub->children) > 0) {
2934  int i;
2935 
2936  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2937  if (generate_initial_notify(AST_VECTOR_GET(&sub->children, i))) {
2938  return -1;
2939  }
2940  }
2941 
2942  return 0;
2943  }
2944 
2945  /* We notify subscription establishment only on the tree leaves. */
2946  if (sub->handler->notifier->subscription_established(sub)) {
2947  return -1;
2948  }
2949 
2950  notify_data = sub->handler->notifier->get_notify_data(sub);
2951  if (!notify_data) {
2952  return -1;
2953  }
2954 
2955  data.body_data = notify_data;
2956 
2958  ast_sip_subscription_get_body_subtype(sub), &data, &sub->body_text);
2959 
2961 
2962  return res;
2963 }
2964 
2965 static int pubsub_on_refresh_timeout(void *userdata);
2966 
2967 static int initial_notify_task(void * obj)
2968 {
2969  struct initial_notify_data *ind = obj;
2970 
2971  if (generate_initial_notify(ind->sub_tree->root)) {
2972  pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE);
2973  } else {
2974  send_notify(ind->sub_tree, 1);
2975  ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
2976  "Resource: %s",
2977  ind->sub_tree->root->resource);
2978  }
2979 
2980  if (ind->expires != PJSIP_EXPIRES_NOT_SPECIFIED) {
2981  char *name = ast_alloca(strlen("->/ ") +
2982  strlen(ind->sub_tree->persistence->endpoint) +
2983  strlen(ind->sub_tree->root->resource) +
2984  strlen(ind->sub_tree->root->handler->event_name) +
2985  ind->sub_tree->dlg->call_id->id.slen + 1);
2986 
2987  sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint,
2989  (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr);
2990 
2991  ast_debug(3, "Scheduling timer: %s\n", name);
2993  ind->expires * 1000, pubsub_on_refresh_timeout, name,
2995  if (!ind->sub_tree->expiration_task) {
2996  ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n",
2997  ind->expires, name);
2998  }
2999  }
3000 
3001  ao2_ref(ind->sub_tree, -1);
3002  ast_free(ind);
3003 
3004  return 0;
3005 }
3006 
3007 static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
3008 {
3009  pjsip_expires_hdr *expires_header;
3011  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3012  struct sip_subscription_tree *sub_tree;
3013  struct ast_sip_pubsub_body_generator *generator;
3014  char *resource;
3015  pjsip_uri *request_uri;
3016  pjsip_sip_uri *request_uri_sip;
3017  size_t resource_size;
3018  int resp;
3019  struct resource_tree tree;
3020  pj_status_t dlg_status;
3021 
3022  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3023  ast_assert(endpoint != NULL);
3024 
3025  if (!endpoint->subscription.allow) {
3026  ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
3027  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
3028  return PJ_TRUE;
3029  }
3030 
3031  request_uri = rdata->msg_info.msg->line.req.uri;
3032 
3033  if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
3034  char uri_str[PJSIP_MAX_URL_SIZE];
3035 
3036  pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3037  ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3038  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3039  return PJ_TRUE;
3040  }
3041 
3042  request_uri_sip = pjsip_uri_get_uri(request_uri);
3043  resource_size = pj_strlen(&request_uri_sip->user) + 1;
3044  resource = ast_alloca(resource_size);
3045  ast_copy_pj_str(resource, &request_uri_sip->user, resource_size);
3046 
3047  /*
3048  * We may want to match without any user options getting
3049  * in the way.
3050  */
3052 
3053  expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3054  if (expires_header) {
3055  if (expires_header->ivalue == 0) {
3056  ast_debug(1, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3057  ast_sorcery_object_get_id(endpoint));
3058  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3059  return PJ_TRUE;
3060  }
3061  if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3062  ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3063  expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subscription.minexpiry);
3064  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
3065  return PJ_TRUE;
3066  }
3067  }
3068 
3070  if (!handler) {
3071  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3072  return PJ_TRUE;
3073  }
3074 
3075  generator = subscription_get_generator_from_rdata(rdata, handler);
3076  if (!generator) {
3077  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3078  return PJ_TRUE;
3079  }
3080 
3081  memset(&tree, 0, sizeof(tree));
3082  resp = build_resource_tree(endpoint, handler, resource, &tree,
3084  if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3085  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3086  resource_tree_destroy(&tree);
3087  return PJ_TRUE;
3088  }
3089 
3090  sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
3091  if (!sub_tree) {
3092  if (dlg_status != PJ_EEXISTS) {
3093  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3094  }
3095  } else {
3096  struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
3097 
3098  if (!ind) {
3099  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3100  resource_tree_destroy(&tree);
3101  return PJ_TRUE;
3102  }
3103 
3104  ind->sub_tree = ao2_bump(sub_tree);
3105  /* Since this is a normal subscribe, pjproject takes care of the timer */
3107 
3110  sip_subscription_accept(sub_tree, rdata, resp);
3112  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3113  ao2_ref(sub_tree, -1);
3114  ast_free(ind);
3115  }
3116  }
3117 
3118  resource_tree_destroy(&tree);
3119  return PJ_TRUE;
3120 }
3121 
3123 {
3124  struct ast_sip_publish_handler *iter = NULL;
3125 
3128  if (strcmp(event, iter->event_name)) {
3129  ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
3130  continue;
3131  }
3132  ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
3133  break;
3134  }
3136 
3137  return iter;
3138 }
3139 
3140 static enum sip_publish_type determine_sip_publish_type(pjsip_rx_data *rdata,
3141  pjsip_generic_string_hdr *etag_hdr, unsigned int *expires, int *entity_id)
3142 {
3143  pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3144 
3145  if (etag_hdr) {
3146  char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3147 
3148  ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
3149 
3150  if (sscanf(etag, "%30d", entity_id) != 1) {
3151  return SIP_PUBLISH_UNKNOWN;
3152  }
3153  }
3154 
3155  *expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3156 
3157  if (!(*expires)) {
3158  return SIP_PUBLISH_REMOVE;
3159  } else if (!etag_hdr && rdata->msg_info.msg->body) {
3160  return SIP_PUBLISH_INITIAL;
3161  } else if (etag_hdr && !rdata->msg_info.msg->body) {
3162  return SIP_PUBLISH_REFRESH;
3163  } else if (etag_hdr && rdata->msg_info.msg->body) {
3164  return SIP_PUBLISH_MODIFY;
3165  }
3166 
3167  return SIP_PUBLISH_UNKNOWN;
3168 }
3169 
3170 /*! \brief Internal destructor for publications */
3171 static void publication_destroy_fn(void *obj)
3172 {
3173  struct ast_sip_publication *publication = obj;
3174 
3175  ast_debug(3, "Destroying SIP publication\n");
3176 
3177  ao2_cleanup(publication->datastores);
3178  ao2_cleanup(publication->endpoint);
3179 
3181 }
3182 
3183 static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
3184  const char *resource, const char *event_configuration_name)
3185 {
3186  struct ast_sip_publication *publication;
3187  pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3188  size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
3189  char *dst;
3190 
3191  ast_assert(endpoint != NULL);
3192 
3193  if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
3194  return NULL;
3195  }
3196 
3198 
3199  if (!(publication->datastores = ast_datastores_alloc())) {
3200  ao2_ref(publication, -1);
3201  return NULL;
3202  }
3203 
3205  ao2_ref(endpoint, +1);
3206  publication->endpoint = endpoint;
3207  publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3208  publication->sched_id = -1;
3209  dst = publication->data;
3210  publication->resource = strcpy(dst, resource);
3211  dst += resource_len;
3212  publication->event_configuration_name = strcpy(dst, event_configuration_name);
3213 
3214  return publication;
3215 }
3216 
3217 static int sip_publication_respond(struct ast_sip_publication *pub, int status_code,
3218  pjsip_rx_data *rdata)
3219 {
3220  pjsip_tx_data *tdata;
3221  pjsip_transaction *tsx;
3222 
3223  if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, status_code, NULL, &tdata) != PJ_SUCCESS) {
3224  return -1;
3225  }
3226 
3227  if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3228  char buf[30];
3229 
3230  snprintf(buf, sizeof(buf), "%d", pub->entity_tag);
3231  ast_sip_add_header(tdata, "SIP-ETag", buf);
3232 
3233  snprintf(buf, sizeof(buf), "%d", pub->expires);
3234  ast_sip_add_header(tdata, "Expires", buf);
3235  }
3236 
3237  if (pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3238  pjsip_tx_data_dec_ref(tdata);
3239  return -1;
3240  }
3241 
3242  pjsip_tsx_recv_msg(tsx, rdata);
3243 
3244  if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3245  pjsip_tx_data_dec_ref(tdata);
3246  return -1;
3247  }
3248 
3249  return 0;
3250 }
3251 
3252 static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
3254 {
3255  struct ast_sip_publication *publication;
3256  char *resource_name;
3257  size_t resource_size;
3259  struct ast_variable *event_configuration_name = NULL;
3260  pjsip_uri *request_uri;
3261  pjsip_sip_uri *request_uri_sip;
3262  int resp;
3263 
3264  request_uri = rdata->msg_info.msg->line.req.uri;
3265 
3266  if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
3267  char uri_str[PJSIP_MAX_URL_SIZE];
3268 
3269  pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3270  ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3271  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3272  return NULL;
3273  }
3274 
3275  request_uri_sip = pjsip_uri_get_uri(request_uri);
3276  resource_size = pj_strlen(&request_uri_sip->user) + 1;
3277  resource_name = ast_alloca(resource_size);
3278  ast_copy_pj_str(resource_name, &request_uri_sip->user, resource_size);
3279 
3280  /*
3281  * We may want to match without any user options getting
3282  * in the way.
3283  */
3284  AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource_name);
3285 
3286  resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
3287  if (!resource) {
3288  ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name);
3289  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3290  return NULL;
3291  }
3292 
3293  if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
3294  ast_debug(1, "Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3295  resource_name, resource->endpoint, ast_sorcery_object_get_id(endpoint));
3296  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
3297  return NULL;
3298  }
3299 
3300  for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
3301  if (!strcmp(event_configuration_name->name, handler->event_name)) {
3302  break;
3303  }
3304  }
3305 
3306  if (!event_configuration_name) {
3307  ast_debug(1, "Event '%s' is not configured for '%s'\n", handler->event_name, resource_name);
3308  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3309  return NULL;
3310  }
3311 
3312  resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
3313 
3314  if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3315  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3316  return NULL;
3317  }
3318 
3319  publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
3320 
3321  if (!publication) {
3322  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
3323  return NULL;
3324  }
3325 
3326  publication->handler = handler;
3327  if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
3329  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3330  ao2_cleanup(publication);
3331  return NULL;
3332  }
3333 
3334  sip_publication_respond(publication, resp, rdata);
3335 
3336  return publication;
3337 }
3338 
3339 static int publish_expire_callback(void *data)
3340 {
3341  RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
3342 
3343  if (publication->handler->publish_expire) {
3344  publication->handler->publish_expire(publication);
3345  }
3346 
3347  return 0;
3348 }
3349 
3350 static int publish_expire(const void *data)
3351 {
3352  struct ast_sip_publication *publication = (struct ast_sip_publication*)data;
3353 
3354  ao2_unlink(publication->handler->publications, publication);
3355  publication->sched_id = -1;
3356 
3357  if (ast_sip_push_task(NULL, publish_expire_callback, publication)) {
3358  ao2_cleanup(publication);
3359  }
3360 
3361  return 0;
3362 }
3363 
3364 static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
3365 {
3366  pjsip_event_hdr *event_header;
3368  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3369  char event[32];
3370  static const pj_str_t str_sip_if_match = { "SIP-If-Match", 12 };
3371  pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
3372  enum sip_publish_type publish_type;
3373  RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
3374  unsigned int expires = 0;
3375  int entity_id, response = 0;
3376 
3377  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3378  ast_assert(endpoint != NULL);
3379 
3380  event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
3381  if (!event_header) {
3382  ast_log(LOG_WARNING, "Incoming PUBLISH request from %s with no Event header\n",
3383  ast_sorcery_object_get_id(endpoint));
3384  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3385  return PJ_TRUE;
3386  }
3387  ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
3388 
3390  if (!handler) {
3391  ast_log(LOG_WARNING, "No registered publish handler for event %s from %s\n", event,
3392  ast_sorcery_object_get_id(endpoint));
3393  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3394  return PJ_TRUE;
3395  }
3396 
3397  publish_type = determine_sip_publish_type(rdata, etag_hdr, &expires, &entity_id);
3398 
3399  /* If this is not an initial publish ensure that a publication is present */
3400  if ((publish_type != SIP_PUBLISH_INITIAL) && (publish_type != SIP_PUBLISH_UNKNOWN)) {
3401  if (!(publication = ao2_find(handler->publications, &entity_id, OBJ_KEY | OBJ_UNLINK))) {
3402  static const pj_str_t str_conditional_request_failed = { "Conditional Request Failed", 26 };
3403 
3404  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 412, &str_conditional_request_failed,
3405  NULL, NULL);
3406  return PJ_TRUE;
3407  }
3408 
3409  /* Per the RFC every response has to have a new entity tag */
3410  publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
3411 
3412  /* Update the expires here so that the created responses will contain the correct value */
3413  publication->expires = expires;
3414  }
3415 
3416  switch (publish_type) {
3417  case SIP_PUBLISH_INITIAL:
3418  publication = publish_request_initial(endpoint, rdata, handler);
3419  break;
3420  case SIP_PUBLISH_REFRESH:
3421  case SIP_PUBLISH_MODIFY:
3422  if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
3424  /* If an error occurs we want to terminate the publication */
3425  expires = 0;
3426  }
3427  response = 200;
3428  break;
3429  case SIP_PUBLISH_REMOVE:
3430  handler->publication_state_change(publication, rdata->msg_info.msg->body,
3432  response = 200;
3433  break;
3434  case SIP_PUBLISH_UNKNOWN:
3435  default:
3436  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3437  break;
3438  }
3439 
3440  if (publication) {
3441  if (expires) {
3442  ao2_link(handler->publications, publication);
3443 
3444  AST_SCHED_REPLACE_UNREF(publication->sched_id, sched, expires * 1000, publish_expire, publication,
3445  ao2_ref(_data, -1), ao2_ref(publication, -1), ao2_ref(publication, +1));
3446  } else {
3447  AST_SCHED_DEL_UNREF(sched, publication->sched_id, ao2_ref(publication, -1));
3448  }
3449  }
3450 
3451  if (response) {
3452  sip_publication_respond(publication, response, rdata);
3453  }
3454 
3455  return PJ_TRUE;
3456 }
3457 
3459 {
3460  return pub->endpoint;
3461 }
3462 
3464 {
3465  return pub->resource;
3466 }
3467 
3469 {
3470  return pub->event_configuration_name;
3471 }
3472 
3473 int ast_sip_pubsub_is_body_generator_registered(const char *type, const char *subtype)
3474 {
3475  return !!find_body_generator_type_subtype(type, subtype);
3476 }
3477 
3479 {
3480  struct ast_sip_pubsub_body_generator *existing;
3481  pj_str_t accept;
3482  pj_size_t accept_len;
3483 
3485  existing = find_body_generator_type_subtype_nolock(generator->type, generator->subtype);
3486  if (existing) {
3488  ast_log(LOG_WARNING, "A body generator for %s/%s is already registered.\n",
3489  generator->type, generator->subtype);
3490  return -1;
3491  }
3494 
3495  /* Lengths of type and subtype plus a slash. */
3496  accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
3497 
3498  /* Add room for null terminator that sprintf() will set. */
3499  pj_strset(&accept, ast_alloca(accept_len + 1), accept_len);
3500  sprintf((char *) pj_strbuf(&accept), "%s/%s", generator->type, generator->subtype);/* Safe */
3501 
3502  pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
3503  PJSIP_H_ACCEPT, NULL, 1, &accept);
3504 
3505  return 0;
3506 }
3507 
3509 {
3510  struct ast_sip_pubsub_body_generator *iter;
3511 
3514  if (iter == generator) {
3516  break;
3517  }
3518  }
3521 }
3522 
3524 {
3528 
3529  return 0;
3530 }
3531 
3533 {
3534  struct ast_sip_pubsub_body_supplement *iter;
3535 
3538  if (iter == supplement) {
3540  break;
3541  }
3542  }
3545 }
3546 
3548 {
3549  return sub->body_generator->type;
3550 }
3551 
3553 {
3554  return sub->body_generator->subtype;
3555 }
3556 
3558  struct ast_sip_body_data *data, struct ast_str **str)
3559 {
3560  struct ast_sip_pubsub_body_supplement *supplement;
3561  struct ast_sip_pubsub_body_generator *generator;
3562  int res = 0;
3563  void *body;
3564 
3566  if (!generator) {
3567  ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
3568  type, subtype);
3569  return -1;
3570  }
3571 
3572  if (strcmp(data->body_type, generator->body_type)) {
3573  ast_log(LOG_WARNING, "%s/%s body generator does not accept the type of data provided\n",
3574  type, subtype);
3575  return -1;
3576  }
3577 
3578  body = generator->allocate_body(data->body_data);
3579  if (!body) {
3580  ast_log(LOG_WARNING, "%s/%s body generator could not to allocate a body\n",
3581  type, subtype);
3582  return -1;
3583  }
3584 
3585  if (generator->generate_body_content(body, data->body_data)) {
3586  res = -1;
3587  goto end;
3588  }
3589 
3591  AST_RWLIST_TRAVERSE(&body_supplements, supplement, list) {
3592  if (!strcmp(generator->type, supplement->type) &&
3593  !strcmp(generator->subtype, supplement->subtype)) {
3594  res = supplement->supplement_body(body, data->body_data);
3595  if (res) {
3596  break;
3597  }
3598  }
3599  }
3601 
3602  if (!res) {
3603  generator->to_string(body, str);
3604  }
3605 
3606 end:
3607  if (generator->destroy_body) {
3608  generator->destroy_body(body);
3609  }
3610 
3611  return res;
3612 }
3613 
3620  char message_account[PJSIP_MAX_URL_SIZE];
3621 };
3622 
3623 static int parse_simple_message_summary(char *body,
3624  struct simple_message_summary *summary)
3625 {
3626  char *line;
3627  char *buffer;
3628  int found_counts = 0;
3629 
3630  if (ast_strlen_zero(body) || !summary) {
3631  return -1;
3632  }
3633 
3634  buffer = ast_strdupa(body);
3635  memset(summary, 0, sizeof(*summary));
3636 
3637  while ((line = ast_read_line_from_buffer(&buffer))) {
3638  line = ast_str_to_lower(line);
3639 
3640  if (sscanf(line, "voice-message: %d/%d (%d/%d)",
3641  &summary->voice_messages_new, &summary->voice_messages_old,
3642  &summary->voice_messages_urgent_new, &summary->voice_messages_urgent_old)) {
3643  found_counts = 1;
3644  } else {
3645  sscanf(line, "message-account: %s", summary->message_account);
3646  }
3647  }
3648 
3649  return !found_counts;
3650 }
3651 
3652 static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata)
3653 {
3654  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3655  struct simple_message_summary summary;
3656  const char *endpoint_name;
3657  char *atsign;
3658  char *context;
3659  char *body;
3660  char *mailbox;
3661  int rc;
3662 
3663  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3664  if (!endpoint) {
3665  ast_debug(1, "Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3666  rc = 404;
3667  goto error;
3668  }
3669 
3670  endpoint_name = ast_sorcery_object_get_id(endpoint);
3671  ast_debug(1, "Incoming MWI: Found endpoint: %s\n", endpoint_name);
3672  if (ast_strlen_zero(endpoint->incoming_mwi_mailbox)) {
3673  ast_debug(1, "Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3674  ast_test_suite_event_notify("PUBSUB_NO_INCOMING_MWI_MAILBOX",
3675  "Endpoint: %s", endpoint_name);
3676  rc = 404;
3677  goto error;
3678  }
3679 
3680  mailbox = ast_strdupa(endpoint->incoming_mwi_mailbox);
3681  atsign = strchr(mailbox, '@');
3682  if (!atsign) {
3683  ast_debug(1, "Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3684  endpoint_name, endpoint->incoming_mwi_mailbox);
3685  rc = 404;
3686  goto error;
3687  }
3688 
3689  *atsign = '\0';
3690  context = atsign + 1;
3691 
3692  body = ast_alloca(rdata->msg_info.msg->body->len + 1);
3693  rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3694  rdata->msg_info.msg->body->len + 1);
3695 
3696  if (parse_simple_message_summary(body, &summary) != 0) {
3697  ast_debug(1, "Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3698  ast_sorcery_object_get_id(endpoint), body);
3699  rc = 404;
3700  goto error;
3701  }
3702 
3704  summary.voice_messages_new, summary.voice_messages_old)) {
3705  ast_log(LOG_ERROR, "Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
3706  "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3707  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3708  summary.voice_messages_new, summary.voice_messages_old,
3710  rc = 404;
3711  } else {
3712  ast_debug(1, "Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3713  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3714  summary.voice_messages_new, summary.voice_messages_old,
3716  ast_test_suite_event_notify("PUBSUB_INCOMING_MWI_PUBLISH",
3717  "Endpoint: %s\r\n"
3718  "Mailbox: %s\r\n"
3719  "MessageAccount: %s\r\n"
3720  "VoiceMessagesNew: %d\r\n"
3721  "VoiceMessagesOld: %d\r\n"
3722  "VoiceMessagesUrgentNew: %d\r\n"
3723  "VoiceMessagesUrgentOld: %d",
3724  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3725  summary.voice_messages_new, summary.voice_messages_old,
3727  rc = 200;
3728  }
3729 
3730 error:
3731  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, rc, NULL, NULL, NULL);
3732  return PJ_TRUE;
3733 }
3734 
3735 static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata)
3736 {
3737  if (rdata->msg_info.msg->body &&
3738  ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type,
3739  "application", "simple-message-summary")) {
3740  return pubsub_on_rx_mwi_notify_request(rdata);
3741  }
3742  return PJ_FALSE;
3743 }
3744 
3745 static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
3746 {
3747  if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3748  return pubsub_on_rx_subscribe_request(rdata);
3749  } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
3750  return pubsub_on_rx_publish_request(rdata);
3751  } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
3752  return pubsub_on_rx_notify_request(rdata);
3753  }
3754 
3755  return PJ_FALSE;
3756 }
3757 
3759 {
3760  int i;
3761 
3762  sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
3763  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
3764  set_state_terminated(AST_VECTOR_GET(&sub->children, i));
3765  }
3766 }
3767 
3768 /*!
3769  * \brief Callback sequence for subscription terminate:
3770  *
3771  * * Client initiated:
3772  * pjproject receives SUBSCRIBE on the subscription's serializer thread
3773  * calls pubsub_on_rx_refresh with dialog locked
3774  * pubsub_on_rx_refresh sets TERMINATE_PENDING
3775  * pushes serialized_pubsub_on_refresh_timeout
3776  * returns to pjproject
3777  * pjproject calls pubsub_on_evsub_state
3778  * pubsub_evsub_set_state checks state == TERMINATE_IN_PROGRESS (no)
3779  * ignore and return
3780  * pjproject unlocks dialog
3781  * serialized_pubsub_on_refresh_timeout starts (1)
3782  * locks dialog
3783  * checks state == TERMINATE_PENDING
3784  * sets TERMINATE_IN_PROGRESS
3785  * calls send_notify (2)
3786  * send_notify ultimately calls pjsip_evsub_send_request
3787  * pjsip_evsub_send_request calls evsub's set_state
3788  * set_state calls pubsub_evsub_set_state
3789  * pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS
3790  * removes the subscriptions
3791  * cleans up references to evsub
3792  * sets state = TERMINATED
3793  * serialized_pubsub_on_refresh_timeout unlocks dialog
3794  *
3795  * * Subscription timer expires:
3796  * pjproject timer expires
3797  * locks dialog
3798  * calls pubsub_on_server_timeout
3799  * pubsub_on_server_timeout checks state == NORMAL
3800  * sets TERMINATE_PENDING
3801  * pushes serialized_pubsub_on_refresh_timeout
3802  * returns to pjproject
3803  * pjproject unlocks dialog
3804  * serialized_pubsub_on_refresh_timeout starts
3805  * See (1) Above
3806  *
3807  * * Transmission failure sending NOTIFY or error response from client
3808  * pjproject transaction timer expires or non OK response
3809  * pjproject locks dialog
3810  * calls pubsub_on_evsub_state with event TSX_STATE
3811  * pubsub_on_evsub_state checks event == TSX_STATE
3812  * removes the subscriptions
3813  * cleans up references to evsub
3814  * sets state = TERMINATED
3815  * pjproject unlocks dialog
3816  *
3817  * * ast_sip_subscription_notify is called
3818  * checks state == NORMAL
3819  * if not batched...
3820  * sets TERMINATE_IN_PROGRESS (if terminate is requested)
3821  * calls send_notify
3822  * See (2) Above
3823  * if batched...
3824  * sets TERMINATE_PENDING
3825  * schedules task
3826  * scheduler runs sched_task
3827  * sched_task pushes serialized_send_notify
3828  * serialized_send_notify starts
3829  * checks state <= TERMINATE_PENDING
3830  * if state == TERMINATE_PENDING set state = TERMINATE_IN_PROGRESS
3831  * call send_notify
3832  * See (2) Above
3833  *
3834  */
3835 
3836 /*!
3837  * \brief PJSIP callback when underlying SIP subscription changes state
3838  *
3839  * Although this function is called for every state change, we only care
3840  * about the TERMINATED state, and only when we're actually processing the final
3841  * notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS) OR when a transmission failure
3842  * occurs (PJSIP_EVENT_TSX_STATE). In this case, we do all the subscription tree
3843  * cleanup tasks and decrement the evsub reference.
3844  */
3845 static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
3846 {
3847  struct sip_subscription_tree *sub_tree =
3848  pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3849 
3850  ast_debug(3, "evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub,
3851  pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree,
3852  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3853 
3854  if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
3855  return;
3856  }
3857 
3858  /* It's easier to write this as what we WANT to process, then negate it. */
3859  if (!(sub_tree->state == SIP_SUB_TREE_TERMINATE_IN_PROGRESS
3860  || (event->type == PJSIP_EVENT_TSX_STATE && sub_tree->state == SIP_SUB_TREE_NORMAL)
3861  )) {
3862  ast_debug(3, "Do nothing.\n");
3863  return;
3864  }
3865 
3866  if (sub_tree->expiration_task) {
3867  char task_name[256];
3868 
3869  ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
3870  ast_debug(3, "Cancelling timer: %s\n", task_name);
3872  ao2_cleanup(sub_tree->expiration_task);
3873  sub_tree->expiration_task = NULL;
3874  }
3875 
3876  remove_subscription(sub_tree);
3877 
3878  pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
3879 
3880 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
3881  pjsip_evsub_dec_ref(sub_tree->evsub);
3882 #endif
3883 
3884  sub_tree->evsub = NULL;
3885 
3887  ast_sip_dialog_set_endpoint(sub_tree->dlg, NULL);
3888 
3890  shutdown_subscriptions(sub_tree->root);
3891 
3892  sub_tree->state = SIP_SUB_TREE_TERMINATED;
3893  /* Remove evsub's reference to the sub_tree */
3894  ao2_ref(sub_tree, -1);
3895 }
3896 
3897 static int pubsub_on_refresh_timeout(void *userdata)
3898 {
3899  struct sip_subscription_tree *sub_tree = userdata;
3900  pjsip_dialog *dlg = sub_tree->dlg;
3901 
3902  ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
3903  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3904 
3905  pjsip_dlg_inc_lock(dlg);
3906  if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) {
3907  pjsip_dlg_dec_lock(dlg);
3908  return 0;
3909  }
3910 
3911  if (sub_tree->state == SIP_SUB_TREE_TERMINATE_PENDING) {
3913  set_state_terminated(sub_tree->root);
3914  }
3915 
3916  if (sub_tree->generate_initial_notify) {
3917  sub_tree->generate_initial_notify = 0;
3918  if (generate_initial_notify(sub_tree->root)) {
3919  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3920  pjsip_dlg_dec_lock(dlg);
3921  return 0;
3922  }
3923  }
3924 
3925  send_notify(sub_tree, 1);
3926 
3927  ast_test_suite_event_notify(sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ?
3928  "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED",
3929  "Resource: %s", sub_tree->root->resource);
3930 
3931  pjsip_dlg_dec_lock(dlg);
3932 
3933  return 0;
3934 }
3935 
3936 static int serialized_pubsub_on_refresh_timeout(void *userdata)
3937 {
3938  struct sip_subscription_tree *sub_tree = userdata;
3939 
3940  ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
3941  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3942 
3943  pubsub_on_refresh_timeout(userdata);
3944  ao2_cleanup(sub_tree);
3945 
3946  return 0;
3947 }
3948 
3949 /*!
3950  * \brief Compare strings for equality checking for NULL.
3951  *
3952  * This function considers NULL values as empty strings.
3953  * This means NULL or empty strings are equal.
3954  *
3955  * \retval 0 The strings are equal
3956  * \retval 1 The strings are not equal
3957  */
3958 static int cmp_strings(char *s1, char *s2)
3959 {
3960  if (!ast_strlen_zero(s1) && !ast_strlen_zero(s2)) {
3961  return strcmp(s1, s2);
3962  }
3963 
3964  return ast_strlen_zero(s1) == ast_strlen_zero(s2) ? 0 : 1;
3965 }
3966 
3967 /*!
3968  * \brief compares the childrens of two ast_sip_subscription s1 and s2
3969  *
3970  * \retval 0 The s1 childrens match the s2 childrens
3971  * \retval 1 The s1 childrens do not match the s2 childrens
3972  */
3974 {
3975  int i;
3976 
3977  if (AST_VECTOR_SIZE(&s1->children) != AST_VECTOR_SIZE(&s2->children)) {
3978  return 1;
3979  }
3980 
3981  for (i = 0; i < AST_VECTOR_SIZE(&s1->children); ++i) {
3982  struct ast_sip_subscription *c1 = AST_VECTOR_GET(&s1->children, i);
3983  struct ast_sip_subscription *c2 = AST_VECTOR_GET(&s2->children, i);
3984 
3985  if (cmp_strings(c1->resource, c2->resource)
3986  || cmp_strings(c1->display_name, c2->display_name)) {
3987 
3988  return 1;
3989  }
3990  }
3991 
3992  return 0;
3993 }
3994 
3995 /*!
3996  * \brief Called whenever an in-dialog SUBSCRIBE is received
3997  *
3998  * This includes both SUBSCRIBE requests that actually refresh the subscription
3999  * as well as SUBSCRIBE requests that end the subscription.
4000  *
4001  * In either case we push serialized_pubsub_on_refresh_timeout to send an
4002  * appropriate NOTIFY request.
4003  */
4004 static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata,
4005  int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4006 {
4007  struct sip_subscription_tree *sub_tree;
4008 
4009  sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4010  ast_debug(3, "evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree,
4011  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4012 
4013  if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4014  return;
4015  }
4016 
4017  if (sub_tree->expiration_task) {
4018  char task_name[256];
4019 
4020  ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
4021  ast_debug(3, "Cancelling timer: %s\n", task_name);
4023  ao2_cleanup(sub_tree->expiration_task);
4024  sub_tree->expiration_task = NULL;
4025  }
4026 
4027  /* PJSIP will set the evsub's state to terminated before calling into this function
4028  * if the Expires value of the incoming SUBSCRIBE is 0.
4029  */
4030 
4031  if (pjsip_evsub_get_state(sub_tree->evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
4033  }
4034 
4035  if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->is_list) {
4036  /* update RLS */
4037  const char *resource = sub_tree->root->resource;
4038  struct ast_sip_subscription *old_root = sub_tree->root;
4039  struct ast_sip_subscription *new_root = NULL;
4040  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
4042  struct ast_sip_pubsub_body_generator *generator = NULL;
4043 
4044  if ((endpoint = ast_pjsip_rdata_get_endpoint(rdata))
4046  && (generator = subscription_get_generator_from_rdata(rdata, handler))) {
4047 
4048  struct resource_tree tree;
4049  int resp;
4050 
4051  memset(&tree, 0, sizeof(tree));
4052  resp = build_resource_tree(endpoint, handler, resource, &tree,
4054  if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
4055  new_root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree.root);
4056  if (new_root) {
4057  if (cmp_subscription_childrens(old_root, new_root)) {
4058  ast_debug(1, "RLS '%s->%s' was modified, regenerate it\n", ast_sorcery_object_get_id(endpoint), old_root->resource);
4059  new_root->version = old_root->version;
4060  sub_tree->root = new_root;
4061  sub_tree->generate_initial_notify = 1;
4062  shutdown_subscriptions(old_root);
4063  destroy_subscriptions(old_root);
4064  } else {
4065  destroy_subscriptions(new_root);
4066  }
4067  }
4068  } else {
4070  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4071  }
4072 
4073  resource_tree_destroy(&tree);
4074  }
4075  }
4076 
4078 
4080  /* If we can't push the NOTIFY refreshing task...we'll just go with it. */
4081  ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n");
4082  sub_tree->state = SIP_SUB_TREE_NORMAL;
4083  ao2_ref(sub_tree, -1);
4084  }
4085 
4086  if (sub_tree->is_list) {
4087  pj_list_insert_before(res_hdr, create_require_eventlist(rdata->tp_info.pool));
4088  }
4089 }
4090 
4091 static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code,
4092  pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4093 {
4094  struct ast_sip_subscription *sub;
4095 
4096  if (!(sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4097  return;
4098  }
4099 
4100  sub->handler->subscriber->state_change(sub, rdata->msg_info.msg->body,
4101  pjsip_evsub_get_state(evsub));
4102 }
4103 
4104 static int serialized_pubsub_on_client_refresh(void *userdata)
4105 {
4106  struct sip_subscription_tree *sub_tree = userdata;
4107  pjsip_tx_data *tdata;
4108 
4109  if (!sub_tree->evsub) {
4110  ao2_cleanup(sub_tree);
4111  return 0;
4112  }
4113 
4114  if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
4115  pjsip_evsub_send_request(sub_tree->evsub, tdata);
4116  } else {
4117  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4118  }
4119 
4120  ao2_cleanup(sub_tree);
4121  return 0;
4122 }
4123 
4124 static void pubsub_on_client_refresh(pjsip_evsub *evsub)
4125 {
4126  struct sip_subscription_tree *sub_tree;
4127 
4128  if (!(sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4129  return;
4130  }
4131 
4133  ao2_cleanup(sub_tree);
4134  }
4135 }
4136 
4137 static void pubsub_on_server_timeout(pjsip_evsub *evsub)
4138 {
4139  struct sip_subscription_tree *sub_tree;
4140 
4141  /* PJSIP does not terminate the server timeout timer when a SUBSCRIBE
4142  * with Expires: 0 arrives to end a subscription, nor does it terminate
4143  * this timer when we send a NOTIFY request in response to receiving such
4144  * a SUBSCRIBE. PJSIP does not stop the server timeout timer until the
4145  * NOTIFY transaction has finished (either through receiving a response
4146  * or through a transaction timeout).
4147  *
4148  * Therefore, it is possible that we can be told that a server timeout
4149  * occurred after we already thought that the subscription had been
4150  * terminated. In such a case, we will have already removed the sub_tree
4151  * from the evsub's mod_data array.
4152  */
4153 
4154  sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4155  if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4156  return;
4157  }
4158 
4161  sub_tree->state = SIP_SUB_TREE_NORMAL;
4162  ao2_cleanup(sub_tree);
4163  }
4164 }
4165 
4167  struct ast_sip_ami *ami,
4168  const char *event)
4169 {
4170  struct ast_str *buf;
4171 
4173  if (!buf) {
4174  return -1;
4175  }
4176 
4177  sip_subscription_to_ami(sub_tree, &buf);
4178  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4179  ast_free(buf);
4180 
4181  ++ami->count;
4182  return 0;
4183 }
4184 
4185 static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4186 {
4187  return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
4188  sub_tree, arg, "InboundSubscriptionDetail") : 0;
4189 }
4190 
4191 static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4192 {
4193  return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
4194  sub_tree, arg, "OutboundSubscriptionDetail") : 0;
4195 }
4196 
4197 static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
4198 {
4199  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4200 
4201  astman_send_listack(s, m, "Following are Events for each inbound Subscription",
4202  "start");
4203 
4205 
4206  astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count);
4208  return 0;
4209 }
4210 
4211 static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
4212 {
4213  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4214 
4215  astman_send_listack(s, m, "Following are Events for each outbound Subscription",
4216  "start");
4217 
4219 
4220  astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count);
4222  return 0;
4223 }
4224 
4225 static int format_ami_resource_lists(void *obj, void *arg, int flags)
4226 {
4227  struct resource_list *list = obj;
4228  struct ast_sip_ami *ami = arg;
4229  struct ast_str *buf;
4230 
4231  buf = ast_sip_create_ami_event("ResourceListDetail", ami);
4232  if (!buf) {
4233  return CMP_STOP;
4234  }
4235 
4236  if (ast_sip_sorcery_object_to_ami(list, &buf)) {
4237  ast_free(buf);
4238  return CMP_STOP;
4239  }
4240  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4241  ast_free(buf);
4242 
4243  ++ami->count;
4244  return 0;
4245 }
4246 
4247 static int ami_show_resource_lists(struct mansession *s, const struct message *m)
4248 {
4249  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4250  struct ao2_container *lists;
4251 
4252  lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
4254 
4255  if (!lists || !ao2_container_count(lists)) {
4256  astman_send_error(s, m, "No resource lists found\n");
4257  return 0;
4258  }
4259 
4260  astman_send_listack(s, m, "A listing of resource lists follows, presented as ResourceListDetail events",
4261  "start");
4262 
4264 
4265  astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count);
4267  return 0;
4268 }
4269 
4270 #define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
4271 #define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
4272 
4273 #define MAX_REGEX_ERROR_LEN 128
4274 
4276  /*! CLI handler entry e parameter */
4277  struct ast_cli_entry *e;
4278  /*! CLI handler entry a parameter */
4279  struct ast_cli_args *a;
4280  /*! CLI subscription entry output line(s) */
4281  struct ast_str *buf;
4282  /*! Compiled regular expression to select if buf is written to CLI when not NULL. */
4283  regex_t *like;
4284  int count;
4285 };
4286 
4288  struct ast_cli_args *a;
4289  /*! Found callid for search position */
4290  char *callid;
4291  int wordlen;
4292  int which;
4293 };
4294 
4296 {
4297  pj_str_t *callid;
4298 
4299  if (!sub_tree->dlg) {
4300  return 0;
4301  }
4302 
4303  callid = &sub_tree->dlg->call_id->id;
4304  if (cli->wordlen <= pj_strlen(callid)
4305  && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
4306  && (++cli->which > cli->a->n)) {
4307  cli->callid = ast_malloc(pj_strlen(callid) + 1);
4308  if (cli->callid) {
4309  ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
4310  }
4311  return -1;
4312  }
4313  return 0;
4314 }
4315 
4316 static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4317 {
4318  return sub_tree->role == AST_SIP_NOTIFIER
4319  ? cli_complete_subscription_common(sub_tree, arg) : 0;
4320 }
4321 
4322 static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4323 {
4324  return sub_tree->role == AST_SIP_SUBSCRIBER
4325  ? cli_complete_subscription_common(sub_tree, arg) : 0;
4326 }
4327 
4329 {
4330  struct cli_sub_complete_parms cli;
4331  on_subscription_t on_subscription;
4332 
4333  if (a->pos != 4) {
4334  return NULL;
4335  }
4336 
4337  if (!strcasecmp(a->argv[3], "inbound")) {
4338  on_subscription = cli_complete_subscription_inbound;
4339  } else if (!strcasecmp(a->argv[3], "outbound")) {
4340  on_subscription = cli_complete_subscription_outbound;
4341  } else {
4342  /* Should never get here */
4343  ast_assert(0);
4344  return NULL;
4345  }
4346 
4347  cli.a = a;
4348  cli.callid = NULL;
4349  cli.wordlen = strlen(a->word);
4350  cli.which = 0;
4351  for_each_subscription(on_subscription, &cli);
4352 
4353  return cli.callid;
4354 }
4355 
4356 static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
4357 {
4358  int expiry;
4359 
4360  expiry = sub_tree->persistence
4361  ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
4362  : 0;
4363  if (expiry < 0) {
4364  /* Subscription expired */
4365  expiry = 0;
4366  }
4367  return expiry;
4368 }
4369 
4371 {
4372  const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
4373  pj_str_t *sub_callid;
4374  struct ast_str *buf;
4375  char *src;
4376  char *dest;
4377  char *key;
4378  char *value;
4379  char *value_end;
4380  int key_len;
4381  int key_filler_width;
4382  int value_len;
4383 
4384  if (!sub_tree->dlg) {
4385  return 0;
4386  }
4387  sub_callid = &sub_tree->dlg->call_id->id;
4388  if (pj_strcmp2(sub_callid, callid)) {
4389  return 0;
4390  }
4391 
4392  buf = ast_str_create(512);
4393  if (!buf) {
4394  return -1;
4395  }
4396 
4397  ast_cli(cli->a->fd,
4398  "%-20s: %s\n"
4399  "===========================================================================\n",
4400  "ParameterName", "ParameterValue");
4401 
4402  ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
4403  ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
4404  ast_str_append(&buf, 0, "Expiry: %u\n", cli_subscription_expiry(sub_tree));
4405 
4406  sip_subscription_to_ami(sub_tree, &buf);
4407 
4408  /* Convert AMI \r\n to \n line terminators. */
4409  src = strchr(ast_str_buffer(buf), '\r');
4410  if (src) {
4411  dest = src;
4412  ++src;
4413  while (*src) {
4414  if (*src == '\r') {
4415  ++src;
4416  continue;
4417  }
4418  *dest++ = *src++;
4419  }
4420  *dest = '\0';
4422  }
4423 
4424  /* Reformat AMI key value pairs to pretty columns */
4425  key = ast_str_buffer(buf);
4426  do {
4427  value = strchr(key, ':');
4428  if (!value) {
4429  break;
4430  }
4431  value_end = strchr(value, '\n');
4432  if (!value_end) {
4433  break;
4434  }
4435 
4436  /* Calculate field lengths */
4437  key_len = value - key;
4438  key_filler_width = 20 - key_len;
4439  if (key_filler_width < 0) {
4440  key_filler_width = 0;
4441  }
4442  value_len = value_end - value;
4443 
4444  ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
4445  key_len, key, key_filler_width, "",
4446  value_len, value);
4447 
4448  key = value_end + 1;
4449  } while (*key);
4450  ast_cli(cli->a->fd, "\n");
4451 
4452  ast_free(buf);
4453 
4454  return -1;
4455 }
4456 
4457 static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4458 {
4459  return sub_tree->role == AST_SIP_NOTIFIER
4460  ? cli_show_subscription_common(sub_tree, arg) : 0;
4461 }
4462 
4463 static int cli_show_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4464 {
4465  return sub_tree->role == AST_SIP_SUBSCRIBER
4466  ? cli_show_subscription_common(sub_tree, arg) : 0;
4467 }
4468 
4469 static char *cli_show_subscription_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4470 {
4471  on_subscription_t on_subscription;
4472  struct cli_sub_parms cli;
4473 
4474  switch (cmd) {
4475  case CLI_INIT:
4476  e->command = "pjsip show subscription {inbound|outbound}";
4477  e->usage = "Usage:\n"
4478  " pjsip show subscription inbound <call-id>\n"
4479  " pjsip show subscription outbound <call-id>\n"
4480  " Show active subscription with the dialog call-id\n";
4481  return NULL;
4482  case CLI_GENERATE:
4484  }
4485 
4486  if (a->argc != 5) {
4487  return CLI_SHOWUSAGE;
4488  }
4489 
4490  if (!strcasecmp(a->argv[3], "inbound")) {
4491  on_subscription = cli_show_subscription_inbound;
4492  } else if (!strcasecmp(a->argv[3], "outbound")) {
4493  on_subscription = cli_show_subscription_outbound;
4494  } else {
4495  /* Should never get here */
4496  ast_assert(0);
4497  return NULL;
4498  }
4499 
4500  /* Find the subscription with the specified call-id */
4501  cli.a = a;
4502  cli.e = e;
4503  cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */
4504  for_each_subscription(on_subscription, &cli);
4505 
4506  return CLI_SUCCESS;
4507 }
4508 
4509 #define CLI_SHOW_SUB_FORMAT_HEADER \
4510  "Endpoint: <Endpoint/Caller-ID.............................................>\n" \
4511  "Resource: <Resource/Event.................................................>\n" \
4512  " Expiry: <Expiry> <Call-id..............................................>\n" \
4513  "===========================================================================\n\n"
4514 #define CLI_SHOW_SUB_FORMAT_ENTRY \
4515  "Endpoint: %s/%s\n" \
4516  "Resource: %s/%s\n" \
4517  " Expiry: %8d %s\n\n"
4518 
4520 {
4521  char caller_id[256];
4522  char callid[256];
4523 
4524  ast_callerid_merge(caller_id, sizeof(caller_id),
4525  S_COR(sub_tree->endpoint->id.self.name.valid,
4526  sub_tree->endpoint->id.self.name.str, NULL),
4527  S_COR(sub_tree->endpoint->id.self.number.valid,
4528  sub_tree->endpoint->id.self.number.str, NULL),
4529  "<none>");
4530 
4531  /* Call-id */
4532  if (sub_tree->dlg) {
4533  ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4534  } else {
4535  ast_copy_string(callid, "<unknown>", sizeof(callid));
4536  }
4537 
4539  ast_sorcery_object_get_id(sub_tree->endpoint), caller_id,
4540  sub_tree->root->resource, sub_tree->root->handler->event_name,
4541  cli_subscription_expiry(sub_tree), callid);
4542 
4543  if (cli->like) {
4544  if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4545  /* Output line did not match the regex */
4546  return 0;
4547  }
4548  }
4549 
4550  ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4551  ++cli->count;
4552 
4553  return 0;
4554 }
4555 
4556 static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4557 {
4558  return sub_tree->role == AST_SIP_NOTIFIER
4559  ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4560 }
4561 
4562 static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4563 {
4564  return sub_tree->role == AST_SIP_SUBSCRIBER
4565  ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4566 }
4567 
4568 static char *cli_show_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4569 {
4570  on_subscription_t on_subscription;
4571  struct cli_sub_parms cli;
4572  regex_t like;
4573  const char *regex;
4574 
4575  switch (cmd) {
4576  case CLI_INIT:
4577  e->command = "pjsip show subscriptions {inbound|outbound} [like]";
4578  e->usage = "Usage:\n"
4579  " pjsip show subscriptions inbound [like <regex>]\n"
4580  " Show active inbound subscriptions\n"
4581  " pjsip show subscriptions outbound [like <regex>]\n"
4582  " Show active outbound subscriptions\n"
4583  "\n"
4584  " The regex selects a subscriptions output that matches.\n"
4585  " i.e., All output lines for a subscription are checked\n"
4586  " as a block by the regex.\n";
4587  return NULL;
4588  case CLI_GENERATE:
4589  return NULL;
4590  }
4591 
4592  if (a->argc != 4 && a->argc != 6) {
4593  return CLI_SHOWUSAGE;
4594  }
4595  if (!strcasecmp(a->argv[3], "inbound")) {
4596  on_subscription = cli_show_subscriptions_inbound;
4597  } else if (!strcasecmp(a->argv[3], "outbound")) {
4598  on_subscription = cli_show_subscriptions_outbound;
4599  } else {
4600  /* Should never get here */
4601  ast_assert(0);
4602  return CLI_SHOWUSAGE;
4603  }
4604  if (a->argc == 6) {
4605  int rc;
4606 
4607  if (strcasecmp(a->argv[4], "like")) {
4608  return CLI_SHOWUSAGE;
4609  }
4610 
4611  /* Setup regular expression */
4612  memset(&like, 0, sizeof(like));
4613  cli.like = &like;
4614  regex = a->argv[5];
4615  rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4616  if (rc) {
4617  char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4618 
4619  regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4620  ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4621  regex, regerr);
4622  return CLI_FAILURE;
4623  }
4624  } else {
4625  cli.like = NULL;
4626  regex = NULL;
4627  }
4628 
4629  cli.a = a;
4630  cli.e = e;
4631  cli.count = 0;
4632  cli.buf = ast_str_create(256);
4633  if (!cli.buf) {
4634  if (cli.like) {
4635  regfree(cli.like);
4636  }
4637  return CLI_FAILURE;
4638  }
4639 
4641  for_each_subscription(on_subscription, &cli);
4642  ast_cli(a->fd, "%d active subscriptions%s%s%s\n",
4643  cli.count,
4644  regex ? " matched \"" : "",
4645  regex ?: "",
4646  regex ? "\"" : "");
4647 
4648  ast_free(cli.buf);
4649  if (cli.like) {
4650  regfree(cli.like);
4651  }
4652 
4653  return CLI_SUCCESS;
4654 }
4655 
4656 #define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n"
4657 #define CLI_LIST_SUB_FORMAT_ENTRY "%-30.30s %-30.30s %6d %s\n"
4658 
4660 {
4661  char ep_cid_buf[50];
4662  char res_evt_buf[50];
4663  char callid[256];
4664 
4665  /* Endpoint/CID column */
4666  snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s",
4668  S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str,
4669  S_COR(sub_tree->endpoint->id.self.number.valid,
4670  sub_tree->endpoint->id.self.number.str, "<none>")));
4671 
4672  /* Resource/Event column */
4673  snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s",
4674  sub_tree->root->resource,
4675  sub_tree->root->handler->event_name);
4676 
4677  /* Call-id column */
4678  if (sub_tree->dlg) {
4679  ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4680  } else {
4681  ast_copy_string(callid, "<unknown>", sizeof(callid));
4682  }
4683 
4685  ep_cid_buf,
4686  res_evt_buf,
4687  cli_subscription_expiry(sub_tree),
4688  callid);
4689 
4690  if (cli->like) {
4691  if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4692  /* Output line did not match the regex */
4693  return 0;
4694  }
4695  }
4696 
4697  ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4698  ++cli->count;
4699 
4700  return 0;
4701 }
4702 
4703 static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4704 {
4705  return sub_tree->role == AST_SIP_NOTIFIER
4706  ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4707 }
4708 
4709 static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4710 {
4711  return sub_tree->role == AST_SIP_SUBSCRIBER
4712  ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4713 }
4714 
4715 static char *cli_list_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4716 {
4717  on_subscription_t on_subscription;
4718  struct cli_sub_parms cli;
4719  regex_t like;
4720  const char *regex;
4721 
4722  switch (cmd) {
4723  case CLI_INIT:
4724  e->command = "pjsip list subscriptions {inbound|outbound} [like]";
4725  e->usage = "Usage:\n"
4726  " pjsip list subscriptions inbound [like <regex>]\n"
4727  " List active inbound subscriptions\n"
4728  " pjsip list subscriptions outbound [like <regex>]\n"
4729  " List active outbound subscriptions\n"
4730  "\n"
4731  " The regex selects output lines that match.\n";
4732  return NULL;
4733  case CLI_GENERATE:
4734  return NULL;
4735  }
4736 
4737  if (a->argc != 4 && a->argc != 6) {
4738  return CLI_SHOWUSAGE;
4739  }
4740  if (!strcasecmp(a->argv[3], "inbound")) {
4741  on_subscription = cli_list_subscriptions_inbound;
4742  } else if (!strcasecmp(a->argv[3], "outbound")) {
4743  on_subscription = cli_list_subscriptions_outbound;
4744  } else {
4745  /* Should never get here */
4746  ast_assert(0);
4747  return CLI_SHOWUSAGE;
4748  }
4749  if (a->argc == 6) {
4750  int rc;
4751 
4752  if (strcasecmp(a->argv[4], "like")) {
4753  return CLI_SHOWUSAGE;
4754  }
4755 
4756  /* Setup regular expression */
4757  memset(&like, 0, sizeof(like));
4758  cli.like = &like;
4759  regex = a->argv[5];
4760  rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4761  if (rc) {
4762  char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4763 
4764  regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4765  ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4766  regex, regerr);
4767  return CLI_FAILURE;
4768  }
4769  } else {
4770  cli.like = NULL;
4771  regex = NULL;
4772  }
4773 
4774  cli.a = a;
4775  cli.e = e;
4776  cli.count = 0;
4777  cli.buf = ast_str_create(256);
4778  if (!cli.buf) {
4779  if (cli.like) {
4780  regfree(cli.like);
4781  }
4782  return CLI_FAILURE;
4783  }
4784 
4786  "Endpoint/CLI", "Resource/Event", "Expiry", "Call-id");
4787  for_each_subscription(on_subscription, &cli);
4788  ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n",
4789  cli.count,
4790  regex ? " matched \"" : "",
4791  regex ?: "",
4792  regex ? "\"" : "");
4793 
4794  ast_free(cli.buf);
4795  if (cli.like) {
4796  regfree(cli.like);
4797  }
4798 
4799  return CLI_SUCCESS;
4800 }
4801 
4802 static struct ast_cli_entry cli_commands[] = {
4803  AST_CLI_DEFINE(cli_list_subscriptions_inout, "List active inbound/outbound subscriptions"),
4804  AST_CLI_DEFINE(cli_show_subscription_inout, "Show active subscription details"),
4805  AST_CLI_DEFINE(cli_show_subscriptions_inout, "Show active inbound/outbound subscriptions"),
4806 };
4807 
4808 static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
4809 {
4810  struct subscription_persistence *persistence = obj;
4811 
4812  persistence->endpoint = ast_strdup(var->value);
4813  return 0;
4814 }
4815 
4816 static int persistence_endpoint_struct2str(const void *obj, const intptr_t *args, char **buf)
4817 {
4818  const struct subscription_persistence *persistence = obj;
4819 
4820  *buf = ast_strdup(persistence->endpoint);
4821  return 0;
4822 }
4823 
4824 static int