Asterisk - The Open Source Telephony Project  21.4.1
res_pjsip_pubsub.c
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"
35 #include "asterisk/res_pjsip_pubsub.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"
48 #include "res_pjsip/include/res_pjsip_private.h"
49 #include "asterisk/res_pjsip_presence_xml.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  */
274 enum sip_publish_type {
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  */
283  SIP_PUBLISH_UNKNOWN,
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  */
294  SIP_PUBLISH_INITIAL,
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  */
304  SIP_PUBLISH_REFRESH,
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  */
314  SIP_PUBLISH_MODIFY,
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  */
323  SIP_PUBLISH_REMOVE,
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 type (UDP,TCP,TLS)*/
393  char transport_type[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  */
415 enum sip_subscription_tree_state {
416  /*! Normal operation */
417  SIP_SUB_TREE_NORMAL = 0,
418  /*! A terminate has been requested by Asterisk, the client, or pjproject */
419  SIP_SUB_TREE_TERMINATE_PENDING,
420  /*! The terminate is in progress */
421  SIP_SUB_TREE_TERMINATE_IN_PROGRESS,
422  /*! The terminate process has finished and the subscription tree is no longer valid */
423  SIP_SUB_TREE_TERMINATED,
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 */
448  enum ast_sip_subscription_role role;
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 */
468  enum sip_subscription_tree_state 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  char transport_key[IP6ADDR_COLON_PORT_BUFLEN];
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 */
502  AST_VECTOR(, struct ast_sip_subscription *) children;
503  /*! Saved NOTIFY body text for this subscription */
504  struct ast_str *body_text;
505  /*! Indicator that the body text has changed since the last notification */
506  int body_changed;
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 */
516  struct ast_json *persistence_data;
517  /*! Display Name of resource */
518  char *display_name;
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 
540 enum sip_persistence_update_type {
541  /*! Called from send request */
542  SUBSCRIPTION_PERSISTENCE_SEND_REQUEST = 0,
543  /*! Subscription created from initial client request */
544  SUBSCRIPTION_PERSISTENCE_CREATED,
545  /*! Subscription recreated by asterisk on startup */
546  SUBSCRIPTION_PERSISTENCE_RECREATED,
547  /*! Subscription created from client refresh */
548  SUBSCRIPTION_PERSISTENCE_REFRESHED,
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 {
586  return ast_sorcery_generic_alloc(sizeof(struct ast_sip_publication_resource), publication_resource_destroy);
587 }
588 
589 static int sub_tree_subscription_terminate_cb(void *data)
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 
603  sub_tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS;
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);
629  if (ast_sip_push_task(sub_tree->serializer, sub_tree_subscription_terminate_cb,
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 {
648  return ast_sorcery_generic_alloc(sizeof(struct subscription_persistence), subscription_persistence_destroy);
649 }
650 
651 /*! \brief Function which creates initial persistence information of a subscription in sorcery */
652 static struct subscription_persistence *subscription_persistence_create(struct sip_subscription_tree *sub_tree)
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  */
659  struct subscription_persistence *persistence = ast_sorcery_alloc(ast_sip_get_sorcery(),
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 */
677 static void subscription_persistence_update(struct sip_subscription_tree *sub_tree,
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;
699  sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1));
700 
701  if (contact_hdr) {
702  if (contact_hdr) {
703  if (type == SUBSCRIPTION_PERSISTENCE_CREATED) {
704  sub_tree->persistence->prune_on_boot =
705  !ast_sip_will_uri_survive_restart(
706  (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
707  sub_tree->endpoint, rdata);
708 
709  if (sub_tree->persistence->prune_on_boot) {
710  ast_debug(3, "adding transport monitor on %s for '%s->%s' prune on boot: %d\n",
711  rdata->tp_info.transport->obj_name,
712  sub_tree->persistence->endpoint, sub_tree->root->resource,
713  sub_tree->persistence->prune_on_boot);
714  AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(rdata->tp_info.transport,
715  sub_tree->transport_key);
717  sub_tree_transport_cb, sub_tree);
718  /*
719  * FYI: ast_sip_transport_monitor_register holds a reference to the sub_tree
720  */
721  }
722  }
723  }
724 
725  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
726  sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri));
727  } else {
728  ast_log(LOG_WARNING, "Contact not updated due to missing contact header\n");
729  }
730 
731  /* When receiving a packet on an streaming transport, it's possible to receive more than one SIP
732  * message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf
733  * will always point to the proper SIP message that is to be processed. When updating subscription
734  * persistence that is pulled from persistent storage, though, the rdata->pkt_info.packet will
735  * only ever have a single SIP message on it, and so we base persistence on that.
736  */
737  if (type == SUBSCRIPTION_PERSISTENCE_CREATED
738  || type == SUBSCRIPTION_PERSISTENCE_RECREATED) {
739  if (rdata->msg_info.msg_buf) {
740  ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf,
741  MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len + 1));
742  } else {
743  ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
744  sizeof(sub_tree->persistence->packet));
745  }
746  }
747  ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
748  sizeof(sub_tree->persistence->src_name));
749  sub_tree->persistence->src_port = rdata->pkt_info.src_port;
750  ast_copy_string(sub_tree->persistence->transport_type, rdata->tp_info.transport->type_name,
751  sizeof(sub_tree->persistence->transport_type));
752  ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host,
753  sizeof(sub_tree->persistence->local_name));
754  sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port;
755  }
756 
757  ast_sorcery_update(ast_sip_get_sorcery(), sub_tree->persistence);
758 }
759 
760 /*! \brief Function which removes persistence of a subscription from sorcery */
761 static void subscription_persistence_remove(struct sip_subscription_tree *sub_tree)
762 {
763  if (!sub_tree->persistence) {
764  return;
765  }
766 
767  if (sub_tree->persistence->prune_on_boot && !ast_strlen_zero(sub_tree->transport_key)) {
768  ast_debug(3, "Unregistering transport monitor on %s '%s->%s'\n",
769  sub_tree->transport_key,
770  sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
771  sub_tree->root ? sub_tree->root->resource : "Unknown");
773  sub_tree_transport_cb, sub_tree, NULL);
774  }
775 
776  ast_sorcery_delete(ast_sip_get_sorcery(), sub_tree->persistence);
777  ao2_ref(sub_tree->persistence, -1);
778  sub_tree->persistence = NULL;
779 }
780 
781 
782 static struct ast_sip_subscription_handler *find_sub_handler_for_event_name(const char *event_name);
783 static struct ast_sip_pubsub_body_generator *find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64],
784  size_t num_accept, const char *body_type);
785 
786 /*! \brief Retrieve a handler using the Event header of an rdata message */
787 static struct ast_sip_subscription_handler *subscription_get_handler_from_rdata(pjsip_rx_data *rdata, const char *endpoint)
788 {
789  pjsip_event_hdr *event_header;
790  char event[32];
791  struct ast_sip_subscription_handler *handler;
792 
793  event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
794  if (!event_header) {
795  ast_log(LOG_WARNING, "Incoming SUBSCRIBE request from %s with no Event header\n",
796  endpoint ? endpoint : "Unknown");
797  return NULL;
798  }
799  ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
800 
801  handler = find_sub_handler_for_event_name(event);
802  if (!handler) {
803  ast_log(LOG_WARNING, "No registered subscribe handler for event %s from %s\n", event,
804  endpoint ? endpoint : "Unknown");
805  }
806 
807  return handler;
808 }
809 
810 /*!
811  * \brief Accept headers that are exceptions to the rule
812  *
813  * Typically, when a SUBSCRIBE arrives, we attempt to find a
814  * body generator that matches one of the Accept headers in
815  * the request. When subscribing to a single resource, this works
816  * great. However, when subscribing to a list, things work
817  * differently. Most Accept header values are fine, but there
818  * are a couple that are endemic to resource lists that need
819  * to be ignored when searching for a body generator to use
820  * for the individual resources of the subscription.
821  */
822 const char *accept_exceptions[] = {
823  "multipart/related",
824  "application/rlmi+xml",
825 };
826 
827 /*!
828  * \brief Is the Accept header from the SUBSCRIBE in the list of exceptions?
829  *
830  * \retval 1 This Accept header value is an exception to the rule.
831  * \retval 0 This Accept header is not an exception to the rule.
832  */
833 static int exceptional_accept(const pj_str_t *accept)
834 {
835  int i;
836 
837  for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
838  if (!pj_strcmp2(accept, accept_exceptions[i])) {
839  return 1;
840  }
841  }
842 
843  return 0;
844 }
845 
846 /*! \brief Retrieve a body generator using the Accept header of an rdata message */
847 static struct ast_sip_pubsub_body_generator *subscription_get_generator_from_rdata(pjsip_rx_data *rdata,
848  const struct ast_sip_subscription_handler *handler)
849 {
850  pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
851  char accept[AST_SIP_MAX_ACCEPT][64];
852  size_t num_accept_headers = 0;
853 
854  while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
855  (num_accept_headers < AST_SIP_MAX_ACCEPT)) {
856  int i;
857 
858  for (i = 0; i < accept_header->count && num_accept_headers < AST_SIP_MAX_ACCEPT; ++i) {
859  if (!exceptional_accept(&accept_header->values[i])) {
860  ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
861  ++num_accept_headers;
862  }
863  }
864  }
865 
866  if (num_accept_headers == 0) {
867  /* If a SUBSCRIBE contains no Accept headers, then we must assume that
868  * the default accept type for the event package is to be used.
869  */
870  ast_copy_string(accept[0], handler->notifier->default_accept, sizeof(accept[0]));
871  num_accept_headers = 1;
872  }
873 
874  return find_body_generator(accept, num_accept_headers, handler->body_type);
875 }
876 
877 /*! \brief Check if the rdata has a Supported header containing 'eventlist'
878  *
879  * \retval 1 rdata has an eventlist containing supported header
880  * \retval 0 rdata doesn't have an eventlist containing supported header
881  */
882 static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
883 {
884  pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
885 
886  while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
887  int i;
888 
889  for (i = 0; i < supported_header->count; i++) {
890  if (!pj_stricmp2(&supported_header->values[i], "eventlist")) {
891  return 1;
892  }
893  }
894  }
895 
896  return 0;
897 }
898 
899 struct resource_tree;
900 
901 /*!
902  * \brief A node for a resource tree.
903  */
904 struct tree_node {
905  AST_VECTOR(, struct tree_node *) children;
906  unsigned int full_state;
907  char *display_name;
908  char resource[0];
909 };
910 
911 /*!
912  * \brief Helper function for retrieving a resource list for a given event.
913  *
914  * This will retrieve a resource list that corresponds to the resource and event provided.
915  *
916  * \param resource The name of the resource list to retrieve
917  * \param event The expected event name on the resource list
918  */
919 static struct resource_list *retrieve_resource_list(const char *resource, const char *event)
920 {
921  struct resource_list *list;
922 
923  list = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
924  if (!list) {
925  return NULL;
926  }
927 
928  if (strcmp(list->event, event)) {
929  ast_log(LOG_WARNING, "Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
930  resource, list->event, event);
931  ao2_cleanup(list);
932  return NULL;
933  }
934 
935  return list;
936 }
937 
938 /*!
939  * \brief Allocate a tree node
940  *
941  * In addition to allocating and initializing the tree node, the node is also added
942  * to the vector of visited resources. See \ref build_resource_tree for more information
943  * on the visited resources.
944  *
945  * \param resource The name of the resource for this tree node.
946  * \param visited The vector of resources that have been visited.
947  * \param full_state if allocating a list, indicate whether full state is requested in notifications.
948  * \param display_name the display name to include with this tree node.
949  *
950  * \retval NULL Allocation failure.
951  * \retval non-NULL The newly-allocated tree_node
952  */
953 static struct tree_node *tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state, const char *display_name)
954 {
955  struct tree_node *node;
956 
957  node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
958  if (!node) {
959  return NULL;
960  }
961 
962  strcpy(node->resource, resource);
963  if (AST_VECTOR_INIT(&node->children, 4)) {
964  ast_free(node);
965  return NULL;
966  }
967  node->full_state = full_state;
968  node->display_name = ast_strdup(display_name);
969 
970  if (visited) {
971  AST_VECTOR_APPEND(visited, resource);
972  }
973  return node;
974 }
975 
976 /*!
977  * \brief Destructor for a tree node
978  *
979  * This function calls recursively in order to destroy
980  * all nodes lower in the tree from the given node in
981  * addition to the node itself.
982  *
983  * \param node The node to destroy.
984  */
985 static void tree_node_destroy(struct tree_node *node)
986 {
987  int i;
988  if (!node) {
989  return;
990  }
991 
992  for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
993  tree_node_destroy(AST_VECTOR_GET(&node->children, i));
994  }
995  AST_VECTOR_FREE(&node->children);
996  ast_free(node->display_name);
997  ast_free(node);
998 }
999 
1000 /*!
1001  * \brief Determine if this resource has been visited already
1002  *
1003  * See \ref build_resource_tree for more information
1004  *
1005  * \param resource The resource currently being visited
1006  * \param visited The resources that have previously been visited
1007  */
1008 static int have_visited(const char *resource, struct resources *visited)
1009 {
1010  int i;
1011 
1012  for (i = 0; i < AST_VECTOR_SIZE(visited); ++i) {
1013  if (!strcmp(resource, AST_VECTOR_GET(visited, i))) {
1014  return 1;
1015  }
1016  }
1017 
1018  return 0;
1019 }
1020 
1021 #define NEW_SUBSCRIBE(notifier, endpoint, resource, rdata) notifier->new_subscribe_with_rdata ? notifier->new_subscribe_with_rdata(endpoint, resource, rdata) : notifier->new_subscribe(endpoint, resource)
1022 
1023 /*!
1024  * \brief Build child nodes for a given parent.
1025  *
1026  * This iterates through the items on a resource list and creates tree nodes for each one. The
1027  * tree nodes created are children of the supplied parent node. If an item in the resource
1028  * list is itself a list, then this function is called recursively to provide children for
1029  * the new node.
1030  *
1031  * If an item in a resource list is not a list, then the supplied subscription handler is
1032  * called into as if a new SUBSCRIBE for the list item were presented. The handler's response
1033  * is used to determine if the node can be added to the tree or not.
1034  *
1035  * If a parent node ends up having no child nodes added under it, then the parent node is
1036  * pruned from the tree.
1037  *
1038  * \param endpoint The endpoint that sent the inbound SUBSCRIBE.
1039  * \param handler The subscription handler for leaf nodes in the tree.
1040  * \param list The configured resource list from which the child node is being built.
1041  * \param parent The parent node for these children.
1042  * \param visited The resources that have already been visited.
1043  */
1044 static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
1045  struct resource_list *list, struct tree_node *parent, struct resources *visited, pjsip_rx_data *rdata)
1046 {
1047  int i;
1048 
1049  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
1050  struct tree_node *current;
1051  struct resource_list *child_list;
1052  const char *resource = AST_VECTOR_GET(&list->items, i);
1053 
1054  if (have_visited(resource, visited)) {
1055  ast_debug(1, "Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1056  continue;
1057  }
1058 
1059  child_list = retrieve_resource_list(resource, list->event);
1060  if (!child_list) {
1061  int resp = NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
1062  if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1063  char display_name[AST_MAX_EXTENSION] = "";
1064  if (list->resource_display_name && handler->notifier->get_resource_display_name) {
1065  handler->notifier->get_resource_display_name(endpoint, resource, display_name, sizeof(display_name));
1066  }
1067  current = tree_node_alloc(resource, visited, 0, ast_strlen_zero(display_name) ? NULL : display_name);
1068  if (!current) {
1069  ast_debug(1,
1070  "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1071  resource);
1072  continue;
1073  }
1074  ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1075  resource, parent->resource);
1076  if (AST_VECTOR_APPEND(&parent->children, current)) {
1077  tree_node_destroy(current);
1078  }
1079  } else {
1080  ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n",
1081  resource, resp);
1082  }
1083  } else {
1084  ast_debug(2, "Resource %s (child of %s) is a list\n", resource, parent->resource);
1085  current = tree_node_alloc(resource, visited, child_list->full_state, NULL);
1086  if (!current) {
1087  ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
1088  continue;
1089  }
1090  build_node_children(endpoint, handler, child_list, current, visited, rdata);
1091  if (AST_VECTOR_SIZE(&current->children) > 0) {
1092  ast_debug(1, "List %s had no successful children.\n", resource);
1093  if (AST_VECTOR_APPEND(&parent->children, current)) {
1094  tree_node_destroy(current);
1095  }
1096  } else {
1097  ast_debug(2, "List %s had successful children. Adding to parent %s\n",
1098  resource, parent->resource);
1099  tree_node_destroy(current);
1100  }
1101  ao2_cleanup(child_list);
1102  }
1103  }
1104 }
1105 
1106 /*!
1107  * \brief A resource tree
1108  *
1109  * When an inbound SUBSCRIBE arrives, the resource being subscribed to may
1110  * be a resource list. If this is the case, the resource list may contain resources
1111  * that are themselves lists. The structure needed to hold the resources is
1112  * a tree.
1113  *
1114  * Upon receipt of the SUBSCRIBE, the tree is built by determining if subscriptions
1115  * to the individual resources in the tree would be successful or not. Any successful
1116  * subscriptions result in a node in the tree being created. Any unsuccessful subscriptions
1117  * result in no node being created.
1118  *
1119  * This tree can be seen as a bare-bones analog of the tree of ast_sip_subscriptions that
1120  * will end up being created to actually carry out the duties of a SIP SUBSCRIBE dialog.
1121  */
1123  struct tree_node *root;
1124  unsigned int notification_batch_interval;
1125 };
1126 
1127 /*!
1128  * \brief Destroy a resource tree.
1129  *
1130  * This function makes no assumptions about how the tree itself was
1131  * allocated and does not attempt to free the tree itself. Callers
1132  * of this function are responsible for freeing the tree.
1133  *
1134  * \param tree The tree to destroy.
1135  */
1136 static void resource_tree_destroy(struct resource_tree *tree)
1137 {
1138  if (tree) {
1139  tree_node_destroy(tree->root);
1140  }
1141 }
1142 
1143 /*!
1144  * \brief Build a resource tree
1145  *
1146  * This function builds a resource tree based on the requested resource in a SUBSCRIBE request.
1147  *
1148  * This function also creates a container that has all resources that have been visited during
1149  * creation of the tree, whether those resources resulted in a tree node being created or not.
1150  * Keeping this container of visited resources allows for misconfigurations such as loops in
1151  * the tree or duplicated resources to be detected.
1152  *
1153  * \param endpoint The endpoint that sent the SUBSCRIBE request.
1154  * \param handler The subscription handler for leaf nodes in the tree.
1155  * \param resource The resource requested in the SUBSCRIBE request.
1156  * \param tree The tree that is to be built.
1157  * \param has_eventlist_support
1158  *
1159  * \retval 200-299 Successfully subscribed to at least one resource.
1160  * \retval 300-699 Failure to subscribe to requested resource.
1161  */
1162 static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler,
1163  const char *resource, struct resource_tree *tree, int has_eventlist_support, pjsip_rx_data *rdata)
1164 {
1165  RAII_VAR(struct resource_list *, list, NULL, ao2_cleanup);
1166  struct resources visited;
1167 
1168  int not_eventlist_but_needs_children = !strcmp(handler->body_type, AST_SIP_DEVICE_FEATURE_SYNC_DATA);
1169 
1170  if ((!has_eventlist_support && !not_eventlist_but_needs_children) || !(list = retrieve_resource_list(resource, handler->event_name))) {
1171  ast_debug(2, "Subscription '%s->%s' is not to a list\n",
1172  ast_sorcery_object_get_id(endpoint), resource);
1173  tree->root = tree_node_alloc(resource, NULL, 0, NULL);
1174  if (!tree->root) {
1175  return 500;
1176  }
1177  return NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
1178  }
1179 
1180  ast_debug(2, "Subscription '%s->%s' is a list\n",
1181  ast_sorcery_object_get_id(endpoint), resource);
1182  if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
1183  return 500;
1184  }
1185 
1186  tree->root = tree_node_alloc(resource, &visited, list->full_state, NULL);
1187  if (!tree->root) {
1188  AST_VECTOR_FREE(&visited);
1189  return 500;
1190  }
1191 
1192  tree->notification_batch_interval = list->notification_batch_interval;
1193 
1194  build_node_children(endpoint, handler, list, tree->root, &visited, rdata);
1195  AST_VECTOR_FREE(&visited);
1196 
1197  if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
1198  return 200;
1199  } else {
1200  return 500;
1201  }
1202 }
1203 
1204 static void add_subscription(struct sip_subscription_tree *obj)
1205 {
1207  AST_RWLIST_INSERT_TAIL(&subscriptions, obj, next);
1209 }
1210 
1211 static void remove_subscription(struct sip_subscription_tree *obj)
1212 {
1213  struct sip_subscription_tree *i;
1214 
1216  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscriptions, i, next) {
1217  if (i == obj) {
1218  AST_RWLIST_REMOVE_CURRENT(next);
1219  if (i->root) {
1220  ast_debug(2, "Removing subscription '%s->%s' from list of subscriptions\n",
1221  ast_sorcery_object_get_id(i->endpoint), ast_sip_subscription_get_resource_name(i->root));
1222  }
1223  break;
1224  }
1225  }
1226  AST_RWLIST_TRAVERSE_SAFE_END;
1228 }
1229 
1230 static void destroy_subscription(struct ast_sip_subscription *sub)
1231 {
1232  ast_debug(3, "Destroying SIP subscription from '%s->%s'\n",
1233  sub->tree && sub->tree->endpoint ? ast_sorcery_object_get_id(sub->tree->endpoint) : "Unknown",
1234  sub->resource);
1235 
1236  ast_free(sub->body_text);
1237 
1238  AST_VECTOR_FREE(&sub->children);
1239  ao2_cleanup(sub->datastores);
1241  ast_free(sub->display_name);
1242  ast_free(sub);
1243 }
1244 
1245 static void destroy_subscriptions(struct ast_sip_subscription *root)
1246 {
1247  int i;
1248 
1249  if (!root) {
1250  return;
1251  }
1252 
1253  for (i = 0; i < AST_VECTOR_SIZE(&root->children); ++i) {
1254  struct ast_sip_subscription *child;
1255 
1256  child = AST_VECTOR_GET(&root->children, i);
1257  destroy_subscriptions(child);
1258  }
1259 
1260  destroy_subscription(root);
1261 }
1262 
1263 static struct ast_sip_subscription *allocate_subscription(const struct ast_sip_subscription_handler *handler,
1264  const char *resource, const char *display_name, struct sip_subscription_tree *tree)
1265 {
1266  struct ast_sip_subscription *sub;
1267  pjsip_msg *msg;
1268  pjsip_sip_uri *request_uri;
1269 
1270  msg = ast_sip_mod_data_get(tree->dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1271  if (!msg) {
1272  ast_log(LOG_ERROR, "No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n", resource);
1273  return NULL;
1274  }
1275 
1276  sub = ast_calloc(1, sizeof(*sub) + strlen(resource) + 1);
1277  if (!sub) {
1278  return NULL;
1279  }
1280  strcpy(sub->resource, resource); /* Safe */
1281 
1282  sub->display_name = ast_strdup(display_name);
1283 
1285  if (!sub->datastores) {
1286  destroy_subscription(sub);
1287  return NULL;
1288  }
1289 
1290  sub->body_text = ast_str_create(128);
1291  if (!sub->body_text) {
1292  destroy_subscription(sub);
1293  return NULL;
1294  }
1295 
1296  sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
1297  request_uri = pjsip_uri_get_uri(msg->line.req.uri);
1298  pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, request_uri);
1299  pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
1300 
1301  /* If there is any persistence information available for this subscription that was persisted
1302  * then make it available so that the NOTIFY has the correct state.
1303  */
1304 
1305  if (tree->persistence && tree->persistence->generator_data) {
1307  }
1308 
1309  sub->handler = handler;
1310  sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1311  sub->tree = ao2_bump(tree);
1312 
1313  return sub;
1314 }
1315 
1316 /*!
1317  * \brief Create a tree of virtual subscriptions based on a resource tree node.
1318  *
1319  * \param handler The handler to supply to leaf subscriptions.
1320  * \param resource The requested resource for this subscription.
1321  * \param generator Body generator to use for leaf subscriptions.
1322  * \param tree The root of the subscription tree.
1323  * \param current The tree node that corresponds to the subscription being created.
1324  */
1325 static struct ast_sip_subscription *create_virtual_subscriptions(const struct ast_sip_subscription_handler *handler,
1326  const char *resource, struct ast_sip_pubsub_body_generator *generator,
1327  struct sip_subscription_tree *tree, struct tree_node *current)
1328 {
1329  int i;
1330  struct ast_sip_subscription *sub;
1331 
1332  sub = allocate_subscription(handler, resource, current->display_name, tree);
1333  if (!sub) {
1334  return NULL;
1335  }
1336 
1337  sub->full_state = current->full_state;
1338  sub->body_generator = generator;
1339  AST_VECTOR_INIT(&sub->children, AST_VECTOR_SIZE(&current->children));
1340 
1341  for (i = 0; i < AST_VECTOR_SIZE(&current->children); ++i) {
1342  struct ast_sip_subscription *child;
1343  struct tree_node *child_node = AST_VECTOR_GET(&current->children, i);
1344 
1345  child = create_virtual_subscriptions(handler, child_node->resource, generator,
1346  tree, child_node);
1347 
1348  if (!child) {
1349  ast_debug(1, "Child subscription to resource %s could not be created\n",
1350  child_node->resource);
1351  continue;
1352  }
1353 
1354  if (AST_VECTOR_APPEND(&sub->children, child)) {
1355  ast_debug(1, "Child subscription to resource %s could not be appended\n",
1356  child_node->resource);
1357  destroy_subscription(child);
1358  /* Have to release tree here too because a ref was added
1359  * to child that destroy_subscription() doesn't release. */
1360  ao2_cleanup(tree);
1361  }
1362  }
1363 
1364  return sub;
1365 }
1366 
1367 static void shutdown_subscriptions(struct ast_sip_subscription *sub)
1368 {
1369  int i;
1370 
1371  if (!sub) {
1372  return;
1373  }
1374 
1375  if (AST_VECTOR_SIZE(&sub->children) > 0) {
1376  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
1377  shutdown_subscriptions(AST_VECTOR_GET(&sub->children, i));
1378  }
1379  return;
1380  }
1381 
1382  /* We notify subscription shutdown only on the tree leaves. */
1383  if (sub->handler->subscription_shutdown) {
1384  sub->handler->subscription_shutdown(sub);
1385  }
1386 }
1387 
1388 static int subscription_unreference_dialog(void *obj)
1389 {
1390  struct sip_subscription_tree *sub_tree = obj;
1391 
1392  /* This is why we keep the dialog on the subscription. When the subscription
1393  * is destroyed, there is no guarantee that the underlying dialog is ready
1394  * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1395  * either. The dialog could be destroyed before our subscription is. We fix
1396  * this problem by keeping a reference to the dialog until it is time to
1397  * destroy the subscription. We need to have the dialog available when the
1398  * subscription is destroyed so that we can guarantee that our attempt to
1399  * remove the serializer will be successful.
1400  */
1401  pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
1402  sub_tree->dlg = NULL;
1403 
1404  return 0;
1405 }
1406 
1407 static void subscription_tree_destructor(void *obj)
1408 {
1409  struct sip_subscription_tree *sub_tree = obj;
1410 
1411  ast_debug(3, "Destroying subscription tree %p '%s->%s'\n",
1412  sub_tree,
1413  sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
1414  sub_tree->root ? sub_tree->root->resource : "Unknown");
1415 
1416  destroy_subscriptions(sub_tree->root);
1417 
1418  if (sub_tree->dlg) {
1420  subscription_unreference_dialog, sub_tree);
1421  }
1422 
1423  ao2_cleanup(sub_tree->endpoint);
1424 
1427 }
1428 
1429 void ast_sip_subscription_destroy(struct ast_sip_subscription *sub)
1430 {
1431  ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1432  sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree);
1433  ao2_cleanup(sub->tree);
1434 }
1435 
1436 static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
1437 {
1438  sub_tree->dlg = dlg;
1439  ast_sip_dialog_set_serializer(dlg, sub_tree->serializer);
1440  ast_sip_dialog_set_endpoint(dlg, sub_tree->endpoint);
1441  pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
1442  pjsip_dlg_inc_session(dlg, &pubsub_module);
1443 }
1444 
1445 static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
1446 {
1447  struct sip_subscription_tree *sub_tree;
1448 
1449  sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
1450  if (!sub_tree) {
1451  return NULL;
1452  }
1453 
1455 
1456  if (rdata) {
1457  /*
1458  * We must continue using the serializer that the original
1459  * SUBSCRIBE came in on for the dialog. There may be
1460  * retransmissions already enqueued in the original
1461  * serializer that can result in reentrancy and message
1462  * sequencing problems.
1463  */
1465  } else {
1466  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1467 
1468  /* Create name with seq number appended. */
1469  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s",
1470  ast_sorcery_object_get_id(endpoint));
1471 
1472  sub_tree->serializer = ast_sip_create_serializer(tps_name);
1473  }
1474  if (!sub_tree->serializer) {
1475  ao2_ref(sub_tree, -1);
1476  return NULL;
1477  }
1478 
1479  sub_tree->endpoint = ao2_bump(endpoint);
1480  sub_tree->notify_sched_id = -1;
1481 
1482  return sub_tree;
1483 }
1484 
1485 /*!
1486  * \brief Create a subscription tree based on a resource tree.
1487  *
1488  * Using the previously-determined valid resources in the provided resource tree,
1489  * a corresponding tree of ast_sip_subscriptions are created. The root of the
1490  * subscription tree is a real subscription, and the rest in the tree are
1491  * virtual subscriptions.
1492  *
1493  * \param handler The handler to use for leaf subscriptions
1494  * \param endpoint The endpoint that sent the SUBSCRIBE request
1495  * \param rdata The SUBSCRIBE content
1496  * \param resource The requested resource in the SUBSCRIBE request
1497  * \param generator The body generator to use in leaf subscriptions
1498  * \param tree The resource tree on which the subscription tree is based
1499  * \param[out] dlg_status The result of attempting to create a dialog
1500  * \param persistence
1501  *
1502  * \retval NULL Could not create the subscription tree
1503  * \retval non-NULL The root of the created subscription tree
1504  */
1505 
1506 static struct sip_subscription_tree *create_subscription_tree(const struct ast_sip_subscription_handler *handler,
1507  struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
1508  struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree,
1509  pj_status_t *dlg_status, struct subscription_persistence *persistence)
1510 {
1511  struct sip_subscription_tree *sub_tree;
1512  pjsip_dialog *dlg;
1513 
1514  sub_tree = allocate_subscription_tree(endpoint, rdata);
1515  if (!sub_tree) {
1516  *dlg_status = PJ_ENOMEM;
1517  return NULL;
1518  }
1519  sub_tree->role = AST_SIP_NOTIFIER;
1520 
1521  dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, dlg_status);
1522  if (!dlg) {
1523  if (*dlg_status != PJ_EEXISTS) {
1524  ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1525  }
1526  ao2_ref(sub_tree, -1);
1527  return NULL;
1528  }
1529 
1530  persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
1531  pubsub_module.id, MOD_DATA_PERSISTENCE);
1532  if (persistence) {
1533  /* Update the created dialog with the persisted information */
1534  pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
1535  pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->tag);
1536  dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
1537  pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
1538  dlg->local.cseq = persistence->cseq;
1539  }
1540 
1541  pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
1542 
1543  subscription_setup_dialog(sub_tree, dlg);
1544 
1545  /*
1546  * The evsub and subscription setup both add dialog refs, so the dialog ref that
1547  * was added when the dialog was created (see ast_sip_create_dialog_uas_lock) can
1548  * now be removed. The lock should no longer be needed so can be removed too.
1549  */
1550  pjsip_dlg_dec_lock(dlg);
1551 
1552 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
1553  pjsip_evsub_add_ref(sub_tree->evsub);
1554 #endif
1555 
1556  ast_sip_mod_data_set(dlg->pool, dlg->mod_data, pubsub_module.id, MOD_DATA_MSG,
1557  pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
1558 
1559  sub_tree->notification_batch_interval = tree->notification_batch_interval;
1560 
1561  /* Persistence information needs to be available for all the subscriptions */
1562  sub_tree->persistence = ao2_bump(persistence);
1563 
1564  sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
1565  if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
1566  sub_tree->is_list = 1;
1567  }
1568 
1569  add_subscription(sub_tree);
1570 
1571  return sub_tree;
1572 }
1573 
1574 /*! Wrapper structure for initial_notify_task */
1576  struct sip_subscription_tree *sub_tree;
1577  unsigned int expires;
1578 };
1579 
1580 static int initial_notify_task(void *obj);
1581 static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state);
1582 
1583 /*! Persistent subscription recreation continuation under distributor serializer data */
1586  pjsip_rx_data *rdata;
1587 };
1588 
1589 /*!
1590  * \internal
1591  * \brief subscription_persistence_recreate continuation under distributor serializer.
1592  * \since 13.10.0
1593  *
1594  * \retval 0 on success.
1595  * \retval -1 on error.
1596  */
1597 static int sub_persistence_recreate(void *obj)
1598 {
1599  struct persistence_recreate_data *recreate_data = obj;
1600  struct subscription_persistence *persistence = recreate_data->persistence;
1601  pjsip_rx_data *rdata = recreate_data->rdata;
1602  struct ast_sip_endpoint *endpoint;
1603  struct sip_subscription_tree *sub_tree;
1604  struct ast_sip_pubsub_body_generator *generator;
1605  struct ast_sip_subscription_handler *handler;
1606  char *resource;
1607  size_t resource_size;
1608  int resp;
1609  struct resource_tree tree;
1610  pjsip_expires_hdr *expires_header;
1611  int64_t expires;
1612  const pj_str_t *user;
1613 
1614  user = ast_sip_pjsip_uri_get_username(rdata->msg_info.msg->line.req.uri);
1615  resource_size = pj_strlen(user) + 1;
1616  resource = ast_alloca(resource_size);
1617  ast_copy_pj_str(resource, user, resource_size);
1618 
1619  /*
1620  * We may want to match without any user options getting
1621  * in the way.
1622  */
1623  AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource);
1624 
1625  handler = subscription_get_handler_from_rdata(rdata, persistence->endpoint);
1626  if (!handler || !handler->notifier) {
1627  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get subscription handler.\n",
1628  persistence->endpoint);
1629  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1630  return 0;
1631  }
1632 
1633  generator = subscription_get_generator_from_rdata(rdata, handler);
1634  if (!generator) {
1635  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Body generator not available.\n",
1636  persistence->endpoint);
1637  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1638  return 0;
1639  }
1640 
1641  ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data,
1642  pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
1643 
1644  /* Getting the endpoint may take some time that can affect the expiration. */
1645  endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1646  persistence->endpoint);
1647  if (!endpoint) {
1648  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The endpoint was not found\n",
1649  persistence->endpoint);
1650  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1651  return 0;
1652  }
1653 
1654  /* Update the expiration header with the new expiration */
1655  expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1656  rdata->msg_info.msg->hdr.next);
1657  if (!expires_header) {
1658  expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1659  if (!expires_header) {
1660  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not update expires header.\n",
1661  persistence->endpoint);
1662  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1663  ao2_ref(endpoint, -1);
1664  return 0;
1665  }
1666  pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1667  }
1668 
1669  expires = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
1670  if (expires <= 0) {
1671  /* The subscription expired since we started recreating the subscription. */
1672  ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1673  persistence->endpoint, persistence->tag);
1674  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1675  ao2_ref(endpoint, -1);
1676  return 0;
1677  }
1678  expires_header->ivalue = expires;
1679 
1680  memset(&tree, 0, sizeof(tree));
1681  resp = build_resource_tree(endpoint, handler, resource, &tree,
1682  ast_sip_pubsub_has_eventlist_support(rdata), rdata);
1683  if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1684  pj_status_t dlg_status;
1685 
1686  sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,
1687  &tree, &dlg_status, persistence);
1688  if (!sub_tree) {
1689  if (dlg_status != PJ_EEXISTS) {
1690  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",
1691  persistence->endpoint);
1692  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1693  }
1694  } else {
1695  struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
1696 
1697  if (!ind) {
1698  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1699  goto error;
1700  }
1701 
1702  ind->sub_tree = ao2_bump(sub_tree);
1703  ind->expires = expires_header->ivalue;
1704 
1705  subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_RECREATED);
1706  if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {
1707  /* Could not send initial subscribe NOTIFY */
1708  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1709  ao2_ref(sub_tree, -1);
1710  ast_free(ind);
1711  }
1712  }
1713  } else {
1714  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1715  }
1716 
1717 error:
1718  resource_tree_destroy(&tree);
1719  ao2_ref(endpoint, -1);
1720 
1721  return 0;
1722 }
1723 
1724 /*! \brief Callback function to perform the actual recreation of a subscription */
1725 static int subscription_persistence_recreate(void *obj, void *arg, int flags)
1726 {
1727  struct subscription_persistence *persistence = obj;
1728  pj_pool_t *pool = arg;
1729  struct ast_taskprocessor *serializer;
1730  pjsip_rx_data rdata;
1731  struct persistence_recreate_data recreate_data;
1732 
1733  /* If this subscription used a reliable transport it can't be reestablished so remove it */
1734  if (persistence->prune_on_boot) {
1735  ast_debug(3, "Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1736  persistence->endpoint, persistence->tag);
1737  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1738  return 0;
1739  }
1740 
1741  /* If this subscription has already expired remove it */
1742  if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) {
1743  ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1744  persistence->endpoint, persistence->tag);
1745  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1746  return 0;
1747  }
1748 
1749  memset(&rdata, 0, sizeof(rdata));
1750  pj_pool_reset(pool);
1751  rdata.tp_info.pool = pool;
1752 
1753  if (ast_sip_create_rdata_with_contact(&rdata, persistence->packet, persistence->src_name,
1754  persistence->src_port, persistence->transport_type, persistence->local_name,
1755  persistence->local_port, persistence->contact_uri)) {
1756  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n",
1757  persistence->endpoint);
1758  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1759  return 0;
1760  }
1761 
1762  if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1763  ast_log(LOG_NOTICE, "Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1764  persistence->endpoint);
1765  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1766  return 0;
1767  }
1768 
1769  /* Continue the remainder in the distributor serializer */
1770  serializer = ast_sip_get_distributor_serializer(&rdata);
1771  if (!serializer) {
1772  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1773  persistence->endpoint);
1774  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1775  return 0;
1776  }
1777  recreate_data.persistence = persistence;
1778  recreate_data.rdata = &rdata;
1779  if (ast_sip_push_task_wait_serializer(serializer, sub_persistence_recreate,
1780  &recreate_data)) {
1781  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
1782  persistence->endpoint);
1783  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1784  }
1785  ast_taskprocessor_unreference(serializer);
1786 
1787  return 0;
1788 }
1789 
1790 /*! \brief Function which loads and recreates persisted subscriptions upon startup when the system is fully booted */
1791 static int subscription_persistence_load(void *data)
1792 {
1793  struct ao2_container *persisted_subscriptions = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
1794  "subscription_persistence", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1795  pj_pool_t *pool;
1796 
1797  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "rtd%p", PJSIP_POOL_RDATA_LEN,
1798  PJSIP_POOL_RDATA_INC);
1799  if (!pool) {
1800  ast_log(LOG_WARNING, "Could not create a memory pool for recreating SIP subscriptions\n");
1801  return 0;
1802  }
1803 
1804  ao2_callback(persisted_subscriptions, OBJ_NODATA, subscription_persistence_recreate, pool);
1805 
1806  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1807 
1808  ao2_ref(persisted_subscriptions, -1);
1809  return 0;
1810 }
1811 
1812 /*! \brief Event callback which fires subscription persistence recreation when the system is fully booted */
1813 static void subscription_persistence_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
1814 {
1815  struct ast_json_payload *payload;
1816  const char *type;
1817 
1819  return;
1820  }
1821 
1822  payload = stasis_message_data(message);
1823  type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1824 
1825  /* This subscription only responds to the FullyBooted event so that all modules have been loaded when we
1826  * recreate SIP subscriptions.
1827  */
1828  if (strcmp(type, "FullyBooted")) {
1829  return;
1830  }
1831 
1832  /* This has to be here so the subscription is recreated when the body generator is available */
1833  ast_sip_push_task(NULL, subscription_persistence_load, NULL);
1834 
1835  /* Once the system is fully booted we don't care anymore */
1836  stasis_unsubscribe(sub);
1837 }
1838 
1839 typedef int (*on_subscription_t)(struct sip_subscription_tree *sub, void *arg);
1840 
1841 static int for_each_subscription(on_subscription_t on_subscription, void *arg)
1842 {
1843  int num = 0;
1844  struct sip_subscription_tree *i;
1845 
1846  if (!on_subscription) {
1847  return num;
1848  }
1849 
1851  AST_RWLIST_TRAVERSE(&subscriptions, i, next) {
1852  if (on_subscription(i, arg)) {
1853  break;
1854  }
1855  ++num;
1856  }
1858  return num;
1859 }
1860 
1861 static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree,
1862  struct ast_str **buf)
1863 {
1864  char str[256];
1865  struct ast_sip_endpoint_id_configuration *id = &sub_tree->endpoint->id;
1866 
1867  ast_str_append(buf, 0, "Role: %s\r\n",
1868  sip_subscription_roles_map[sub_tree->role]);
1869  ast_str_append(buf, 0, "Endpoint: %s\r\n",
1870  ast_sorcery_object_get_id(sub_tree->endpoint));
1871 
1872  if (sub_tree->dlg) {
1873  ast_copy_pj_str(str, &sub_tree->dlg->call_id->id, sizeof(str));
1874  } else {
1875  ast_copy_string(str, "<unknown>", sizeof(str));
1876  }
1877  ast_str_append(buf, 0, "Callid: %s\r\n", str);
1878 
1879  ast_str_append(buf, 0, "State: %s\r\n", pjsip_evsub_get_state_name(sub_tree->evsub));
1880 
1881  ast_callerid_merge(str, sizeof(str),
1882  S_COR(id->self.name.valid, id->self.name.str, NULL),
1883  S_COR(id->self.number.valid, id->self.number.str, NULL),
1884  "Unknown");
1885 
1886  ast_str_append(buf, 0, "Callerid: %s\r\n", str);
1887 
1888  /* XXX This needs to be done recursively for lists */
1889  if (sub_tree->root->handler->to_ami) {
1890  sub_tree->root->handler->to_ami(sub_tree->root, buf);
1891  }
1892 }
1893 
1894 
1895 void *ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, const char *header)
1896 {
1897  pjsip_dialog *dlg;
1898  pjsip_msg *msg;
1899  pj_str_t name;
1900 
1901  dlg = sub->tree->dlg;
1902  msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1903  pj_cstr(&name, header);
1904 
1905  return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
1906 }
1907 
1908 /* XXX This function is not used. */
1909 struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
1910  struct ast_sip_endpoint *endpoint, const char *resource)
1911 {
1912  struct ast_sip_subscription *sub;
1913  pjsip_dialog *dlg;
1914  struct ast_sip_contact *contact;
1915  pj_str_t event;
1916  pjsip_tx_data *tdata;
1917  pjsip_evsub *evsub;
1918  struct sip_subscription_tree *sub_tree = NULL;
1919 
1920  sub_tree = allocate_subscription_tree(endpoint, NULL);
1921  if (!sub_tree) {
1922  return NULL;
1923  }
1924 
1925  sub = allocate_subscription(handler, resource, NULL, sub_tree);
1926  if (!sub) {
1927  ao2_cleanup(sub_tree);
1928  return NULL;
1929  }
1930 
1931  contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
1932  if (!contact || ast_strlen_zero(contact->uri)) {
1933  ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
1934  ast_sorcery_object_get_id(endpoint));
1935  ao2_ref(sub_tree, -1);
1936  ao2_cleanup(contact);
1937  return NULL;
1938  }
1939 
1940  dlg = ast_sip_create_dialog_uac(endpoint, contact->uri, NULL);
1941  ao2_cleanup(contact);
1942  if (!dlg) {
1943  ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1944  ao2_ref(sub_tree, -1);
1945  return NULL;
1946  }
1947 
1948  pj_cstr(&event, handler->event_name);
1949  pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub_tree->evsub);
1950  subscription_setup_dialog(sub_tree, dlg);
1951 
1952  evsub = sub_tree->evsub;
1953 
1954  if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
1955  pjsip_evsub_send_request(sub_tree->evsub, tdata);
1956  } else {
1957  /* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
1958  * being called and terminating the subscription. Therefore, we don't
1959  * need to decrease the reference count of sub here.
1960  */
1961  pjsip_evsub_terminate(evsub, PJ_TRUE);
1962  ao2_ref(sub_tree, -1);
1963  return NULL;
1964  }
1965 
1966  add_subscription(sub_tree);
1967 
1968  return sub;
1969 }
1970 
1971 pjsip_dialog *ast_sip_subscription_get_dialog(struct ast_sip_subscription *sub)
1972 {
1973  ast_assert(sub->tree->dlg != NULL);
1974  return sub->tree->dlg;
1975 }
1976 
1977 struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
1978 {
1979  ast_assert(sub->tree->endpoint != NULL);
1980  return ao2_bump(sub->tree->endpoint);
1981 }
1982 
1983 struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub)
1984 {
1985  ast_assert(sub->tree->serializer != NULL);
1986  return sub->tree->serializer;
1987 }
1988 
1989 /*!
1990  * \brief Pre-allocate a buffer for the transmission
1991  *
1992  * Typically, we let PJSIP do this step for us when we send a request. PJSIP's buffer
1993  * allocation algorithm is to allocate a buffer of PJSIP_MAX_PKT_LEN bytes and attempt
1994  * to write the packet to the allocated buffer. If the buffer is too small to hold the
1995  * packet, then we get told the message is too long to be sent.
1996  *
1997  * When dealing with SIP NOTIFY, especially with RLS, it is possible to exceed
1998  * PJSIP_MAX_PKT_LEN. Rather than accepting the limitation imposed on us by default,
1999  * we instead take the strategy of pre-allocating the buffer, testing for ourselves
2000  * if the message will fit, and resizing the buffer as required.
2001  *
2002  * The limit we impose is double that of the maximum packet length.
2003  *
2004  * \param tdata The tdata onto which to allocate a buffer
2005  * \retval 0 Success
2006  * \retval -1 The message is too large
2007  */
2008 static int allocate_tdata_buffer(pjsip_tx_data *tdata)
2009 {
2010  int buf_size;
2011  int size = -1;
2012  char *buf;
2013 
2014  for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
2015  buf = pj_pool_alloc(tdata->pool, buf_size);
2016  size = pjsip_msg_print(tdata->msg, buf, buf_size);
2017  }
2018 
2019  if (size == -1) {
2020  return -1;
2021  }
2022 
2023  tdata->buf.start = buf;
2024  tdata->buf.cur = tdata->buf.start;
2025  tdata->buf.end = tdata->buf.start + buf_size;
2026 
2027  return 0;
2028 }
2029 
2030 static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
2031 {
2032 #ifdef TEST_FRAMEWORK
2033  struct ast_sip_endpoint *endpoint = sub_tree->endpoint;
2034  pjsip_evsub *evsub = sub_tree->evsub;
2035 #endif
2036  int res;
2037 
2038  if (allocate_tdata_buffer(tdata)) {
2039  ast_log(LOG_ERROR, "SIP request %s is too large to send.\n", tdata->info);
2040  pjsip_tx_data_dec_ref(tdata);
2041  return -1;
2042  }
2043 
2044  res = pjsip_evsub_send_request(sub_tree->evsub, tdata);
2045 
2046  subscription_persistence_update(sub_tree, NULL, SUBSCRIPTION_PERSISTENCE_SEND_REQUEST);
2047 
2048  ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
2049  "StateText: %s\r\n"
2050  "Endpoint: %s\r\n",
2051  pjsip_evsub_get_state_name(evsub),
2052  ast_sorcery_object_get_id(endpoint));
2053 
2054  return (res == PJ_SUCCESS ? 0 : -1);
2055 }
2056 
2057 /*!
2058  * \brief Add a resource XML element to an RLMI body
2059  *
2060  * Each resource element represents a subscribed resource in the list. This function currently
2061  * will unconditionally add an instance element to each created resource element. Instance
2062  * elements refer to later parts in the multipart body.
2063  *
2064  * \param pool PJLIB allocation pool
2065  * \param rlmi
2066  * \param cid Content-ID header of the resource
2067  * \param resource_name Name of the resource
2068  * \param resource_uri URI of the resource
2069  * \param state State of the subscribed resource
2070  */
2071 static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid,
2072  const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
2073 {
2074  static pj_str_t cid_name = { "cid", 3 };
2075  pj_xml_node *resource;
2076  pj_xml_node *name;
2077  pj_xml_node *instance;
2078  pj_xml_attr *cid_attr;
2079  char id[6];
2080  char uri[PJSIP_MAX_URL_SIZE];
2081  char name_sanitized[PJSIP_MAX_URL_SIZE];
2082 
2083  /* This creates a string representing the Content-ID without the enclosing < > */
2084  const pj_str_t cid_stripped = {
2085  .ptr = cid->hvalue.ptr + 1,
2086  .slen = cid->hvalue.slen - 2,
2087  };
2088 
2089  resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
2090  name = ast_sip_presence_xml_create_node(pool, resource, "name");
2091  instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
2092 
2093  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
2094  ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
2095 
2096  ast_sip_sanitize_xml(resource_name, name_sanitized, sizeof(name_sanitized));
2097  pj_strdup2(pool, &name->content, name_sanitized);
2098 
2099  ast_generate_random_string(id, sizeof(id));
2100 
2101  ast_sip_presence_xml_create_attr(pool, instance, "id", id);
2102  ast_sip_presence_xml_create_attr(pool, instance, "state",
2103  state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
2104 
2105  /* Use the PJLIB-util XML library directly here since we are using a
2106  * pj_str_t
2107  */
2108 
2109  cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2110  pj_xml_add_attr(instance, cid_attr);
2111 }
2112 
2113 /*!
2114  * \brief A multipart body part and meta-information
2115  *
2116  * When creating a multipart body part, the end result (the
2117  * pjsip_multipart_part) is hard to inspect without undoing
2118  * a lot of what was done to create it. Therefore, we use this
2119  * structure to store meta-information about the body part.
2120  *
2121  * The main consumer of this is the creator of the RLMI body
2122  * part of a multipart resource list body.
2123  */
2124 struct body_part {
2125  /*! Content-ID header for the body part */
2126  pjsip_generic_string_hdr *cid;
2127  /*! Subscribed resource represented in the body part */
2128  const char *resource;
2129  /*! URI for the subscribed body part */
2130  pjsip_sip_uri *uri;
2131  /*! Subscription state of the resource represented in the body part */
2132  pjsip_evsub_state state;
2133  /*! The actual body part that will be present in the multipart body */
2134  pjsip_multipart_part *part;
2135  /*! Display name for the resource */
2136  const char *display_name;
2137 };
2138 
2139 /*!
2140  * \brief Type declaration for container of body part structures
2141  */
2143 
2144 /*!
2145  * \brief Create a Content-ID header
2146  *
2147  * Content-ID headers are required by RFC2387 for multipart/related
2148  * bodies. They serve as identifiers for each part of the multipart body.
2149  *
2150  * \param pool PJLIB allocation pool
2151  * \param sub Subscription to a resource
2152  */
2153 static pjsip_generic_string_hdr *generate_content_id_hdr(pj_pool_t *pool,
2154  const struct ast_sip_subscription *sub)
2155 {
2156  static const pj_str_t cid_name = { "Content-ID", 10 };
2157  pjsip_generic_string_hdr *cid;
2158  char id[6];
2159  size_t alloc_size;
2160  pj_str_t cid_value;
2161 
2162  /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
2163  alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
2164  cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2165  cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
2166  ast_generate_random_string(id, sizeof(id)),
2167  (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
2168  cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2169 
2170  return cid;
2171 }
2172 
2173 static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
2174 {
2175  int num_printed;
2176  pj_xml_node *rlmi = msg_body->data;
2177 
2178  num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
2179  if (num_printed <= AST_PJSIP_XML_PROLOG_LEN) {
2180  return -1;
2181  }
2182 
2183  return num_printed;
2184 }
2185 
2186 static void *rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
2187 {
2188  const pj_xml_node *rlmi = data;
2189 
2190  return pj_xml_clone(pool, rlmi);
2191 }
2192 
2193 /*!
2194  * \brief Create an RLMI body part for a multipart resource list body
2195  *
2196  * RLMI (Resource list meta information) is a special body type that lists
2197  * the subscribed resources and tells subscribers the number of subscribed
2198  * resources and what other body parts are in the multipart body. The
2199  * RLMI body also has a version number that a subscriber can use to ensure
2200  * that the locally-stored state corresponds to server state.
2201  *
2202  * \param pool The allocation pool
2203  * \param sub The subscription representing the subscribed resource list
2204  * \param body_parts A container of body parts that RLMI will refer to
2205  * \param full_state Indicates whether this is a full or partial state notification
2206  * \return The multipart part representing the RLMI body
2207  */
2208 static pjsip_multipart_part *build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
2209  struct body_part_list *body_parts, unsigned int full_state)
2210 {
2211  pj_xml_node *rlmi;
2212  pj_xml_node *name;
2213  pjsip_multipart_part *rlmi_part;
2214  char version_str[32];
2215  char uri[PJSIP_MAX_URL_SIZE];
2216  pjsip_generic_string_hdr *cid;
2217  int i;
2218 
2219  rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
2220  ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
2221 
2222  ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
2223  ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
2224 
2225  snprintf(version_str, sizeof(version_str), "%u", sub->version++);
2226  ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
2227  ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
2228 
2229  name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
2230  pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
2231 
2232  for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
2233  const struct body_part *part = AST_VECTOR_GET(body_parts, i);
2234 
2235  add_rlmi_resource(pool, rlmi, part->cid, S_OR(part->display_name, part->resource), part->uri, part->state);
2236  }
2237 
2238  rlmi_part = pjsip_multipart_create_part(pool);
2239 
2240  rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2241  pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &rlmi_media_type);
2242 
2243  rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2244  rlmi_part->body->clone_data = rlmi_clone_data;
2245  rlmi_part->body->print_body = rlmi_print_body;
2246 
2247  cid = generate_content_id_hdr(pool, sub);
2248  pj_list_insert_before(&rlmi_part->hdr, cid);
2249 
2250  return rlmi_part;
2251 }
2252 
2253 static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
2254  unsigned int force_full_state);
2255 
2256 /*!
2257  * \brief Destroy a list of body parts
2258  *
2259  * \param parts The container of parts to destroy
2260  */
2261 static void free_body_parts(struct body_part_list *parts)
2262 {
2263  int i;
2264 
2265  for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
2266  struct body_part *part = AST_VECTOR_GET(parts, i);
2267  ast_free(part);
2268  }
2269 
2270  AST_VECTOR_FREE(parts);
2271 }
2272 
2273 /*!
2274  * \brief Allocate and initialize a body part structure
2275  *
2276  * \param pool PJLIB allocation pool
2277  * \param sub Subscription representing a subscribed resource
2278  */
2279 static struct body_part *allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
2280 {
2281  struct body_part *bp;
2282 
2283  bp = ast_calloc(1, sizeof(*bp));
2284  if (!bp) {
2285  return NULL;
2286  }
2287 
2288  bp->cid = generate_content_id_hdr(pool, sub);
2289  bp->resource = sub->resource;
2290  bp->state = sub->subscription_state;
2291  bp->uri = sub->uri;
2292  bp->display_name = sub->display_name;
2293 
2294  return bp;
2295 }
2296 
2297 /*!
2298  * \brief Create a multipart body part for a subscribed resource
2299  *
2300  * \param pool PJLIB allocation pool
2301  * \param sub The subscription representing a subscribed resource
2302  * \param parts A vector of parts to append the created part to.
2303  * \param use_full_state Unused locally, but may be passed to other functions
2304  */
2305 static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub,
2306  struct body_part_list *parts, unsigned int use_full_state)
2307 {
2308  struct body_part *bp;
2309  pjsip_msg_body *body;
2310 
2311  bp = allocate_body_part(pool, sub);
2312  if (!bp) {
2313  return;
2314  }
2315 
2316  body = generate_notify_body(pool, sub, use_full_state);
2317  if (!body) {
2318  /* Partial state was requested and the resource has not changed state */
2319  ast_free(bp);
2320  return;
2321  }
2322 
2323  bp->part = pjsip_multipart_create_part(pool);
2324  bp->part->body = body;
2325  pj_list_insert_before(&bp->part->hdr, bp->cid);
2326 
2327  if (AST_VECTOR_APPEND(parts, bp)) {
2328  ast_free(bp);
2329  }
2330 }
2331 
2332 /*!
2333  * \brief Create and initialize the PJSIP multipart body structure for a resource list subscription
2334  *
2335  * \param pool
2336  * \return The multipart message body
2337  */
2338 static pjsip_msg_body *create_multipart_body(pj_pool_t *pool)
2339 {
2340  pjsip_media_type media_type;
2341  pjsip_param *media_type_param;
2342  char boundary[6];
2343  pj_str_t pj_boundary;
2344 
2345  pjsip_media_type_init2(&media_type, "multipart", "related");
2346 
2347  media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
2348  pj_list_init(media_type_param);
2349 
2350  pj_strdup2(pool, &media_type_param->name, "type");
2351  pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
2352 
2353  pj_list_insert_before(&media_type.param, media_type_param);
2354 
2355  pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
2356  return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2357 }
2358 
2359 /*!
2360  * \brief Create a resource list body for NOTIFY requests
2361  *
2362  * Resource list bodies are multipart/related bodies. The first part of the multipart body
2363  * is an RLMI body that describes the rest of the parts to come. The other parts of the body
2364  * convey state of individual subscribed resources.
2365  *
2366  * \param pool PJLIB allocation pool
2367  * \param sub Subscription details from which to generate body
2368  * \param force_full_state If true, ignore resource list settings and send a full state notification
2369  * \return The generated multipart/related body
2370  */
2371 static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
2372  unsigned int force_full_state)
2373 {
2374  int i;
2375  pjsip_multipart_part *rlmi_part;
2376  pjsip_msg_body *multipart;
2377  struct body_part_list body_parts;
2378  unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
2379 
2380  if (AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children))) {
2381  return NULL;
2382  }
2383 
2384  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2385  build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
2386  }
2387 
2388  /* This can happen if issuing partial state and no children of the list have changed state */
2389  if (AST_VECTOR_SIZE(&body_parts) == 0) {
2390  free_body_parts(&body_parts);
2391  return NULL;
2392  }
2393 
2394  multipart = create_multipart_body(pool);
2395 
2396  rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
2397  if (!rlmi_part) {
2398  free_body_parts(&body_parts);
2399  return NULL;
2400  }
2401  pjsip_multipart_add_part(pool, multipart, rlmi_part);
2402 
2403  for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
2404  pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
2405  }
2406 
2407  free_body_parts(&body_parts);
2408  return multipart;
2409 }
2410 
2411 /*!
2412  * \brief Create the body for a NOTIFY request.
2413  *
2414  * \param pool The pool used for allocations
2415  * \param root The root of the subscription tree
2416  * \param force_full_state If true, ignore resource list settings and send a full state notification
2417  */
2418 static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
2419  unsigned int force_full_state)
2420 {
2421  pjsip_msg_body *body;
2422 
2423  if (AST_VECTOR_SIZE(&root->children) == 0) {
2424  if (force_full_state || root->body_changed) {
2425  /* Not a list. We've already generated the body and saved it on the subscription.
2426  * Use that directly.
2427  */
2428  pj_str_t type;
2429  pj_str_t subtype;
2430  pj_str_t text;
2431 
2432  pj_cstr(&type, ast_sip_subscription_get_body_type(root));
2433  pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
2434  pj_cstr(&text, ast_str_buffer(root->body_text));
2435 
2436  body = pjsip_msg_body_create(pool, &type, &subtype, &text);
2437  root->body_changed = 0;
2438  } else {
2439  body = NULL;
2440  }
2441  } else {
2442  body = generate_list_body(pool, root, force_full_state);
2443  }
2444 
2445  return body;
2446 }
2447 
2448 /*!
2449  * \brief Shortcut method to create a Require: eventlist header
2450  */
2451 static pjsip_require_hdr *create_require_eventlist(pj_pool_t *pool)
2452 {
2453  pjsip_require_hdr *require;
2454 
2455  require = pjsip_require_hdr_create(pool);
2456  pj_strdup2(pool, &require->values[0], "eventlist");
2457  require->count = 1;
2458 
2459  return require;
2460 }
2461 
2462 static void set_state_terminated(struct ast_sip_subscription *sub)
2463 {
2464  int i;
2465 
2466  sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2467  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2468  set_state_terminated(AST_VECTOR_GET(&sub->children, i));
2469  }
2470 }
2471 
2472 /*!
2473  * \brief Send a NOTIFY request to a subscriber
2474  *
2475  * \pre sub_tree->dlg is locked
2476  *
2477  * \param sub_tree The subscription tree representing the subscription
2478  * \param force_full_state If true, ignore resource list settings and send full resource list state.
2479  * \retval 0 Success
2480  * \retval non-zero Failure
2481  */
2482 static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
2483 {
2484  pjsip_evsub *evsub = sub_tree->evsub;
2485  pjsip_tx_data *tdata;
2486 
2487  if (ast_shutdown_final()
2488  && sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED
2489  && sub_tree->persistence) {
2490  return 0;
2491  }
2492 
2493  if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
2494  NULL, NULL, &tdata) != PJ_SUCCESS) {
2495  return -1;
2496  }
2497 
2498  tdata->msg->body = generate_notify_body(tdata->pool, sub_tree->root, force_full_state);
2499  if (!tdata->msg->body) {
2500  pjsip_tx_data_dec_ref(tdata);
2501  return -1;
2502  }
2503 
2504  if (sub_tree->is_list) {
2505  pjsip_require_hdr *require = create_require_eventlist(tdata->pool);
2506  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2507  }
2508 
2509  if (sub_tree->root->handler->notifier->notify_created) {
2510  /* The module for this event wants a callback to the pjsip_tx_data,
2511  * e.g. so it can add custom headers or do something custom to the response. */
2512  sub_tree->root->handler->notifier->notify_created(sub_tree->root, tdata);
2513  }
2514 
2515  if (sip_subscription_send_request(sub_tree, tdata)) {
2516  /* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */
2517  return -1;
2518  }
2519 
2520  sub_tree->send_scheduled_notify = 0;
2521 
2522  return 0;
2523 }
2524 
2525 static int serialized_send_notify(void *userdata)
2526 {
2527  struct sip_subscription_tree *sub_tree = userdata;
2528  pjsip_dialog *dlg = sub_tree->dlg;
2529 
2530  pjsip_dlg_inc_lock(dlg);
2531 
2532  sub_tree->notify_sched_id = -1;
2533 
2534  /* It's possible that between when the notification was scheduled
2535  * and now a new SUBSCRIBE arrived requiring full state to be
2536  * sent out in an immediate NOTIFY. It's also possible that we're
2537  * already processing a terminate. If that has happened, we need to
2538  * bail out here instead of sending the batched NOTIFY.
2539  */
2540 
2541  if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS
2542  || !sub_tree->send_scheduled_notify) {
2543  pjsip_dlg_dec_lock(dlg);
2544  ao2_cleanup(sub_tree);
2545  return 0;
2546  }
2547 
2548  if (sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) {
2549  sub_tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS;
2550  }
2551 
2552  send_notify(sub_tree, 0);
2553 
2555  sub_tree->state == SIP_SUB_TREE_TERMINATED
2556  ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2557  "Resource: %s", sub_tree->root->resource);
2558 
2559  pjsip_dlg_dec_lock(dlg);
2560  ao2_cleanup(sub_tree);
2561  return 0;
2562 }
2563 
2564 static int sched_cb(const void *data)
2565 {
2566  struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
2567 
2568  /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
2569  if (ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree)) {
2570  ao2_cleanup(sub_tree);
2571  }
2572 
2573  return 0;
2574 }
2575 
2576 static int schedule_notification(struct sip_subscription_tree *sub_tree)
2577 {
2578  /* There's already a notification scheduled */
2579  if (sub_tree->notify_sched_id > -1) {
2580  return 0;
2581  }
2582 
2583  sub_tree->send_scheduled_notify = 1;
2584  sub_tree->notify_sched_id = ast_sched_add(sched, sub_tree->notification_batch_interval, sched_cb, ao2_bump(sub_tree));
2585  if (sub_tree->notify_sched_id < 0) {
2586  ao2_cleanup(sub_tree);
2587  return -1;
2588  }
2589 
2590  return 0;
2591 }
2592 
2593 int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data,
2594  int terminate)
2595 {
2596  int res;
2597  pjsip_dialog *dlg = sub->tree->dlg;
2598 
2599  pjsip_dlg_inc_lock(dlg);
2600 
2601  if (sub->tree->state != SIP_SUB_TREE_NORMAL) {
2602  pjsip_dlg_dec_lock(dlg);
2603  return 0;
2604  }
2605 
2606  if (ast_sip_pubsub_generate_body_content(ast_sip_subscription_get_body_type(sub),
2607  ast_sip_subscription_get_body_subtype(sub), notify_data, &sub->body_text)) {
2608  pjsip_dlg_dec_lock(dlg);
2609  return -1;
2610  }
2611 
2612  sub->body_changed = 1;
2613  if (terminate) {
2614  sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2615  sub->tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
2616  }
2617 
2618  if (sub->tree->notification_batch_interval) {
2619  res = schedule_notification(sub->tree);
2620  } else {
2621  /* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */
2622  ao2_ref(sub->tree, +1);
2623  if (terminate) {
2624  sub->tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS;
2625  }
2626  res = send_notify(sub->tree, 0);
2627  ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2628  "Resource: %s",
2629  sub->tree->root->resource);
2630  ao2_ref(sub->tree, -1);
2631  }
2632 
2633  pjsip_dlg_dec_lock(dlg);
2634  return res;
2635 }
2636 
2637 pjsip_sip_uri *ast_sip_subscription_get_sip_uri(struct ast_sip_subscription *sub)
2638 {
2639  return sub->uri;
2640 }
2641 
2642 void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
2643 {
2644  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2645 }
2646 
2647 void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
2648 {
2649  pjsip_dialog *dlg;
2650  pjsip_sip_uri *uri;
2651 
2652  dlg = sub->tree->dlg;
2653  uri = pjsip_uri_get_uri(dlg->remote.info->uri);
2654 
2655  if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
2656  *buf = '\0';
2657  }
2658 }
2659 
2660 const char *ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
2661 {
2662  return sub->resource;
2663 }
2664 
2665 int ast_sip_subscription_is_terminated(const struct ast_sip_subscription *sub)
2666 {
2667  return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2668 }
2669 
2670 static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
2671 {
2672  pjsip_hdr res_hdr;
2673 
2674  /* If this is a persistence recreation the subscription has already been accepted */
2675  if (ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_PERSISTENCE)) {
2676  return 0;
2677  }
2678 
2679  pj_list_init(&res_hdr);
2680  if (sub_tree->is_list) {
2681  /* If subscribing to a list, our response has to have a Require: eventlist header in it */
2682  pj_list_insert_before(&res_hdr, create_require_eventlist(rdata->tp_info.pool));
2683  }
2684 
2685  return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2686 }
2687 
2688 struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
2689 {
2690  return ast_datastores_alloc_datastore(info, uid);
2691 }
2692 
2693 int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
2694 {
2695  return ast_datastores_add(subscription->datastores, datastore);
2696 }
2697 
2698 struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name)
2699 {
2700  return ast_datastores_find(subscription->datastores, name);
2701 }
2702 
2703 void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
2704 {
2705  ast_datastores_remove(subscription->datastores, name);
2706 }
2707 
2708 struct ao2_container *ast_sip_subscription_get_datastores(const struct ast_sip_subscription *subscription)
2709 {
2710  return subscription->datastores;
2711 }
2712 
2713 int ast_sip_publication_add_datastore(struct ast_sip_publication *publication, struct ast_datastore *datastore)
2714 {
2715  return ast_datastores_add(publication->datastores, datastore);
2716 }
2717 
2718 struct ast_datastore *ast_sip_publication_get_datastore(struct ast_sip_publication *publication, const char *name)
2719 {
2720  return ast_datastores_find(publication->datastores, name);
2721 }
2722 
2723 void ast_sip_publication_remove_datastore(struct ast_sip_publication *publication, const char *name)
2724 {
2725  ast_datastores_remove(publication->datastores, name);
2726 }
2727 
2728 struct ao2_container *ast_sip_publication_get_datastores(const struct ast_sip_publication *publication)
2729 {
2730  return publication->datastores;
2731 }
2732 
2733 void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, struct ast_json *persistence_data)
2734 {
2735  ast_json_unref(subscription->persistence_data);
2736  subscription->persistence_data = persistence_data;
2737 
2738  if (subscription->tree->persistence) {
2739  if (!subscription->tree->persistence->generator_data) {
2741  if (!subscription->tree->persistence->generator_data) {
2742  return;
2743  }
2744  }
2745  ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
2746  ast_json_ref(persistence_data));
2747  }
2748 }
2749 
2750 const struct ast_json *ast_sip_subscription_get_persistence_data(const struct ast_sip_subscription *subscription)
2751 {
2752  return subscription->persistence_data;
2753 }
2754 
2756 
2757 static int publication_hash_fn(const void *obj, const int flags)
2758 {
2759  const struct ast_sip_publication *publication = obj;
2760  const int *entity_tag = obj;
2761 
2762  return flags & OBJ_KEY ? *entity_tag : publication->entity_tag;
2763 }
2764 
2765 static int publication_cmp_fn(void *obj, void *arg, int flags)
2766 {
2767  const struct ast_sip_publication *publication1 = obj;
2768  const struct ast_sip_publication *publication2 = arg;
2769  const int *entity_tag = arg;
2770 
2771  return (publication1->entity_tag == (flags & OBJ_KEY ? *entity_tag : publication2->entity_tag) ?
2772  CMP_MATCH | CMP_STOP : 0);
2773 }
2774 
2775 static void publish_add_handler(struct ast_sip_publish_handler *handler)
2776 {
2778  AST_RWLIST_INSERT_TAIL(&publish_handlers, handler, next);
2780 }
2781 
2782 int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler)
2783 {
2784  if (ast_strlen_zero(handler->event_name)) {
2785  ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
2786  return -1;
2787  }
2788 
2790  PUBLICATIONS_BUCKETS, publication_hash_fn, NULL, publication_cmp_fn);
2791  if (!handler->publications) {
2792  ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
2793  handler->event_name);
2794  return -1;
2795  }
2796 
2797  publish_add_handler(handler);
2798 
2799  return 0;
2800 }
2801 
2802 void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler)
2803 {
2804  struct ast_sip_publish_handler *iter;
2805 
2807  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&publish_handlers, iter, next) {
2808  if (handler == iter) {
2809  AST_RWLIST_REMOVE_CURRENT(next);
2810  ao2_cleanup(handler->publications);
2811  break;
2812  }
2813  }
2814  AST_RWLIST_TRAVERSE_SAFE_END;
2816 }
2817 
2819 
2820 static void sub_add_handler(struct ast_sip_subscription_handler *handler)
2821 {
2823  AST_RWLIST_INSERT_TAIL(&subscription_handlers, handler, next);
2825 }
2826 
2827 static struct ast_sip_subscription_handler *find_sub_handler_for_event_name(const char *event_name)
2828 {
2829  struct ast_sip_subscription_handler *iter;
2830 
2832  AST_RWLIST_TRAVERSE(&subscription_handlers, iter, next) {
2833  if (!strcmp(iter->event_name, event_name)) {
2834  break;
2835  }
2836  }
2838  return iter;
2839 }
2840 
2841 int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
2842 {
2843  pj_str_t event;
2844  pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
2845  struct ast_sip_subscription_handler *existing;
2846  int i = 0;
2847 
2848  if (ast_strlen_zero(handler->event_name)) {
2849  ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
2850  return -1;
2851  }
2852 
2853  existing = find_sub_handler_for_event_name(handler->event_name);
2854  if (existing) {
2855  ast_log(LOG_ERROR,
2856  "Unable to register subscription handler for event %s. A handler is already registered\n",
2857  handler->event_name);
2858  return -1;
2859  }
2860 
2861  for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
2862  pj_cstr(&accept[i], handler->accept[i]);
2863  }
2864 
2865  pj_cstr(&event, handler->event_name);
2866 
2867  pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
2868 
2869  sub_add_handler(handler);
2870 
2871  return 0;
2872 }
2873 
2874 void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
2875 {
2876  struct ast_sip_subscription_handler *iter;
2877 
2879  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscription_handlers, iter, next) {
2880  if (handler == iter) {
2881  AST_RWLIST_REMOVE_CURRENT(next);
2882  break;
2883  }
2884  }
2885  AST_RWLIST_TRAVERSE_SAFE_END;
2887 }
2888 
2889 static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype_nolock(const char *type, const char *subtype)
2890 {
2891  struct ast_sip_pubsub_body_generator *gen;
2892 
2893  AST_LIST_TRAVERSE(&body_generators, gen, list) {
2894  if (!strcmp(gen->type, type)
2895  && !strcmp(gen->subtype, subtype)) {
2896  break;
2897  }
2898  }
2899 
2900  return gen;
2901 }
2902 
2903 static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype(const char *type, const char *subtype)
2904 {
2905  struct ast_sip_pubsub_body_generator *gen;
2906 
2908  gen = find_body_generator_type_subtype_nolock(type, subtype);
2910  return gen;
2911 }
2912 
2913 static struct ast_sip_pubsub_body_generator *find_body_generator_accept(const char *accept)
2914 {
2915  char *accept_copy = ast_strdupa(accept);
2916  char *subtype = accept_copy;
2917  char *type = strsep(&subtype, "/");
2918 
2919  if (ast_strlen_zero(type) || ast_strlen_zero(subtype)) {
2920  return NULL;
2921  }
2922 
2923  return find_body_generator_type_subtype(type, subtype);
2924 }
2925 
2926 static struct ast_sip_pubsub_body_generator *find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64],
2927  size_t num_accept, const char *body_type)
2928 {
2929  int i;
2930  struct ast_sip_pubsub_body_generator *generator = NULL;
2931 
2932  for (i = 0; i < num_accept; ++i) {
2933  generator = find_body_generator_accept(accept[i]);
2934  if (generator) {
2935  ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
2936  if (strcmp(generator->body_type, body_type)) {
2937  ast_log(LOG_WARNING, "Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
2938  generator->type, generator->subtype, generator);
2939  generator = NULL;
2940  continue;
2941  }
2942  break;
2943  } else {
2944  ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
2945  }
2946  }
2947 
2948  return generator;
2949 }
2950 
2951 static int generate_initial_notify(struct ast_sip_subscription *sub)
2952 {
2953  void *notify_data;
2954  int res;
2955  struct ast_sip_body_data data = {
2956  .body_type = sub->handler->body_type,
2957  };
2958 
2959  if (AST_VECTOR_SIZE(&sub->children) > 0) {
2960  int i;
2961 
2962  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2964  return -1;
2965  }
2966  }
2967 
2968  return 0;
2969  }
2970 
2971  /* We notify subscription establishment only on the tree leaves. */
2972  if (sub->handler->notifier->subscription_established(sub)) {
2973  return -1;
2974  }
2975 
2976  notify_data = sub->handler->notifier->get_notify_data(sub);
2977  if (!notify_data) {
2978  ast_debug(3, "No notify data, not generating any body content\n");
2979  return -1;
2980  }
2981 
2982  data.body_data = notify_data;
2983 
2984  res = ast_sip_pubsub_generate_body_content(ast_sip_subscription_get_body_type(sub),
2985  ast_sip_subscription_get_body_subtype(sub), &data, &sub->body_text);
2986 
2987  ao2_cleanup(notify_data);
2988 
2989  return res;
2990 }
2991 
2992 static int pubsub_on_refresh_timeout(void *userdata);
2993 
2994 static int initial_notify_task(void * obj)
2995 {
2996  struct initial_notify_data *ind = obj;
2997 
2998  if (generate_initial_notify(ind->sub_tree->root)) {
2999  pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE);
3000  } else {
3001  send_notify(ind->sub_tree, 1);
3002  ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
3003  "Resource: %s",
3004  ind->sub_tree->root->resource);
3005  }
3006 
3007  if (ind->expires != PJSIP_EXPIRES_NOT_SPECIFIED) {
3008  char *name = ast_alloca(strlen("->/ ") +
3009  strlen(ind->sub_tree->persistence->endpoint) +
3010  strlen(ind->sub_tree->root->resource) +
3011  strlen(ind->sub_tree->root->handler->event_name) +
3012  ind->sub_tree->dlg->call_id->id.slen + 1);
3013 
3014  sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint,
3015  ind->sub_tree->root->resource, ind->sub_tree->root->handler->event_name,
3016  (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr);
3017 
3018  ast_debug(3, "Scheduling timer: %s\n", name);
3019  ind->sub_tree->expiration_task = ast_sip_schedule_task(ind->sub_tree->serializer,
3020  ind->expires * 1000, pubsub_on_refresh_timeout, name,
3022  if (!ind->sub_tree->expiration_task) {
3023  ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n",
3024  ind->expires, name);
3025  }
3026  }
3027 
3028  ao2_ref(ind->sub_tree, -1);
3029  ast_free(ind);
3030 
3031  return 0;
3032 }
3033 
3034 static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
3035 {
3036  pjsip_expires_hdr *expires_header;
3037  struct ast_sip_subscription_handler *handler;
3038  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3039  struct sip_subscription_tree *sub_tree;
3040  struct ast_sip_pubsub_body_generator *generator;
3041  char *resource;
3042  pjsip_uri *request_uri;
3043  size_t resource_size;
3044  int resp;
3045  struct resource_tree tree;
3046  pj_status_t dlg_status;
3047  const pj_str_t *user;
3048 
3049  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3050  ast_assert(endpoint != NULL);
3051 
3052  if (!endpoint->subscription.allow) {
3053  ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
3054  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
3055  return PJ_TRUE;
3056  }
3057 
3058  request_uri = rdata->msg_info.msg->line.req.uri;
3059 
3060  if (!ast_sip_is_uri_sip_sips(request_uri)) {
3061  char uri_str[PJSIP_MAX_URL_SIZE];
3062 
3063  pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3064  ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3065  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3066  return PJ_TRUE;
3067  }
3068 
3069  user = ast_sip_pjsip_uri_get_username(request_uri);
3070  resource_size = pj_strlen(user) + 1;
3071  resource = ast_alloca(resource_size);
3072  ast_copy_pj_str(resource, user, resource_size);
3073 
3074  /*
3075  * We may want to match without any user options getting
3076  * in the way.
3077  */
3078  AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource);
3079 
3080  expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3081  if (expires_header) {
3082  if (expires_header->ivalue == 0) {
3083  ast_debug(1, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3084  ast_sorcery_object_get_id(endpoint));
3085  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3086  return PJ_TRUE;
3087  }
3088  if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3089  ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3090  expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subscription.minexpiry);
3091  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
3092  return PJ_TRUE;
3093  }
3094  }
3095 
3096  handler = subscription_get_handler_from_rdata(rdata, ast_sorcery_object_get_id(endpoint));
3097  if (!handler) {
3098  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3099  return PJ_TRUE;
3100  }
3101 
3102  generator = subscription_get_generator_from_rdata(rdata, handler);
3103  if (!generator) {
3104  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3105  return PJ_TRUE;
3106  }
3107 
3108  memset(&tree, 0, sizeof(tree));
3109  resp = build_resource_tree(endpoint, handler, resource, &tree,
3110  ast_sip_pubsub_has_eventlist_support(rdata), rdata);
3111  if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3112  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3113  resource_tree_destroy(&tree);
3114  return PJ_TRUE;
3115  }
3116 
3117  sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
3118  if (!sub_tree) {
3119  if (dlg_status != PJ_EEXISTS) {
3120  ast_debug(3, "No dialog exists, rejecting\n");
3121  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3122  }
3123  } else {
3124  struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
3125 
3126  if (!ind) {
3127  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3128  resource_tree_destroy(&tree);
3129  return PJ_TRUE;
3130  }
3131 
3132  ind->sub_tree = ao2_bump(sub_tree);
3133  /* Since this is a normal subscribe, pjproject takes care of the timer */
3134  ind->expires = PJSIP_EXPIRES_NOT_SPECIFIED;
3135 
3136  sub_tree->persistence = subscription_persistence_create(sub_tree);
3137  subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_CREATED);
3138  sip_subscription_accept(sub_tree, rdata, resp);
3139  if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {
3140  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3141  ao2_ref(sub_tree, -1);
3142  ast_free(ind);
3143  }
3144  }
3145 
3146  resource_tree_destroy(&tree);
3147  return PJ_TRUE;
3148 }
3149 
3150 static struct ast_sip_publish_handler *find_pub_handler(const char *event)
3151 {
3152  struct ast_sip_publish_handler *iter = NULL;
3153 
3155  AST_RWLIST_TRAVERSE(&publish_handlers, iter, next) {
3156  if (strcmp(event, iter->event_name)) {
3157  ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
3158  continue;
3159  }
3160  ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
3161  break;
3162  }
3164 
3165  return iter;
3166 }
3167 
3168 static enum sip_publish_type determine_sip_publish_type(pjsip_rx_data *rdata,
3169  pjsip_generic_string_hdr *etag_hdr, unsigned int *expires, int *entity_id)
3170 {
3171  pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3172 
3173  if (etag_hdr) {
3174  char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3175 
3176  ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
3177 
3178  if (sscanf(etag, "%30d", entity_id) != 1) {
3179  return SIP_PUBLISH_UNKNOWN;
3180  }
3181  }
3182 
3183  *expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3184 
3185  if (!(*expires)) {
3186  return SIP_PUBLISH_REMOVE;
3187  } else if (!etag_hdr && rdata->msg_info.msg->body) {
3188  return SIP_PUBLISH_INITIAL;
3189  } else if (etag_hdr && !rdata->msg_info.msg->body) {
3190  return SIP_PUBLISH_REFRESH;
3191  } else if (etag_hdr && rdata->msg_info.msg->body) {
3192  return SIP_PUBLISH_MODIFY;
3193  }
3194 
3195  return SIP_PUBLISH_UNKNOWN;
3196 }
3197 
3198 /*! \brief Internal destructor for publications */
3199 static void publication_destroy_fn(void *obj)
3200 {
3201  struct ast_sip_publication *publication = obj;
3202 
3203  ast_debug(3, "Destroying SIP publication\n");
3204 
3205  ao2_cleanup(publication->datastores);
3206  ao2_cleanup(publication->endpoint);
3207 
3209 }
3210 
3211 static struct ast_sip_publication *sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
3212  const char *resource, const char *event_configuration_name)
3213 {
3214  struct ast_sip_publication *publication;
3215  pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3216  size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
3217  char *dst;
3218 
3219  ast_assert(endpoint != NULL);
3220 
3221  if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
3222  return NULL;
3223  }
3224 
3226 
3227  if (!(publication->datastores = ast_datastores_alloc())) {
3228  ao2_ref(publication, -1);
3229  return NULL;
3230  }
3231 
3232  publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
3233  ao2_ref(endpoint, +1);
3234  publication->endpoint = endpoint;
3235  publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3236  publication->sched_id = -1;
3237  dst = publication->data;
3238  publication->resource = strcpy(dst, resource);
3239  dst += resource_len;
3240  publication->event_configuration_name = strcpy(dst, event_configuration_name);
3241 
3242  return publication;
3243 }
3244 
3245 static int sip_publication_respond(struct ast_sip_publication *pub, int status_code,
3246  pjsip_rx_data *rdata)
3247 {
3248  pjsip_tx_data *tdata;
3249  pjsip_transaction *tsx;
3250 
3251  if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, status_code, NULL, &tdata) != PJ_SUCCESS) {
3252  return -1;
3253  }
3254 
3255  if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3256  char buf[30];
3257 
3258  snprintf(buf, sizeof(buf), "%d", pub->entity_tag);
3259  ast_sip_add_header(tdata, "SIP-ETag", buf);
3260 
3261  snprintf(buf, sizeof(buf), "%d", pub->expires);
3262  ast_sip_add_header(tdata, "Expires", buf);
3263  }
3264 
3265  if (pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3266  pjsip_tx_data_dec_ref(tdata);
3267  return -1;
3268  }
3269 
3270  pjsip_tsx_recv_msg(tsx, rdata);
3271 
3272  if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3273  pjsip_tx_data_dec_ref(tdata);
3274  return -1;
3275  }
3276 
3277  return 0;
3278 }
3279 
3280 static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata,
3281  struct ast_sip_publish_handler *handler)
3282 {
3283  struct ast_sip_publication *publication;
3284  char *resource_name;
3285  size_t resource_size;
3286  RAII_VAR(struct ast_sip_publication_resource *, resource, NULL, ao2_cleanup);
3287  struct ast_variable *event_configuration_name = NULL;
3288  pjsip_uri *request_uri;
3289  int resp;
3290  const pj_str_t *user;
3291 
3292  request_uri = rdata->msg_info.msg->line.req.uri;
3293 
3294  if (!ast_sip_is_uri_sip_sips(request_uri)) {
3295  char uri_str[PJSIP_MAX_URL_SIZE];
3296 
3297  pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3298  ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3299  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3300  return NULL;
3301  }
3302 
3303  user = ast_sip_pjsip_uri_get_username(request_uri);
3304  resource_size = pj_strlen(user) + 1;
3305  resource_name = ast_alloca(resource_size);
3306  ast_copy_pj_str(resource_name, user, resource_size);
3307 
3308  /*
3309  * We may want to match without any user options getting
3310  * in the way.
3311  */
3312  AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource_name);
3313 
3314  resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
3315  if (!resource) {
3316  ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name);
3317  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3318  return NULL;
3319  }
3320 
3321  if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
3322  ast_debug(1, "Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3323  resource_name, resource->endpoint, ast_sorcery_object_get_id(endpoint));
3324  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
3325  return NULL;
3326  }
3327 
3328  for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
3329  if (!strcmp(event_configuration_name->name, handler->event_name)) {
3330  break;
3331  }
3332  }
3333 
3334  if (!event_configuration_name) {
3335  ast_debug(1, "Event '%s' is not configured for '%s'\n", handler->event_name, resource_name);
3336  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3337  return NULL;
3338  }
3339 
3340  resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
3341 
3342  if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3343  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3344  return NULL;
3345  }
3346 
3347  publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
3348 
3349  if (!publication) {
3350  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
3351  return NULL;
3352  }
3353 
3354  publication->handler = handler;
3355  if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
3356  AST_SIP_PUBLISH_STATE_INITIALIZED)) {
3357  ast_debug(3, "Publication state change failed\n");
3358  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3359  ao2_cleanup(publication);
3360  return NULL;
3361  }
3362 
3363  sip_publication_respond(publication, resp, rdata);
3364 
3365  return publication;
3366 }
3367 
3368 static int publish_expire_callback(void *data)
3369 {
3370  RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
3371 
3372  if (publication->handler->publish_expire) {
3373  publication->handler->publish_expire(publication);
3374  }
3375 
3376  return 0;
3377 }
3378 
3379 static int publish_expire(const void *data)
3380 {
3381  struct ast_sip_publication *publication = (struct ast_sip_publication*)data;
3382 
3383  ao2_unlink(publication->handler->publications, publication);
3384  publication->sched_id = -1;
3385 
3386  if (ast_sip_push_task(NULL, publish_expire_callback, publication)) {
3387  ao2_cleanup(publication);
3388  }
3389 
3390  return 0;
3391 }
3392 
3393 static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
3394 {
3395  pjsip_event_hdr *event_header;
3396  struct ast_sip_publish_handler *handler;
3397  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3398  char event[32];
3399  static const pj_str_t str_sip_if_match = { "SIP-If-Match", 12 };
3400  pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
3401  enum sip_publish_type publish_type;
3402  RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
3403  unsigned int expires = 0;
3404  int entity_id, response = 0;
3405 
3406  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3407  ast_assert(endpoint != NULL);
3408 
3409  event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
3410  if (!event_header) {
3411  ast_log(LOG_WARNING, "Incoming PUBLISH request from %s with no Event header\n",
3412  ast_sorcery_object_get_id(endpoint));
3413  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3414  return PJ_TRUE;
3415  }
3416  ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
3417 
3418  handler = find_pub_handler(event);
3419  if (!handler) {
3420  ast_log(LOG_WARNING, "No registered publish handler for event %s from %s\n", event,
3421  ast_sorcery_object_get_id(endpoint));
3422  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3423  return PJ_TRUE;
3424  }
3425 
3426  publish_type = determine_sip_publish_type(rdata, etag_hdr, &expires, &entity_id);
3427 
3428  /* If this is not an initial publish ensure that a publication is present */
3429  if ((publish_type != SIP_PUBLISH_INITIAL) && (publish_type != SIP_PUBLISH_UNKNOWN)) {
3430  if (!(publication = ao2_find(handler->publications, &entity_id, OBJ_KEY | OBJ_UNLINK))) {
3431  static const pj_str_t str_conditional_request_failed = { "Conditional Request Failed", 26 };
3432 
3433  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 412, &str_conditional_request_failed,
3434  NULL, NULL);
3435  return PJ_TRUE;
3436  }
3437 
3438  /* Per the RFC every response has to have a new entity tag */
3439  publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
3440 
3441  /* Update the expires here so that the created responses will contain the correct value */
3442  publication->expires = expires;
3443  }
3444 
3445  switch (publish_type) {
3446  case SIP_PUBLISH_INITIAL:
3447  publication = publish_request_initial(endpoint, rdata, handler);
3448  break;
3449  case SIP_PUBLISH_REFRESH:
3450  case SIP_PUBLISH_MODIFY:
3451  if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
3452  AST_SIP_PUBLISH_STATE_ACTIVE)) {
3453  /* If an error occurs we want to terminate the publication */
3454  expires = 0;
3455  }
3456  response = 200;
3457  break;
3458  case SIP_PUBLISH_REMOVE:
3459  handler->publication_state_change(publication, rdata->msg_info.msg->body,
3460  AST_SIP_PUBLISH_STATE_TERMINATED);
3461  response = 200;
3462  break;
3463  case SIP_PUBLISH_UNKNOWN:
3464  default:
3465  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3466  break;
3467  }
3468 
3469  if (publication) {
3470  if (expires) {
3471  ao2_link(handler->publications, publication);
3472 
3473  AST_SCHED_REPLACE_UNREF(publication->sched_id, sched, expires * 1000, publish_expire, publication,
3474  ao2_ref(_data, -1), ao2_ref(publication, -1), ao2_ref(publication, +1));
3475  } else {
3476  AST_SCHED_DEL_UNREF(sched, publication->sched_id, ao2_ref(publication, -1));
3477  }
3478  }
3479 
3480  if (response) {
3481  sip_publication_respond(publication, response, rdata);
3482  }
3483 
3484  return PJ_TRUE;
3485 }
3486 
3487 struct ast_sip_endpoint *ast_sip_publication_get_endpoint(struct ast_sip_publication *pub)
3488 {
3489  return pub->endpoint;
3490 }
3491 
3492 const char *ast_sip_publication_get_resource(const struct ast_sip_publication *pub)
3493 {
3494  return pub->resource;
3495 }
3496 
3497 const char *ast_sip_publication_get_event_configuration(const struct ast_sip_publication *pub)
3498 {
3499  return pub->event_configuration_name;
3500 }
3501 
3502 int ast_sip_pubsub_is_body_generator_registered(const char *type, const char *subtype)
3503 {
3504  return !!find_body_generator_type_subtype(type, subtype);
3505 }
3506 
3507 int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator *generator)
3508 {
3509  struct ast_sip_pubsub_body_generator *existing;
3510  pj_str_t accept;
3511  pj_size_t accept_len;
3512 
3514  existing = find_body_generator_type_subtype_nolock(generator->type, generator->subtype);
3515  if (existing) {
3517  ast_log(LOG_WARNING, "A body generator for %s/%s is already registered.\n",
3518  generator->type, generator->subtype);
3519  return -1;
3520  }
3521  AST_LIST_INSERT_HEAD(&body_generators, generator, list);
3523 
3524  /* Lengths of type and subtype plus a slash. */
3525  accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
3526 
3527  /* Add room for null terminator that sprintf() will set. */
3528  pj_strset(&accept, ast_alloca(accept_len + 1), accept_len);
3529  sprintf((char *) pj_strbuf(&accept), "%s/%s", generator->type, generator->subtype);/* Safe */
3530 
3531  pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
3532  PJSIP_H_ACCEPT, NULL, 1, &accept);
3533 
3534  return 0;
3535 }
3536 
3537 void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator)
3538 {
3539  struct ast_sip_pubsub_body_generator *iter;
3540 
3542  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_generators, iter, list) {
3543  if (iter == generator) {
3545  break;
3546  }
3547  }
3548  AST_RWLIST_TRAVERSE_SAFE_END;
3550 }
3551 
3552 int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
3553 {
3555  AST_RWLIST_INSERT_TAIL(&body_supplements, supplement, list);
3557 
3558  return 0;
3559 }
3560 
3561 void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
3562 {
3563  struct ast_sip_pubsub_body_supplement *iter;
3564 
3566  AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_supplements, iter, list) {
3567  if (iter == supplement) {
3569  break;
3570  }
3571  }
3572  AST_RWLIST_TRAVERSE_SAFE_END;
3574 }
3575 
3576 const char *ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
3577 {
3578  return sub->body_generator->type;
3579 }
3580 
3581 const char *ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub)
3582 {
3583  return sub->body_generator->subtype;
3584 }
3585 
3586 int ast_sip_pubsub_generate_body_content(const char *type, const char *subtype,
3587  struct ast_sip_body_data *data, struct ast_str **str)
3588 {
3589  struct ast_sip_pubsub_body_supplement *supplement;
3590  struct ast_sip_pubsub_body_generator *generator;
3591  int res = 0;
3592  void *body;
3593 
3594  generator = find_body_generator_type_subtype(type, subtype);
3595  if (!generator) {
3596  ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
3597  type, subtype);
3598  return -1;
3599  }
3600 
3601  if (strcmp(data->body_type, generator->body_type)) {
3602  ast_log(LOG_WARNING, "%s/%s body generator does not accept the type of data provided\n",
3603  type, subtype);
3604  return -1;
3605  }
3606 
3607  body = generator->allocate_body(data->body_data);
3608  if (!body) {
3609  ast_log(LOG_WARNING, "%s/%s body generator could not to allocate a body\n",
3610  type, subtype);
3611  return -1;
3612  }
3613 
3614  if (generator->generate_body_content(body, data->body_data)) {
3615  res = -1;
3616  goto end;
3617  }
3618 
3620  AST_RWLIST_TRAVERSE(&body_supplements, supplement, list) {
3621  if (!strcmp(generator->type, supplement->type) &&
3622  !strcmp(generator->subtype, supplement->subtype)) {
3623  res = supplement->supplement_body(body, data->body_data);
3624  if (res) {
3625  break;
3626  }
3627  }
3628  }
3630 
3631  if (!res) {
3632  generator->to_string(body, str);
3633  }
3634 
3635 end:
3636  if (generator->destroy_body) {
3637  generator->destroy_body(body);
3638  }
3639 
3640  return res;
3641 }
3642 
3644  int messages_waiting;
3645  int voice_messages_new;
3646  int voice_messages_old;
3647  int voice_messages_urgent_new;
3648  int voice_messages_urgent_old;
3649  char message_account[PJSIP_MAX_URL_SIZE];
3650 };
3651 
3652 static int parse_simple_message_summary(char *body,
3653  struct simple_message_summary *summary)
3654 {
3655  char *line;
3656  char *buffer;
3657  int found_counts = 0;
3658 
3659  if (ast_strlen_zero(body) || !summary) {
3660  return -1;
3661  }
3662 
3663  buffer = ast_strdupa(body);
3664  memset(summary, 0, sizeof(*summary));
3665 
3666  while ((line = ast_read_line_from_buffer(&buffer))) {
3667  line = ast_str_to_lower(line);
3668 
3669  if (sscanf(line, "voice-message: %d/%d (%d/%d)",
3670  &summary->voice_messages_new, &summary->voice_messages_old,
3671  &summary->voice_messages_urgent_new, &summary->voice_messages_urgent_old)) {
3672  found_counts = 1;
3673  } else {
3674  sscanf(line, "message-account: %s", summary->message_account);
3675  }
3676  }
3677 
3678  return !found_counts;
3679 }
3680 
3681 static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata)
3682 {
3683  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3684  struct simple_message_summary summary;
3685  const char *endpoint_name;
3686  char *atsign;
3687  char *context;
3688  char *body;
3689  char *mailbox;
3690  int rc;
3691 
3692  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3693  if (!endpoint) {
3694  ast_debug(1, "Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3695  rc = 404;
3696  goto error;
3697  }
3698 
3699  endpoint_name = ast_sorcery_object_get_id(endpoint);
3700  ast_debug(1, "Incoming MWI: Found endpoint: %s\n", endpoint_name);
3701  if (ast_strlen_zero(endpoint->incoming_mwi_mailbox)) {
3702  ast_debug(1, "Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3703  ast_test_suite_event_notify("PUBSUB_NO_INCOMING_MWI_MAILBOX",
3704  "Endpoint: %s", endpoint_name);
3705  rc = 404;
3706  goto error;
3707  }
3708 
3709  mailbox = ast_strdupa(endpoint->incoming_mwi_mailbox);
3710  atsign = strchr(mailbox, '@');
3711  if (!atsign) {
3712  ast_debug(1, "Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3713  endpoint_name, endpoint->incoming_mwi_mailbox);
3714  rc = 404;
3715  goto error;
3716  }
3717 
3718  *atsign = '\0';
3719  context = atsign + 1;
3720 
3721  body = ast_alloca(rdata->msg_info.msg->body->len + 1);
3722  rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3723  rdata->msg_info.msg->body->len + 1);
3724 
3725  if (parse_simple_message_summary(body, &summary) != 0) {
3726  ast_debug(1, "Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3727  ast_sorcery_object_get_id(endpoint), body);
3728  rc = 404;
3729  goto error;
3730  }
3731 
3732  if (ast_publish_mwi_state(mailbox, context,
3733  summary.voice_messages_new, summary.voice_messages_old)) {
3734  ast_log(LOG_ERROR, "Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
3735  "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3736  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3737  summary.voice_messages_new, summary.voice_messages_old,
3738  summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3739  rc = 404;
3740  } else {
3741  ast_debug(1, "Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3742  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3743  summary.voice_messages_new, summary.voice_messages_old,
3744  summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3745  ast_test_suite_event_notify("PUBSUB_INCOMING_MWI_PUBLISH",
3746  "Endpoint: %s\r\n"
3747  "Mailbox: %s\r\n"
3748  "MessageAccount: %s\r\n"
3749  "VoiceMessagesNew: %d\r\n"
3750  "VoiceMessagesOld: %d\r\n"
3751  "VoiceMessagesUrgentNew: %d\r\n"
3752  "VoiceMessagesUrgentOld: %d",
3753  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3754  summary.voice_messages_new, summary.voice_messages_old,
3755  summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3756  rc = 200;
3757  }
3758 
3759 error:
3760  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, rc, NULL, NULL, NULL);
3761  return PJ_TRUE;
3762 }
3763 
3764 static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata)
3765 {
3766  if (rdata->msg_info.msg->body &&
3767  ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type,
3768  "application", "simple-message-summary")) {
3769  return pubsub_on_rx_mwi_notify_request(rdata);
3770  }
3771  return PJ_FALSE;
3772 }
3773 
3774 static pj_bool_t pubsub_on_rx_request(pjsip_rx_data *rdata)
3775 {
3776  if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3777  return pubsub_on_rx_subscribe_request(rdata);
3778  } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
3779  return pubsub_on_rx_publish_request(rdata);
3780  } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
3781  return pubsub_on_rx_notify_request(rdata);
3782  }
3783 
3784  return PJ_FALSE;
3785 }
3786 
3787 /*!
3788  * \brief Callback sequence for subscription terminate:
3789  *
3790  * * Please note that the descriptions below represent pjproject behavior on versions
3791  * >= 2.13.
3792  * * Client initiated:
3793  * pjproject receives SUBSCRIBE on the subscription's serializer thread
3794  * calls pubsub_evsub_set_state with state = TERMINATED
3795  * pubsub_on_evsub_state checks the event and finds it is due to a received
3796  * SUBSCRIBE with an expires of 0 and so does nothing.
3797  * calls pubsub_on_rx_refresh with dialog locked
3798  * pubsub_on_rx_refresh sets TERMINATE_PENDING
3799  * calls pubsub_on_refresh_timeout to push final NOTIFY to pjproject
3800  * checks state == TERMINATE_PENDING
3801  * sets TERMINATE_IN_PROGRESS
3802  * calls send_notify (2)
3803  * send_notify ultimately calls pjsip_evsub_send_request
3804  * pjsip_evsub_send_request calls evsub's set_state
3805  * set_state calls pubsub_evsub_set_state
3806  * pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS
3807  * removes the subscriptions
3808  * cleans up references to evsub
3809  * sets state = TERMINATED
3810  * pubsub_on_refresh_timeout unlocks dialog
3811  * returns to pjproject
3812  * pjproject unlocks dialog
3813  *
3814  * * Subscription timer expires:
3815  * pjproject timer expires
3816  * locks dialog
3817  * calls pubsub_on_server_timeout
3818  * pubsub_on_server_timeout checks state == NORMAL
3819  * sets TERMINATE_PENDING
3820  * pushes serialized_pubsub_on_refresh_timeout
3821  * returns to pjproject
3822  * pjproject unlocks dialog
3823  * serialized_pubsub_on_refresh_timeout starts (1)
3824  * locks dialog
3825  * checks state == TERMINATE_PENDING
3826  * sets TERMINATE_IN_PROGRESS
3827  * calls send_notify (2)
3828  * send_notify ultimately calls pjsip_evsub_send_request
3829  * pjsip_evsub_send_request calls evsub's set_state
3830  * set_state calls pubsub_evsub_set_state
3831  * pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS
3832  * checks that the event is not due to un-SUBSCRIBE
3833  * removes the subscriptions
3834  * cleans up references to evsub
3835  * sets state = TERMINATED
3836  * serialized_pubsub_on_refresh_timeout unlocks dialog
3837  *
3838  * * Transmission failure sending NOTIFY or error response from client
3839  * pjproject transaction timer expires or non OK response
3840  * pjproject locks dialog
3841  * calls pubsub_on_evsub_state with event TSX_STATE
3842  * pubsub_on_evsub_state checks event == TSX_STATE
3843  * removes the subscriptions
3844  * cleans up references to evsub
3845  * sets state = TERMINATED
3846  * pjproject unlocks dialog
3847  *
3848  * * ast_sip_subscription_notify is called
3849  * checks state == NORMAL
3850  * if not batched...
3851  * sets TERMINATE_IN_PROGRESS (if terminate is requested)
3852  * calls send_notify
3853  * See (2) Above
3854  * if batched...
3855  * sets TERMINATE_PENDING
3856  * schedules task
3857  * scheduler runs sched_task
3858  * sched_task pushes serialized_send_notify
3859  * serialized_send_notify starts
3860  * checks state <= TERMINATE_PENDING
3861  * if state == TERMINATE_PENDING set state = TERMINATE_IN_PROGRESS
3862  * call send_notify
3863  * See (2) Above
3864  *
3865  */
3866 
3867 
3868 /* The code in this function was previously in pubsub_on_evsub_state. */
3869 static void clean_sub_tree(pjsip_evsub *evsub)
3870 {
3871 
3872  struct sip_subscription_tree *sub_tree;
3873  sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3874 
3875  ast_debug(3, "Cleaning subscription %p\n", evsub);
3876 
3877  if (sub_tree->expiration_task) {
3878  char task_name[256];
3879 
3880  ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
3881  ast_debug(3, "Cancelling timer: %s\n", task_name);
3883  ao2_cleanup(sub_tree->expiration_task);
3884  sub_tree->expiration_task = NULL;
3885  }
3886 
3887  remove_subscription(sub_tree);
3888 
3889  pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
3890 
3891 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
3892  pjsip_evsub_dec_ref(sub_tree->evsub);
3893 #endif
3894 
3895  sub_tree->evsub = NULL;
3896 
3897  ast_sip_dialog_set_serializer(sub_tree->dlg, NULL);
3898  ast_sip_dialog_set_endpoint(sub_tree->dlg, NULL);
3899 
3900  subscription_persistence_remove(sub_tree);
3901  shutdown_subscriptions(sub_tree->root);
3902 
3903  sub_tree->state = SIP_SUB_TREE_TERMINATED;
3904  /* Remove evsub's reference to the sub_tree */
3905  ao2_ref(sub_tree, -1);
3906 }
3907 
3908 /* This functionality appeared in pjsip 2.13 */
3909 #if PJ_VERSION_NUM >= 0x020D0000
3910 # define HAVE_PJSIP_EVSUB_PENDING_NOTIFY 1
3911 #endif
3912 
3913 /*!
3914  * \brief PJSIP callback when underlying SIP subscription changes state
3915  *
3916  * Although this function is called for every state change, we only care
3917  * about the TERMINATED state, and only when we're actually processing the final
3918  * notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS) OR when a transmission failure
3919  * occurs (PJSIP_EVENT_TSX_STATE). In this case, we do all the subscription tree
3920  * cleanup tasks and decrement the evsub reference.
3921  */
3922 static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
3923 {
3924  struct sip_subscription_tree *sub_tree =
3925  pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3926 
3927  ast_debug(3, "evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub,
3928  pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree,
3929  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3930 
3931  if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
3932  return;
3933  }
3934 
3935  /* It's easier to write this as what we WANT to process, then negate it. */
3936  if (!(sub_tree->state == SIP_SUB_TREE_TERMINATE_IN_PROGRESS
3937  || (event->type == PJSIP_EVENT_TSX_STATE && sub_tree->state == SIP_SUB_TREE_NORMAL)
3938  )) {
3939  ast_debug(3, "Do nothing.\n");
3940  return;
3941  }
3942 
3943 #ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
3944  /* This check looks for re-subscribes with an expires of 0. If we receive one of those,
3945  we don't want to clean the evsub because we still need it to send the final NOTIFY.
3946  This was previously handled by pubsub_on_rx_refresh setting:
3947  'sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING' */
3948  if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&
3949  !pjsip_method_cmp(&event->body.tsx_state.tsx->method, &pjsip_subscribe_method) &&
3950  pjsip_evsub_get_expires(evsub) == 0) {
3951  ast_debug(3, "Subscription ending, do nothing.\n");
3952  return;
3953  }
3954 #endif
3955  /* If we made it this far, we want to clean the sub tree. For pjproject <2.13, the sub_tree
3956  state check makes sure the evsub is not cleaned at the wrong time */
3957  clean_sub_tree(evsub);
3958 }
3959 
3960 static int pubsub_on_refresh_timeout(void *userdata)
3961 {
3962  struct sip_subscription_tree *sub_tree = userdata;
3963  pjsip_dialog *dlg = sub_tree->dlg;
3964 
3965  ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
3966  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3967 
3968  pjsip_dlg_inc_lock(dlg);
3969  if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) {
3970  pjsip_dlg_dec_lock(dlg);
3971  return 0;
3972  }
3973 
3974  if (sub_tree->state == SIP_SUB_TREE_TERMINATE_PENDING) {
3975  sub_tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS;
3976  set_state_terminated(sub_tree->root);
3977  }
3978 
3979  if (sub_tree->generate_initial_notify) {
3980  sub_tree->generate_initial_notify = 0;
3981  if (generate_initial_notify(sub_tree->root)) {
3982  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3983  pjsip_dlg_dec_lock(dlg);
3984  return 0;
3985  }
3986  }
3987 
3988  send_notify(sub_tree, 1);
3989 
3990  ast_test_suite_event_notify(sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ?
3991  "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED",
3992  "Resource: %s", sub_tree->root->resource);
3993 
3994  pjsip_dlg_dec_lock(dlg);
3995 
3996  return 0;
3997 }
3998 
3999 static int serialized_pubsub_on_refresh_timeout(void *userdata)
4000 {
4001  struct sip_subscription_tree *sub_tree = userdata;
4002 
4003  ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
4004  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4005 
4006  pubsub_on_refresh_timeout(userdata);
4007  ao2_cleanup(sub_tree);
4008 
4009  return 0;
4010 }
4011 
4012 /*!
4013  * \brief Compare strings for equality checking for NULL.
4014  *
4015  * This function considers NULL values as empty strings.
4016  * This means NULL or empty strings are equal.
4017  *
4018  * \retval 0 The strings are equal
4019  * \retval 1 The strings are not equal
4020  */
4021 static int cmp_strings(char *s1, char *s2)
4022 {
4023  if (!ast_strlen_zero(s1) && !ast_strlen_zero(s2)) {
4024  return strcmp(s1, s2);
4025  }
4026 
4027  return ast_strlen_zero(s1) == ast_strlen_zero(s2) ? 0 : 1;
4028 }
4029 
4030 /*!
4031  * \brief compares the childrens of two ast_sip_subscription s1 and s2
4032  *
4033  * \retval 0 The s1 childrens match the s2 childrens
4034  * \retval 1 The s1 childrens do not match the s2 childrens
4035  */
4036 static int cmp_subscription_childrens(struct ast_sip_subscription *s1, struct ast_sip_subscription *s2)
4037 {
4038  int i;
4039 
4040  if (AST_VECTOR_SIZE(&s1->children) != AST_VECTOR_SIZE(&s2->children)) {
4041  return 1;
4042  }
4043 
4044  for (i = 0; i < AST_VECTOR_SIZE(&s1->children); ++i) {
4045  struct ast_sip_subscription *c1 = AST_VECTOR_GET(&s1->children, i);
4046  struct ast_sip_subscription *c2 = AST_VECTOR_GET(&s2->children, i);
4047 
4048  if (cmp_strings(c1->resource, c2->resource)
4049  || cmp_strings(c1->display_name, c2->display_name)) {
4050 
4051  return 1;
4052  }
4053  }
4054 
4055  return 0;
4056 }
4057 
4058 static int destroy_subscriptions_task(void *obj)
4059 {
4060  struct ast_sip_subscription *sub = (struct ast_sip_subscription *) obj;
4061 
4062  destroy_subscriptions(sub);
4063 
4064  return 0;
4065 }
4066 
4067 /*!
4068  * \brief Called whenever an in-dialog SUBSCRIBE is received
4069  *
4070  * This includes both SUBSCRIBE requests that actually refresh the subscription
4071  * as well as SUBSCRIBE requests that end the subscription.
4072  *
4073  * In either case we push an appropriate NOTIFY via pubsub_on_refresh_timeout.
4074  */
4075 static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata,
4076  int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4077 {
4078  struct sip_subscription_tree *sub_tree;
4079  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
4080 
4081  sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4082  ast_debug(3, "evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree,
4083  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4084 
4085  if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4086  return;
4087  }
4088 
4089  if (sub_tree->expiration_task) {
4090  char task_name[256];
4091 
4092  ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
4093  ast_debug(3, "Cancelling timer: %s\n", task_name);
4095  ao2_cleanup(sub_tree->expiration_task);
4096  sub_tree->expiration_task = NULL;
4097  }
4098 
4099  /* PJSIP will set the evsub's state to terminated before calling into this function
4100  * if the Expires value of the incoming SUBSCRIBE is 0.
4101  */
4102 
4103  if (pjsip_evsub_get_state(sub_tree->evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
4104  sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
4105  }
4106 
4107  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
4108 
4109  /* If the handler wants a callback on refresh, then do it (some protocols require this). */
4110  if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->root->handler->notifier->refresh_subscribe) {
4111  if (!sub_tree->root->handler->notifier->refresh_subscribe(sub_tree->root, rdata)) {
4112  return; /* If the callback handled it, we're done. */
4113  }
4114  }
4115 
4116  if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->is_list) {
4117  /* update RLS */
4118  const char *resource = sub_tree->root->resource;
4119  struct ast_sip_subscription *old_root = sub_tree->root;
4120  struct ast_sip_subscription *new_root = NULL;
4121 
4122  struct ast_sip_pubsub_body_generator *generator = NULL;
4123 
4124  if (endpoint && (generator = subscription_get_generator_from_rdata(rdata, sub_tree->root->handler))) {
4125 
4126  struct resource_tree tree;
4127  int resp;
4128 
4129  memset(&tree, 0, sizeof(tree));
4130  resp = build_resource_tree(endpoint, sub_tree->root->handler, resource, &tree,
4131  ast_sip_pubsub_has_eventlist_support(rdata), rdata);
4132  if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
4133  new_root = create_virtual_subscriptions(sub_tree->root->handler, resource, generator, sub_tree, tree.root);
4134  if (new_root) {
4135  if (cmp_subscription_childrens(old_root, new_root)) {
4136  ast_debug(1, "RLS '%s->%s' was modified, regenerate it\n", ast_sorcery_object_get_id(endpoint), old_root->resource);
4137  new_root->version = old_root->version;
4138  sub_tree->root = new_root;
4139  sub_tree->generate_initial_notify = 1;
4140 
4141  /* If there is scheduled notification need to delete it to avoid use old subscriptions */
4142  if (sub_tree->notify_sched_id > -1) {
4143  AST_SCHED_DEL_UNREF(sched, sub_tree->notify_sched_id, ao2_ref(sub_tree, -1));
4144  sub_tree->send_scheduled_notify = 0;
4145  }
4146 
4147  /* Terminate old subscriptions to stop sending NOTIFY messages on exten/device state changes */
4148  set_state_terminated(old_root);
4149 
4150  /* Shutdown old subscriptions to remove exten/device state change callbacks
4151  that can queue tasks for old subscriptions */
4152  shutdown_subscriptions(old_root);
4153 
4154  /* Postpone destruction until all already queued tasks that may be using old subscriptions have completed */
4155  if (ast_sip_push_task(sub_tree->serializer, destroy_subscriptions_task, old_root)) {
4156  ast_log(LOG_ERROR, "Failed to push task to destroy old subscriptions for RLS '%s->%s'.\n",
4157  ast_sorcery_object_get_id(endpoint), old_root->resource);
4158  }
4159  } else {
4160  destroy_subscriptions(new_root);
4161  }
4162  }
4163  } else {
4164  sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
4165  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4166  }
4167 
4168  resource_tree_destroy(&tree);
4169  }
4170  }
4171 
4172  subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_REFRESHED);
4173 
4174 #ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
4175  /* As of pjsip 2.13, the NOTIFY has to be sent within this function as pjproject now
4176  requires it. Previously this would have caused an early NOTIFY to go out before the
4177  SUBSCRIBE's 200 OK. The previous solution was to push the NOTIFY, but now pjproject
4178  looks for the NOTIFY to be sent from this function and caches it to send after it
4179  auto-replies to the SUBSCRIBE. */
4180  pubsub_on_refresh_timeout(sub_tree);
4181 #else
4182  if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_refresh_timeout, ao2_bump(sub_tree))) {
4183  /* If we can't push the NOTIFY refreshing task...we'll just go with it. */
4184  ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n");
4185  sub_tree->state = SIP_SUB_TREE_NORMAL;
4186  ao2_ref(sub_tree, -1);
4187  }
4188 #endif
4189 
4190  if (sub_tree->is_list) {
4191  pj_list_insert_before(res_hdr, create_require_eventlist(rdata->tp_info.pool));
4192  }
4193 }
4194 
4195 static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code,
4196  pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
4197 {
4198  struct ast_sip_subscription *sub;
4199 
4200  if (!(sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4201  return;
4202  }
4203 
4204  sub->handler->subscriber->state_change(sub, rdata->msg_info.msg->body,
4205  pjsip_evsub_get_state(evsub));
4206 }
4207 
4208 static int serialized_pubsub_on_client_refresh(void *userdata)
4209 {
4210  struct sip_subscription_tree *sub_tree = userdata;
4211  pjsip_tx_data *tdata;
4212 
4213  if (!sub_tree->evsub) {
4214  ao2_cleanup(sub_tree);
4215  return 0;
4216  }
4217 
4218  if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
4219  pjsip_evsub_send_request(sub_tree->evsub, tdata);
4220  } else {
4221  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4222  }
4223 
4224  ao2_cleanup(sub_tree);
4225  return 0;
4226 }
4227 
4228 static void pubsub_on_client_refresh(pjsip_evsub *evsub)
4229 {
4230  struct sip_subscription_tree *sub_tree;
4231 
4232  if (!(sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4233  return;
4234  }
4235 
4236  if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_client_refresh, ao2_bump(sub_tree))) {
4237  ao2_cleanup(sub_tree);
4238  }
4239 }
4240 
4241 static void pubsub_on_server_timeout(pjsip_evsub *evsub)
4242 {
4243  struct sip_subscription_tree *sub_tree;
4244 
4245  /* PJSIP does not terminate the server timeout timer when a SUBSCRIBE
4246  * with Expires: 0 arrives to end a subscription, nor does it terminate
4247  * this timer when we send a NOTIFY request in response to receiving such
4248  * a SUBSCRIBE. PJSIP does not stop the server timeout timer until the
4249  * NOTIFY transaction has finished (either through receiving a response
4250  * or through a transaction timeout).
4251  *
4252  * Therefore, it is possible that we can be told that a server timeout
4253  * occurred after we already thought that the subscription had been
4254  * terminated. In such a case, we will have already removed the sub_tree
4255  * from the evsub's mod_data array.
4256  */
4257 
4258  sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4259  if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4260  return;
4261  }
4262 
4263  sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
4264  if (ast_sip_push_task(sub_tree->serializer, serialized_pubsub_on_refresh_timeout, ao2_bump(sub_tree))) {
4265  sub_tree->state = SIP_SUB_TREE_NORMAL;
4266  ao2_cleanup(sub_tree);
4267  }
4268 }
4269 
4270 static int ami_subscription_detail(struct sip_subscription_tree *sub_tree,
4271  struct ast_sip_ami *ami,
4272  const char *event)
4273 {
4274  struct ast_str *buf;
4275 
4276  buf = ast_sip_create_ami_event(event, ami);
4277  if (!buf) {
4278  return -1;
4279  }
4280 
4281  sip_subscription_to_ami(sub_tree, &buf);
4282  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4283  ast_free(buf);
4284 
4285  ++ami->count;
4286  return 0;
4287 }
4288 
4289 static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4290 {
4291  return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
4292  sub_tree, arg, "InboundSubscriptionDetail") : 0;
4293 }
4294 
4295 static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4296 {
4297  return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
4298  sub_tree, arg, "OutboundSubscriptionDetail") : 0;
4299 }
4300 
4301 static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
4302 {
4303  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4304 
4305  astman_send_listack(s, m, "Following are Events for each inbound Subscription",
4306  "start");
4307 
4308  for_each_subscription(ami_subscription_detail_inbound, &ami);
4309 
4310  astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count);
4312  return 0;
4313 }
4314 
4315 static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
4316 {
4317  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4318 
4319  astman_send_listack(s, m, "Following are Events for each outbound Subscription",
4320  "start");
4321 
4322  for_each_subscription(ami_subscription_detail_outbound, &ami);
4323 
4324  astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count);
4326  return 0;
4327 }
4328 
4329 static int format_ami_resource_lists(void *obj, void *arg, int flags)
4330 {
4331  struct resource_list *list = obj;
4332  struct ast_sip_ami *ami = arg;
4333  struct ast_str *buf;
4334 
4335  buf = ast_sip_create_ami_event("ResourceListDetail", ami);
4336  if (!buf) {
4337  return CMP_STOP;
4338  }
4339 
4340  if (ast_sip_sorcery_object_to_ami(list, &buf)) {
4341  ast_free(buf);
4342  return CMP_STOP;
4343  }
4344  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4345  ast_free(buf);
4346 
4347  ++ami->count;
4348  return 0;
4349 }
4350 
4351 static int ami_show_resource_lists(struct mansession *s, const struct message *m)
4352 {
4353  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4354  struct ao2_container *lists;
4355 
4356  lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
4358 
4359  if (!lists || !ao2_container_count(lists)) {
4360  astman_send_error(s, m, "No resource lists found\n");
4361  return 0;
4362  }
4363 
4364  astman_send_listack(s, m, "A listing of resource lists follows, presented as ResourceListDetail events",
4365  "start");
4366 
4367  ao2_callback(lists, OBJ_NODATA, format_ami_resource_lists, &ami);
4368 
4369  astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count);
4371  return 0;
4372 }
4373 
4374 #define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
4375 #define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
4376 
4377 #define MAX_REGEX_ERROR_LEN 128
4378 
4380  /*! CLI handler entry e parameter */
4381  struct ast_cli_entry *e;
4382  /*! CLI handler entry a parameter */
4383  struct ast_cli_args *a;
4384  /*! CLI subscription entry output line(s) */
4385  struct ast_str *buf;
4386  /*! Compiled regular expression to select if buf is written to CLI when not NULL. */
4387  regex_t *like;
4388  int count;
4389 };
4390 
4392  struct ast_cli_args *a;
4393  /*! Found callid for search position */
4394  char *callid;
4395  int wordlen;
4396  int which;
4397 };
4398 
4399 static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)
4400 {
4401  pj_str_t *callid;
4402 
4403  if (!sub_tree->dlg) {
4404  return 0;
4405  }
4406 
4407  callid = &sub_tree->dlg->call_id->id;
4408  if (cli->wordlen <= pj_strlen(callid)
4409  && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
4410  && (++cli->which > cli->a->n)) {
4411  cli->callid = ast_malloc(pj_strlen(callid) + 1);
4412  if (cli->callid) {
4413  ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
4414  }
4415  return -1;
4416  }
4417  return 0;
4418 }
4419 
4420 static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4421 {
4422  return sub_tree->role == AST_SIP_NOTIFIER
4423  ? cli_complete_subscription_common(sub_tree, arg) : 0;
4424 }
4425 
4426 static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4427 {
4428  return sub_tree->role == AST_SIP_SUBSCRIBER
4429  ? cli_complete_subscription_common(sub_tree, arg) : 0;
4430 }
4431 
4432 static char *cli_complete_subscription_callid(struct ast_cli_args *a)
4433 {
4434  struct cli_sub_complete_parms cli;
4435  on_subscription_t on_subscription;
4436 
4437  if (a->pos != 4) {
4438  return NULL;
4439  }
4440 
4441  if (!strcasecmp(a->argv[3], "inbound")) {
4442  on_subscription = cli_complete_subscription_inbound;
4443  } else if (!strcasecmp(a->argv[3], "outbound")) {
4444  on_subscription = cli_complete_subscription_outbound;
4445  } else {
4446  /* Should never get here */
4447  ast_assert(0);
4448  return NULL;
4449  }
4450 
4451  cli.a = a;
4452  cli.callid = NULL;
4453  cli.wordlen = strlen(a->word);
4454  cli.which = 0;
4455  for_each_subscription(on_subscription, &cli);
4456 
4457  return cli.callid;
4458 }
4459 
4460 static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
4461 {
4462  int expiry;
4463 
4464  expiry = sub_tree->persistence
4465  ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
4466  : 0;
4467  if (expiry < 0) {
4468  /* Subscription expired */
4469  expiry = 0;
4470  }
4471  return expiry;
4472 }
4473 
4474 static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
4475 {
4476  const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
4477  pj_str_t *sub_callid;
4478  struct ast_str *buf;
4479  char *src;
4480  char *dest;
4481  char *key;
4482  char *value;
4483  char *value_end;
4484  int key_len;
4485  int key_filler_width;
4486  int value_len;
4487 
4488  if (!sub_tree->dlg) {
4489  return 0;
4490  }
4491  sub_callid = &sub_tree->dlg->call_id->id;
4492  if (pj_strcmp2(sub_callid, callid)) {
4493  return 0;
4494  }
4495 
4496  buf = ast_str_create(512);
4497  if (!buf) {
4498  return -1;
4499  }
4500 
4501  ast_cli(cli->a->fd,
4502  "%-20s: %s\n"
4503  "===========================================================================\n",
4504  "ParameterName", "ParameterValue");
4505 
4506  ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
4507  ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
4508  ast_str_append(&buf, 0, "Expiry: %u\n", cli_subscription_expiry(sub_tree));
4509 
4510  sip_subscription_to_ami(sub_tree, &buf);
4511 
4512  /* Convert AMI \r\n to \n line terminators. */
4513  src = strchr(ast_str_buffer(buf), '\r');
4514  if (src) {
4515  dest = src;
4516  ++src;
4517  while (*src) {
4518  if (*src == '\r') {
4519  ++src;
4520  continue;
4521  }
4522  *dest++ = *src++;
4523  }
4524  *dest = '\0';
4525  ast_str_update(buf);
4526  }
4527 
4528  /* Reformat AMI key value pairs to pretty columns */
4529  key = ast_str_buffer(buf);
4530  do {
4531  value = strchr(key, ':');
4532  if (!value) {
4533  break;
4534  }
4535  value_end = strchr(value, '\n');
4536  if (!value_end) {
4537  break;
4538  }
4539 
4540  /* Calculate field lengths */
4541  key_len = value - key;
4542  key_filler_width = 20 - key_len;
4543  if (key_filler_width < 0) {
4544  key_filler_width = 0;
4545  }
4546  value_len = value_end - value;
4547 
4548  ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
4549  key_len, key, key_filler_width, "",
4550  value_len, value);
4551 
4552  key = value_end + 1;
4553  } while (*key);
4554  ast_cli(cli->a->fd, "\n");
4555 
4556  ast_free(buf);
4557 
4558  return -1;
4559 }
4560 
4561 static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4562 {
4563  return sub_tree->role == AST_SIP_NOTIFIER
4564  ? cli_show_subscription_common(sub_tree, arg) : 0;
4565 }
4566 
4567 static int cli_show_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4568 {
4569  return sub_tree->role == AST_SIP_SUBSCRIBER
4570  ? cli_show_subscription_common(sub_tree, arg) : 0;
4571 }
4572 
4573 static char *cli_show_subscription_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4574 {
4575  on_subscription_t on_subscription;
4576  struct cli_sub_parms cli;
4577 
4578  switch (cmd) {
4579  case CLI_INIT:
4580  e->command = "pjsip show subscription {inbound|outbound}";
4581  e->usage = "Usage:\n"
4582  " pjsip show subscription inbound <call-id>\n"
4583  " pjsip show subscription outbound <call-id>\n"
4584  " Show active subscription with the dialog call-id\n";
4585  return NULL;
4586  case CLI_GENERATE:
4587  return cli_complete_subscription_callid(a);
4588  }
4589 
4590  if (a->argc != 5) {
4591  return CLI_SHOWUSAGE;
4592  }
4593 
4594  if (!strcasecmp(a->argv[3], "inbound")) {
4595  on_subscription = cli_show_subscription_inbound;
4596  } else if (!strcasecmp(a->argv[3], "outbound")) {
4597  on_subscription = cli_show_subscription_outbound;
4598  } else {
4599  /* Should never get here */
4600  ast_assert(0);
4601  return NULL;
4602  }
4603 
4604  /* Find the subscription with the specified call-id */
4605  cli.a = a;
4606  cli.e = e;
4607  cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */
4608  for_each_subscription(on_subscription, &cli);
4609 
4610  return CLI_SUCCESS;
4611 }
4612 
4613 #define CLI_SHOW_SUB_FORMAT_HEADER \
4614  "Endpoint: <Endpoint/Caller-ID.............................................>\n" \
4615  "Resource: <Resource/Event.................................................>\n" \
4616  " Expiry: <Expiry> <Call-id..............................................>\n" \
4617  "===========================================================================\n\n"
4618 #define CLI_SHOW_SUB_FORMAT_ENTRY \
4619  "Endpoint: %s/%s\n" \
4620  "Resource: %s/%s\n" \
4621  " Expiry: %8d %s\n\n"
4622 
4623 static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
4624 {
4625  char caller_id[256];
4626  char callid[256];
4627 
4628  ast_callerid_merge(caller_id, sizeof(caller_id),
4629  S_COR(sub_tree->endpoint->id.self.name.valid,
4630  sub_tree->endpoint->id.self.name.str, NULL),
4631  S_COR(sub_tree->endpoint->id.self.number.valid,
4632  sub_tree->endpoint->id.self.number.str, NULL),
4633  "<none>");
4634 
4635  /* Call-id */
4636  if (sub_tree->dlg) {
4637  ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4638  } else {
4639  ast_copy_string(callid, "<unknown>", sizeof(callid));
4640  }
4641 
4642  ast_str_set(&cli->buf, 0, CLI_SHOW_SUB_FORMAT_ENTRY,
4643  ast_sorcery_object_get_id(sub_tree->endpoint), caller_id,
4644  sub_tree->root->resource, sub_tree->root->handler->event_name,
4645  cli_subscription_expiry(sub_tree), callid);
4646 
4647  if (cli->like) {
4648  if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4649  /* Output line did not match the regex */
4650  return 0;
4651  }
4652  }
4653 
4654  ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4655  ++cli->count;
4656 
4657  return 0;
4658 }
4659 
4660 static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4661 {
4662  return sub_tree->role == AST_SIP_NOTIFIER
4663  ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4664 }
4665 
4666 static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4667 {
4668  return sub_tree->role == AST_SIP_SUBSCRIBER
4669  ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4670 }
4671 
4672 static char *cli_show_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4673 {
4674  on_subscription_t on_subscription;
4675  struct cli_sub_parms cli;
4676  regex_t like;
4677  const char *regex;
4678 
4679  switch (cmd) {
4680  case CLI_INIT:
4681  e->command = "pjsip show subscriptions {inbound|outbound} [like]";
4682  e->usage = "Usage:\n"
4683  " pjsip show subscriptions inbound [like <regex>]\n"
4684  " Show active inbound subscriptions\n"
4685  " pjsip show subscriptions outbound [like <regex>]\n"
4686  " Show active outbound subscriptions\n"
4687  "\n"
4688  " The regex selects a subscriptions output that matches.\n"
4689  " i.e., All output lines for a subscription are checked\n"
4690  " as a block by the regex.\n";
4691  return NULL;
4692  case CLI_GENERATE:
4693  return NULL;
4694  }
4695 
4696  if (a->argc != 4 && a->argc != 6) {
4697  return CLI_SHOWUSAGE;
4698  }
4699  if (!strcasecmp(a->argv[3], "inbound")) {
4700  on_subscription = cli_show_subscriptions_inbound;
4701  } else if (!strcasecmp(a->argv[3], "outbound")) {
4702  on_subscription = cli_show_subscriptions_outbound;
4703  } else {
4704  /* Should never get here */
4705  ast_assert(0);
4706  return CLI_SHOWUSAGE;
4707  }
4708  if (a->argc == 6) {
4709  int rc;
4710 
4711  if (strcasecmp(a->argv[4], "like")) {
4712  return CLI_SHOWUSAGE;
4713  }
4714 
4715  /* Setup regular expression */
4716  memset(&like, 0, sizeof(like));
4717  cli.like = &like;
4718  regex = a->argv[5];
4719  rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4720  if (rc) {
4721  char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4722 
4723  regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4724  ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4725  regex, regerr);
4726  return CLI_FAILURE;
4727  }
4728  } else {
4729  cli.like = NULL;
4730  regex = NULL;
4731  }
4732 
4733  cli.a = a;
4734  cli.e = e;
4735  cli.count = 0;
4736  cli.buf = ast_str_create(256);
4737  if (!cli.buf) {
4738  if (cli.like) {
4739  regfree(cli.like);
4740  }
4741  return CLI_FAILURE;
4742  }
4743 
4744  ast_cli(a->fd, CLI_SHOW_SUB_FORMAT_HEADER);
4745  for_each_subscription(on_subscription, &cli);
4746  ast_cli(a->fd, "%d active subscriptions%s%s%s\n",
4747  cli.count,
4748  regex ? " matched \"" : "",
4749  regex ?: "",
4750  regex ? "\"" : "");
4751 
4752  ast_free(cli.buf);
4753  if (cli.like) {
4754  regfree(cli.like);
4755  }
4756 
4757  return CLI_SUCCESS;
4758 }
4759 
4760 #define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n"
4761 #define CLI_LIST_SUB_FORMAT_ENTRY "%-30.30s %-30.30s %6d %s\n"
4762 
4763 static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
4764 {
4765  char ep_cid_buf[50];
4766  char res_evt_buf[50];
4767  char callid[256];
4768 
4769  /* Endpoint/CID column */
4770  snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s",
4772  S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str,
4773  S_COR(sub_tree->endpoint->id.self.number.valid,
4774  sub_tree->endpoint->id.self.number.str, "<none>")));
4775 
4776  /* Resource/Event column */
4777  snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s",
4778  sub_tree->root->resource,
4779  sub_tree->root->handler->event_name);
4780 
4781  /* Call-id column */
4782  if (sub_tree->dlg) {
4783  ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4784  } else {
4785  ast_copy_string(callid, "<unknown>", sizeof(callid));
4786  }
4787 
4788  ast_str_set(&cli->buf, 0, CLI_LIST_SUB_FORMAT_ENTRY,
4789  ep_cid_buf,
4790  res_evt_buf,
4791  cli_subscription_expiry(sub_tree),
4792  callid);
4793 
4794  if (cli->like) {
4795  if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4796  /* Output line did not match the regex */
4797  return 0;
4798  }
4799  }
4800 
4801  ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4802  ++cli->count;
4803 
4804  return 0;
4805 }
4806 
4807 static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
4808 {
4809  return sub_tree->role == AST_SIP_NOTIFIER
4810  ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4811 }
4812 
4813 static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
4814 {
4815  return sub_tree->role == AST_SIP_SUBSCRIBER
4816  ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4817 }
4818 
4819 static char *cli_list_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4820 {
4821  on_subscription_t on_subscription;
4822  struct cli_sub_parms cli;
4823  regex_t like;
4824  const char *regex;
4825 
4826  switch (cmd) {
4827  case CLI_INIT:
4828  e->command = "pjsip list subscriptions {inbound|outbound} [like]";
4829  e->usage = "Usage:\n"
4830  " pjsip list subscriptions inbound [like <regex>]\n"
4831  " List active inbound subscriptions\n"
4832  " pjsip list subscriptions outbound [like <regex>]\n"
4833  " List active outbound subscriptions\n"
4834  "\n"
4835  " The regex selects output lines that match.\n";
4836  return NULL;
4837  case CLI_GENERATE:
4838  return NULL;
4839  }
4840 
4841  if (a->argc != 4 && a->argc != 6) {
4842  return CLI_SHOWUSAGE;
4843  }
4844  if (!strcasecmp(a->argv[3], "inbound")) {
4845  on_subscription = cli_list_subscriptions_inbound;
4846  } else if (!strcasecmp(a->argv[3], "outbound")) {
4847  on_subscription = cli_list_subscriptions_outbound;
4848  } else {
4849  /* Should never get here */
4850  ast_assert(0);
4851  return CLI_SHOWUSAGE;
4852  }
4853  if (a->argc == 6) {
4854  int rc;
4855 
4856  if (strcasecmp(a->argv[4], "like")) {
4857  return CLI_SHOWUSAGE;
4858  }
4859 
4860  /* Setup regular expression */
4861  memset(&like, 0, sizeof(like));
4862  cli.like = &like;
4863  regex = a->argv[5];
4864  rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4865  if (rc) {
4866  char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4867 
4868  regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4869  ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4870  regex, regerr);
4871  return CLI_FAILURE;
4872  }
4873  } else {
4874  cli.like = NULL;
4875  regex = NULL;
4876  }
4877 
4878  cli.a = a;
4879  cli.e = e;
4880  cli.count = 0;
4881  cli.buf = ast_str_create(256);
4882  if (!cli.buf) {
4883  if (cli.like) {
4884  regfree(cli.like);
4885  }
4886  return CLI_FAILURE;
4887  }
4888 
4889  ast_cli(a->fd, CLI_LIST_SUB_FORMAT_HEADER,
4890  "Endpoint/CLI", "Resource/Event", "Expiry", "Call-id");
4891  for_each_subscription(on_subscription, &cli);
4892  ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n",
4893  cli.count,
4894  regex ? " matched \"" : "",
4895  regex ?: "",
4896  regex ? "\"" : "");
4897 
4898  ast_free(cli.buf);
4899  if (cli.like) {
4900  regfree(cli.like);
4901  }
4902 
4903  return CLI_SUCCESS;
4904 }
4905 
4906 static struct ast_cli_entry cli_commands[] = {
4907  AST_CLI_DEFINE(cli_list_subscriptions_inout, "List active inbound/outbound subscriptions"),
4908  AST_CLI_DEFINE(cli_show_subscription_inout, "Show active subscription details"),
4909  AST_CLI_DEFINE(cli_show_subscriptions_inout, "Show active inbound/outbound subscriptions"),
4910 };
4911 
4912 static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
4913 {
4914  struct subscription_persistence *persistence = obj;
4915 
4916  persistence->endpoint = ast_strdup(var->value);
4917  return 0;
4918 }
4919 
4920 static int persistence_endpoint_struct2str(const void *obj, const intptr_t *args, char **buf)
4921 {
4922  const struct subscription_persistence *persistence = obj;
4923 
4924  *buf = ast_strdup(persistence->endpoint);
4925  return 0;
4926 }
4927 
4928 static int persistence_tag_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
4929 {
4930  struct subscription_persistence *persistence = obj;
4931 
4932  persistence->tag = ast_strdup(var->value);
4933  return 0;
4934 }
4935 
4936 static int persistence_tag_struct2str(const void *obj, const intptr_t *args, char **buf)
4937 {
4938  const struct subscription_persistence *persistence = obj;
4939 
4940  *buf = ast_strdup(persistence->tag);
4941  return 0;
4942 }
4943 
4944 static int persistence_generator_data_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
4945 {
4946  struct subscription_persistence *persistence = obj;
4947  struct ast_json_error error;
4948 
4949  /* We tolerate a failure of the JSON to load and instead start fresh, since this field
4950  * originates from the persistence code and not a user.
4951  */
4952  persistence->generator_data = ast_json_load_string(var->value, &error);
4953 
4954  return 0;
4955 }
4956 
4957 static int persistence_generator_data_struct2str(const void *obj, const intptr_t *args, char **buf)
4958 {
4959  const struct subscription_persistence *persistence = obj;
4960  char *value;
4961 
4962  if (!persistence->generator_data) {
4963  return 0;
4964  }
4965 
4966  value = ast_json_dump_string(persistence->generator_data);
4967  if (!value) {
4968  return -1;
4969  }
4970 
4971  *buf = ast_strdup(value);
4972  ast_json_free(value);
4973 
4974  return 0;
4975 }
4976 
4977 static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
4978 {
4979  struct subscription_persistence *persistence = obj;
4980  return ast_get_timeval(var->value, &persistence->expires, ast_tv(0, 0), NULL);
4981 }
4982 
4983 static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
4984 {
4985  const struct subscription_persistence *persistence = obj;
4986  char secs[AST_TIME_T_LEN];
4987 
4988  ast_time_t_to_string(persistence->expires.tv_sec, secs, sizeof(secs));
4989 
4990  return (ast_asprintf(buf, "%s", secs) < 0) ? -1 : 0;
4991 }
4992 
4993 #define RESOURCE_LIST_INIT_SIZE 4
4994 
4995 static void resource_list_destructor(void *obj)
4996 {
4997  struct resource_list *list = obj;
4998  int i;
4999 
5000  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5001  ast_free((char *) AST_VECTOR_GET(&list->items, i));
5002  }
5003 
5004  AST_VECTOR_FREE(&list->items);
5005 }
5006 
5007 static void *resource_list_alloc(const char *name)
5008 {
5009  struct resource_list *list;
5010 
5011  list = ast_sorcery_generic_alloc(sizeof(*list), resource_list_destructor);
5012  if (!list) {
5013  return NULL;
5014  }
5015 
5016  if (AST_VECTOR_INIT(&list->items, RESOURCE_LIST_INIT_SIZE)) {
5017  ao2_cleanup(list);
5018  return NULL;
5019  }
5020 
5021  return list;
5022 }
5023 
5024 static int item_in_vector(const struct resource_list *list, const char *item)
5025 {
5026  int i;
5027 
5028  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5029  if (!strcmp(item, AST_VECTOR_GET(&list->items, i))) {
5030  return 1;
5031  }
5032  }
5033 
5034  return 0;
5035 }
5036 
5037 static int list_item_handler(const struct aco_option *opt,
5038  struct ast_variable *var, void *obj)
5039 {
5040  struct resource_list *list = obj;
5041  char *items = ast_strdupa(var->value);
5042  char *item;
5043 
5044  while ((item = ast_strip(strsep(&items, ",")))) {
5045  if (ast_strlen_zero(item)) {
5046  continue;
5047  }
5048 
5049  if (item_in_vector(list, item)) {
5050  ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);
5051  continue;
5052  }
5053 
5054  item = ast_strdup(item);
5055  if (!item || AST_VECTOR_APPEND(&list->items, item)) {
5056  ast_free(item);
5057  return -1;
5058  }
5059  }
5060 
5061  return 0;
5062 }
5063 
5064 static int list_item_to_str(const void *obj, const intptr_t *args, char **buf)
5065 {
5066  const struct resource_list *list = obj;
5067  int i;
5068  struct ast_str *str = ast_str_create(32);
5069 
5070  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5071  ast_str_append(&str, 0, "%s,", AST_VECTOR_GET(&list->items, i));
5072  }
5073 
5074  /* Chop off trailing comma */
5075  ast_str_truncate(str, -1);
5076  *buf = ast_strdup(ast_str_buffer(str));
5077  ast_free(str);
5078  return 0;
5079 }
5080 
5081 static int resource_list_apply_handler(const struct ast_sorcery *sorcery, void *obj)
5082 {
5083  struct resource_list *list = obj;
5084 
5085  if (ast_strlen_zero(list->event)) {
5086  ast_log(LOG_WARNING, "Resource list '%s' has no event set\n",
5088  return -1;
5089  }
5090 
5091  if (AST_VECTOR_SIZE(&list->items) == 0) {
5092  ast_log(LOG_WARNING, "Resource list '%s' has no list items\n",
5094  return -1;
5095  }
5096 
5097  return 0;
5098 }
5099 
5100 static int apply_list_configuration(struct ast_sorcery *sorcery)
5101 {
5102  ast_sorcery_apply_default(sorcery, "resource_list", "config",
5103  "pjsip.conf,criteria=type=resource_list");
5104  if (ast_sorcery_object_register(sorcery, "resource_list", resource_list_alloc,
5105  NULL, resource_list_apply_handler)) {
5106  return -1;
5107  }
5108 
5109  ast_sorcery_object_field_register(sorcery, "resource_list", "type", "",
5110  OPT_NOOP_T, 0, 0);
5111  ast_sorcery_object_field_register(sorcery, "resource_list", "event", "",
5112  OPT_CHAR_ARRAY_T, 1, CHARFLDSET(struct resource_list, event));
5113  ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "no",
5114  OPT_BOOL_T, 1, FLDSET(struct resource_list, full_state));
5115  ast_sorcery_object_field_register(sorcery, "resource_list", "notification_batch_interval",
5116  "0", OPT_UINT_T, 0, FLDSET(struct resource_list, notification_batch_interval));
5117  ast_sorcery_object_field_register_custom(sorcery, "resource_list", "list_item",
5118  "", list_item_handler, list_item_to_str, NULL, 0, 0);
5119  ast_sorcery_object_field_register(sorcery, "resource_list", "resource_display_name", "no",
5121 
5122  ast_sorcery_reload_object(sorcery, "resource_list");
5123 
5124  return 0;
5125 }
5126 
5127 #ifdef TEST_FRAMEWORK
5128 
5129 /*!
5130  * \brief "bad" resources
5131  *
5132  * These are resources that the test handler will reject subscriptions to.
5133  */
5134 const char *bad_resources[] = {
5135  "coconut",
5136  "cilantro",
5137  "olive",
5138  "cheese",
5139 };
5140 
5141 /*!
5142  * \brief new_subscribe callback for unit tests
5143  *
5144  * Will give a 200 OK response to any resource except the "bad" ones.
5145  */
5146 static int test_new_subscribe(struct ast_sip_endpoint *endpoint, const char *resource)
5147 {
5148  int i;
5149 
5150  for (i = 0; i < ARRAY_LEN(bad_resources); ++i) {
5151  if (!strcmp(resource, bad_resources[i])) {
5152  return 400;
5153  }
5154  }
5155 
5156  return 200;
5157 }
5158 
5159 /*!
5160  * \brief Subscription notifier for unit tests.
5161  *
5162  * Since unit tests are only concerned with building a resource tree,
5163  * only the new_subscribe callback needs to be defined.
5164  */
5165 struct ast_sip_notifier test_notifier = {
5166  .new_subscribe = test_new_subscribe,
5167 };
5168 
5169 /*!
5170  * \brief Subscription handler for unit tests.
5171  */
5172 struct ast_sip_subscription_handler test_handler = {
5173  .event_name = "test",
5174  .body_type = "",
5175  .notifier = &test_notifier,
5176 };
5177 
5178 /*!
5179  * \brief Set properties on an allocated resource list
5180  *
5181  * \param list The list to set details on.
5182  * \param event The list's event.
5183  * \param resources Array of resources to add to the list.
5184  * \param num_resources Number of resources in the array.
5185  * \retval 0 Success
5186  * \retval non-zero Failure
5187  */
5188 static int populate_list(struct resource_list *list, const char *event, const char **resources, size_t num_resources)
5189 {
5190  int i;
5191 
5192  ast_copy_string(list->event, event, sizeof(list->event));
5193 
5194  for (i = 0; i < num_resources; ++i) {
5195  char *resource = ast_strdup(resources[i]);
5196 
5197  if (!resource || AST_VECTOR_APPEND(&list->items, resource)) {
5198  ast_free(resource);
5199  return -1;
5200  }
5201  }
5202  return 0;
5203 }
5204 
5205 /*!
5206  * \brief RAII callback to destroy a resource list
5207  */
5208 static void cleanup_resource_list(struct resource_list *list)
5209 {
5210  if (!list) {
5211  return;
5212  }
5213 
5214  ast_sorcery_delete(ast_sip_get_sorcery(), list);
5215  ao2_cleanup(list);
5216 }
5217 
5218 /*!
5219  * \brief allocate a resource list, store it in sorcery, and set its details
5220  *
5221  * \param test The unit test. Used for logging status messages.
5222  * \param list_name The name of the list to create.
5223  * \param event The event the list services
5224  * \param resources Array of resources to apply to the list
5225  * \param num_resources The number of resources in the array
5226  * \retval NULL Failed to allocate or populate list
5227  * \retval non-NULL The created list
5228  */
5229 static struct resource_list *create_resource_list(struct ast_test *test,
5230  const char *list_name, const char *event, const char **resources, size_t num_resources)
5231 {
5232  struct resource_list *list;
5233 
5234  list = ast_sorcery_alloc(ast_sip_get_sorcery(), "resource_list", list_name);
5235  if (!list) {
5236  ast_test_status_update(test, "Could not allocate resource list in sorcery\n");
5237  return NULL;
5238  }
5239 
5240  if (ast_sorcery_create(ast_sip_get_sorcery(), list)) {
5241  ast_test_status_update(test, "Could not store the resource list in sorcery\n");
5242  ao2_cleanup(list);
5243  return NULL;
5244  }
5245 
5246  if (populate_list(list, event, resources, num_resources)) {
5247  ast_test_status_update(test, "Could not add resources to the resource list\n");
5248  cleanup_resource_list(list);
5249  return NULL;
5250  }
5251 
5252  return list;
5253 }
5254 
5255 /*!
5256  * \brief Check the integrity of a tree node against a set of resources.
5257  *
5258  * The tree node's resources must be in the same order as the resources in
5259  * the supplied resources array. Because of this constraint, tests can misrepresent
5260  * the size of the resources array as being smaller than it really is if resources
5261  * at the end of the array should not be present in the tree node.
5262  *
5263  * \param test The unit test. Used for printing status messages.
5264  * \param node The constructed tree node whose integrity is under question.
5265  * \param resources Array of expected resource values
5266  * \param num_resources The number of resources to check in the array.
5267  */
5268 static int check_node(struct ast_test *test, struct tree_node *node,
5269  const char **resources, size_t num_resources)
5270 {
5271  int i;
5272 
5273  if (AST_VECTOR_SIZE(&node->children) != num_resources) {
5274  ast_test_status_update(test, "Unexpected number of resources in tree. Expected %zu, got %zu\n",
5275  num_resources, AST_VECTOR_SIZE(&node->children));
5276  return -1;
5277  }
5278 
5279  for (i = 0; i < num_resources; ++i) {
5280  if (strcmp(resources[i], AST_VECTOR_GET(&node->children, i)->resource)) {
5281  ast_test_status_update(test, "Mismatched resources. Expected '%s' but got '%s'\n",
5282  resources[i], AST_VECTOR_GET(&node->children, i)->resource);
5283  return -1;
5284  }
5285  }
5286 
5287  return 0;
5288 }
5289 
5290 /*!
5291  * \brief RAII_VAR callback to destroy an allocated resource tree
5292  */
5293 static void test_resource_tree_destroy(struct resource_tree *tree)
5294 {
5295  resource_tree_destroy(tree);
5296  ast_free(tree);
5297 }
5298 
5299 static int ineligible_configuration(void)
5300 {
5301  struct ast_config *config;
5302  struct ast_flags flags = {0,};
5303  const char *value;
5304 
5305  config = ast_config_load("sorcery.conf", flags);
5306  if (!config) {
5307  return 1;
5308  }
5309 
5310  value = ast_variable_retrieve(config, "res_pjsip_pubsub", "resource_list");
5311  if (ast_strlen_zero(value)) {
5312  ast_config_destroy(config);
5313  return 1;
5314  }
5315 
5316  if (strcasecmp(value, "memory") && strcasecmp(value, "astdb")) {
5317  ast_config_destroy(config);
5318  return 1;
5319  }
5320 
5321  return 0;
5322 }
5323 
5325 {
5326  RAII_VAR(struct resource_list *, list, NULL, cleanup_resource_list);
5327  RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
5328  const char *resources[] = {
5329  "huey",
5330  "dewey",
5331  "louie",
5332  };
5333  int resp;
5334 
5335  switch (cmd) {
5336  case TEST_INIT:
5337  info->name = "resource_tree";
5338  info->category = "/res/res_pjsip_pubsub/";
5339  info->summary = "Basic resource tree integrity check";
5340  info->description =
5341  "Create a resource list and ensure that our attempt to build a tree works as expected.";
5342  return AST_TEST_NOT_RUN;
5343  case TEST_EXECUTE:
5344  break;
5345  }
5346 
5347  if (ineligible_configuration()) {
5348  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5349  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5350  return AST_TEST_NOT_RUN;
5351  }
5352 
5353  list = create_resource_list(test, "foo", "test", resources, ARRAY_LEN(resources));
5354  if (!list) {
5355  return AST_TEST_FAIL;
5356  }
5357 
5358  tree = ast_calloc(1, sizeof(*tree));
5359  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
5360  if (resp != 200) {
5361  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5362  return AST_TEST_FAIL;
5363  }
5364 
5365  if (!tree->root) {
5366  ast_test_status_update(test, "Resource tree has no root\n");
5367  return AST_TEST_FAIL;
5368  }
5369 
5370  if (check_node(test, tree->root, resources, ARRAY_LEN(resources))) {
5371  return AST_TEST_FAIL;
5372  }
5373 
5374  return AST_TEST_PASS;
5375 }
5376 
5377 AST_TEST_DEFINE(complex_resource_tree)
5378 {
5379  RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
5380  RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
5381  RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
5382  const char *resources_1[] = {
5383  "huey",
5384  "dewey",
5385  "louie",
5386  "dwarves",
5387  };
5388  const char *resources_2[] = {
5389  "happy",
5390  "grumpy",
5391  "doc",
5392  "bashful",
5393  "dopey",
5394  "sneezy",
5395  "sleepy",
5396  };
5397  int resp;
5398  struct tree_node *node;
5399 
5400  switch (cmd) {
5401  case TEST_INIT:
5402  info->name = "complex_resource_tree";
5403  info->category = "/res/res_pjsip_pubsub/";
5404  info->summary = "Complex resource tree integrity check";
5405  info->description =
5406  "Create a complex resource list and ensure that our attempt to build a tree works as expected.";
5407  return AST_TEST_NOT_RUN;
5408  case TEST_EXECUTE:
5409  break;
5410  }
5411 
5412  if (ineligible_configuration()) {
5413  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5414  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5415  return AST_TEST_NOT_RUN;
5416  }
5417 
5418  list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
5419  if (!list_1) {
5420  return AST_TEST_FAIL;
5421  }
5422 
5423  list_2 = create_resource_list(test, "dwarves", "test", resources_2, ARRAY_LEN(resources_2));
5424  if (!list_2) {
5425  return AST_TEST_FAIL;
5426  }
5427 
5428  tree = ast_calloc(1, sizeof(*tree));
5429  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
5430  if (resp != 200) {
5431  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5432  return AST_TEST_FAIL;
5433  }
5434 
5435  if (!tree->root) {
5436  ast_test_status_update(test, "Resource tree has no root\n");
5437  return AST_TEST_FAIL;
5438  }
5439 
5440  node = tree->root;
5441  if (check_node(test, node, resources_1, ARRAY_LEN(resources_1))) {
5442  return AST_TEST_FAIL;
5443  }
5444 
5445  /* The embedded list is at index 3 in the root node's children */
5446  node = AST_VECTOR_GET(&node->children, 3);
5447  if (check_node(test, node, resources_2, ARRAY_LEN(resources_2))) {
5448  return AST_TEST_FAIL;
5449  }
5450 
5451  return AST_TEST_PASS;
5452 }
5453 
5454 AST_TEST_DEFINE(bad_resource)
5455 {
5456  RAII_VAR(struct resource_list *, list, NULL, cleanup_resource_list);
5457  RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
5458  const char *resources[] = {
5459  "huey",
5460  "dewey",
5461  "louie",
5462  "coconut", /* A "bad" resource */
5463  };
5464  int resp;
5465 
5466  switch (cmd) {
5467  case TEST_INIT:
5468  info->name = "bad_resource";
5469  info->category = "/res/res_pjsip_pubsub/";
5470  info->summary = "Ensure bad resources do not end up in the tree";
5471  info->description =
5472  "Create a resource list with a single bad resource. Ensure the bad resource does not end up in the tree.";
5473  return AST_TEST_NOT_RUN;
5474  case TEST_EXECUTE:
5475  break;
5476  }
5477 
5478  if (ineligible_configuration()) {
5479  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5480  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5481  return AST_TEST_NOT_RUN;
5482  }
5483 
5484  list = create_resource_list(test, "foo", "test", resources, ARRAY_LEN(resources));
5485  if (!list) {
5486  return AST_TEST_FAIL;
5487  }
5488 
5489  tree = ast_calloc(1, sizeof(*tree));
5490  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
5491  if (resp != 200) {
5492  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5493  return AST_TEST_FAIL;
5494  }
5495 
5496  if (!tree->root) {
5497  ast_test_status_update(test, "Resource tree has no root\n");
5498  return AST_TEST_FAIL;
5499  }
5500 
5501  /* We check against all but the final resource since we expect it not to be in the tree */
5502  if (check_node(test, tree->root, resources, ARRAY_LEN(resources) - 1)) {
5503  return AST_TEST_FAIL;
5504  }
5505 
5506  return AST_TEST_PASS;
5507 
5508 }
5509 
5510 AST_TEST_DEFINE(bad_branch)
5511 {
5512  RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
5513  RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
5514  RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
5515  const char *resources_1[] = {
5516  "huey",
5517  "dewey",
5518  "louie",
5519  "gross",
5520  };
5521  /* This list has nothing but bad resources */
5522  const char *resources_2[] = {
5523  "coconut",
5524  "cilantro",
5525  "olive",
5526  "cheese",
5527  };
5528  int resp;
5529 
5530  switch (cmd) {
5531  case TEST_INIT:
5532  info->name = "bad_branch";
5533  info->category = "/res/res_pjsip_pubsub/";
5534  info->summary = "Ensure bad branches are pruned from the tree";
5535  info->description =
5536  "Create a resource list that makes a tree with an entire branch of bad resources.\n"
5537  "Ensure the bad branch is pruned from the tree.";
5538  return AST_TEST_NOT_RUN;
5539  case TEST_EXECUTE:
5540  break;
5541  }
5542 
5543  if (ineligible_configuration()) {
5544  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5545  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5546  return AST_TEST_NOT_RUN;
5547  }
5548 
5549  list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
5550  if (!list_1) {
5551  return AST_TEST_FAIL;
5552  }
5553  list_2 = create_resource_list(test, "gross", "test", resources_2, ARRAY_LEN(resources_2));
5554  if (!list_2) {
5555  return AST_TEST_FAIL;
5556  }
5557 
5558  tree = ast_calloc(1, sizeof(*tree));
5559  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
5560  if (resp != 200) {
5561  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5562  return AST_TEST_FAIL;
5563  }
5564 
5565  if (!tree->root) {
5566  ast_test_status_update(test, "Resource tree has no root\n");
5567  return AST_TEST_FAIL;
5568  }
5569 
5570  /* We check against all but the final resource of the list since the entire branch should
5571  * be pruned from the tree
5572  */
5573  if (check_node(test, tree->root, resources_1, ARRAY_LEN(resources_1) - 1)) {
5574  return AST_TEST_FAIL;
5575  }
5576 
5577  return AST_TEST_PASS;
5578 
5579 }
5580 
5581 AST_TEST_DEFINE(duplicate_resource)
5582 {
5583  RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
5584  RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
5585  RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
5586  const char *resources_1[] = {
5587  "huey",
5588  "ducks",
5589  "dewey",
5590  "louie",
5591  };
5592  const char *resources_2[] = {
5593  "donald",
5594  "daisy",
5595  "scrooge",
5596  "dewey",
5597  "louie",
5598  "huey",
5599  };
5600  int resp;
5601  struct tree_node *node;
5602 
5603  switch (cmd) {
5604  case TEST_INIT:
5605  info->name = "duplicate_resource";
5606  info->category = "/res/res_pjsip_pubsub/";
5607  info->summary = "Ensure duplicated resources do not end up in the tree";
5608  info->description =
5609  "Create a resource list with a single duplicated resource. Ensure the duplicated resource does not end up in the tree.";
5610  return AST_TEST_NOT_RUN;
5611  case TEST_EXECUTE:
5612  break;
5613  }
5614 
5615  if (ineligible_configuration()) {
5616  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5617  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5618  return AST_TEST_NOT_RUN;
5619  }
5620 
5621  list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
5622  if (!list_1) {
5623  return AST_TEST_FAIL;
5624  }
5625 
5626  list_2 = create_resource_list(test, "ducks", "test", resources_2, ARRAY_LEN(resources_2));
5627  if (!list_2) {
5628  return AST_TEST_FAIL;
5629  }
5630 
5631  tree = ast_calloc(1, sizeof(*tree));
5632  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
5633  if (resp != 200) {
5634  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5635  return AST_TEST_FAIL;
5636  }
5637 
5638  if (!tree->root) {
5639  ast_test_status_update(test, "Resource tree has no root\n");
5640  return AST_TEST_FAIL;
5641  }
5642 
5643  node = tree->root;
5644  /* This node should have "huey" and "ducks". "dewey" and "louie" should not
5645  * be present since they were found in the "ducks" list.
5646  */
5647  if (check_node(test, node, resources_1, ARRAY_LEN(resources_1) - 2)) {
5648  return AST_TEST_FAIL;
5649  }
5650 
5651  /* This node should have "donald", "daisy", "scrooge", "dewey", and "louie".
5652  * "huey" is not here since that was already encountered in the parent list
5653  */
5654  node = AST_VECTOR_GET(&node->children, 1);
5655  if (check_node(test, node, resources_2, ARRAY_LEN(resources_2) - 1)) {
5656  return AST_TEST_FAIL;
5657  }
5658 
5659  return AST_TEST_PASS;
5660 }
5661 
5662 AST_TEST_DEFINE(loop)
5663 {
5664  RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
5665  RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
5666  RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
5667  const char *resources_1[] = {
5668  "derp",
5669  };
5670  const char *resources_2[] = {
5671  "herp",
5672  };
5673  int resp;
5674 
5675  switch (cmd) {
5676  case TEST_INIT:
5677  info->name = "loop";
5678  info->category = "/res/res_pjsip_pubsub/";
5679  info->summary = "Test that loops are properly detected.";
5680  info->description =
5681  "Create two resource lists that refer to each other. Ensure that attempting to build a tree\n"
5682  "results in an empty tree.";
5683  return AST_TEST_NOT_RUN;
5684  case TEST_EXECUTE:
5685  break;
5686  }
5687 
5688  if (ineligible_configuration()) {
5689  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5690  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5691  return AST_TEST_NOT_RUN;
5692  }
5693 
5694  list_1 = create_resource_list(test, "herp", "test", resources_1, ARRAY_LEN(resources_1));
5695  if (!list_1) {
5696  return AST_TEST_FAIL;
5697  }
5698  list_2 = create_resource_list(test, "derp", "test", resources_2, ARRAY_LEN(resources_2));
5699  if (!list_2) {
5700  return AST_TEST_FAIL;
5701  }
5702 
5703  tree = ast_calloc(1, sizeof(*tree));
5704  resp = build_resource_tree(NULL, &test_handler, "herp", tree, 1, NULL);
5705  if (resp == 200) {
5706  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5707  return AST_TEST_FAIL;
5708  }
5709 
5710  return AST_TEST_PASS;
5711 }
5712 
5713 AST_TEST_DEFINE(bad_event)
5714 {
5715  RAII_VAR(struct resource_list *, list, NULL, cleanup_resource_list);
5716  RAII_VAR(struct resource_tree *, tree, NULL, test_resource_tree_destroy);
5717  const char *resources[] = {
5718  "huey",
5719  "dewey",
5720  "louie",
5721  };
5722  int resp;
5723 
5724  switch (cmd) {
5725  case TEST_INIT:
5726  info->name = "bad_event";
5727  info->category = "/res/res_pjsip_pubsub/";
5728  info->summary = "Ensure that list with wrong event specified is not retrieved";
5729  info->description =
5730  "Create a simple resource list for event 'tsetse'. Ensure that trying to retrieve the list for event 'test' fails.";
5731  return AST_TEST_NOT_RUN;
5732  case TEST_EXECUTE:
5733  break;
5734  }
5735 
5736  if (ineligible_configuration()) {
5737  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5738  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5739  return AST_TEST_NOT_RUN;
5740  }
5741 
5742  list = create_resource_list(test, "foo", "tsetse", resources, ARRAY_LEN(resources));
5743  if (!list) {
5744  return AST_TEST_FAIL;
5745  }
5746 
5747  tree = ast_calloc(1, sizeof(*tree));
5748  /* Since the test_handler is for event "test", this should not build a list, but
5749  * instead result in a single resource being created, called "foo"
5750  */
5751  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1, NULL);
5752  if (resp != 200) {
5753  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5754  return AST_TEST_FAIL;
5755  }
5756 
5757  if (!tree->root) {
5758  ast_test_status_update(test, "Resource tree has no root\n");
5759  return AST_TEST_FAIL;
5760  }
5761 
5762  if (strcmp(tree->root->resource, "foo")) {
5763  ast_test_status_update(test, "Unexpected resource %s found in tree\n", tree->root->resource);
5764  return AST_TEST_FAIL;
5765  }
5766 
5767  return AST_TEST_PASS;
5768 }
5769 
5770 #endif
5771 
5772 static int resource_endpoint_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
5773 {
5774  struct ast_sip_publication_resource *resource = obj;
5775 
5776  ast_free(resource->endpoint);
5777  resource->endpoint = ast_strdup(var->value);
5778 
5779  return 0;
5780 }
5781 
5782 static int resource_event_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
5783 {
5784  struct ast_sip_publication_resource *resource = obj;
5785  /* The event configuration name starts with 'event_' so skip past it to get the real name */
5786  const char *event = var->name + 6;
5787  struct ast_variable *item;
5788 
5789  if (ast_strlen_zero(event) || ast_strlen_zero(var->value)) {
5790  return -1;
5791  }
5792 
5793  item = ast_variable_new(event, var->value, "");
5794  if (!item) {
5795  return -1;
5796  }
5797 
5798  if (resource->events) {
5799  item->next = resource->events;
5800  }
5801  resource->events = item;
5802 
5803  return 0;
5804 }
5805 
5806 static int load_module(void)
5807 {
5808  static const pj_str_t str_PUBLISH = { "PUBLISH", 7 };
5809  struct ast_sorcery *sorcery;
5810 
5811  sorcery = ast_sip_get_sorcery();
5812 
5813  if (!(sched = ast_sched_context_create())) {
5814  ast_log(LOG_ERROR, "Could not create scheduler for publication expiration\n");
5815  return AST_MODULE_LOAD_DECLINE;
5816  }
5817 
5818  if (ast_sched_start_thread(sched)) {
5819  ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n");
5821  return AST_MODULE_LOAD_DECLINE;
5822  }
5823 
5824  ast_sorcery_apply_config(sorcery, "res_pjsip_pubsub");
5825  ast_sorcery_apply_default(sorcery, "subscription_persistence", "astdb", "subscription_persistence");
5826  if (ast_sorcery_object_register(sorcery, "subscription_persistence", subscription_persistence_alloc,
5827  NULL, NULL)) {
5828  ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
5830  return AST_MODULE_LOAD_DECLINE;
5831  }
5832  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "packet", "", OPT_CHAR_ARRAY_T, 0,
5833  CHARFLDSET(struct subscription_persistence, packet));
5834  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_name", "", OPT_CHAR_ARRAY_T, 0,
5835  CHARFLDSET(struct subscription_persistence, src_name));
5836  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_port", "0", OPT_UINT_T, 0,
5837  FLDSET(struct subscription_persistence, src_port));
5838  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "transport_key", "0", OPT_CHAR_ARRAY_T, 0,
5839  CHARFLDSET(struct subscription_persistence, transport_type));
5840  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_name", "", OPT_CHAR_ARRAY_T, 0,
5841  CHARFLDSET(struct subscription_persistence, local_name));
5842  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_port", "0", OPT_UINT_T, 0,
5843  FLDSET(struct subscription_persistence, local_port));
5844  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "cseq", "0", OPT_UINT_T, 0,
5845  FLDSET(struct subscription_persistence, cseq));
5846  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "endpoint", "",
5847  persistence_endpoint_str2struct, persistence_endpoint_struct2str, NULL, 0, 0);
5848  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "tag", "",
5849  persistence_tag_str2struct, persistence_tag_struct2str, NULL, 0, 0);
5850  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
5851  persistence_expires_str2struct, persistence_expires_struct2str, NULL, 0, 0);
5852  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "contact_uri", "", OPT_CHAR_ARRAY_T, 0,
5853  CHARFLDSET(struct subscription_persistence, contact_uri));
5854  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "no", OPT_YESNO_T, 1,
5855  FLDSET(struct subscription_persistence, prune_on_boot));
5856  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "generator_data", "",
5857  persistence_generator_data_str2struct, persistence_generator_data_struct2str, NULL, 0, 0);
5858 
5859  if (apply_list_configuration(sorcery)) {
5861  return AST_MODULE_LOAD_DECLINE;
5862  }
5863 
5864  ast_sorcery_apply_default(sorcery, "inbound-publication", "config", "pjsip.conf,criteria=type=inbound-publication");
5865  if (ast_sorcery_object_register(sorcery, "inbound-publication", publication_resource_alloc,
5866  NULL, NULL)) {
5867  ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
5869  return AST_MODULE_LOAD_DECLINE;
5870  }
5871  ast_sorcery_object_field_register(sorcery, "inbound-publication", "type", "", OPT_NOOP_T, 0, 0);
5872  ast_sorcery_object_field_register_custom(sorcery, "inbound-publication", "endpoint", "",
5873  resource_endpoint_handler, NULL, NULL, 0, 0);
5874  ast_sorcery_object_fields_register(sorcery, "inbound-publication", "^event_", resource_event_handler, NULL);
5875  ast_sorcery_reload_object(sorcery, "inbound-publication");
5876 
5877  if (ast_sip_register_service(&pubsub_module)) {
5878  ast_log(LOG_ERROR, "Could not register pubsub service\n");
5880  return AST_MODULE_LOAD_DECLINE;
5881  }
5882 
5883  if (pjsip_evsub_init_module(ast_sip_get_pjsip_endpoint()) != PJ_SUCCESS) {
5884  ast_log(LOG_ERROR, "Could not initialize pjsip evsub module.\n");
5885  ast_sip_unregister_service(&pubsub_module);
5887  return AST_MODULE_LOAD_DECLINE;
5888  }
5889 
5890  /* Once pjsip_evsub_init_module succeeds we cannot unload.
5891  * Keep all module_load errors above this point. */
5893 
5894  pjsip_media_type_init2(&rlmi_media_type, "application", "rlmi+xml");
5895 
5896  pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &str_PUBLISH);
5897 
5898  if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
5899  ast_sip_push_task(NULL, subscription_persistence_load, NULL);
5900  } else {
5901  struct stasis_subscription *sub;
5902 
5903  sub = stasis_subscribe_pool(ast_manager_get_topic(), subscription_persistence_event_cb, NULL);
5906  }
5907 
5908  ast_manager_register_xml(AMI_SHOW_SUBSCRIPTIONS_INBOUND, EVENT_FLAG_SYSTEM,
5909  ami_show_subscriptions_inbound);
5910  ast_manager_register_xml(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND, EVENT_FLAG_SYSTEM,
5911  ami_show_subscriptions_outbound);
5912  ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
5913  ami_show_resource_lists);
5914 
5915  ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
5916 
5917  AST_TEST_REGISTER(resource_tree);
5918  AST_TEST_REGISTER(complex_resource_tree);
5919  AST_TEST_REGISTER(bad_resource);
5920  AST_TEST_REGISTER(bad_branch);
5921  AST_TEST_REGISTER(duplicate_resource);
5922  AST_TEST_REGISTER(loop);
5923  AST_TEST_REGISTER(bad_event);
5924 
5925  return AST_MODULE_LOAD_SUCCESS;
5926 }
5927 
5928 static int unload_module(void)
5929 {
5930  AST_TEST_UNREGISTER(resource_tree);
5931  AST_TEST_UNREGISTER(complex_resource_tree);
5932  AST_TEST_UNREGISTER(bad_resource);
5933  AST_TEST_UNREGISTER(bad_branch);
5934  AST_TEST_UNREGISTER(duplicate_resource);
5935  AST_TEST_UNREGISTER(loop);
5936  AST_TEST_UNREGISTER(bad_event);
5937 
5938  ast_sip_transport_monitor_unregister_all(sub_tree_transport_cb, NULL, NULL);
5939 
5940  ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
5941 
5942  ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND);
5943  ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_INBOUND);
5944  ast_manager_unregister("PJSIPShowResourceLists");
5945 
5946  ast_sip_unregister_service(&pubsub_module);
5947  if (sched) {
5949  }
5950 
5951  return 0;
5952 }
5953 
5954 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP event resource",
5955  .support_level = AST_MODULE_SUPPORT_CORE,
5956  .load = load_module,
5957  .unload = unload_module,
5958  .load_pri = AST_MODPRI_CHANNEL_DEPEND,
5959  .requires = "res_pjsip",
5960 );
void(* to_string)(void *body, struct ast_str **str)
Convert the body to a string.
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:197
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct ast_variable * next
unsigned int generate_initial_notify
const char * event_name
The name of the event this handler deals with.
void *(* get_notify_data)(struct ast_sip_subscription *sub)
Supply data needed to create a NOTIFY body.
Definition: test_heap.c:38
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
char data[0]
Data containing the above.
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
struct ast_sip_subscription * root
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
Asterisk main include file. File version handling, generic pbx functions.
int(* notify_created)(struct ast_sip_subscription *sub, pjsip_tx_data *tdata)
Optional callback to execute before sending outgoing NOTIFY requests. Because res_pjsip_pubsub create...
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_sip_subscriber * subscriber
struct ast_cli_entry * e
struct sip_subscription_tree * tree
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
Pubsub body generator.
A multipart body part and meta-information.
const char * type
Content type In "plain/text", "plain" is the type.
struct ast_sip_endpoint * endpoint
const char * body_type
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch. Returns -1 on failure, zero otherwise.
Definition: time.c:152
Data used to create bodies for NOTIFY/PUBLISH requests.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
#define OBJ_KEY
Definition: astobj2.h:1151
const struct message * m
Definition: res_pjsip.h:3035
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
Set a serializer on a SIP dialog so requests and responses are automatically serialized.
Type declaration for container of body part structures.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3467
descriptor for a cli entry.
Definition: cli.h:171
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1693
struct ast_sip_notifier * notifier
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
void * arg
Definition: res_pjsip.h:3039
AMI variable container.
Definition: res_pjsip.h:3031
char local_name[PJ_INET6_ADDRSTRLEN]
const char * accept[AST_SIP_MAX_ACCEPT]
static void destroy_subscriptions(void)
Destroy the active Stasis subscriptions.
Definition: cdr.c:4369
Party identification options for endpoints.
Definition: res_pjsip.h:763
Structure for variables, used for configurations and for channel variables.
static pj_pool_t * pool
Global memory pool for configuration and timers.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
struct ast_sip_subscription::@470 children
struct ast_str * body_text
Universally unique identifier support.
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:810
struct ast_sip_endpoint_subscription_configuration subscription
Definition: res_pjsip.h:982
Test Framework API.
Perform no matching, return all objects.
Definition: sorcery.h:123
int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore)
Add a data store to a container.
Definition: datastore.c:105
Definition: sched.c:76
int(* new_publication)(struct ast_sip_endpoint *endpoint, const char *resource, const char *event_configuration)
Called when a PUBLISH to establish a new publication arrives.
int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
Register a regex for multiple fields within an object.
Definition: sorcery.c:1160
#define CHARFLDSET(type, field)
A helper macro to pass the appropriate arguments to aco_option_register for OPT_CHAR_ARRAY_T.
Full structure for sorcery.
Definition: sorcery.c:230
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
Type for a default handler that should do nothing.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1077
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
Structure for a data store type.
Definition: datastore.h:31
char * str
Subscriber name (Malloced)
Definition: channel.h:264
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
Definition: sched.h:82
#define SORCERY_OBJECT(details)
Macro which must be used at the beginning of each sorcery capable object.
Definition: sorcery.h:356
const char * resource
Definition: astman.c:222
Structure used for persisting an inbound subscription.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
const char * type
Content type In "plain/text", "plain" is the type.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Return all matching objects.
Definition: sorcery.h:120
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
Definition: json.c:567
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
Structure for a data store object.
Definition: datastore.h:64
int(* get_resource_display_name)(struct ast_sip_endpoint *endpoint, const char *resource, char *display_name, int display_name_size)
Supply Display Name for resource.
void ast_sip_transport_monitor_unregister_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
void(* to_ami)(struct ast_sip_subscription *sub, struct ast_str **buf)
Converts the subscriber to AMI.
char packet[PJSIP_MAX_PKT_LEN]
struct subscription_persistence * persistence
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:61
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:2165
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
Parse a time (float) string.
Definition: utils.c:2419
A node for a resource tree.
JSON parsing error information.
Definition: json.h:887
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
enum ast_sip_subscription_role role
#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs)
Publish a MWI state update via stasis.
Definition: mwi.h:378
A vector of strings commonly used throughout this module.
Resource list configuration item.
const char * uid
Definition: datastore.h:65
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
struct ast_sip_pubsub_body_generator * body_generator
struct ast_datastore * ast_datastores_find(struct ao2_container *datastores, const char *name)
Find a data store in a container.
Definition: datastore.c:123
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
void(* publish_expire)(struct ast_sip_publication *pub)
Called when a publication has reached its expiration.
struct ao2_container * ast_datastores_alloc(void)
Allocate a specialized data stores container.
Definition: datastore.c:99
struct ao2_container * datastores
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:333
Asterisk datastore objects.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Type for default option handler for character array strings.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Type for default option handler for bools (ast_true/ast_false)
struct ast_sip_sched_task * ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, const char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)
Schedule a task to run in the res_pjsip thread pool.
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2062
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
Definition: sorcery.h:1005
#define ast_config_load(filename, flags)
Load a config file.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
struct ast_module * self
Definition: module.h:356
struct ao2_container * datastores
A resource tree.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3475
pjsip_sip_uri * uri
Type for default option handler for unsigned integers.
void *(* allocate_body)(void *data)
allocate body structure.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2179
const struct ast_sip_subscription_handler * handler
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define AST_MAX_EXTENSION
Definition: channel.h:134
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Scheduler Routines (derived from cheops)
struct ast_cli_args * a
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1785
const struct ast_datastore_info * info
Definition: datastore.h:67
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:282
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_datastore * ast_datastores_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Allocate a datastore for use with the datastores container.
Definition: datastore.c:142
int(* subscription_established)(struct ast_sip_subscription *sub)
Called when an inbound subscription has been accepted.
struct mansession * s
Definition: res_pjsip.h:3033
A set of macros to manage forward-linked lists.
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
An entity with which Asterisk communicates.
Definition: res_pjsip.h:949
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition: strings.h:1321
enum sip_subscription_tree_state state
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
Structure representing a "virtual" SIP subscription.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
pjsip_evsub_state subscription_state
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:986
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
int(* publication_state_change)(struct ast_sip_publication *pub, pjsip_msg_body *body, enum ast_sip_publish_state state)
Published resource has changed states.
int(* new_subscribe)(struct ast_sip_endpoint *endpoint, const char *resource)
Called when a SUBSCRIBE arrives attempting to establish a new subscription.
int ast_shutdown_final(void)
Definition: asterisk.c:1871
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2238
unsigned int expires
Expiration time of the publication.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
struct ast_sip_publish_handler * handler
Handler for this publication.
Support for dynamic strings.
Definition: strings.h:623
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
char * event_configuration_name
The name of the event type configuration.
Type for default option handler for bools (ast_true/ast_false)
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
Definition: strings.c:226
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:478
Contact associated with an address of record.
Definition: res_pjsip.h:392
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2094
void(* destroy_body)(void *body)
Deallocate resources created for the body.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:971
Callbacks that publication handlers will define.
char * resource
The resource the publication is to.
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:457
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
char transport_key[IP6ADDR_COLON_PORT_BUFLEN]
struct ast_sip_endpoint * endpoint
The endpoint with which the subscription is communicating.
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
struct ast_sip_sched_task * expiration_task
struct resources items
void(* state_change)(struct ast_sip_subscription *sub, pjsip_msg_body *body, enum pjsip_evsub_state state)
A NOTIFY has been received.
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
void ast_datastores_remove(struct ao2_container *datastores, const char *name)
Remove a data store from a container.
Definition: datastore.c:118
pjsip_generic_string_hdr * cid
char * endpoint
Optional name of an endpoint that is only allowed to publish to this resource.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
An API for managing task processing threads that can be shared across modules.
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:567
structure to hold users read from users.conf
struct ast_taskprocessor * serializer
Structure used to handle boolean flags.
Definition: utils.h:199
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1880
const char * usage
Definition: cli.h:177
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1897
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
int(* refresh_subscribe)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata)
Called when a SUBSCRIBE arrives for an already active subscription.
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:399
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
const ast_string_field incoming_mwi_mailbox
Definition: res_pjsip.h:974
Standard Command Line Interface.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
char contact_uri[PJSIP_MAX_URL_SIZE]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:703
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235
unsigned int resource_display_name
Asterisk MWI API.
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1023
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
Abstract JSON element (object, array, string, int, ...).
Structure representing a SIP publication.
int entity_tag
Entity tag for the publication.
pjsip_multipart_part * part
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
const char * display_name
Generic container type.
struct ast_str * buf
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
int(* supplement_body)(void *body, void *data)
Add additional content to a SIP request body.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
Gets the task name.
const ast_string_field aors
Definition: res_pjsip.h:958
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
const char * default_accept
Default body type defined for the event package this notifier handles.
const ast_string_field uri
Definition: res_pjsip.h:414
Structure representing a publication resource.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
Asterisk module definitions.
struct ast_variable * events
Mapping for event types to configuration.
struct ast_json * persistence_data
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
unsigned int send_scheduled_notify
struct ao2_container * publications
Publications.
char src_name[PJ_INET6_ADDRSTRLEN]
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
int(* generate_body_content)(void *body, void *data)
Add content to the body of a SIP request.
void(* subscription_shutdown)(struct ast_sip_subscription *subscription)
Called when a subscription is to be destroyed.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
unsigned int notification_batch_interval
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
Definition: sorcery.c:1442
unsigned int full_state
A tree of SIP subscriptions.
struct ast_json * generator_data
pjsip_evsub_state state
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2150
int sched_id
Scheduled item for expiration of publication.
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.
Definition: strings.c:371
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3431
unsigned int notification_batch_interval
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532