Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Data Structures | Macros | Typedefs | Enumerations | Functions | Variables
res_pjsip_pubsub.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_simple.h>
#include <pjlib.h>
#include "asterisk/mwi.h"
#include "asterisk/res_pjsip_pubsub.h"
#include "asterisk/module.h"
#include "asterisk/linkedlists.h"
#include "asterisk/astobj2.h"
#include "asterisk/datastore.h"
#include "asterisk/uuid.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/sched.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/callerid.h"
#include "asterisk/manager.h"
#include "asterisk/cli.h"
#include "asterisk/test.h"
#include "res_pjsip/include/res_pjsip_private.h"
#include "asterisk/res_pjsip_presence_xml.h"
Include dependency graph for res_pjsip_pubsub.c:

Go to the source code of this file.

Data Structures

struct  ast_sip_publication
 Structure representing a SIP publication. More...
 
struct  ast_sip_publication_resource
 Structure representing a publication resource. More...
 
struct  ast_sip_subscription
 Structure representing a "virtual" SIP subscription. More...
 
struct  body_generators
 
struct  body_part
 A multipart body part and meta-information. More...
 
struct  body_part_list
 Type declaration for container of body part structures. More...
 
struct  body_supplements
 
struct  cli_sub_complete_parms
 
struct  cli_sub_parms
 
struct  initial_notify_data
 
struct  persistence_recreate_data
 
struct  publish_handlers
 
struct  resource_list
 Resource list configuration item. More...
 
struct  resource_tree
 A resource tree. More...
 
struct  resources
 A vector of strings commonly used throughout this module. More...
 
struct  simple_message_summary
 
struct  sip_subscription_tree
 A tree of SIP subscriptions. More...
 
struct  subscription_handlers
 
struct  subscription_persistence
 Structure used for persisting an inbound subscription. More...
 
struct  subscriptions
 
struct  tree_node
 A node for a resource tree. More...
 

Macros

#define AMI_SHOW_SUBSCRIPTIONS_INBOUND   "PJSIPShowSubscriptionsInbound"
 
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND   "PJSIPShowSubscriptionsOutbound"
 
#define CLI_LIST_SUB_FORMAT_ENTRY   "%-30.30s %-30.30s %6d %s\n"
 
#define CLI_LIST_SUB_FORMAT_HEADER   "%-30.30s %-30.30s %6.6s %s\n"
 
#define CLI_SHOW_SUB_FORMAT_ENTRY
 
#define CLI_SHOW_SUB_FORMAT_HEADER
 
#define DATASTORE_BUCKETS   53
 Number of buckets for subscription datastore. More...
 
#define DEFAULT_EXPIRES   3600
 Default expiration for subscriptions. More...
 
#define DEFAULT_PUBLISH_EXPIRES   3600
 Default expiration time for PUBLISH if one is not specified. More...
 
#define MAX_REGEX_ERROR_LEN   128
 
#define MOD_DATA_MSG   "sub_msg"
 
#define MOD_DATA_PERSISTENCE   "sub_persistence"
 
#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)
 
#define PUBLICATIONS_BUCKETS   37
 Number of buckets for publications (on a per handler) More...
 
#define RESOURCE_LIST_INIT_SIZE   4
 

Typedefs

typedef int(* on_subscription_t) (struct sip_subscription_tree *sub, void *arg)
 

Enumerations

enum  sip_persistence_update_type { SUBSCRIPTION_PERSISTENCE_SEND_REQUEST = 0 , SUBSCRIPTION_PERSISTENCE_CREATED , SUBSCRIPTION_PERSISTENCE_RECREATED , SUBSCRIPTION_PERSISTENCE_REFRESHED }
 
enum  sip_publish_type {
  SIP_PUBLISH_UNKNOWN , SIP_PUBLISH_INITIAL , SIP_PUBLISH_REFRESH , SIP_PUBLISH_MODIFY ,
  SIP_PUBLISH_REMOVE
}
 The types of PUBLISH messages defined in RFC 3903. More...
 
enum  sip_subscription_tree_state { SIP_SUB_TREE_NORMAL = 0 , SIP_SUB_TREE_TERMINATE_PENDING , SIP_SUB_TREE_TERMINATE_IN_PROGRESS , SIP_SUB_TREE_TERMINATED }
 The state of the subscription tree. More...
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void add_rlmi_resource (pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid, const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
 Add a resource XML element to an RLMI body. More...
 
static void add_subscription (struct sip_subscription_tree *obj)
 
static struct body_partallocate_body_part (pj_pool_t *pool, const struct ast_sip_subscription *sub)
 Allocate and initialize a body part structure. More...
 
static struct ast_sip_subscriptionallocate_subscription (const struct ast_sip_subscription_handler *handler, const char *resource, const char *display_name, struct sip_subscription_tree *tree)
 
static struct sip_subscription_treeallocate_subscription_tree (struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 
static int allocate_tdata_buffer (pjsip_tx_data *tdata)
 Pre-allocate a buffer for the transmission. More...
 
static int ami_show_resource_lists (struct mansession *s, const struct message *m)
 
static int ami_show_subscriptions_inbound (struct mansession *s, const struct message *m)
 
static int ami_show_subscriptions_outbound (struct mansession *s, const struct message *m)
 
static int ami_subscription_detail (struct sip_subscription_tree *sub_tree, struct ast_sip_ami *ami, const char *event)
 
static int ami_subscription_detail_inbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static int ami_subscription_detail_outbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static int apply_list_configuration (struct ast_sorcery *sorcery)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
struct ast_sip_subscriptionast_sip_create_subscription (const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, const char *resource)
 Create a new ast_sip_subscription structure. More...
 
int ast_sip_publication_add_datastore (struct ast_sip_publication *publication, struct ast_datastore *datastore)
 Add a datastore to a SIP publication. More...
 
struct ast_datastoreast_sip_publication_get_datastore (struct ast_sip_publication *publication, const char *name)
 Retrieve a publication datastore. More...
 
struct ao2_containerast_sip_publication_get_datastores (const struct ast_sip_publication *publication)
 Get the datastores container for a publication. More...
 
struct ast_sip_endpointast_sip_publication_get_endpoint (struct ast_sip_publication *pub)
 Given a publication, get the associated endpoint. More...
 
const char * ast_sip_publication_get_event_configuration (const struct ast_sip_publication *pub)
 Given a publication, get the configuration name for the event type in use. More...
 
const char * ast_sip_publication_get_resource (const struct ast_sip_publication *pub)
 Given a publication, get the resource the publication is to. More...
 
void ast_sip_publication_remove_datastore (struct ast_sip_publication *publication, const char *name)
 Remove a publication datastore from the publication. More...
 
int ast_sip_pubsub_generate_body_content (const char *type, const char *subtype, struct ast_sip_body_data *data, struct ast_str **str)
 Generate body content for a PUBLISH or NOTIFY. More...
 
static int ast_sip_pubsub_has_eventlist_support (pjsip_rx_data *rdata)
 Check if the rdata has a Supported header containing 'eventlist'. More...
 
int ast_sip_pubsub_is_body_generator_registered (const char *type, const char *subtype)
 Is a body generator registered for the given type/subtype. More...
 
int ast_sip_pubsub_register_body_generator (struct ast_sip_pubsub_body_generator *generator)
 Register a body generator with the pubsub core. More...
 
int ast_sip_pubsub_register_body_supplement (struct ast_sip_pubsub_body_supplement *supplement)
 Register a body generator with the pubsub core. More...
 
void ast_sip_pubsub_unregister_body_generator (struct ast_sip_pubsub_body_generator *generator)
 Unregister a body generator with the pubsub core. More...
 
void ast_sip_pubsub_unregister_body_supplement (struct ast_sip_pubsub_body_supplement *supplement)
 Unregister a body generator with the pubsub core. More...
 
int ast_sip_register_publish_handler (struct ast_sip_publish_handler *handler)
 Register a publish handler. More...
 
int ast_sip_register_subscription_handler (struct ast_sip_subscription_handler *handler)
 Register a subscription handler. More...
 
int ast_sip_subscription_add_datastore (struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
 Add a datastore to a SIP subscription. More...
 
struct ast_datastoreast_sip_subscription_alloc_datastore (const struct ast_datastore_info *info, const char *uid)
 Alternative for ast_datastore_alloc() More...
 
void ast_sip_subscription_destroy (struct ast_sip_subscription *sub)
 Alert the pubsub core that the subscription is ready for destruction. More...
 
const char * ast_sip_subscription_get_body_subtype (struct ast_sip_subscription *sub)
 Get the body subtype used for this subscription. More...
 
const char * ast_sip_subscription_get_body_type (struct ast_sip_subscription *sub)
 Get the body type used for this subscription. More...
 
struct ast_datastoreast_sip_subscription_get_datastore (struct ast_sip_subscription *subscription, const char *name)
 Retrieve a subscription datastore. More...
 
struct ao2_containerast_sip_subscription_get_datastores (const struct ast_sip_subscription *subscription)
 Get the datastores container for a subscription. More...
 
pjsip_dialog * ast_sip_subscription_get_dialog (struct ast_sip_subscription *sub)
 Get the pjsip dialog that is associated with this subscription. More...
 
struct ast_sip_endpointast_sip_subscription_get_endpoint (struct ast_sip_subscription *sub)
 Get the endpoint that is associated with this subscription. More...
 
void * ast_sip_subscription_get_header (const struct ast_sip_subscription *sub, const char *header)
 Get a header value for a subscription. More...
 
void ast_sip_subscription_get_local_uri (struct ast_sip_subscription *sub, char *buf, size_t size)
 Retrieve the local URI for this subscription. More...
 
const struct ast_jsonast_sip_subscription_get_persistence_data (const struct ast_sip_subscription *subscription)
 Retrieve persistence data for a subscription. More...
 
void ast_sip_subscription_get_remote_uri (struct ast_sip_subscription *sub, char *buf, size_t size)
 Retrive the remote URI for this subscription. More...
 
const char * ast_sip_subscription_get_resource_name (struct ast_sip_subscription *sub)
 Get the name of the subscribed resource. More...
 
struct ast_taskprocessorast_sip_subscription_get_serializer (struct ast_sip_subscription *sub)
 Get the serializer for the subscription. More...
 
pjsip_sip_uri * ast_sip_subscription_get_sip_uri (struct ast_sip_subscription *sub)
 Retrieve the local sip uri for this subscription. More...
 
int ast_sip_subscription_is_terminated (const struct ast_sip_subscription *sub)
 Get whether the subscription has been terminated or not. More...
 
int ast_sip_subscription_notify (struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data, int terminate)
 Notify a SIP subscription of a state change. More...
 
void ast_sip_subscription_remove_datastore (struct ast_sip_subscription *subscription, const char *name)
 Remove a subscription datastore from the subscription. More...
 
void ast_sip_subscription_set_persistence_data (struct ast_sip_subscription *subscription, struct ast_json *persistence_data)
 Set persistence data for a subscription. More...
 
void ast_sip_unregister_publish_handler (struct ast_sip_publish_handler *handler)
 Unregister a publish handler. More...
 
void ast_sip_unregister_subscription_handler (struct ast_sip_subscription_handler *handler)
 Unregister a subscription handler. More...
 
static void build_body_part (pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *parts, unsigned int use_full_state)
 Create a multipart body part for a subscribed resource. More...
 
static void build_node_children (struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler, struct resource_list *list, struct tree_node *parent, struct resources *visited, pjsip_rx_data *rdata)
 Build child nodes for a given parent. More...
 
static int build_resource_tree (struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler, const char *resource, struct resource_tree *tree, int has_eventlist_support, pjsip_rx_data *rdata)
 Build a resource tree. More...
 
static pjsip_multipart_part * build_rlmi_body (pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *body_parts, unsigned int full_state)
 Create an RLMI body part for a multipart resource list body. More...
 
static void clean_sub_tree (pjsip_evsub *evsub)
 Callback sequence for subscription terminate: More...
 
static char * cli_complete_subscription_callid (struct ast_cli_args *a)
 
static int cli_complete_subscription_common (struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)
 
static int cli_complete_subscription_inbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static int cli_complete_subscription_outbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static int cli_list_subscriptions_detail (struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
 
static int cli_list_subscriptions_inbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static char * cli_list_subscriptions_inout (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int cli_list_subscriptions_outbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static int cli_show_subscription_common (struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
 
static int cli_show_subscription_inbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static char * cli_show_subscription_inout (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int cli_show_subscription_outbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static int cli_show_subscriptions_detail (struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
 
static int cli_show_subscriptions_inbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static char * cli_show_subscriptions_inout (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static int cli_show_subscriptions_outbound (struct sip_subscription_tree *sub_tree, void *arg)
 
static unsigned int cli_subscription_expiry (struct sip_subscription_tree *sub_tree)
 
static int cmp_strings (char *s1, char *s2)
 Compare strings for equality checking for NULL. More...
 
static int cmp_subscription_childrens (struct ast_sip_subscription *s1, struct ast_sip_subscription *s2)
 compares the childrens of two ast_sip_subscription s1 and s2 More...
 
static pjsip_msg_body * create_multipart_body (pj_pool_t *pool)
 Create and initialize the PJSIP multipart body structure for a resource list subscription. More...
 
static pjsip_require_hdr * create_require_eventlist (pj_pool_t *pool)
 Shortcut method to create a Require: eventlist header. More...
 
static struct sip_subscription_treecreate_subscription_tree (const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree, pj_status_t *dlg_status, struct subscription_persistence *persistence)
 Create a subscription tree based on a resource tree. More...
 
static struct ast_sip_subscriptioncreate_virtual_subscriptions (const struct ast_sip_subscription_handler *handler, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct sip_subscription_tree *tree, struct tree_node *current)
 Create a tree of virtual subscriptions based on a resource tree node. More...
 
static void destroy_subscription (struct ast_sip_subscription *sub)
 
static void destroy_subscriptions (struct ast_sip_subscription *root)
 
static int destroy_subscriptions_task (void *obj)
 
static enum sip_publish_type determine_sip_publish_type (pjsip_rx_data *rdata, pjsip_generic_string_hdr *etag_hdr, unsigned int *expires, int *entity_id)
 
static int exceptional_accept (const pj_str_t *accept)
 Is the Accept header from the SUBSCRIBE in the list of exceptions? More...
 
static struct ast_sip_pubsub_body_generatorfind_body_generator (char accept[AST_SIP_MAX_ACCEPT][64], size_t num_accept, const char *body_type)
 
static struct ast_sip_pubsub_body_generatorfind_body_generator_accept (const char *accept)
 
static struct ast_sip_pubsub_body_generatorfind_body_generator_type_subtype (const char *type, const char *subtype)
 
static struct ast_sip_pubsub_body_generatorfind_body_generator_type_subtype_nolock (const char *type, const char *subtype)
 
static struct ast_sip_publish_handlerfind_pub_handler (const char *event)
 
static struct ast_sip_subscription_handlerfind_sub_handler_for_event_name (const char *event_name)
 
static int for_each_subscription (on_subscription_t on_subscription, void *arg)
 
static int format_ami_resource_lists (void *obj, void *arg, int flags)
 
static void free_body_parts (struct body_part_list *parts)
 Destroy a list of body parts. More...
 
static pjsip_generic_string_hdr * generate_content_id_hdr (pj_pool_t *pool, const struct ast_sip_subscription *sub)
 Create a Content-ID header. More...
 
static int generate_initial_notify (struct ast_sip_subscription *sub)
 
static pjsip_msg_body * generate_list_body (pj_pool_t *pool, struct ast_sip_subscription *sub, unsigned int force_full_state)
 Create a resource list body for NOTIFY requests. More...
 
static pjsip_msg_body * generate_notify_body (pj_pool_t *pool, struct ast_sip_subscription *root, unsigned int force_full_state)
 Create the body for a NOTIFY request. More...
 
static int have_visited (const char *resource, struct resources *visited)
 Determine if this resource has been visited already. More...
 
static int initial_notify_task (void *obj)
 
static int item_in_vector (const struct resource_list *list, const char *item)
 
static int list_item_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
 
static int list_item_to_str (const void *obj, const intptr_t *args, char **buf)
 
static int load_module (void)
 
static int parse_simple_message_summary (char *body, struct simple_message_summary *summary)
 
static int persistence_endpoint_str2struct (const struct aco_option *opt, struct ast_variable *var, void *obj)
 
static int persistence_endpoint_struct2str (const void *obj, const intptr_t *args, char **buf)
 
static int persistence_expires_str2struct (const struct aco_option *opt, struct ast_variable *var, void *obj)
 
static int persistence_expires_struct2str (const void *obj, const intptr_t *args, char **buf)
 
static int persistence_generator_data_str2struct (const struct aco_option *opt, struct ast_variable *var, void *obj)
 
static int persistence_generator_data_struct2str (const void *obj, const intptr_t *args, char **buf)
 
static int persistence_tag_str2struct (const struct aco_option *opt, struct ast_variable *var, void *obj)
 
static int persistence_tag_struct2str (const void *obj, const intptr_t *args, char **buf)
 
static int publication_cmp_fn (void *obj, void *arg, int flags)
 
static void publication_destroy_fn (void *obj)
 Internal destructor for publications. More...
 
static int publication_hash_fn (const void *obj, const int flags)
 
static void * publication_resource_alloc (const char *name)
 Allocator for publication resource. More...
 
static void publication_resource_destroy (void *obj)
 Destructor for publication resource. More...
 
static void publish_add_handler (struct ast_sip_publish_handler *handler)
 
static int publish_expire (const void *data)
 
static int publish_expire_callback (void *data)
 
static struct ast_sip_publicationpublish_request_initial (struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, struct ast_sip_publish_handler *handler)
 
static void pubsub_on_client_refresh (pjsip_evsub *sub)
 
static void pubsub_on_evsub_state (pjsip_evsub *evsub, pjsip_event *event)
 PJSIP callback when underlying SIP subscription changes state. More...
 
static int pubsub_on_refresh_timeout (void *userdata)
 
static pj_bool_t pubsub_on_rx_mwi_notify_request (pjsip_rx_data *rdata)
 
static void pubsub_on_rx_notify (pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
 
static pj_bool_t pubsub_on_rx_notify_request (pjsip_rx_data *rdata)
 
static pj_bool_t pubsub_on_rx_publish_request (pjsip_rx_data *rdata)
 
static void pubsub_on_rx_refresh (pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
 Called whenever an in-dialog SUBSCRIBE is received. More...
 
static pj_bool_t pubsub_on_rx_request (pjsip_rx_data *rdata)
 Opaque structure representing an RFC 3265 SIP subscription. More...
 
static pj_bool_t pubsub_on_rx_subscribe_request (pjsip_rx_data *rdata)
 
static void pubsub_on_server_timeout (pjsip_evsub *sub)
 
static void remove_subscription (struct sip_subscription_tree *obj)
 
static int resource_endpoint_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
 
static int resource_event_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
 
static void * resource_list_alloc (const char *name)
 
static int resource_list_apply_handler (const struct ast_sorcery *sorcery, void *obj)
 
static void resource_list_destructor (void *obj)
 
static void resource_tree_destroy (struct resource_tree *tree)
 Destroy a resource tree. More...
 
static struct resource_listretrieve_resource_list (const char *resource, const char *event)
 Helper function for retrieving a resource list for a given event. More...
 
static void * rlmi_clone_data (pj_pool_t *pool, const void *data, unsigned len)
 
static int rlmi_print_body (struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
 
static int sched_cb (const void *data)
 
static int schedule_notification (struct sip_subscription_tree *sub_tree)
 
static int send_notify (struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
 Send a NOTIFY request to a subscriber. More...
 
static int serialized_pubsub_on_client_refresh (void *userdata)
 
static int serialized_pubsub_on_refresh_timeout (void *userdata)
 
static int serialized_send_notify (void *userdata)
 
static void set_state_terminated (struct ast_sip_subscription *sub)
 
static void shutdown_subscriptions (struct ast_sip_subscription *sub)
 
static struct ast_sip_publicationsip_create_publication (struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, const char *event_configuration_name)
 
static int sip_publication_respond (struct ast_sip_publication *pub, int status_code, pjsip_rx_data *rdata)
 
static int sip_subscription_accept (struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
 
static int sip_subscription_send_request (struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
 
static void sip_subscription_to_ami (struct sip_subscription_tree *sub_tree, struct ast_str **buf)
 
static void sub_add_handler (struct ast_sip_subscription_handler *handler)
 
static int sub_persistence_recreate (void *obj)
 
static int sub_tree_subscription_terminate_cb (void *data)
 
static void sub_tree_transport_cb (void *data)
 
static struct ast_sip_pubsub_body_generatorsubscription_get_generator_from_rdata (pjsip_rx_data *rdata, const struct ast_sip_subscription_handler *handler)
 Retrieve a body generator using the Accept header of an rdata message. More...
 
static struct ast_sip_subscription_handlersubscription_get_handler_from_rdata (pjsip_rx_data *rdata, const char *endpoint)
 Retrieve a handler using the Event header of an rdata message. More...
 
static void * subscription_persistence_alloc (const char *name)
 Allocator for subscription persistence. More...
 
static struct subscription_persistencesubscription_persistence_create (struct sip_subscription_tree *sub_tree)
 Function which creates initial persistence information of a subscription in sorcery. More...
 
static void subscription_persistence_destroy (void *obj)
 Destructor for subscription persistence. More...
 
static void subscription_persistence_event_cb (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 Event callback which fires subscription persistence recreation when the system is fully booted. More...
 
static int subscription_persistence_load (void *data)
 Function which loads and recreates persisted subscriptions upon startup when the system is fully booted. More...
 
static int subscription_persistence_recreate (void *obj, void *arg, int flags)
 Callback function to perform the actual recreation of a subscription. More...
 
static void subscription_persistence_remove (struct sip_subscription_tree *sub_tree)
 Function which removes persistence of a subscription from sorcery. More...
 
static void subscription_persistence_update (struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, enum sip_persistence_update_type type)
 Function which updates persistence information of a subscription in sorcery. More...
 
static void subscription_setup_dialog (struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
 
static void subscription_tree_destructor (void *obj)
 
static int subscription_unreference_dialog (void *obj)
 
static struct tree_nodetree_node_alloc (const char *resource, struct resources *visited, unsigned int full_state, const char *display_name)
 Allocate a tree node. More...
 
static void tree_node_destroy (struct tree_node *node)
 Destructor for a tree node. More...
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "PJSIP event resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, .requires = "res_pjsip", }
 
const char * accept_exceptions []
 Accept headers that are exceptions to the rule. More...
 
static const struct ast_module_infoast_module_info = &__mod_info
 
struct body_generators body_generators = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
struct body_supplements body_supplements = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static struct ast_cli_entry cli_commands []
 
static int esc_etag_counter
 
const pjsip_method pjsip_publish_method
 Defined method for PUBLISH. More...
 
struct publish_handlers publish_handlers = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
static pjsip_evsub_user pubsub_cb
 
static struct pjsip_module pubsub_module
 
static pjsip_media_type rlmi_media_type
 
static struct ast_sched_contextsched
 Scheduler used for automatically expiring publications. More...
 
static const char * sip_subscription_roles_map []
 
static const pj_str_t str_event_name = { "Event", 5 }
 
static char * sub_tree_state_description []
 
struct subscription_handlers subscription_handlers = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 
struct subscriptions subscriptions = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }
 

Macro Definition Documentation

◆ AMI_SHOW_SUBSCRIPTIONS_INBOUND

#define AMI_SHOW_SUBSCRIPTIONS_INBOUND   "PJSIPShowSubscriptionsInbound"

Definition at line 4581 of file res_pjsip_pubsub.c.

◆ AMI_SHOW_SUBSCRIPTIONS_OUTBOUND

#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND   "PJSIPShowSubscriptionsOutbound"

Definition at line 4582 of file res_pjsip_pubsub.c.

◆ CLI_LIST_SUB_FORMAT_ENTRY

#define CLI_LIST_SUB_FORMAT_ENTRY   "%-30.30s %-30.30s %6d %s\n"

Definition at line 4968 of file res_pjsip_pubsub.c.

◆ CLI_LIST_SUB_FORMAT_HEADER

#define CLI_LIST_SUB_FORMAT_HEADER   "%-30.30s %-30.30s %6.6s %s\n"

Definition at line 4967 of file res_pjsip_pubsub.c.

◆ CLI_SHOW_SUB_FORMAT_ENTRY

#define CLI_SHOW_SUB_FORMAT_ENTRY
Value:
"Endpoint: %s/%s\n" \
"Resource: %s/%s\n" \
" Expiry: %8d %s\n\n"

Definition at line 4825 of file res_pjsip_pubsub.c.

◆ CLI_SHOW_SUB_FORMAT_HEADER

#define CLI_SHOW_SUB_FORMAT_HEADER
Value:
"Endpoint: <Endpoint/Caller-ID.............................................>\n" \
"Resource: <Resource/Event.................................................>\n" \
" Expiry: <Expiry> <Call-id..............................................>\n" \
"===========================================================================\n\n"

Definition at line 4820 of file res_pjsip_pubsub.c.

◆ DATASTORE_BUCKETS

#define DATASTORE_BUCKETS   53

Number of buckets for subscription datastore.

Definition at line 466 of file res_pjsip_pubsub.c.

◆ DEFAULT_EXPIRES

#define DEFAULT_EXPIRES   3600

Default expiration for subscriptions.

Definition at line 469 of file res_pjsip_pubsub.c.

◆ DEFAULT_PUBLISH_EXPIRES

#define DEFAULT_PUBLISH_EXPIRES   3600

Default expiration time for PUBLISH if one is not specified.

Definition at line 463 of file res_pjsip_pubsub.c.

◆ MAX_REGEX_ERROR_LEN

#define MAX_REGEX_ERROR_LEN   128

Definition at line 4584 of file res_pjsip_pubsub.c.

◆ MOD_DATA_MSG

#define MOD_DATA_MSG   "sub_msg"

Definition at line 452 of file res_pjsip_pubsub.c.

◆ MOD_DATA_PERSISTENCE

#define MOD_DATA_PERSISTENCE   "sub_persistence"

Definition at line 451 of file res_pjsip_pubsub.c.

◆ NEW_SUBSCRIBE

#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)

Definition at line 1228 of file res_pjsip_pubsub.c.

◆ PUBLICATIONS_BUCKETS

#define PUBLICATIONS_BUCKETS   37

Number of buckets for publications (on a per handler)

Definition at line 460 of file res_pjsip_pubsub.c.

◆ RESOURCE_LIST_INIT_SIZE

#define RESOURCE_LIST_INIT_SIZE   4

Definition at line 5200 of file res_pjsip_pubsub.c.

Typedef Documentation

◆ on_subscription_t

typedef int(* on_subscription_t) (struct sip_subscription_tree *sub, void *arg)

Definition at line 2046 of file res_pjsip_pubsub.c.

Enumeration Type Documentation

◆ sip_persistence_update_type

Enumerator
SUBSCRIPTION_PERSISTENCE_SEND_REQUEST 

Called from send request

SUBSCRIPTION_PERSISTENCE_CREATED 

Subscription created from initial client request

SUBSCRIPTION_PERSISTENCE_RECREATED 

Subscription recreated by asterisk on startup

SUBSCRIPTION_PERSISTENCE_REFRESHED 

Subscription created from client refresh

Definition at line 747 of file res_pjsip_pubsub.c.

747 {
748 /*! Called from send request */
750 /*! Subscription created from initial client request */
752 /*! Subscription recreated by asterisk on startup */
754 /*! Subscription created from client refresh */
756};
@ SUBSCRIPTION_PERSISTENCE_CREATED
@ SUBSCRIPTION_PERSISTENCE_SEND_REQUEST
@ SUBSCRIPTION_PERSISTENCE_REFRESHED
@ SUBSCRIPTION_PERSISTENCE_RECREATED

◆ sip_publish_type

The types of PUBLISH messages defined in RFC 3903.

Enumerator
SIP_PUBLISH_UNKNOWN 

Unknown.

This actually is not defined in RFC 3903. We use this as a constant to indicate that an incoming PUBLISH does not fit into any of the other categories and is thus invalid.

SIP_PUBLISH_INITIAL 

Initial.

The first PUBLISH sent. This will contain a non-zero Expires header as well as a body that indicates the current state of the endpoint that has sent the message. The initial PUBLISH is the only type of PUBLISH to not contain a Sip-If-Match header in it.

SIP_PUBLISH_REFRESH 

Refresh.

Used to keep a published state from expiring. This will contain a non-zero Expires header but no body since its purpose is not to update state.

SIP_PUBLISH_MODIFY 

Modify.

Used to change state from its previous value. This will contain a body updating the published state. May or may not contain an Expires header.

SIP_PUBLISH_REMOVE 

Remove.

Used to remove published state from an ESC. This will contain an Expires header set to 0 and likely no body.

Definition at line 481 of file res_pjsip_pubsub.c.

481 {
482 /*!
483 * \brief Unknown
484 *
485 * \details
486 * This actually is not defined in RFC 3903. We use this as a constant
487 * to indicate that an incoming PUBLISH does not fit into any of the
488 * other categories and is thus invalid.
489 */
491
492 /*!
493 * \brief Initial
494 *
495 * \details
496 * The first PUBLISH sent. This will contain a non-zero Expires header
497 * as well as a body that indicates the current state of the endpoint
498 * that has sent the message. The initial PUBLISH is the only type
499 * of PUBLISH to not contain a Sip-If-Match header in it.
500 */
502
503 /*!
504 * \brief Refresh
505 *
506 * \details
507 * Used to keep a published state from expiring. This will contain a
508 * non-zero Expires header but no body since its purpose is not to
509 * update state.
510 */
512
513 /*!
514 * \brief Modify
515 *
516 * \details
517 * Used to change state from its previous value. This will contain
518 * a body updating the published state. May or may not contain an
519 * Expires header.
520 */
522
523 /*!
524 * \brief Remove
525 *
526 * \details
527 * Used to remove published state from an ESC. This will contain
528 * an Expires header set to 0 and likely no body.
529 */
531};
@ SIP_PUBLISH_REMOVE
Remove.
@ SIP_PUBLISH_REFRESH
Refresh.
@ SIP_PUBLISH_UNKNOWN
Unknown.
@ SIP_PUBLISH_MODIFY
Modify.
@ SIP_PUBLISH_INITIAL
Initial.

◆ sip_subscription_tree_state

The state of the subscription tree.

Enumerator
SIP_SUB_TREE_NORMAL 

Normal operation

SIP_SUB_TREE_TERMINATE_PENDING 

A terminate has been requested by Asterisk, the client, or pjproject

SIP_SUB_TREE_TERMINATE_IN_PROGRESS 

The terminate is in progress

SIP_SUB_TREE_TERMINATED 

The terminate process has finished and the subscription tree is no longer valid

Definition at line 622 of file res_pjsip_pubsub.c.

622 {
623 /*! Normal operation */
625 /*! A terminate has been requested by Asterisk, the client, or pjproject */
627 /*! The terminate is in progress */
629 /*! The terminate process has finished and the subscription tree is no longer valid */
631};
@ SIP_SUB_TREE_TERMINATE_PENDING
@ SIP_SUB_TREE_TERMINATED
@ SIP_SUB_TREE_NORMAL
@ SIP_SUB_TREE_TERMINATE_IN_PROGRESS

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 6167 of file res_pjsip_pubsub.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 6167 of file res_pjsip_pubsub.c.

◆ add_rlmi_resource()

static void add_rlmi_resource ( pj_pool_t *  pool,
pj_xml_node *  rlmi,
const pjsip_generic_string_hdr *  cid,
const char *  resource_name,
const pjsip_sip_uri *  resource_uri,
pjsip_evsub_state  state 
)
static

Add a resource XML element to an RLMI body.

Each resource element represents a subscribed resource in the list. This function currently will unconditionally add an instance element to each created resource element. Instance elements refer to later parts in the multipart body.

Parameters
poolPJLIB allocation pool
rlmi
cidContent-ID header of the resource
resource_nameName of the resource
resource_uriURI of the resource
stateState of the subscribed resource

Definition at line 2278 of file res_pjsip_pubsub.c.

2280{
2281 static pj_str_t cid_name = { "cid", 3 };
2282 pj_xml_node *resource;
2283 pj_xml_node *name;
2284 pj_xml_node *instance;
2285 pj_xml_attr *cid_attr;
2286 char id[6];
2287 char uri[PJSIP_MAX_URL_SIZE];
2288 char name_sanitized[PJSIP_MAX_URL_SIZE];
2289
2290 /* This creates a string representing the Content-ID without the enclosing < > */
2291 const pj_str_t cid_stripped = {
2292 .ptr = cid->hvalue.ptr + 1,
2293 .slen = cid->hvalue.slen - 2,
2294 };
2295
2296 resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
2297 name = ast_sip_presence_xml_create_node(pool, resource, "name");
2298 instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
2299
2300 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
2301 ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
2302
2303 ast_sip_sanitize_xml(resource_name, name_sanitized, sizeof(name_sanitized));
2304 pj_strdup2(pool, &name->content, name_sanitized);
2305
2306 ast_generate_random_string(id, sizeof(id));
2307
2308 ast_sip_presence_xml_create_attr(pool, instance, "id", id);
2309 ast_sip_presence_xml_create_attr(pool, instance, "state",
2310 state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
2311
2312 /* Use the PJLIB-util XML library directly here since we are using a
2313 * pj_str_t
2314 */
2315
2316 cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2317 pj_xml_add_attr(instance, cid_attr);
2318}
static const char name[]
Definition: format_mp3.c:68
void ast_sip_sanitize_xml(const char *input, char *output, size_t len)
Replace offensive XML characters with XML entities.
Definition: presence_xml.c:29
pj_xml_node * ast_sip_presence_xml_create_node(pj_pool_t *pool, pj_xml_node *parent, const char *name)
Create XML node.
Definition: presence_xml.c:152
pj_xml_attr * ast_sip_presence_xml_create_attr(pj_pool_t *pool, pj_xml_node *node, const char *name, const char *value)
Create XML attribute.
Definition: presence_xml.c:140
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
Definition: strings.c:226

References ast_generate_random_string(), ast_sip_presence_xml_create_attr(), ast_sip_presence_xml_create_node(), ast_sip_sanitize_xml(), and name.

Referenced by build_rlmi_body().

◆ add_subscription()

static void add_subscription ( struct sip_subscription_tree obj)
static

Definition at line 1411 of file res_pjsip_pubsub.c.

1412{
1416}
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:741

References AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by ast_sip_create_subscription(), and create_subscription_tree().

◆ allocate_body_part()

static struct body_part * allocate_body_part ( pj_pool_t *  pool,
const struct ast_sip_subscription sub 
)
static

Allocate and initialize a body part structure.

Parameters
poolPJLIB allocation pool
subSubscription representing a subscribed resource

Definition at line 2486 of file res_pjsip_pubsub.c.

2487{
2488 struct body_part *bp;
2489
2490 bp = ast_calloc(1, sizeof(*bp));
2491 if (!bp) {
2492 return NULL;
2493 }
2494
2495 bp->cid = generate_content_id_hdr(pool, sub);
2496 bp->resource = sub->resource;
2497 bp->state = sub->subscription_state;
2498 bp->uri = sub->uri;
2499 bp->display_name = sub->display_name;
2500
2501 return bp;
2502}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
struct stasis_forward * sub
Definition: res_corosync.c:240
static pjsip_generic_string_hdr * generate_content_id_hdr(pj_pool_t *pool, const struct ast_sip_subscription *sub)
Create a Content-ID header.
#define NULL
Definition: resample.c:96
A multipart body part and meta-information.
pjsip_evsub_state state
const char * display_name
const char * resource
pjsip_generic_string_hdr * cid
pjsip_sip_uri * uri

References ast_calloc, body_part::cid, body_part::display_name, generate_content_id_hdr(), NULL, body_part::resource, body_part::state, sub, and body_part::uri.

Referenced by build_body_part().

◆ allocate_subscription()

static struct ast_sip_subscription * allocate_subscription ( const struct ast_sip_subscription_handler handler,
const char *  resource,
const char *  display_name,
struct sip_subscription_tree tree 
)
static

Definition at line 1470 of file res_pjsip_pubsub.c.

1472{
1473 struct ast_sip_subscription *sub;
1474 pjsip_msg *msg;
1475 pjsip_sip_uri *request_uri;
1476
1478 if (!msg) {
1479 ast_log(LOG_ERROR, "No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n", resource);
1480 return NULL;
1481 }
1482
1483 sub = ast_calloc(1, sizeof(*sub) + strlen(resource) + 1);
1484 if (!sub) {
1485 return NULL;
1486 }
1487 strcpy(sub->resource, resource); /* Safe */
1488
1489 sub->display_name = ast_strdup(display_name);
1490
1491 sub->datastores = ast_datastores_alloc();
1492 if (!sub->datastores) {
1494 return NULL;
1495 }
1496
1497 sub->body_text = ast_str_create(128);
1498 if (!sub->body_text) {
1500 return NULL;
1501 }
1502
1503 sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
1504 request_uri = pjsip_uri_get_uri(msg->line.req.uri);
1505 pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, request_uri);
1506 pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
1507
1508 /* If there is any persistence information available for this subscription that was persisted
1509 * then make it available so that the NOTIFY has the correct state.
1510 */
1511
1514 }
1515
1516 sub->handler = handler;
1517 sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1518 sub->tree = ao2_bump(tree);
1519
1520 return sub;
1521}
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_log
Definition: astobj2.c:42
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
struct ao2_container * ast_datastores_alloc(void)
Allocate a specialized data stores container.
Definition: datastore.c:99
#define LOG_ERROR
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
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
#define ast_sip_mod_data_get(mod_data, id, key)
Using the dictionary stored in mod_data array at a given id, retrieve the value associated with the g...
Definition: res_pjsip.h:3067
static struct pjsip_module pubsub_module
#define MOD_DATA_MSG
static void destroy_subscription(struct ast_sip_subscription *sub)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
Structure representing a "virtual" SIP subscription.
struct sip_subscription_tree * tree
struct subscription_persistence * persistence
struct ast_json * generator_data
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59

References ao2_bump, ast_calloc, ast_datastores_alloc(), ast_json_object_get(), ast_json_ref(), ast_log, ast_sip_mod_data_get, ast_str_create, ast_strdup, destroy_subscription(), ast_sip_subscription::display_name, sip_subscription_tree::dlg, subscription_persistence::generator_data, handler(), LOG_ERROR, MOD_DATA_MSG, NULL, sip_subscription_tree::persistence, pubsub_module, ast_sip_subscription::resource, sub, and ast_sip_subscription::tree.

Referenced by ast_sip_create_subscription(), and create_virtual_subscriptions().

◆ allocate_subscription_tree()

static struct sip_subscription_tree * allocate_subscription_tree ( struct ast_sip_endpoint endpoint,
pjsip_rx_data *  rdata 
)
static

Definition at line 1652 of file res_pjsip_pubsub.c.

1653{
1654 struct sip_subscription_tree *sub_tree;
1655
1656 sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
1657 if (!sub_tree) {
1658 return NULL;
1659 }
1660
1662
1663 if (rdata) {
1664 /*
1665 * We must continue using the serializer that the original
1666 * SUBSCRIBE came in on for the dialog. There may be
1667 * retransmissions already enqueued in the original
1668 * serializer that can result in reentrancy and message
1669 * sequencing problems.
1670 */
1672 } else {
1673 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1674
1675 /* Create name with seq number appended. */
1676 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s",
1678
1679 sub_tree->serializer = ast_sip_create_serializer(tps_name);
1680 }
1681 if (!sub_tree->serializer) {
1682 ao2_ref(sub_tree, -1);
1683 return NULL;
1684 }
1685
1686 sub_tree->endpoint = ao2_bump(endpoint);
1687 sub_tree->notify_sched_id = -1;
1688
1689 return sub_tree;
1690}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2094
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:457
static void subscription_tree_destructor(void *obj)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
struct ast_module * self
Definition: module.h:356
A tree of SIP subscriptions.
struct ast_sip_endpoint * endpoint
struct ast_taskprocessor * serializer
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:61

References ao2_alloc, ao2_bump, ao2_ref, ast_module_ref, ast_sip_create_serializer(), ast_sip_get_distributor_serializer(), ast_sorcery_object_get_id(), ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, sip_subscription_tree::endpoint, sip_subscription_tree::notify_sched_id, NULL, ast_module_info::self, sip_subscription_tree::serializer, and subscription_tree_destructor().

Referenced by ast_sip_create_subscription(), and create_subscription_tree().

◆ allocate_tdata_buffer()

static int allocate_tdata_buffer ( pjsip_tx_data *  tdata)
static

Pre-allocate a buffer for the transmission.

Typically, we let PJSIP do this step for us when we send a request. PJSIP's buffer allocation algorithm is to allocate a buffer of PJSIP_MAX_PKT_LEN bytes and attempt to write the packet to the allocated buffer. If the buffer is too small to hold the packet, then we get told the message is too long to be sent.

When dealing with SIP NOTIFY, especially with RLS, it is possible to exceed PJSIP_MAX_PKT_LEN. Rather than accepting the limitation imposed on us by default, we instead take the strategy of pre-allocating the buffer, testing for ourselves if the message will fit, and resizing the buffer as required.

The limit we impose is double that of the maximum packet length.

Parameters
tdataThe tdata onto which to allocate a buffer
Return values
0Success
-1The message is too large

Definition at line 2215 of file res_pjsip_pubsub.c.

2216{
2217 int buf_size;
2218 int size = -1;
2219 char *buf;
2220
2221 for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
2222 buf = pj_pool_alloc(tdata->pool, buf_size);
2223 size = pjsip_msg_print(tdata->msg, buf, buf_size);
2224 }
2225
2226 if (size == -1) {
2227 return -1;
2228 }
2229
2230 tdata->buf.start = buf;
2231 tdata->buf.cur = tdata->buf.start;
2232 tdata->buf.end = tdata->buf.start + buf_size;
2233
2234 return 0;
2235}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66

References buf.

Referenced by sip_subscription_send_request().

◆ ami_show_resource_lists()

static int ami_show_resource_lists ( struct mansession s,
const struct message m 
)
static

Definition at line 4558 of file res_pjsip_pubsub.c.

4559{
4560 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4561 struct ao2_container *lists;
4562
4563 lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
4565
4566 if (!lists || !ao2_container_count(lists)) {
4567 astman_send_error(s, m, "No resource lists found\n");
4568 return 0;
4569 }
4570
4571 astman_send_listack(s, m, "A listing of resource lists follows, presented as ResourceListDetail events",
4572 "start");
4573
4575
4576 astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count);
4578 return 0;
4579}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
@ OBJ_NODATA
Definition: astobj2.h:1044
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:2028
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1986
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:2064
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int format_ami_resource_lists(void *obj, void *arg, int flags)
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
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
Generic container type.
AMI variable container.
Definition: res_pjsip.h:3200
struct mansession * s
Definition: res_pjsip.h:3202
const struct message * m
Definition: res_pjsip.h:3204

References ao2_callback, ao2_container_count(), AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_sorcery(), ast_sorcery_retrieve_by_fields(), astman_get_header(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_sip_ami::count, format_ami_resource_lists(), ast_sip_ami::m, NULL, OBJ_NODATA, and ast_sip_ami::s.

Referenced by load_module().

◆ ami_show_subscriptions_inbound()

static int ami_show_subscriptions_inbound ( struct mansession s,
const struct message m 
)
static

Definition at line 4508 of file res_pjsip_pubsub.c.

4509{
4510 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4511
4512 astman_send_listack(s, m, "Following are Events for each inbound Subscription",
4513 "start");
4514
4516
4517 astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count);
4519 return 0;
4520}
static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static int for_each_subscription(on_subscription_t on_subscription, void *arg)

References ami_subscription_detail_inbound(), astman_get_header(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_sip_ami::count, for_each_subscription(), ast_sip_ami::m, and ast_sip_ami::s.

Referenced by load_module().

◆ ami_show_subscriptions_outbound()

static int ami_show_subscriptions_outbound ( struct mansession s,
const struct message m 
)
static

Definition at line 4522 of file res_pjsip_pubsub.c.

4523{
4524 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4525
4526 astman_send_listack(s, m, "Following are Events for each outbound Subscription",
4527 "start");
4528
4530
4531 astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count);
4533 return 0;
4534}
static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)

References ami_subscription_detail_outbound(), astman_get_header(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_sip_ami::count, for_each_subscription(), ast_sip_ami::m, and ast_sip_ami::s.

Referenced by load_module().

◆ ami_subscription_detail()

static int ami_subscription_detail ( struct sip_subscription_tree sub_tree,
struct ast_sip_ami ami,
const char *  event 
)
static

Definition at line 4477 of file res_pjsip_pubsub.c.

4480{
4481 struct ast_str *buf;
4482
4484 if (!buf) {
4485 return -1;
4486 }
4487
4488 sip_subscription_to_ami(sub_tree, &buf);
4489 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4490 ast_free(buf);
4491
4492 ++ami->count;
4493 return 0;
4494}
#define ast_free(a)
Definition: astmm.h:180
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1907
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree, struct ast_str **buf)
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
Support for dynamic strings.
Definition: strings.h:623
Definition: astman.c:222

References ast_free, ast_sip_create_ami_event(), ast_str_buffer(), astman_append(), buf, ast_sip_ami::count, ast_sip_ami::s, and sip_subscription_to_ami().

Referenced by ami_subscription_detail_inbound(), and ami_subscription_detail_outbound().

◆ ami_subscription_detail_inbound()

static int ami_subscription_detail_inbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 4496 of file res_pjsip_pubsub.c.

4497{
4498 return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
4499 sub_tree, arg, "InboundSubscriptionDetail") : 0;
4500}
static int ami_subscription_detail(struct sip_subscription_tree *sub_tree, struct ast_sip_ami *ami, const char *event)
@ AST_SIP_NOTIFIER
enum ast_sip_subscription_role role

References ami_subscription_detail(), AST_SIP_NOTIFIER, and sip_subscription_tree::role.

Referenced by ami_show_subscriptions_inbound().

◆ ami_subscription_detail_outbound()

static int ami_subscription_detail_outbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 4502 of file res_pjsip_pubsub.c.

4503{
4504 return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
4505 sub_tree, arg, "OutboundSubscriptionDetail") : 0;
4506}
@ AST_SIP_SUBSCRIBER

References ami_subscription_detail(), AST_SIP_SUBSCRIBER, and sip_subscription_tree::role.

Referenced by ami_show_subscriptions_outbound().

◆ apply_list_configuration()

static int apply_list_configuration ( struct ast_sorcery sorcery)
static

Definition at line 5307 of file res_pjsip_pubsub.c.

5308{
5309 ast_sorcery_apply_default(sorcery, "resource_list", "config",
5310 "pjsip.conf,criteria=type=resource_list");
5313 return -1;
5314 }
5315
5316 ast_sorcery_object_field_register(sorcery, "resource_list", "type", "",
5317 OPT_NOOP_T, 0, 0);
5318 ast_sorcery_object_field_register(sorcery, "resource_list", "event", "",
5320 ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "no",
5321 OPT_BOOL_T, 1, FLDSET(struct resource_list, full_state));
5322 ast_sorcery_object_field_register(sorcery, "resource_list", "notification_batch_interval",
5323 "0", OPT_UINT_T, 0, FLDSET(struct resource_list, notification_batch_interval));
5324 ast_sorcery_object_field_register_custom(sorcery, "resource_list", "list_item",
5326 ast_sorcery_object_field_register(sorcery, "resource_list", "resource_display_name", "no",
5327 OPT_BOOL_T, 1, FLDSET(struct resource_list, resource_display_name));
5328
5329 ast_sorcery_reload_object(sorcery, "resource_list");
5330
5331 return 0;
5332}
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define CHARFLDSET(type, field)
A helper macro to pass the appropriate arguments to aco_option_register for OPT_CHAR_ARRAY_T.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
static struct ast_sorcery * sorcery
static int resource_list_apply_handler(const struct ast_sorcery *sorcery, void *obj)
static int list_item_to_str(const void *obj, const intptr_t *args, char **buf)
static int list_item_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static void * resource_list_alloc(const char *name)
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
#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_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
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
Resource list configuration item.

References ast_sorcery_apply_default, ast_sorcery_object_field_register, ast_sorcery_object_field_register_custom, ast_sorcery_object_register, ast_sorcery_reload_object(), CHARFLDSET, FLDSET, resource_list::full_state, list_item_handler(), list_item_to_str(), resource_list::notification_batch_interval, NULL, OPT_BOOL_T, OPT_CHAR_ARRAY_T, OPT_NOOP_T, OPT_UINT_T, resource_list::resource_display_name, resource_list_alloc(), resource_list_apply_handler(), and sorcery.

Referenced by load_module().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 6167 of file res_pjsip_pubsub.c.

◆ ast_sip_create_subscription()

struct ast_sip_subscription * ast_sip_create_subscription ( const struct ast_sip_subscription_handler handler,
struct ast_sip_endpoint endpoint,
const char *  resource 
)

Create a new ast_sip_subscription structure.

When a subscriber wishes to create a subscription, it may call this function to allocate resources and to send the initial SUBSCRIBE out.

Parameters
handlerThe subscriber that is making the request.
endpointThe endpoint to whome the SUBSCRIBE will be sent.
resourceThe resource to place in the SUBSCRIBE's Request-URI.

Definition at line 2116 of file res_pjsip_pubsub.c.

2118{
2119 struct ast_sip_subscription *sub;
2120 pjsip_dialog *dlg;
2121 struct ast_sip_contact *contact;
2122 pj_str_t event;
2123 pjsip_tx_data *tdata;
2124 pjsip_evsub *evsub;
2125 struct sip_subscription_tree *sub_tree = NULL;
2126
2128 if (!sub_tree) {
2129 return NULL;
2130 }
2131
2132 sub = allocate_subscription(handler, resource, NULL, sub_tree);
2133 if (!sub) {
2134 ao2_cleanup(sub_tree);
2135 return NULL;
2136 }
2137
2139 if (!contact || ast_strlen_zero(contact->uri)) {
2140 ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
2142 ao2_ref(sub_tree, -1);
2143 ao2_cleanup(contact);
2144 return NULL;
2145 }
2146
2148 ao2_cleanup(contact);
2149 if (!dlg) {
2150 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
2151 ao2_ref(sub_tree, -1);
2152 return NULL;
2153 }
2154
2155 pj_cstr(&event, handler->event_name);
2156 pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub_tree->evsub);
2157 subscription_setup_dialog(sub_tree, dlg);
2158
2159 evsub = sub_tree->evsub;
2160
2161 if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
2162 pjsip_evsub_send_request(sub_tree->evsub, tdata);
2163 } else {
2164 /* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
2165 * being called and terminating the subscription. Therefore, we don't
2166 * need to decrease the reference count of sub here.
2167 */
2168 pjsip_evsub_terminate(evsub, PJ_TRUE);
2169 ao2_ref(sub_tree, -1);
2170 return NULL;
2171 }
2172
2173 add_subscription(sub_tree);
2174
2175 return sub;
2176}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define LOG_WARNING
struct ast_sip_contact * ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
Retrieve the first bound contact from a list of AORs.
Definition: location.c:304
pjsip_dialog * ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *aor_name, const char *request_user)
General purpose method for creating a UAC dialog with an endpoint.
Definition: res_pjsip.c:964
static struct ast_sip_subscription * allocate_subscription(const struct ast_sip_subscription_handler *handler, const char *resource, const char *display_name, struct sip_subscription_tree *tree)
static pjsip_evsub_user pubsub_cb
static void add_subscription(struct sip_subscription_tree *obj)
static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
static struct sip_subscription_tree * allocate_subscription_tree(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Contact associated with an address of record.
Definition: res_pjsip.h:390
const ast_string_field uri
Definition: res_pjsip.h:412
const ast_string_field aors
Definition: res_pjsip.h:1080

References add_subscription(), allocate_subscription(), allocate_subscription_tree(), ao2_cleanup, ao2_ref, ast_sip_endpoint::aors, ast_log, ast_sip_create_dialog_uac(), ast_sip_location_retrieve_contact_from_aor_list(), ast_sorcery_object_get_id(), ast_strlen_zero(), sip_subscription_tree::dlg, sip_subscription_tree::endpoint, sip_subscription_tree::evsub, handler(), LOG_WARNING, NULL, pubsub_cb, sub, subscription_setup_dialog(), and ast_sip_contact::uri.

◆ ast_sip_publication_add_datastore()

int ast_sip_publication_add_datastore ( struct ast_sip_publication publication,
struct ast_datastore datastore 
)

Add a datastore to a SIP publication.

Note that SIP uses reference counted datastores. The datastore passed into this function must have been allocated using ao2_alloc() or there will be serious problems.

Parameters
publicationThe publication to add the datastore to
datastoreThe datastore to be added to the subscription
Return values
0Success
-1Failure

Definition at line 2920 of file res_pjsip_pubsub.c.

2921{
2922 return ast_datastores_add(publication->datastores, datastore);
2923}
int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore)
Add a data store to a container.
Definition: datastore.c:105
struct ao2_container * datastores

References ast_datastores_add(), and ast_sip_publication::datastores.

◆ ast_sip_publication_get_datastore()

struct ast_datastore * ast_sip_publication_get_datastore ( struct ast_sip_publication publication,
const char *  name 
)

Retrieve a publication datastore.

The datastore retrieved will have its reference count incremented. When the caller is done with the datastore, the reference counted needs to be decremented using ao2_ref().

Parameters
publicationThe publication from which to retrieve the datastore
nameThe name of the datastore to retrieve
Return values
NULLFailed to find the specified datastore
non-NULLThe specified datastore

Definition at line 2925 of file res_pjsip_pubsub.c.

2926{
2927 return ast_datastores_find(publication->datastores, name);
2928}
struct ast_datastore * ast_datastores_find(struct ao2_container *datastores, const char *name)
Find a data store in a container.
Definition: datastore.c:123

References ast_datastores_find(), ast_sip_publication::datastores, and name.

◆ ast_sip_publication_get_datastores()

struct ao2_container * ast_sip_publication_get_datastores ( const struct ast_sip_publication publication)

Get the datastores container for a publication.

Parameters
publicationThe publication to get the datastores container from
Return values
NULLdatastores container not present
non-NULLdatastores container
Note
The container is NOT returned with reference count bumped
Since
14.0.0

Definition at line 2935 of file res_pjsip_pubsub.c.

2936{
2937 return publication->datastores;
2938}

References ast_sip_publication::datastores.

◆ ast_sip_publication_get_endpoint()

struct ast_sip_endpoint * ast_sip_publication_get_endpoint ( struct ast_sip_publication pub)

Given a publication, get the associated endpoint.

Parameters
pubThe publication
Return values
NULLFailure
non-NULLThe associated endpoint

Definition at line 3694 of file res_pjsip_pubsub.c.

3695{
3696 return pub->endpoint;
3697}
struct ast_sip_endpoint * endpoint
The endpoint with which the subscription is communicating.

References ast_sip_publication::endpoint.

◆ ast_sip_publication_get_event_configuration()

const char * ast_sip_publication_get_event_configuration ( const struct ast_sip_publication pub)

Given a publication, get the configuration name for the event type in use.

Parameters
pubThe publication
Returns
The configuration name

Definition at line 3704 of file res_pjsip_pubsub.c.

3705{
3706 return pub->event_configuration_name;
3707}
char * event_configuration_name
The name of the event type configuration.

References ast_sip_publication::event_configuration_name.

Referenced by asterisk_publication_devicestate_state_change(), and asterisk_publication_mwi_state_change().

◆ ast_sip_publication_get_resource()

const char * ast_sip_publication_get_resource ( const struct ast_sip_publication pub)

Given a publication, get the resource the publication is to.

Parameters
pubThe publication
Returns
The resource

Definition at line 3699 of file res_pjsip_pubsub.c.

3700{
3701 return pub->resource;
3702}
char * resource
The resource the publication is to.

References ast_sip_publication::resource.

◆ ast_sip_publication_remove_datastore()

void ast_sip_publication_remove_datastore ( struct ast_sip_publication publication,
const char *  name 
)

Remove a publication datastore from the publication.

This operation may cause the datastore's free() callback to be called if the reference count reaches zero.

Parameters
publicationThe publication to remove the datastore from
nameThe name of the datastore to remove

Definition at line 2930 of file res_pjsip_pubsub.c.

2931{
2932 ast_datastores_remove(publication->datastores, name);
2933}
void ast_datastores_remove(struct ao2_container *datastores, const char *name)
Remove a data store from a container.
Definition: datastore.c:118

References ast_datastores_remove(), ast_sip_publication::datastores, and name.

◆ ast_sip_pubsub_generate_body_content()

int ast_sip_pubsub_generate_body_content ( const char *  content_type,
const char *  content_subtype,
struct ast_sip_body_data data,
struct ast_str **  str 
)

Generate body content for a PUBLISH or NOTIFY.

Since
13.0.0

This function takes a pre-allocated body and calls into registered body generators in order to fill in the body with appropriate details. The primary body generator will be called first, followed by the supplementary body generators

Parameters
content_typeThe content type of the body
content_subtypeThe content subtype of the body
dataThe data associated with body generation.
[out]strThe string representation of the generated body
Return values
0Success
non-zeroFailure

Definition at line 3793 of file res_pjsip_pubsub.c.

3795{
3796 struct ast_sip_pubsub_body_supplement *supplement;
3797 struct ast_sip_pubsub_body_generator *generator;
3798 int res = 0;
3799 void *body;
3800
3802 if (!generator) {
3803 ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
3804 type, subtype);
3805 return -1;
3806 }
3807
3808 if (strcmp(data->body_type, generator->body_type)) {
3809 ast_log(LOG_WARNING, "%s/%s body generator does not accept the type of data provided\n",
3810 type, subtype);
3811 return -1;
3812 }
3813
3814 body = generator->allocate_body(data->body_data);
3815 if (!body) {
3816 ast_log(LOG_WARNING, "%s/%s body generator could not to allocate a body\n",
3817 type, subtype);
3818 return -1;
3819 }
3820
3821 if (generator->generate_body_content(body, data->body_data)) {
3822 res = -1;
3823 goto end;
3824 }
3825
3828 if (!strcmp(generator->type, supplement->type) &&
3829 !strcmp(generator->subtype, supplement->subtype)) {
3830 res = supplement->supplement_body(body, data->body_data);
3831 if (res) {
3832 break;
3833 }
3834 }
3835 }
3837
3838 if (!res) {
3839 generator->to_string(body, str);
3840 }
3841
3842end:
3843 if (generator->destroy_body) {
3844 generator->destroy_body(body);
3845 }
3846
3847 return res;
3848}
const char * str
Definition: app_jack.c:150
static const char type[]
Definition: chan_ooh323.c:109
char * end
Definition: eagi_proxy.c:73
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype(const char *type, const char *subtype)
const char * body_type
Pubsub body generator.
void(* to_string)(void *body, struct ast_str **str)
Convert the body to a string.
struct ast_sip_pubsub_body_generator::@263 list
void(* destroy_body)(void *body)
Deallocate resources created for the body.
const char * type
Content type In "plain/text", "plain" is the type.
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
void *(* allocate_body)(void *data)
allocate body structure.
int(* generate_body_content)(void *body, void *data)
Add content to the body of a SIP request.
int(* supplement_body)(void *body, void *data)
Add additional content to a SIP request body.
const char * type
Content type In "plain/text", "plain" is the type.
const char * subtype
Content subtype In "plain/text", "text" is the subtype.

References ast_sip_pubsub_body_generator::allocate_body, ast_log, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_sip_body_data::body_data, ast_sip_body_data::body_type, ast_sip_pubsub_body_generator::body_type, ast_sip_pubsub_body_generator::destroy_body, end, find_body_generator_type_subtype(), ast_sip_pubsub_body_generator::generate_body_content, ast_sip_pubsub_body_generator::list, LOG_WARNING, str, ast_sip_pubsub_body_generator::subtype, ast_sip_pubsub_body_supplement::subtype, ast_sip_pubsub_body_supplement::supplement_body, ast_sip_pubsub_body_generator::to_string, type, ast_sip_pubsub_body_generator::type, and ast_sip_pubsub_body_supplement::type.

Referenced by ast_sip_subscription_notify(), exten_state_publisher_cb(), generate_initial_notify(), and send_unsolicited_mwi_notify_to_contact().

◆ ast_sip_pubsub_has_eventlist_support()

static int ast_sip_pubsub_has_eventlist_support ( pjsip_rx_data *  rdata)
static

Check if the rdata has a Supported header containing 'eventlist'.

Return values
1rdata has an eventlist containing supported header
0rdata doesn't have an eventlist containing supported header

Definition at line 1089 of file res_pjsip_pubsub.c.

1090{
1091 pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
1092
1093 while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
1094 int i;
1095
1096 for (i = 0; i < supported_header->count; i++) {
1097 if (!pj_stricmp2(&supported_header->values[i], "eventlist")) {
1098 return 1;
1099 }
1100 }
1101 }
1102
1103 return 0;
1104}
while(1)
Definition: ast_expr2f.c:880

References while().

Referenced by pubsub_on_rx_refresh(), pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

◆ ast_sip_pubsub_is_body_generator_registered()

int ast_sip_pubsub_is_body_generator_registered ( const char *  type,
const char *  subtype 
)

Is a body generator registered for the given type/subtype.

Since
14.0.0
Parameters
typeThe content type of the body
subtypeThe content subtype of the body
Note
In "plain/text", "plain" is the type and "text" is the subtype.
Return values
non-zeroif a generator is registered.

Definition at line 3709 of file res_pjsip_pubsub.c.

3710{
3711 return !!find_body_generator_type_subtype(type, subtype);
3712}

References find_body_generator_type_subtype(), and type.

Referenced by publisher_start().

◆ ast_sip_pubsub_register_body_generator()

int ast_sip_pubsub_register_body_generator ( struct ast_sip_pubsub_body_generator generator)

Register a body generator with the pubsub core.

Since
13.0.0

This may fail if an attempt is made to register a primary body supplement for a given content type if a primary body supplement for that content type has already been registered.

Parameters
generatorBody generator to register
Return values
0Success
-1Failure

Definition at line 3714 of file res_pjsip_pubsub.c.

3715{
3716 struct ast_sip_pubsub_body_generator *existing;
3717 pj_str_t accept;
3718 pj_size_t accept_len;
3719
3721 existing = find_body_generator_type_subtype_nolock(generator->type, generator->subtype);
3722 if (existing) {
3724 ast_log(LOG_WARNING, "A body generator for %s/%s is already registered.\n",
3725 generator->type, generator->subtype);
3726 return -1;
3727 }
3730
3731 /* Lengths of type and subtype plus a slash. */
3732 accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
3733
3734 /* Add room for null terminator that sprintf() will set. */
3735 pj_strset(&accept, ast_alloca(accept_len + 1), accept_len);
3736 sprintf((char *) pj_strbuf(&accept), "%s/%s", generator->type, generator->subtype);/* Safe */
3737
3738 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
3739 PJSIP_H_ACCEPT, NULL, 1, &accept);
3740
3741 return 0;
3742}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype_nolock(const char *type, const char *subtype)

References ast_alloca, AST_LIST_INSERT_HEAD, ast_log, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sip_get_pjsip_endpoint(), find_body_generator_type_subtype_nolock(), ast_sip_pubsub_body_generator::list, LOG_WARNING, NULL, pubsub_module, ast_sip_pubsub_body_generator::subtype, and ast_sip_pubsub_body_generator::type.

Referenced by load_module().

◆ ast_sip_pubsub_register_body_supplement()

int ast_sip_pubsub_register_body_supplement ( struct ast_sip_pubsub_body_supplement supplement)

Register a body generator with the pubsub core.

Since
13.0.0

This may fail if an attempt is made to register a primary body supplement for a given content type if a primary body supplement for that content type has already been registered.

Parameters
supplementBody generator to register
Return values
0Success
-1Failure

Definition at line 3759 of file res_pjsip_pubsub.c.

3760{
3762 AST_RWLIST_INSERT_TAIL(&body_supplements, supplement, list);
3764
3765 return 0;
3766}

References AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_sip_pubsub_body_generator::list.

Referenced by load_module().

◆ ast_sip_pubsub_unregister_body_generator()

void ast_sip_pubsub_unregister_body_generator ( struct ast_sip_pubsub_body_generator generator)

Unregister a body generator with the pubsub core.

Since
13.0.0
Parameters
generatorBody generator to unregister

Definition at line 3744 of file res_pjsip_pubsub.c.

3745{
3746 struct ast_sip_pubsub_body_generator *iter;
3747
3750 if (iter == generator) {
3752 break;
3753 }
3754 }
3757}
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557

References AST_LIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_sip_pubsub_body_generator::list.

Referenced by unload_module(), and unregister_all().

◆ ast_sip_pubsub_unregister_body_supplement()

void ast_sip_pubsub_unregister_body_supplement ( struct ast_sip_pubsub_body_supplement supplement)

Unregister a body generator with the pubsub core.

Since
13.0.0
Parameters
supplementBody generator to unregister

Definition at line 3768 of file res_pjsip_pubsub.c.

3769{
3770 struct ast_sip_pubsub_body_supplement *iter;
3771
3774 if (iter == supplement) {
3776 break;
3777 }
3778 }
3781}
struct ast_sip_pubsub_body_supplement::@264 list

References AST_LIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_sip_pubsub_body_supplement::list.

Referenced by unload_module().

◆ ast_sip_register_publish_handler()

int ast_sip_register_publish_handler ( struct ast_sip_publish_handler handler)

Register a publish handler.

Return values
0Handler was registered successfully
non-zeroHandler was not registered successfully

Definition at line 2989 of file res_pjsip_pubsub.c.

2990{
2991 if (ast_strlen_zero(handler->event_name)) {
2992 ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
2993 return -1;
2994 }
2995
2998 if (!handler->publications) {
2999 ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
3000 handler->event_name);
3001 return -1;
3002 }
3003
3005
3006 return 0;
3007}
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#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
static int publication_hash_fn(const void *obj, const int flags)
static int publication_cmp_fn(void *obj, void *arg, int flags)
#define PUBLICATIONS_BUCKETS
Number of buckets for publications (on a per handler)
static void publish_add_handler(struct ast_sip_publish_handler *handler)

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ast_log, ast_strlen_zero(), handler(), LOG_ERROR, NULL, publication_cmp_fn(), publication_hash_fn(), PUBLICATIONS_BUCKETS, and publish_add_handler().

Referenced by load_module().

◆ ast_sip_register_subscription_handler()

int ast_sip_register_subscription_handler ( struct ast_sip_subscription_handler handler)

Register a subscription handler.

Return values
0Handler was registered successfully
non-zeroHandler was not registered successfully

Definition at line 3048 of file res_pjsip_pubsub.c.

3049{
3050 pj_str_t event;
3051 pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
3052 struct ast_sip_subscription_handler *existing;
3053 int i = 0;
3054
3055 if (ast_strlen_zero(handler->event_name)) {
3056 ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
3057 return -1;
3058 }
3059
3060 existing = find_sub_handler_for_event_name(handler->event_name);
3061 if (existing) {
3063 "Unable to register subscription handler for event %s. A handler is already registered\n",
3064 handler->event_name);
3065 return -1;
3066 }
3067
3068 for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
3069 pj_cstr(&accept[i], handler->accept[i]);
3070 }
3071
3072 pj_cstr(&event, handler->event_name);
3073
3074 pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
3075
3077
3078 return 0;
3079}
static struct ast_sip_subscription_handler * find_sub_handler_for_event_name(const char *event_name)
static void sub_add_handler(struct ast_sip_subscription_handler *handler)
#define DEFAULT_EXPIRES
Default expiration for subscriptions.
#define AST_SIP_MAX_ACCEPT
const char * accept[AST_SIP_MAX_ACCEPT]

References ast_sip_subscription_handler::accept, ast_log, AST_SIP_MAX_ACCEPT, ast_strlen_zero(), DEFAULT_EXPIRES, find_sub_handler_for_event_name(), handler(), LOG_ERROR, pubsub_module, and sub_add_handler().

Referenced by load_module().

◆ ast_sip_subscription_add_datastore()

int ast_sip_subscription_add_datastore ( struct ast_sip_subscription subscription,
struct ast_datastore datastore 
)

Add a datastore to a SIP subscription.

Note that SIP uses reference counted datastores. The datastore passed into this function must have been allocated using ao2_alloc() or there will be serious problems.

Parameters
subscriptionThe ssubscription to add the datastore to
datastoreThe datastore to be added to the subscription
Return values
0Success
-1Failure

Definition at line 2900 of file res_pjsip_pubsub.c.

2901{
2902 return ast_datastores_add(subscription->datastores, datastore);
2903}
struct ao2_container * datastores

References ast_datastores_add(), and ast_sip_subscription::datastores.

Referenced by add_datastore(), and add_mwi_datastore().

◆ ast_sip_subscription_alloc_datastore()

struct ast_datastore * ast_sip_subscription_alloc_datastore ( const struct ast_datastore_info info,
const char *  uid 
)

Alternative for ast_datastore_alloc()

There are two major differences between this and ast_datastore_alloc() 1) This allocates a refcounted object 2) This will fill in a uid if one is not provided

DO NOT call ast_datastore_free() on a datastore allocated in this way since that function will attempt to free the datastore rather than play nicely with its refcount.

Parameters
infoCallbacks for datastore
uidIdentifier for datastore
Return values
NULLFailed to allocate datastore
non-NULLNewly allocated datastore

Definition at line 2895 of file res_pjsip_pubsub.c.

2896{
2898}
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
def info(msg)

References ast_datastores_alloc_datastore(), sip_to_pjsip::info(), and ast_datastore::uid.

Referenced by add_datastore(), and add_mwi_datastore().

◆ ast_sip_subscription_destroy()

void ast_sip_subscription_destroy ( struct ast_sip_subscription sub)

Alert the pubsub core that the subscription is ready for destruction.

Since
13.6.0
Parameters
subThe subscription that is complete

Definition at line 1636 of file res_pjsip_pubsub.c.

1637{
1638 ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1639 sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree);
1640 ao2_cleanup(sub->tree);
1641}
#define ast_debug(level,...)
Log a DEBUG message.

References ao2_cleanup, ast_debug, ast_sorcery_object_get_id(), and sub.

Referenced by exten_state_subscription_destructor(), and mwi_subscription_destructor().

◆ ast_sip_subscription_get_body_subtype()

const char * ast_sip_subscription_get_body_subtype ( struct ast_sip_subscription sub)

Get the body subtype used for this subscription.

Since
13.0.0

Definition at line 3788 of file res_pjsip_pubsub.c.

3789{
3790 return sub->body_generator->subtype;
3791}

References sub.

Referenced by ast_sip_subscription_notify(), generate_initial_notify(), and generate_notify_body().

◆ ast_sip_subscription_get_body_type()

const char * ast_sip_subscription_get_body_type ( struct ast_sip_subscription sub)

Get the body type used for this subscription.

Since
13.0.0

Definition at line 3783 of file res_pjsip_pubsub.c.

3784{
3785 return sub->body_generator->type;
3786}

References sub.

Referenced by ast_sip_subscription_notify(), generate_initial_notify(), and generate_notify_body().

◆ ast_sip_subscription_get_datastore()

struct ast_datastore * ast_sip_subscription_get_datastore ( struct ast_sip_subscription subscription,
const char *  name 
)

Retrieve a subscription datastore.

The datastore retrieved will have its reference count incremented. When the caller is done with the datastore, the reference counted needs to be decremented using ao2_ref().

Parameters
subscriptionThe subscription from which to retrieve the datastore
nameThe name of the datastore to retrieve
Return values
NULLFailed to find the specified datastore
non-NULLThe specified datastore

Definition at line 2905 of file res_pjsip_pubsub.c.

2906{
2907 return ast_datastores_find(subscription->datastores, name);
2908}

References ast_datastores_find(), ast_sip_subscription::datastores, and name.

Referenced by get_exten_state_sub(), mwi_get_notify_data(), mwi_subscription_shutdown(), and mwi_to_ami().

◆ ast_sip_subscription_get_datastores()

struct ao2_container * ast_sip_subscription_get_datastores ( const struct ast_sip_subscription subscription)

Get the datastores container for a subscription.

Parameters
subscriptionThe subscription to get the datastores container from
Return values
NULLdatastores container not present
non-NULLdatastores container
Note
The container is NOT returned with reference count bumped
Since
14.0.0

Definition at line 2915 of file res_pjsip_pubsub.c.

2916{
2917 return subscription->datastores;
2918}

References ast_sip_subscription::datastores.

Referenced by alloc_notify_task_data(), exten_state_data_alloc(), and notify_task().

◆ ast_sip_subscription_get_dialog()

pjsip_dialog * ast_sip_subscription_get_dialog ( struct ast_sip_subscription sub)

Get the pjsip dialog that is associated with this subscription.

Since
13.9.0
Return values
NULLCould not get dialog
non-NULLThe dialog

Definition at line 2178 of file res_pjsip_pubsub.c.

2179{
2180 ast_assert(sub->tree->dlg != NULL);
2181 return sub->tree->dlg;
2182}
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, NULL, and sub.

Referenced by dialog_info_generate_body_content(), mwi_get_notify_data(), and send_mwi_notify().

◆ ast_sip_subscription_get_endpoint()

struct ast_sip_endpoint * ast_sip_subscription_get_endpoint ( struct ast_sip_subscription sub)

Get the endpoint that is associated with this subscription.

This function will increase the reference count of the endpoint. Be sure to release the reference to it when you are finished with the endpoint.

Return values
NULLCould not get endpoint
non-NULLThe endpoint

Definition at line 2184 of file res_pjsip_pubsub.c.

2185{
2186 ast_assert(sub->tree->endpoint != NULL);
2187 return ao2_bump(sub->tree->endpoint);
2188}

References ao2_bump, ast_assert, NULL, and sub.

Referenced by dialog_info_generate_body_content(), mwi_get_notify_data(), mwi_subscription_established(), send_mwi_notify(), and subscription_established().

◆ ast_sip_subscription_get_header()

void * ast_sip_subscription_get_header ( const struct ast_sip_subscription sub,
const char *  header 
)

Get a header value for a subscription.

For notifiers, the headers of the inbound SUBSCRIBE that started the dialog are stored on the subscription. This method allows access to the header. The return is the same as pjsip_msg_find_hdr_by_name(), meaning that it is dependent on the header being searched for.

Parameters
subThe subscription to search in.
headerThe name of the header to search for.
Returns
The discovered header, or NULL if the header cannot be found.

Definition at line 2102 of file res_pjsip_pubsub.c.

2103{
2104 pjsip_dialog *dlg;
2105 pjsip_msg *msg;
2106 pj_str_t name;
2107
2108 dlg = sub->tree->dlg;
2109 msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
2110 pj_cstr(&name, header);
2111
2112 return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
2113}

References ast_sip_mod_data_get, MOD_DATA_MSG, name, NULL, pubsub_module, and sub.

Referenced by get_user_agent().

◆ ast_sip_subscription_get_local_uri()

void ast_sip_subscription_get_local_uri ( struct ast_sip_subscription sub,
char *  buf,
size_t  size 
)

Retrieve the local URI for this subscription.

This is the local URI of the subscribed resource.

Parameters
subThe subscription
[out]bufThe buffer into which to store the URI.
sizeThe size of the buffer.

Definition at line 2849 of file res_pjsip_pubsub.c.

2850{
2851 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2852}

References buf, and sub.

Referenced by build_rlmi_body(), exten_state_data_alloc(), and notify_task().

◆ ast_sip_subscription_get_persistence_data()

const struct ast_json * ast_sip_subscription_get_persistence_data ( const struct ast_sip_subscription subscription)

Retrieve persistence data for a subscription.

Since
13.31.0
16.8.0
17.2.0
Parameters
subscriptionThe subscription to retrieve persistence data from

Definition at line 2957 of file res_pjsip_pubsub.c.

2958{
2959 return subscription->persistence_data;
2960}
struct ast_json * persistence_data

References ast_sip_subscription::persistence_data.

Referenced by dialog_info_generate_body_content().

◆ ast_sip_subscription_get_remote_uri()

void ast_sip_subscription_get_remote_uri ( struct ast_sip_subscription sub,
char *  buf,
size_t  size 
)

Retrive the remote URI for this subscription.

This is the remote URI as determined by the underlying SIP dialog.

Parameters
subThe subscription
[out]bufThe buffer into which to store the URI.
sizeThe size of the buffer.

Definition at line 2854 of file res_pjsip_pubsub.c.

2855{
2856 pjsip_dialog *dlg;
2857 pjsip_sip_uri *uri;
2858
2859 dlg = sub->tree->dlg;
2860 uri = pjsip_uri_get_uri(dlg->remote.info->uri);
2861
2862 if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
2863 *buf = '\0';
2864 }
2865}

References buf, sip_subscription_tree::dlg, and sub.

Referenced by exten_state_data_alloc(), and notify_task().

◆ ast_sip_subscription_get_resource_name()

const char * ast_sip_subscription_get_resource_name ( struct ast_sip_subscription sub)

Get the name of the subscribed resource.

Definition at line 2867 of file res_pjsip_pubsub.c.

2868{
2869 return sub->resource;
2870}

References sub.

Referenced by build_rlmi_body(), mwi_get_notify_data(), mwi_subscription_established(), remove_subscription(), send_mwi_notify(), and subscription_established().

◆ ast_sip_subscription_get_serializer()

struct ast_taskprocessor * ast_sip_subscription_get_serializer ( struct ast_sip_subscription sub)

Get the serializer for the subscription.

Tasks that originate outside of a SIP servant thread should get the serializer and push the task to the serializer.

Parameters
subThe subscription
Return values
NULLFailure
non-NULLThe subscription's serializer

Definition at line 2190 of file res_pjsip_pubsub.c.

2191{
2192 ast_assert(sub->tree->serializer != NULL);
2193 return sub->tree->serializer;
2194}

References ast_assert, NULL, and sub.

Referenced by exten_state_subscription_alloc(), and send_notify().

◆ ast_sip_subscription_get_sip_uri()

pjsip_sip_uri * ast_sip_subscription_get_sip_uri ( struct ast_sip_subscription sub)

Retrieve the local sip uri for this subscription.

Since
13.9.0

This is the local sip URI of the subscribed resource.

Parameters
subThe subscription
Return values
NULLCould not get uri
non-NULLThe local pjsip_sip_uri

Definition at line 2844 of file res_pjsip_pubsub.c.

2845{
2846 return sub->uri;
2847}

References sub.

Referenced by mwi_get_notify_data(), and send_mwi_notify().

◆ ast_sip_subscription_is_terminated()

int ast_sip_subscription_is_terminated ( const struct ast_sip_subscription sub)

Get whether the subscription has been terminated or not.

Parameters
subThe subscription.
Return values
0not terminated.
1terminated.
Since
13.4.0

Definition at line 2872 of file res_pjsip_pubsub.c.

2873{
2874 return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2875}

References sub.

Referenced by notify_task(), and state_changed().

◆ ast_sip_subscription_notify()

int ast_sip_subscription_notify ( struct ast_sip_subscription sub,
struct ast_sip_body_data notify_data,
int  terminate 
)

Notify a SIP subscription of a state change.

This tells the pubsub core that the state of a subscribed resource has changed. The pubsub core will generate an appropriate NOTIFY request to send to the subscriber.

Parameters
subThe subscription on which a state change is occurring.
notify_dataEvent package-specific data used to create the NOTIFY body.
terminateTrue if this NOTIFY is intended to terminate the subscription.
Return values
0Success
non-zeroFailure

Definition at line 2800 of file res_pjsip_pubsub.c.

2802{
2803 int res;
2804 pjsip_dialog *dlg = sub->tree->dlg;
2805
2806 pjsip_dlg_inc_lock(dlg);
2807
2808 if (sub->tree->state != SIP_SUB_TREE_NORMAL) {
2809 pjsip_dlg_dec_lock(dlg);
2810 return 0;
2811 }
2812
2815 pjsip_dlg_dec_lock(dlg);
2816 return -1;
2817 }
2818
2819 sub->body_changed = 1;
2820 if (terminate) {
2821 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2822 sub->tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
2823 }
2824
2825 if (sub->tree->notification_batch_interval) {
2826 res = schedule_notification(sub->tree);
2827 } else {
2828 /* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */
2829 ao2_ref(sub->tree, +1);
2830 if (terminate) {
2832 }
2833 res = send_notify(sub->tree, 0);
2834 ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2835 "Resource: %s",
2836 sub->tree->root->resource);
2837 ao2_ref(sub->tree, -1);
2838 }
2839
2840 pjsip_dlg_dec_lock(dlg);
2841 return res;
2842}
const char * ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
Get the body type used for this subscription.
static int schedule_notification(struct sip_subscription_tree *sub_tree)
const char * ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub)
Get the body subtype used for this subscription.
static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
Send a NOTIFY request to a subscriber.
int ast_sip_pubsub_generate_body_content(const char *type, const char *subtype, struct ast_sip_body_data *data, struct ast_str **str)
Generate body content for a PUBLISH or NOTIFY.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189

References ao2_ref, ast_sip_pubsub_generate_body_content(), ast_sip_subscription_get_body_subtype(), ast_sip_subscription_get_body_type(), ast_test_suite_event_notify, sip_subscription_tree::dlg, schedule_notification(), send_notify(), SIP_SUB_TREE_NORMAL, SIP_SUB_TREE_TERMINATE_IN_PROGRESS, SIP_SUB_TREE_TERMINATE_PENDING, and sub.

Referenced by notify_task(), and send_mwi_notify().

◆ ast_sip_subscription_remove_datastore()

void ast_sip_subscription_remove_datastore ( struct ast_sip_subscription subscription,
const char *  name 
)

Remove a subscription datastore from the subscription.

This operation may cause the datastore's free() callback to be called if the reference count reaches zero.

Parameters
subscriptionThe subscription to remove the datastore from
nameThe name of the datastore to remove

Definition at line 2910 of file res_pjsip_pubsub.c.

2911{
2912 ast_datastores_remove(subscription->datastores, name);
2913}

References ast_datastores_remove(), ast_sip_subscription::datastores, and name.

Referenced by mwi_subscription_established(), mwi_subscription_shutdown(), and subscription_shutdown().

◆ ast_sip_subscription_set_persistence_data()

void ast_sip_subscription_set_persistence_data ( struct ast_sip_subscription subscription,
struct ast_json persistence_data 
)

Set persistence data for a subscription.

Since
13.31.0
16.8.0
17.2.0
Parameters
subscriptionThe subscription to set persistence data on
persistence_dataThe persistence data to set
Note
This steals the reference to persistence_data

Definition at line 2940 of file res_pjsip_pubsub.c.

2941{
2942 ast_json_unref(subscription->persistence_data);
2943 subscription->persistence_data = persistence_data;
2944
2945 if (subscription->tree->persistence) {
2946 if (!subscription->tree->persistence->generator_data) {
2948 if (!subscription->tree->persistence->generator_data) {
2949 return;
2950 }
2951 }
2952 ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
2953 ast_json_ref(persistence_data));
2954 }
2955}
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_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:399
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

References ast_json_object_create(), ast_json_object_set(), ast_json_ref(), ast_json_unref(), subscription_persistence::generator_data, sip_subscription_tree::persistence, ast_sip_subscription::persistence_data, ast_sip_subscription::resource, and ast_sip_subscription::tree.

Referenced by dialog_info_generate_body_content().

◆ ast_sip_unregister_publish_handler()

void ast_sip_unregister_publish_handler ( struct ast_sip_publish_handler handler)

Unregister a publish handler.

Definition at line 3009 of file res_pjsip_pubsub.c.

3010{
3011 struct ast_sip_publish_handler *iter;
3012
3015 if (handler == iter) {
3017 ao2_cleanup(handler->publications);
3018 break;
3019 }
3020 }
3023}
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
Callbacks that publication handlers will define.
struct ast_sip_publish_handler * next

References ao2_cleanup, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, handler(), and ast_sip_publish_handler::next.

Referenced by load_module(), and unload_module().

◆ ast_sip_unregister_subscription_handler()

void ast_sip_unregister_subscription_handler ( struct ast_sip_subscription_handler handler)

◆ build_body_part()

static void build_body_part ( pj_pool_t *  pool,
struct ast_sip_subscription sub,
struct body_part_list parts,
unsigned int  use_full_state 
)
static

Create a multipart body part for a subscribed resource.

Parameters
poolPJLIB allocation pool
subThe subscription representing a subscribed resource
partsA vector of parts to append the created part to.
use_full_stateUnused locally, but may be passed to other functions

Definition at line 2512 of file res_pjsip_pubsub.c.

2514{
2515 struct body_part *bp;
2516 pjsip_msg_body *body;
2517
2518 bp = allocate_body_part(pool, sub);
2519 if (!bp) {
2520 return;
2521 }
2522
2523 body = generate_notify_body(pool, sub, use_full_state);
2524 if (!body) {
2525 /* Partial state was requested and the resource has not changed state */
2526 ast_free(bp);
2527 return;
2528 }
2529
2530 bp->part = pjsip_multipart_create_part(pool);
2531 bp->part->body = body;
2532 pj_list_insert_before(&bp->part->hdr, bp->cid);
2533
2534 if (AST_VECTOR_APPEND(parts, bp)) {
2535 ast_free(bp);
2536 }
2537}
static pjsip_msg_body * generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root, unsigned int force_full_state)
Create the body for a NOTIFY request.
static struct body_part * allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
Allocate and initialize a body part structure.
pjsip_multipart_part * part
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256

References allocate_body_part(), ast_free, AST_VECTOR_APPEND, body_part::cid, generate_notify_body(), body_part::part, and sub.

Referenced by generate_list_body().

◆ build_node_children()

static void build_node_children ( struct ast_sip_endpoint endpoint,
const struct ast_sip_subscription_handler handler,
struct resource_list list,
struct tree_node parent,
struct resources visited,
pjsip_rx_data *  rdata 
)
static

Build child nodes for a given parent.

This iterates through the items on a resource list and creates tree nodes for each one. The tree nodes created are children of the supplied parent node. If an item in the resource list is itself a list, then this function is called recursively to provide children for the new node.

If an item in a resource list is not a list, then the supplied subscription handler is called into as if a new SUBSCRIBE for the list item were presented. The handler's response is used to determine if the node can be added to the tree or not.

If a parent node ends up having no child nodes added under it, then the parent node is pruned from the tree.

Parameters
endpointThe endpoint that sent the inbound SUBSCRIBE.
handlerThe subscription handler for leaf nodes in the tree.
listThe configured resource list from which the child node is being built.
parentThe parent node for these children.
visitedThe resources that have already been visited.

Definition at line 1251 of file res_pjsip_pubsub.c.

1253{
1254 int i;
1255
1256 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
1257 struct tree_node *current;
1258 struct resource_list *child_list;
1259 const char *resource = AST_VECTOR_GET(&list->items, i);
1260
1261 if (have_visited(resource, visited)) {
1262 ast_debug(1, "Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1263 continue;
1264 }
1265
1266 child_list = retrieve_resource_list(resource, list->event);
1267 if (!child_list) {
1268 int resp = NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
1269 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1270 char display_name[AST_MAX_EXTENSION] = "";
1271 if (list->resource_display_name && handler->notifier->get_resource_display_name) {
1272 handler->notifier->get_resource_display_name(endpoint, resource, display_name, sizeof(display_name));
1273 }
1274 current = tree_node_alloc(resource, visited, 0, ast_strlen_zero(display_name) ? NULL : display_name);
1275 if (!current) {
1276 ast_debug(1,
1277 "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1278 resource);
1279 continue;
1280 }
1281 ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1282 resource, parent->resource);
1283 if (AST_VECTOR_APPEND(&parent->children, current)) {
1285 }
1286 } else {
1287 ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n",
1288 resource, resp);
1289 }
1290 } else {
1291 ast_debug(2, "Resource %s (child of %s) is a list\n", resource, parent->resource);
1292 current = tree_node_alloc(resource, visited, child_list->full_state, NULL);
1293 if (!current) {
1294 ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
1295 continue;
1296 }
1297 build_node_children(endpoint, handler, child_list, current, visited, rdata);
1298 if (AST_VECTOR_SIZE(&current->children) > 0) {
1299 ast_debug(1, "List %s had no successful children.\n", resource);
1300 if (AST_VECTOR_APPEND(&parent->children, current)) {
1302 }
1303 } else {
1304 ast_debug(2, "List %s had successful children. Adding to parent %s\n",
1305 resource, parent->resource);
1307 }
1308 ao2_cleanup(child_list);
1309 }
1310 }
1311}
#define AST_MAX_EXTENSION
Definition: channel.h:134
size_t current
#define NEW_SUBSCRIBE(notifier, endpoint, resource, rdata)
static int have_visited(const char *resource, struct resources *visited)
Determine if this resource has been visited already.
static void build_node_children(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler, struct resource_list *list, struct tree_node *parent, struct resources *visited, pjsip_rx_data *rdata)
Build child nodes for a given parent.
static void tree_node_destroy(struct tree_node *node)
Destructor for a tree node.
static struct tree_node * tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state, const char *display_name)
Allocate a tree node.
static struct resource_list * retrieve_resource_list(const char *resource, const char *event)
Helper function for retrieving a resource list for a given event.
unsigned int full_state
struct resources items
unsigned int resource_display_name
A node for a resource tree.
struct tree_node::@467 children
char resource[0]
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References ao2_cleanup, ast_debug, AST_MAX_EXTENSION, ast_strlen_zero(), AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_SIZE, build_node_children(), tree_node::children, current, resource_list::event, resource_list::full_state, handler(), have_visited(), resource_list::items, NEW_SUBSCRIBE, NULL, tree_node::resource, resource_list::resource_display_name, retrieve_resource_list(), tree_node_alloc(), and tree_node_destroy().

Referenced by build_node_children(), and build_resource_tree().

◆ build_resource_tree()

static int build_resource_tree ( struct ast_sip_endpoint endpoint,
const struct ast_sip_subscription_handler handler,
const char *  resource,
struct resource_tree tree,
int  has_eventlist_support,
pjsip_rx_data *  rdata 
)
static

Build a resource tree.

This function builds a resource tree based on the requested resource in a SUBSCRIBE request.

This function also creates a container that has all resources that have been visited during creation of the tree, whether those resources resulted in a tree node being created or not. Keeping this container of visited resources allows for misconfigurations such as loops in the tree or duplicated resources to be detected.

Parameters
endpointThe endpoint that sent the SUBSCRIBE request.
handlerThe subscription handler for leaf nodes in the tree.
resourceThe resource requested in the SUBSCRIBE request.
treeThe tree that is to be built.
has_eventlist_support
Return values
200-299Successfully subscribed to at least one resource.
300-699Failure to subscribe to requested resource.

Definition at line 1369 of file res_pjsip_pubsub.c.

1371{
1372 RAII_VAR(struct resource_list *, list, NULL, ao2_cleanup);
1373 struct resources visited;
1374
1375 int not_eventlist_but_needs_children = !strcmp(handler->body_type, AST_SIP_DEVICE_FEATURE_SYNC_DATA);
1376
1377 if ((!has_eventlist_support && !not_eventlist_but_needs_children) || !(list = retrieve_resource_list(resource, handler->event_name))) {
1378 ast_debug(2, "Subscription '%s->%s' is not to a list\n",
1379 ast_sorcery_object_get_id(endpoint), resource);
1380 tree->root = tree_node_alloc(resource, NULL, 0, NULL);
1381 if (!tree->root) {
1382 return 500;
1383 }
1384 return NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
1385 }
1386
1387 ast_debug(2, "Subscription '%s->%s' is a list\n",
1388 ast_sorcery_object_get_id(endpoint), resource);
1389 if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
1390 return 500;
1391 }
1392
1393 tree->root = tree_node_alloc(resource, &visited, list->full_state, NULL);
1394 if (!tree->root) {
1395 AST_VECTOR_FREE(&visited);
1396 return 500;
1397 }
1398
1399 tree->notification_batch_interval = list->notification_batch_interval;
1400
1401 build_node_children(endpoint, handler, list, tree->root, &visited, rdata);
1402 AST_VECTOR_FREE(&visited);
1403
1404 if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
1405 return 200;
1406 } else {
1407 return 500;
1408 }
1409}
#define AST_SIP_DEVICE_FEATURE_SYNC_DATA
struct tree_node * root
unsigned int notification_batch_interval
A vector of strings commonly used throughout this module.
#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
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

References ao2_cleanup, ast_debug, AST_SIP_DEVICE_FEATURE_SYNC_DATA, ast_sorcery_object_get_id(), AST_VECTOR_FREE, AST_VECTOR_INIT, AST_VECTOR_SIZE, build_node_children(), tree_node::children, handler(), NEW_SUBSCRIBE, resource_tree::notification_batch_interval, NULL, RAII_VAR, retrieve_resource_list(), resource_tree::root, and tree_node_alloc().

Referenced by pubsub_on_rx_refresh(), pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

◆ build_rlmi_body()

static pjsip_multipart_part * build_rlmi_body ( pj_pool_t *  pool,
struct ast_sip_subscription sub,
struct body_part_list body_parts,
unsigned int  full_state 
)
static

Create an RLMI body part for a multipart resource list body.

RLMI (Resource list meta information) is a special body type that lists the subscribed resources and tells subscribers the number of subscribed resources and what other body parts are in the multipart body. The RLMI body also has a version number that a subscriber can use to ensure that the locally-stored state corresponds to server state.

Parameters
poolThe allocation pool
subThe subscription representing the subscribed resource list
body_partsA container of body parts that RLMI will refer to
full_stateIndicates whether this is a full or partial state notification
Returns
The multipart part representing the RLMI body

Definition at line 2415 of file res_pjsip_pubsub.c.

2417{
2418 pj_xml_node *rlmi;
2419 pj_xml_node *name;
2420 pjsip_multipart_part *rlmi_part;
2421 char version_str[32];
2422 char uri[PJSIP_MAX_URL_SIZE];
2423 pjsip_generic_string_hdr *cid;
2424 int i;
2425
2426 rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
2427 ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
2428
2429 ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
2430 ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
2431
2432 snprintf(version_str, sizeof(version_str), "%u", sub->version++);
2433 ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
2434 ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
2435
2436 name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
2437 pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
2438
2439 for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
2440 const struct body_part *part = AST_VECTOR_GET(body_parts, i);
2441
2442 add_rlmi_resource(pool, rlmi, part->cid, S_OR(part->display_name, part->resource), part->uri, part->state);
2443 }
2444
2445 rlmi_part = pjsip_multipart_create_part(pool);
2446
2447 rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2448 pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &rlmi_media_type);
2449
2450 rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2451 rlmi_part->body->clone_data = rlmi_clone_data;
2452 rlmi_part->body->print_body = rlmi_print_body;
2453
2455 pj_list_insert_before(&rlmi_part->hdr, cid);
2456
2457 return rlmi_part;
2458}
static void * rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
const char * ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
Get the name of the subscribed resource.
static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid, const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
Add a resource XML element to an RLMI body.
static pjsip_media_type rlmi_media_type
void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
Retrieve the local URI for this subscription.
#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

References add_rlmi_resource(), ast_sip_presence_xml_create_attr(), ast_sip_presence_xml_create_node(), ast_sip_subscription_get_local_uri(), ast_sip_subscription_get_resource_name(), AST_VECTOR_GET, AST_VECTOR_SIZE, body_part::cid, generate_content_id_hdr(), name, NULL, body_part::part, rlmi_clone_data(), rlmi_media_type, rlmi_print_body(), S_OR, and sub.

Referenced by generate_list_body().

◆ clean_sub_tree()

static void clean_sub_tree ( pjsip_evsub *  evsub)
static

Callback sequence for subscription terminate:

  • Please note that the descriptions below represent pjproject behavior on versions >= 2.13.
  • Client initiated: pjproject receives SUBSCRIBE on the subscription's serializer thread calls pubsub_evsub_set_state with state = TERMINATED pubsub_on_evsub_state checks the event and finds it is due to a received SUBSCRIBE with an expires of 0 and so does nothing. calls pubsub_on_rx_refresh with dialog locked pubsub_on_rx_refresh sets TERMINATE_PENDING calls pubsub_on_refresh_timeout to push final NOTIFY to pjproject checks state == TERMINATE_PENDING sets TERMINATE_IN_PROGRESS calls send_notify (2) send_notify ultimately calls pjsip_evsub_send_request pjsip_evsub_send_request calls evsub's set_state set_state calls pubsub_evsub_set_state pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS removes the subscriptions cleans up references to evsub sets state = TERMINATED pubsub_on_refresh_timeout unlocks dialog returns to pjproject pjproject unlocks dialog
  • Subscription timer expires: pjproject timer expires locks dialog calls pubsub_on_server_timeout pubsub_on_server_timeout checks state == NORMAL sets TERMINATE_PENDING pushes serialized_pubsub_on_refresh_timeout returns to pjproject pjproject unlocks dialog serialized_pubsub_on_refresh_timeout starts (1) locks dialog checks state == TERMINATE_PENDING sets TERMINATE_IN_PROGRESS calls send_notify (2) send_notify ultimately calls pjsip_evsub_send_request pjsip_evsub_send_request calls evsub's set_state set_state calls pubsub_evsub_set_state pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS checks that the event is not due to un-SUBSCRIBE removes the subscriptions cleans up references to evsub sets state = TERMINATED serialized_pubsub_on_refresh_timeout unlocks dialog
  • Transmission failure sending NOTIFY or error response from client pjproject transaction timer expires or non OK response pjproject locks dialog calls pubsub_on_evsub_state with event TSX_STATE pubsub_on_evsub_state checks event == TSX_STATE removes the subscriptions cleans up references to evsub sets state = TERMINATED pjproject unlocks dialog
  • ast_sip_subscription_notify is called checks state == NORMAL if not batched... sets TERMINATE_IN_PROGRESS (if terminate is requested) calls send_notify See (2) Above if batched... sets TERMINATE_PENDING schedules task scheduler runs sched_task sched_task pushes serialized_send_notify serialized_send_notify starts checks state <= TERMINATE_PENDING if state == TERMINATE_PENDING set state = TERMINATE_IN_PROGRESS call send_notify See (2) Above

Definition at line 4076 of file res_pjsip_pubsub.c.

4077{
4078
4079 struct sip_subscription_tree *sub_tree;
4080 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4081
4082 ast_debug(3, "Cleaning subscription %p\n", evsub);
4083
4084 if (sub_tree->expiration_task) {
4085 char task_name[256];
4086
4087 ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
4088 ast_debug(3, "Cancelling timer: %s\n", task_name);
4090 ao2_cleanup(sub_tree->expiration_task);
4091 sub_tree->expiration_task = NULL;
4092 }
4093
4094 remove_subscription(sub_tree);
4095
4096 pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
4097
4098#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
4099 pjsip_evsub_dec_ref(sub_tree->evsub);
4100#endif
4101
4102 sub_tree->evsub = NULL;
4103
4106
4108 shutdown_subscriptions(sub_tree->root);
4109
4110 sub_tree->state = SIP_SUB_TREE_TERMINATED;
4111 /* Remove evsub's reference to the sub_tree */
4112 ao2_ref(sub_tree, -1);
4113}
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.
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
Gets the task name.
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.
static void shutdown_subscriptions(struct ast_sip_subscription *sub)
static void remove_subscription(struct sip_subscription_tree *obj)
static void subscription_persistence_remove(struct sip_subscription_tree *sub_tree)
Function which removes persistence of a subscription from sorcery.
enum sip_subscription_tree_state state
struct ast_sip_subscription * root
struct ast_sip_sched_task * expiration_task

References ao2_cleanup, ao2_ref, ast_debug, ast_sip_dialog_set_endpoint(), ast_sip_dialog_set_serializer(), ast_sip_sched_task_cancel(), ast_sip_sched_task_get_name(), sip_subscription_tree::dlg, sip_subscription_tree::evsub, sip_subscription_tree::expiration_task, NULL, pubsub_module, remove_subscription(), sip_subscription_tree::root, shutdown_subscriptions(), SIP_SUB_TREE_TERMINATED, sip_subscription_tree::state, and subscription_persistence_remove().

Referenced by pubsub_on_evsub_state().

◆ cli_complete_subscription_callid()

static char * cli_complete_subscription_callid ( struct ast_cli_args a)
static

Definition at line 4639 of file res_pjsip_pubsub.c.

4640{
4642 on_subscription_t on_subscription;
4643
4644 if (a->pos != 4) {
4645 return NULL;
4646 }
4647
4648 if (!strcasecmp(a->argv[3], "inbound")) {
4649 on_subscription = cli_complete_subscription_inbound;
4650 } else if (!strcasecmp(a->argv[3], "outbound")) {
4651 on_subscription = cli_complete_subscription_outbound;
4652 } else {
4653 /* Should never get here */
4654 ast_assert(0);
4655 return NULL;
4656 }
4657
4658 cli.a = a;
4659 cli.callid = NULL;
4660 cli.wordlen = strlen(a->word);
4661 cli.which = 0;
4662 for_each_subscription(on_subscription, &cli);
4663
4664 return cli.callid;
4665}
static struct ast_cli_entry cli[]
Definition: codec_dahdi.c:265
int(* on_subscription_t)(struct sip_subscription_tree *sub, void *arg)
static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
static struct test_val a

References a, ast_assert, cli, cli_complete_subscription_inbound(), cli_complete_subscription_outbound(), for_each_subscription(), and NULL.

Referenced by cli_show_subscription_inout().

◆ cli_complete_subscription_common()

static int cli_complete_subscription_common ( struct sip_subscription_tree sub_tree,
struct cli_sub_complete_parms cli 
)
static

Definition at line 4606 of file res_pjsip_pubsub.c.

4607{
4608 pj_str_t *callid;
4609
4610 if (!sub_tree->dlg) {
4611 return 0;
4612 }
4613
4614 callid = &sub_tree->dlg->call_id->id;
4615 if (cli->wordlen <= pj_strlen(callid)
4616 && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
4617 && (++cli->which > cli->a->n)) {
4618 cli->callid = ast_malloc(pj_strlen(callid) + 1);
4619 if (cli->callid) {
4620 ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
4621 }
4622 return -1;
4623 }
4624 return 0;
4625}
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201

References ast_copy_pj_str(), ast_malloc, cli, and sip_subscription_tree::dlg.

Referenced by cli_complete_subscription_inbound(), and cli_complete_subscription_outbound().

◆ cli_complete_subscription_inbound()

static int cli_complete_subscription_inbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 4627 of file res_pjsip_pubsub.c.

4628{
4629 return sub_tree->role == AST_SIP_NOTIFIER
4630 ? cli_complete_subscription_common(sub_tree, arg) : 0;
4631}
static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)

References AST_SIP_NOTIFIER, cli_complete_subscription_common(), and sip_subscription_tree::role.

Referenced by cli_complete_subscription_callid().

◆ cli_complete_subscription_outbound()

static int cli_complete_subscription_outbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 4633 of file res_pjsip_pubsub.c.

4634{
4635 return sub_tree->role == AST_SIP_SUBSCRIBER
4636 ? cli_complete_subscription_common(sub_tree, arg) : 0;
4637}

References AST_SIP_SUBSCRIBER, cli_complete_subscription_common(), and sip_subscription_tree::role.

Referenced by cli_complete_subscription_callid().

◆ cli_list_subscriptions_detail()

static int cli_list_subscriptions_detail ( struct sip_subscription_tree sub_tree,
struct cli_sub_parms cli 
)
static

Definition at line 4970 of file res_pjsip_pubsub.c.

4971{
4972 char ep_cid_buf[50];
4973 char res_evt_buf[50];
4974 char callid[256];
4975
4976 /* Endpoint/CID column */
4977 snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s",
4979 S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str,
4980 S_COR(sub_tree->endpoint->id.self.number.valid,
4981 sub_tree->endpoint->id.self.number.str, "<none>")));
4982
4983 /* Resource/Event column */
4984 snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s",
4985 sub_tree->root->resource,
4986 sub_tree->root->handler->event_name);
4987
4988 /* Call-id column */
4989 if (sub_tree->dlg) {
4990 ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4991 } else {
4992 ast_copy_string(callid, "<unknown>", sizeof(callid));
4993 }
4994
4996 ep_cid_buf,
4997 res_evt_buf,
4998 cli_subscription_expiry(sub_tree),
4999 callid);
5000
5001 if (cli->like) {
5002 if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
5003 /* Output line did not match the regex */
5004 return 0;
5005 }
5006 }
5007
5008 ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
5009 ++cli->count;
5010
5011 return 0;
5012}
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
#define CLI_LIST_SUB_FORMAT_ENTRY
#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
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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
struct ast_party_name name
Subscriber name.
Definition: channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:281
char * str
Subscriber name (Malloced)
Definition: channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:299
char * str
Subscriber phone number (Malloced)
Definition: channel.h:293
struct ast_party_id self
Definition: res_pjsip.h:860
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:1090
const struct ast_sip_subscription_handler * handler

References ast_cli(), ast_copy_pj_str(), ast_copy_string(), ast_sorcery_object_get_id(), ast_str_buffer(), ast_str_set(), cli, CLI_LIST_SUB_FORMAT_ENTRY, cli_subscription_expiry(), sip_subscription_tree::dlg, sip_subscription_tree::endpoint, ast_sip_subscription_handler::event_name, ast_sip_subscription::handler, ast_sip_endpoint::id, ast_party_id::name, NULL, ast_party_id::number, ast_sip_subscription::resource, sip_subscription_tree::root, S_COR, ast_sip_endpoint_id_configuration::self, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

Referenced by cli_list_subscriptions_inbound(), and cli_list_subscriptions_outbound().

◆ cli_list_subscriptions_inbound()

static int cli_list_subscriptions_inbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 5014 of file res_pjsip_pubsub.c.

5015{
5016 return sub_tree->role == AST_SIP_NOTIFIER
5017 ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
5018}
static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

References AST_SIP_NOTIFIER, cli_list_subscriptions_detail(), and sip_subscription_tree::role.

Referenced by cli_list_subscriptions_inout().

◆ cli_list_subscriptions_inout()

static char * cli_list_subscriptions_inout ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 5026 of file res_pjsip_pubsub.c.

5027{
5028 on_subscription_t on_subscription;
5029 struct cli_sub_parms cli;
5030 regex_t like;
5031 const char *regex;
5032
5033 switch (cmd) {
5034 case CLI_INIT:
5035 e->command = "pjsip list subscriptions {inbound|outbound} [like]";
5036 e->usage = "Usage:\n"
5037 " pjsip list subscriptions inbound [like <regex>]\n"
5038 " List active inbound subscriptions\n"
5039 " pjsip list subscriptions outbound [like <regex>]\n"
5040 " List active outbound subscriptions\n"
5041 "\n"
5042 " The regex selects output lines that match.\n";
5043 return NULL;
5044 case CLI_GENERATE:
5045 return NULL;
5046 }
5047
5048 if (a->argc != 4 && a->argc != 6) {
5049 return CLI_SHOWUSAGE;
5050 }
5051 if (!strcasecmp(a->argv[3], "inbound")) {
5052 on_subscription = cli_list_subscriptions_inbound;
5053 } else if (!strcasecmp(a->argv[3], "outbound")) {
5054 on_subscription = cli_list_subscriptions_outbound;
5055 } else {
5056 /* Should never get here */
5057 ast_assert(0);
5058 return CLI_SHOWUSAGE;
5059 }
5060 if (a->argc == 6) {
5061 int rc;
5062
5063 if (strcasecmp(a->argv[4], "like")) {
5064 return CLI_SHOWUSAGE;
5065 }
5066
5067 /* Setup regular expression */
5068 memset(&like, 0, sizeof(like));
5069 cli.like = &like;
5070 regex = a->argv[5];
5071 rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
5072 if (rc) {
5073 char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
5074
5075 regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
5076 ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
5077 regex, regerr);
5078 return CLI_FAILURE;
5079 }
5080 } else {
5081 cli.like = NULL;
5082 regex = NULL;
5083 }
5084
5085 cli.a = a;
5086 cli.e = e;
5087 cli.count = 0;
5088 cli.buf = ast_str_create(256);
5089 if (!cli.buf) {
5090 if (cli.like) {
5091 regfree(cli.like);
5092 }
5093 return CLI_FAILURE;
5094 }
5095
5097 "Endpoint/CLI", "Resource/Event", "Expiry", "Call-id");
5098 for_each_subscription(on_subscription, &cli);
5099 ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n",
5100 cli.count,
5101 regex ? " matched \"" : "",
5102 regex ?: "",
5103 regex ? "\"" : "");
5104
5105 ast_free(cli.buf);
5106 if (cli.like) {
5107 regfree(cli.like);
5108 }
5109
5110 return CLI_SUCCESS;
5111}
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
#define MAX_REGEX_ERROR_LEN
static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
#define CLI_LIST_SUB_FORMAT_HEADER
static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
struct ast_cli_entry * e

References a, ast_alloca, ast_assert, ast_cli(), ast_free, ast_str_create, cli, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_LIST_SUB_FORMAT_HEADER, cli_list_subscriptions_inbound(), cli_list_subscriptions_outbound(), CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, cli_sub_parms::e, for_each_subscription(), cli_sub_parms::like, MAX_REGEX_ERROR_LEN, NULL, regex(), and ast_cli_entry::usage.

◆ cli_list_subscriptions_outbound()

static int cli_list_subscriptions_outbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 5020 of file res_pjsip_pubsub.c.

5021{
5022 return sub_tree->role == AST_SIP_SUBSCRIBER
5023 ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
5024}

References AST_SIP_SUBSCRIBER, cli_list_subscriptions_detail(), and sip_subscription_tree::role.

Referenced by cli_list_subscriptions_inout().

◆ cli_show_subscription_common()

static int cli_show_subscription_common ( struct sip_subscription_tree sub_tree,
struct cli_sub_parms cli 
)
static

Definition at line 4681 of file res_pjsip_pubsub.c.

4682{
4683 const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
4684 pj_str_t *sub_callid;
4685 struct ast_str *buf;
4686 char *src;
4687 char *dest;
4688 char *key;
4689 char *value;
4690 char *value_end;
4691 int key_len;
4692 int key_filler_width;
4693 int value_len;
4694
4695 if (!sub_tree->dlg) {
4696 return 0;
4697 }
4698 sub_callid = &sub_tree->dlg->call_id->id;
4699 if (pj_strcmp2(sub_callid, callid)) {
4700 return 0;
4701 }
4702
4703 buf = ast_str_create(512);
4704 if (!buf) {
4705 return -1;
4706 }
4707
4708 ast_cli(cli->a->fd,
4709 "%-20s: %s\n"
4710 "===========================================================================\n",
4711 "ParameterName", "ParameterValue");
4712
4713 ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
4714 ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
4715 ast_str_append(&buf, 0, "Expiry: %u\n", cli_subscription_expiry(sub_tree));
4716
4717 sip_subscription_to_ami(sub_tree, &buf);
4718
4719 /* Convert AMI \r\n to \n line terminators. */
4720 src = strchr(ast_str_buffer(buf), '\r');
4721 if (src) {
4722 dest = src;
4723 ++src;
4724 while (*src) {
4725 if (*src == '\r') {
4726 ++src;
4727 continue;
4728 }
4729 *dest++ = *src++;
4730 }
4731 *dest = '\0';
4733 }
4734
4735 /* Reformat AMI key value pairs to pretty columns */
4736 key = ast_str_buffer(buf);
4737 do {
4738 value = strchr(key, ':');
4739 if (!value) {
4740 break;
4741 }
4742 value_end = strchr(value, '\n');
4743 if (!value_end) {
4744 break;
4745 }
4746
4747 /* Calculate field lengths */
4748 key_len = value - key;
4749 key_filler_width = 20 - key_len;
4750 if (key_filler_width < 0) {
4751 key_filler_width = 0;
4752 }
4753 value_len = value_end - value;
4754
4755 ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
4756 key_len, key, key_filler_width, "",
4757 value_len, value);
4758
4759 key = value_end + 1;
4760 } while (*key);
4761 ast_cli(cli->a->fd, "\n");
4762
4763 ast_free(buf);
4764
4765 return -1;
4766}
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
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
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
int value
Definition: syslog.c:37

References ast_cli(), ast_free, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_update(), buf, cli_sub_complete_parms::callid, cli, cli_subscription_expiry(), sip_subscription_tree::dlg, ast_sip_subscription_handler::event_name, ast_sip_subscription::handler, if(), ast_sip_subscription::resource, sip_subscription_tree::root, sip_subscription_to_ami(), and value.

Referenced by cli_show_subscription_inbound(), and cli_show_subscription_outbound().

◆ cli_show_subscription_inbound()

static int cli_show_subscription_inbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 4768 of file res_pjsip_pubsub.c.

4769{
4770 return sub_tree->role == AST_SIP_NOTIFIER
4771 ? cli_show_subscription_common(sub_tree, arg) : 0;
4772}
static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

References AST_SIP_NOTIFIER, cli_show_subscription_common(), and sip_subscription_tree::role.

Referenced by cli_show_subscription_inout().

◆ cli_show_subscription_inout()

static char * cli_show_subscription_inout ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 4780 of file res_pjsip_pubsub.c.

4781{
4782 on_subscription_t on_subscription;
4783 struct cli_sub_parms cli;
4784
4785 switch (cmd) {
4786 case CLI_INIT:
4787 e->command = "pjsip show subscription {inbound|outbound}";
4788 e->usage = "Usage:\n"
4789 " pjsip show subscription inbound <call-id>\n"
4790 " pjsip show subscription outbound <call-id>\n"
4791 " Show active subscription with the dialog call-id\n";
4792 return NULL;
4793 case CLI_GENERATE:
4795 }
4796
4797 if (a->argc != 5) {
4798 return CLI_SHOWUSAGE;
4799 }
4800
4801 if (!strcasecmp(a->argv[3], "inbound")) {
4802 on_subscription = cli_show_subscription_inbound;
4803 } else if (!strcasecmp(a->argv[3], "outbound")) {
4804 on_subscription = cli_show_subscription_outbound;
4805 } else {
4806 /* Should never get here */
4807 ast_assert(0);
4808 return NULL;
4809 }
4810
4811 /* Find the subscription with the specified call-id */
4812 cli.a = a;
4813 cli.e = e;
4814 cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */
4815 for_each_subscription(on_subscription, &cli);
4816
4817 return CLI_SUCCESS;
4818}
static char * cli_complete_subscription_callid(struct ast_cli_args *a)
static int cli_show_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)

References a, ast_assert, cli, cli_complete_subscription_callid(), CLI_GENERATE, CLI_INIT, cli_show_subscription_inbound(), cli_show_subscription_outbound(), CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, cli_sub_parms::e, for_each_subscription(), NULL, and ast_cli_entry::usage.

◆ cli_show_subscription_outbound()

static int cli_show_subscription_outbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 4774 of file res_pjsip_pubsub.c.

4775{
4776 return sub_tree->role == AST_SIP_SUBSCRIBER
4777 ? cli_show_subscription_common(sub_tree, arg) : 0;
4778}

References AST_SIP_SUBSCRIBER, cli_show_subscription_common(), and sip_subscription_tree::role.

Referenced by cli_show_subscription_inout().

◆ cli_show_subscriptions_detail()

static int cli_show_subscriptions_detail ( struct sip_subscription_tree sub_tree,
struct cli_sub_parms cli 
)
static

Definition at line 4830 of file res_pjsip_pubsub.c.

4831{
4832 char caller_id[256];
4833 char callid[256];
4834
4835 ast_callerid_merge(caller_id, sizeof(caller_id),
4836 S_COR(sub_tree->endpoint->id.self.name.valid,
4837 sub_tree->endpoint->id.self.name.str, NULL),
4838 S_COR(sub_tree->endpoint->id.self.number.valid,
4839 sub_tree->endpoint->id.self.number.str, NULL),
4840 "<none>");
4841
4842 /* Call-id */
4843 if (sub_tree->dlg) {
4844 ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4845 } else {
4846 ast_copy_string(callid, "<unknown>", sizeof(callid));
4847 }
4848
4850 ast_sorcery_object_get_id(sub_tree->endpoint), caller_id,
4851 sub_tree->root->resource, sub_tree->root->handler->event_name,
4852 cli_subscription_expiry(sub_tree), callid);
4853
4854 if (cli->like) {
4855 if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4856 /* Output line did not match the regex */
4857 return 0;
4858 }
4859 }
4860
4861 ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4862 ++cli->count;
4863
4864 return 0;
4865}
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1273
#define CLI_SHOW_SUB_FORMAT_ENTRY

References ast_callerid_merge(), ast_cli(), ast_copy_pj_str(), ast_copy_string(), ast_sorcery_object_get_id(), ast_str_buffer(), ast_str_set(), cli, CLI_SHOW_SUB_FORMAT_ENTRY, cli_subscription_expiry(), sip_subscription_tree::dlg, sip_subscription_tree::endpoint, ast_sip_subscription_handler::event_name, ast_sip_subscription::handler, ast_sip_endpoint::id, ast_party_id::name, NULL, ast_party_id::number, ast_sip_subscription::resource, sip_subscription_tree::root, S_COR, ast_sip_endpoint_id_configuration::self, ast_party_name::str, ast_party_number::str, ast_party_name::valid, and ast_party_number::valid.

Referenced by cli_show_subscriptions_inbound(), and cli_show_subscriptions_outbound().

◆ cli_show_subscriptions_inbound()

static int cli_show_subscriptions_inbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 4867 of file res_pjsip_pubsub.c.

4868{
4869 return sub_tree->role == AST_SIP_NOTIFIER
4870 ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4871}
static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

References AST_SIP_NOTIFIER, cli_show_subscriptions_detail(), and sip_subscription_tree::role.

Referenced by cli_show_subscriptions_inout().

◆ cli_show_subscriptions_inout()

static char * cli_show_subscriptions_inout ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 4879 of file res_pjsip_pubsub.c.

4880{
4881 on_subscription_t on_subscription;
4882 struct cli_sub_parms cli;
4883 regex_t like;
4884 const char *regex;
4885
4886 switch (cmd) {
4887 case CLI_INIT:
4888 e->command = "pjsip show subscriptions {inbound|outbound} [like]";
4889 e->usage = "Usage:\n"
4890 " pjsip show subscriptions inbound [like <regex>]\n"
4891 " Show active inbound subscriptions\n"
4892 " pjsip show subscriptions outbound [like <regex>]\n"
4893 " Show active outbound subscriptions\n"
4894 "\n"
4895 " The regex selects a subscriptions output that matches.\n"
4896 " i.e., All output lines for a subscription are checked\n"
4897 " as a block by the regex.\n";
4898 return NULL;
4899 case CLI_GENERATE:
4900 return NULL;
4901 }
4902
4903 if (a->argc != 4 && a->argc != 6) {
4904 return CLI_SHOWUSAGE;
4905 }
4906 if (!strcasecmp(a->argv[3], "inbound")) {
4907 on_subscription = cli_show_subscriptions_inbound;
4908 } else if (!strcasecmp(a->argv[3], "outbound")) {
4909 on_subscription = cli_show_subscriptions_outbound;
4910 } else {
4911 /* Should never get here */
4912 ast_assert(0);
4913 return CLI_SHOWUSAGE;
4914 }
4915 if (a->argc == 6) {
4916 int rc;
4917
4918 if (strcasecmp(a->argv[4], "like")) {
4919 return CLI_SHOWUSAGE;
4920 }
4921
4922 /* Setup regular expression */
4923 memset(&like, 0, sizeof(like));
4924 cli.like = &like;
4925 regex = a->argv[5];
4926 rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4927 if (rc) {
4928 char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4929
4930 regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4931 ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4932 regex, regerr);
4933 return CLI_FAILURE;
4934 }
4935 } else {
4936 cli.like = NULL;
4937 regex = NULL;
4938 }
4939
4940 cli.a = a;
4941 cli.e = e;
4942 cli.count = 0;
4943 cli.buf = ast_str_create(256);
4944 if (!cli.buf) {
4945 if (cli.like) {
4946 regfree(cli.like);
4947 }
4948 return CLI_FAILURE;
4949 }
4950
4952 for_each_subscription(on_subscription, &cli);
4953 ast_cli(a->fd, "%d active subscriptions%s%s%s\n",
4954 cli.count,
4955 regex ? " matched \"" : "",
4956 regex ?: "",
4957 regex ? "\"" : "");
4958
4959 ast_free(cli.buf);
4960 if (cli.like) {
4961 regfree(cli.like);
4962 }
4963
4964 return CLI_SUCCESS;
4965}
static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
#define CLI_SHOW_SUB_FORMAT_HEADER
static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)

References a, ast_alloca, ast_assert, ast_cli(), ast_free, ast_str_create, cli, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOW_SUB_FORMAT_HEADER, cli_show_subscriptions_inbound(), cli_show_subscriptions_outbound(), CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, cli_sub_parms::e, for_each_subscription(), cli_sub_parms::like, MAX_REGEX_ERROR_LEN, NULL, regex(), and ast_cli_entry::usage.

◆ cli_show_subscriptions_outbound()

static int cli_show_subscriptions_outbound ( struct sip_subscription_tree sub_tree,
void *  arg 
)
static

Definition at line 4873 of file res_pjsip_pubsub.c.

4874{
4875 return sub_tree->role == AST_SIP_SUBSCRIBER
4876 ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4877}

References AST_SIP_SUBSCRIBER, cli_show_subscriptions_detail(), and sip_subscription_tree::role.

Referenced by cli_show_subscriptions_inout().

◆ cli_subscription_expiry()

static unsigned int cli_subscription_expiry ( struct sip_subscription_tree sub_tree)
static

Definition at line 4667 of file res_pjsip_pubsub.c.

4668{
4669 int expiry;
4670
4671 expiry = sub_tree->persistence
4672 ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
4673 : 0;
4674 if (expiry < 0) {
4675 /* Subscription expired */
4676 expiry = 0;
4677 }
4678 return expiry;
4679}
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
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ast_tvdiff_ms(), ast_tvnow(), subscription_persistence::expires, and sip_subscription_tree::persistence.

Referenced by cli_list_subscriptions_detail(), cli_show_subscription_common(), and cli_show_subscriptions_detail().

◆ cmp_strings()

static int cmp_strings ( char *  s1,
char *  s2 
)
static

Compare strings for equality checking for NULL.

This function considers NULL values as empty strings. This means NULL or empty strings are equal.

Return values
0The strings are equal
1The strings are not equal

Definition at line 4228 of file res_pjsip_pubsub.c.

4229{
4230 if (!ast_strlen_zero(s1) && !ast_strlen_zero(s2)) {
4231 return strcmp(s1, s2);
4232 }
4233
4234 return ast_strlen_zero(s1) == ast_strlen_zero(s2) ? 0 : 1;
4235}

References ast_strlen_zero().

Referenced by cmp_subscription_childrens().

◆ cmp_subscription_childrens()

static int cmp_subscription_childrens ( struct ast_sip_subscription s1,
struct ast_sip_subscription s2 
)
static

compares the childrens of two ast_sip_subscription s1 and s2

Return values
0The s1 childrens match the s2 childrens
1The s1 childrens do not match the s2 childrens

Definition at line 4243 of file res_pjsip_pubsub.c.

4244{
4245 int i;
4246
4247 if (AST_VECTOR_SIZE(&s1->children) != AST_VECTOR_SIZE(&s2->children)) {
4248 return 1;
4249 }
4250
4251 for (i = 0; i < AST_VECTOR_SIZE(&s1->children); ++i) {
4252 struct ast_sip_subscription *c1 = AST_VECTOR_GET(&s1->children, i);
4253 struct ast_sip_subscription *c2 = AST_VECTOR_GET(&s2->children, i);
4254
4255 if (cmp_strings(c1->resource, c2->resource)
4256 || cmp_strings(c1->display_name, c2->display_name)) {
4257
4258 return 1;
4259 }
4260 }
4261
4262 return 0;
4263}
static int cmp_strings(char *s1, char *s2)
Compare strings for equality checking for NULL.
struct ast_sip_subscription::@466 children

References AST_VECTOR_GET, AST_VECTOR_SIZE, ast_sip_subscription::children, cmp_strings(), ast_sip_subscription::display_name, and ast_sip_subscription::resource.

Referenced by pubsub_on_rx_refresh().

◆ create_multipart_body()

static pjsip_msg_body * create_multipart_body ( pj_pool_t *  pool)
static

Create and initialize the PJSIP multipart body structure for a resource list subscription.

Parameters
pool
Returns
The multipart message body

Definition at line 2545 of file res_pjsip_pubsub.c.

2546{
2547 pjsip_media_type media_type;
2548 pjsip_param *media_type_param;
2549 char boundary[6];
2550 pj_str_t pj_boundary;
2551
2552 pjsip_media_type_init2(&media_type, "multipart", "related");
2553
2554 media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
2555 pj_list_init(media_type_param);
2556
2557 pj_strdup2(pool, &media_type_param->name, "type");
2558 pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
2559
2560 pj_list_insert_before(&media_type.param, media_type_param);
2561
2562 pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
2563 return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2564}

References ast_generate_random_string().

Referenced by generate_list_body().

◆ create_require_eventlist()

static pjsip_require_hdr * create_require_eventlist ( pj_pool_t *  pool)
static

Shortcut method to create a Require: eventlist header.

Definition at line 2658 of file res_pjsip_pubsub.c.

2659{
2660 pjsip_require_hdr *require;
2661
2662 require = pjsip_require_hdr_create(pool);
2663 pj_strdup2(pool, &require->values[0], "eventlist");
2664 require->count = 1;
2665
2666 return require;
2667}

Referenced by pubsub_on_rx_refresh(), send_notify(), and sip_subscription_accept().

◆ create_subscription_tree()

static struct sip_subscription_tree * create_subscription_tree ( const struct ast_sip_subscription_handler handler,
struct ast_sip_endpoint endpoint,
pjsip_rx_data *  rdata,
const char *  resource,
struct ast_sip_pubsub_body_generator generator,
struct resource_tree tree,
pj_status_t *  dlg_status,
struct subscription_persistence persistence 
)
static

Create a subscription tree based on a resource tree.

Using the previously-determined valid resources in the provided resource tree, a corresponding tree of ast_sip_subscriptions are created. The root of the subscription tree is a real subscription, and the rest in the tree are virtual subscriptions.

Parameters
handlerThe handler to use for leaf subscriptions
endpointThe endpoint that sent the SUBSCRIBE request
rdataThe SUBSCRIBE content
resourceThe requested resource in the SUBSCRIBE request
generatorThe body generator to use in leaf subscriptions
treeThe resource tree on which the subscription tree is based
[out]dlg_statusThe result of attempting to create a dialog
persistence
Return values
NULLCould not create the subscription tree
non-NULLThe root of the created subscription tree

Definition at line 1713 of file res_pjsip_pubsub.c.

1717{
1718 struct sip_subscription_tree *sub_tree;
1719 pjsip_dialog *dlg;
1720
1721 sub_tree = allocate_subscription_tree(endpoint, rdata);
1722 if (!sub_tree) {
1723 *dlg_status = PJ_ENOMEM;
1724 return NULL;
1725 }
1726 sub_tree->role = AST_SIP_NOTIFIER;
1727
1728 dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, dlg_status);
1729 if (!dlg) {
1730 if (*dlg_status != PJ_EEXISTS) {
1731 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1732 }
1733 ao2_ref(sub_tree, -1);
1734 return NULL;
1735 }
1736
1737 persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
1739 if (persistence) {
1740 /* Update the created dialog with the persisted information */
1741 pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
1742 pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->tag);
1743 dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
1744 pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
1745 dlg->local.cseq = persistence->cseq;
1746 }
1747
1748 pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
1749
1750 subscription_setup_dialog(sub_tree, dlg);
1751
1752 /*
1753 * The evsub and subscription setup both add dialog refs, so the dialog ref that
1754 * was added when the dialog was created (see ast_sip_create_dialog_uas_lock) can
1755 * now be removed. The lock should no longer be needed so can be removed too.
1756 */
1757 pjsip_dlg_dec_lock(dlg);
1758
1759#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
1760 pjsip_evsub_add_ref(sub_tree->evsub);
1761#endif
1762
1764 pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
1765
1767
1768 /* Persistence information needs to be available for all the subscriptions */
1769 sub_tree->persistence = ao2_bump(persistence);
1770
1771 sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
1772 if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
1773 sub_tree->is_list = 1;
1774 }
1775
1776 add_subscription(sub_tree);
1777
1778 return sub_tree;
1779}
pjsip_dialog * ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
General purpose method for creating a UAS dialog with an endpoint.
Definition: res_pjsip.c:1192
#define ast_sip_mod_data_set(pool, mod_data, id, key, val)
Utilizing a mod_data array for a given id, set the value associated with the given key.
Definition: res_pjsip.h:3099
static struct ast_sip_subscription * create_virtual_subscriptions(const struct ast_sip_subscription_handler *handler, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct sip_subscription_tree *tree, struct tree_node *current)
Create a tree of virtual subscriptions based on a resource tree node.
#define MOD_DATA_PERSISTENCE
unsigned int notification_batch_interval

References add_subscription(), allocate_subscription_tree(), ao2_bump, ao2_ref, ast_log, ast_sip_create_dialog_uas_locked(), ast_sip_mod_data_get, ast_sip_mod_data_set, AST_SIP_NOTIFIER, AST_VECTOR_SIZE, ast_sip_subscription::children, create_virtual_subscriptions(), subscription_persistence::cseq, sip_subscription_tree::dlg, sip_subscription_tree::endpoint, sip_subscription_tree::evsub, handler(), sip_subscription_tree::is_list, LOG_WARNING, MOD_DATA_MSG, MOD_DATA_PERSISTENCE, sip_subscription_tree::notification_batch_interval, resource_tree::notification_batch_interval, NULL, sip_subscription_tree::persistence, pubsub_cb, pubsub_module, sip_subscription_tree::role, sip_subscription_tree::root, resource_tree::root, subscription_setup_dialog(), and subscription_persistence::tag.

Referenced by pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

◆ create_virtual_subscriptions()

static struct ast_sip_subscription * create_virtual_subscriptions ( const struct ast_sip_subscription_handler handler,
const char *  resource,
struct ast_sip_pubsub_body_generator generator,
struct sip_subscription_tree tree,
struct tree_node current 
)
static

Create a tree of virtual subscriptions based on a resource tree node.

Parameters
handlerThe handler to supply to leaf subscriptions.
resourceThe requested resource for this subscription.
generatorBody generator to use for leaf subscriptions.
treeThe root of the subscription tree.
currentThe tree node that corresponds to the subscription being created.

Definition at line 1532 of file res_pjsip_pubsub.c.

1535{
1536 int i;
1537 struct ast_sip_subscription *sub;
1538
1540 if (!sub) {
1541 return NULL;
1542 }
1543
1544 sub->full_state = current->full_state;
1545 sub->body_generator = generator;
1546 AST_VECTOR_INIT(&sub->children, AST_VECTOR_SIZE(&current->children));
1547
1548 for (i = 0; i < AST_VECTOR_SIZE(&current->children); ++i) {
1549 struct ast_sip_subscription *child;
1550 struct tree_node *child_node = AST_VECTOR_GET(&current->children, i);
1551
1552 child = create_virtual_subscriptions(handler, child_node->resource, generator,
1553 tree, child_node);
1554
1555 if (!child) {
1556 ast_debug(1, "Child subscription to resource %s could not be created\n",
1557 child_node->resource);
1558 continue;
1559 }
1560
1561 if (AST_VECTOR_APPEND(&sub->children, child)) {
1562 ast_debug(1, "Child subscription to resource %s could not be appended\n",
1563 child_node->resource);
1564 destroy_subscription(child);
1565 /* Have to release tree here too because a ref was added
1566 * to child that destroy_subscription() doesn't release. */
1567 ao2_cleanup(tree);
1568 }
1569 }
1570
1571 return sub;
1572}

References allocate_subscription(), ao2_cleanup, ast_debug, AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, create_virtual_subscriptions(), current, destroy_subscription(), handler(), NULL, ast_sip_subscription::resource, tree_node::resource, sub, and ast_sip_subscription::tree.

Referenced by create_subscription_tree(), create_virtual_subscriptions(), and pubsub_on_rx_refresh().

◆ destroy_subscription()

static void destroy_subscription ( struct ast_sip_subscription sub)
static

Definition at line 1437 of file res_pjsip_pubsub.c.

1438{
1439 ast_debug(3, "Destroying SIP subscription from '%s->%s'\n",
1440 sub->tree && sub->tree->endpoint ? ast_sorcery_object_get_id(sub->tree->endpoint) : "Unknown",
1441 sub->resource);
1442
1443 ast_free(sub->body_text);
1444
1445 AST_VECTOR_FREE(&sub->children);
1446 ao2_cleanup(sub->datastores);
1447 ast_json_unref(sub->persistence_data);
1448 ast_free(sub->display_name);
1449 ast_free(sub);
1450}

References ao2_cleanup, ast_debug, ast_free, ast_json_unref(), ast_sorcery_object_get_id(), AST_VECTOR_FREE, and sub.

Referenced by allocate_subscription(), create_virtual_subscriptions(), and destroy_subscriptions().

◆ destroy_subscriptions()

static void destroy_subscriptions ( struct ast_sip_subscription root)
static

Definition at line 1452 of file res_pjsip_pubsub.c.

1453{
1454 int i;
1455
1456 if (!root) {
1457 return;
1458 }
1459
1460 for (i = 0; i < AST_VECTOR_SIZE(&root->children); ++i) {
1461 struct ast_sip_subscription *child;
1462
1463 child = AST_VECTOR_GET(&root->children, i);
1464 destroy_subscriptions(child);
1465 }
1466
1468}
static void destroy_subscriptions(struct ast_sip_subscription *root)

References AST_VECTOR_GET, AST_VECTOR_SIZE, ast_sip_subscription::children, destroy_subscription(), destroy_subscriptions(), and sip_subscription_tree::root.

Referenced by destroy_subscriptions(), destroy_subscriptions_task(), pubsub_on_rx_refresh(), and subscription_tree_destructor().

◆ destroy_subscriptions_task()

static int destroy_subscriptions_task ( void *  obj)
static

Definition at line 4265 of file res_pjsip_pubsub.c.

4266{
4267 struct ast_sip_subscription *sub = (struct ast_sip_subscription *) obj;
4268
4270
4271 return 0;
4272}

References destroy_subscriptions(), and sub.

Referenced by pubsub_on_rx_refresh().

◆ determine_sip_publish_type()

static enum sip_publish_type determine_sip_publish_type ( pjsip_rx_data *  rdata,
pjsip_generic_string_hdr *  etag_hdr,
unsigned int *  expires,
int *  entity_id 
)
static

Definition at line 3375 of file res_pjsip_pubsub.c.

3377{
3378 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3379
3380 if (etag_hdr) {
3381 char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3382
3383 ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
3384
3385 if (sscanf(etag, "%30d", entity_id) != 1) {
3386 return SIP_PUBLISH_UNKNOWN;
3387 }
3388 }
3389
3390 *expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3391
3392 if (!(*expires)) {
3393 return SIP_PUBLISH_REMOVE;
3394 } else if (!etag_hdr && rdata->msg_info.msg->body) {
3395 return SIP_PUBLISH_INITIAL;
3396 } else if (etag_hdr && !rdata->msg_info.msg->body) {
3397 return SIP_PUBLISH_REFRESH;
3398 } else if (etag_hdr && rdata->msg_info.msg->body) {
3399 return SIP_PUBLISH_MODIFY;
3400 }
3401
3402 return SIP_PUBLISH_UNKNOWN;
3403}
#define DEFAULT_PUBLISH_EXPIRES
Default expiration time for PUBLISH if one is not specified.

References ast_copy_pj_str(), DEFAULT_PUBLISH_EXPIRES, NULL, SIP_PUBLISH_INITIAL, SIP_PUBLISH_MODIFY, SIP_PUBLISH_REFRESH, SIP_PUBLISH_REMOVE, and SIP_PUBLISH_UNKNOWN.

Referenced by pubsub_on_rx_publish_request().

◆ exceptional_accept()

static int exceptional_accept ( const pj_str_t *  accept)
static

Is the Accept header from the SUBSCRIBE in the list of exceptions?

Return values
1This Accept header value is an exception to the rule.
0This Accept header is not an exception to the rule.

Definition at line 1040 of file res_pjsip_pubsub.c.

1041{
1042 int i;
1043
1044 for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
1045 if (!pj_strcmp2(accept, accept_exceptions[i])) {
1046 return 1;
1047 }
1048 }
1049
1050 return 0;
1051}
const char * accept_exceptions[]
Accept headers that are exceptions to the rule.
#define ARRAY_LEN(a)
Definition: utils.h:666

References ast_sip_subscription_handler::accept, accept_exceptions, and ARRAY_LEN.

Referenced by subscription_get_generator_from_rdata().

◆ find_body_generator()

static struct ast_sip_pubsub_body_generator * find_body_generator ( char  accept[AST_SIP_MAX_ACCEPT][64],
size_t  num_accept,
const char *  body_type 
)
static

Definition at line 3133 of file res_pjsip_pubsub.c.

3135{
3136 int i;
3137 struct ast_sip_pubsub_body_generator *generator = NULL;
3138
3139 for (i = 0; i < num_accept; ++i) {
3140 generator = find_body_generator_accept(accept[i]);
3141 if (generator) {
3142 ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
3143 if (strcmp(generator->body_type, body_type)) {
3144 ast_log(LOG_WARNING, "Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
3145 generator->type, generator->subtype, generator);
3146 generator = NULL;
3147 continue;
3148 }
3149 break;
3150 } else {
3151 ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
3152 }
3153 }
3154
3155 return generator;
3156}
static struct ast_sip_pubsub_body_generator * find_body_generator_accept(const char *accept)

References ast_debug, ast_log, ast_sip_pubsub_body_generator::body_type, find_body_generator_accept(), LOG_WARNING, NULL, ast_sip_pubsub_body_generator::subtype, and ast_sip_pubsub_body_generator::type.

Referenced by subscription_get_generator_from_rdata().

◆ find_body_generator_accept()

static struct ast_sip_pubsub_body_generator * find_body_generator_accept ( const char *  accept)
static

Definition at line 3120 of file res_pjsip_pubsub.c.

3121{
3122 char *accept_copy = ast_strdupa(accept);
3123 char *subtype = accept_copy;
3124 char *type = strsep(&subtype, "/");
3125
3126 if (ast_strlen_zero(type) || ast_strlen_zero(subtype)) {
3127 return NULL;
3128 }
3129
3130 return find_body_generator_type_subtype(type, subtype);
3131}
char * strsep(char **str, const char *delims)
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298

References ast_strdupa, ast_strlen_zero(), find_body_generator_type_subtype(), NULL, strsep(), ast_sip_pubsub_body_generator::subtype, and type.

Referenced by find_body_generator().

◆ find_body_generator_type_subtype()

static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype ( const char *  type,
const char *  subtype 
)
static

◆ find_body_generator_type_subtype_nolock()

static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype_nolock ( const char *  type,
const char *  subtype 
)
static

Definition at line 3096 of file res_pjsip_pubsub.c.

3097{
3099
3101 if (!strcmp(gen->type, type)
3102 && !strcmp(gen->subtype, subtype)) {
3103 break;
3104 }
3105 }
3106
3107 return gen;
3108}
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491

References AST_LIST_TRAVERSE, gen, ast_sip_pubsub_body_generator::list, ast_sip_pubsub_body_generator::subtype, and type.

Referenced by ast_sip_pubsub_register_body_generator(), and find_body_generator_type_subtype().

◆ find_pub_handler()

static struct ast_sip_publish_handler * find_pub_handler ( const char *  event)
static

Definition at line 3357 of file res_pjsip_pubsub.c.

3358{
3359 struct ast_sip_publish_handler *iter = NULL;
3360
3363 if (strcmp(event, iter->event_name)) {
3364 ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
3365 continue;
3366 }
3367 ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
3368 break;
3369 }
3371
3372 return iter;
3373}
const char * event_name
The name of the event this handler deals with.

References ast_debug, AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_sip_publish_handler::event_name, ast_sip_publish_handler::next, and NULL.

Referenced by pubsub_on_rx_publish_request().

◆ find_sub_handler_for_event_name()

static struct ast_sip_subscription_handler * find_sub_handler_for_event_name ( const char *  event_name)
static

◆ for_each_subscription()

static int for_each_subscription ( on_subscription_t  on_subscription,
void *  arg 
)
static

Definition at line 2048 of file res_pjsip_pubsub.c.

2049{
2050 int num = 0;
2051 struct sip_subscription_tree *i;
2052
2053 if (!on_subscription) {
2054 return num;
2055 }
2056
2059 if (on_subscription(i, arg)) {
2060 break;
2061 }
2062 ++num;
2063 }
2065 return num;
2066}
struct sip_subscription_tree * next

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, and sip_subscription_tree::next.

Referenced by ami_show_subscriptions_inbound(), ami_show_subscriptions_outbound(), cli_complete_subscription_callid(), cli_list_subscriptions_inout(), cli_show_subscription_inout(), and cli_show_subscriptions_inout().

◆ format_ami_resource_lists()

static int format_ami_resource_lists ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 4536 of file res_pjsip_pubsub.c.

4537{
4538 struct resource_list *list = obj;
4539 struct ast_sip_ami *ami = arg;
4540 struct ast_str *buf;
4541
4542 buf = ast_sip_create_ami_event("ResourceListDetail", ami);
4543 if (!buf) {
4544 return CMP_STOP;
4545 }
4546
4547 if (ast_sip_sorcery_object_to_ami(list, &buf)) {
4548 ast_free(buf);
4549 return CMP_STOP;
4550 }
4551 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4552 ast_free(buf);
4553
4554 ++ami->count;
4555 return 0;
4556}
@ CMP_STOP
Definition: astobj2.h:1028
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
void * arg
Definition: res_pjsip.h:3208

References ast_sip_ami::arg, ast_free, ast_sip_create_ami_event(), ast_sip_sorcery_object_to_ami(), ast_str_buffer(), astman_append(), buf, CMP_STOP, ast_sip_ami::count, and ast_sip_ami::s.

Referenced by ami_show_resource_lists().

◆ free_body_parts()

static void free_body_parts ( struct body_part_list parts)
static

Destroy a list of body parts.

Parameters
partsThe container of parts to destroy

Definition at line 2468 of file res_pjsip_pubsub.c.

2469{
2470 int i;
2471
2472 for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
2473 struct body_part *part = AST_VECTOR_GET(parts, i);
2474 ast_free(part);
2475 }
2476
2477 AST_VECTOR_FREE(parts);
2478}

References ast_free, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_SIZE, and body_part::part.

Referenced by generate_list_body().

◆ generate_content_id_hdr()

static pjsip_generic_string_hdr * generate_content_id_hdr ( pj_pool_t *  pool,
const struct ast_sip_subscription sub 
)
static

Create a Content-ID header.

Content-ID headers are required by RFC2387 for multipart/related bodies. They serve as identifiers for each part of the multipart body.

Parameters
poolPJLIB allocation pool
subSubscription to a resource

Definition at line 2360 of file res_pjsip_pubsub.c.

2362{
2363 static const pj_str_t cid_name = { "Content-ID", 10 };
2364 pjsip_generic_string_hdr *cid;
2365 char id[6];
2366 size_t alloc_size;
2367 pj_str_t cid_value;
2368
2369 /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
2370 alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
2371 cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2372 cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
2373 ast_generate_random_string(id, sizeof(id)),
2374 (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
2375 cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2376
2377 return cid;
2378}
enum queue_result id
Definition: app_queue.c:1808

References ast_generate_random_string(), id, and sub.

Referenced by allocate_body_part(), and build_rlmi_body().

◆ generate_initial_notify()

static int generate_initial_notify ( struct ast_sip_subscription sub)
static

Definition at line 3158 of file res_pjsip_pubsub.c.

3159{
3160 void *notify_data;
3161 int res;
3162 struct ast_sip_body_data data = {
3163 .body_type = sub->handler->body_type,
3164 };
3165
3166 if (AST_VECTOR_SIZE(&sub->children) > 0) {
3167 int i;
3168
3169 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
3170 if (generate_initial_notify(AST_VECTOR_GET(&sub->children, i))) {
3171 return -1;
3172 }
3173 }
3174
3175 return 0;
3176 }
3177
3178 /* We notify subscription establishment only on the tree leaves. */
3179 if (sub->handler->notifier->subscription_established(sub)) {
3180 return -1;
3181 }
3182
3183 notify_data = sub->handler->notifier->get_notify_data(sub);
3184 if (!notify_data) {
3185 ast_debug(3, "No notify data, not generating any body content\n");
3186 return -1;
3187 }
3188
3189 data.body_data = notify_data;
3190
3192 ast_sip_subscription_get_body_subtype(sub), &data, &sub->body_text);
3193
3195
3196 return res;
3197}
static int generate_initial_notify(struct ast_sip_subscription *sub)
Data used to create bodies for NOTIFY/PUBLISH requests.

References ao2_cleanup, ast_debug, ast_sip_pubsub_generate_body_content(), ast_sip_subscription_get_body_subtype(), ast_sip_subscription_get_body_type(), AST_VECTOR_GET, AST_VECTOR_SIZE, ast_sip_body_data::body_data, ast_sip_body_data::body_type, generate_initial_notify(), and sub.

Referenced by generate_initial_notify(), initial_notify_task(), and pubsub_on_refresh_timeout().

◆ generate_list_body()

static pjsip_msg_body * generate_list_body ( pj_pool_t *  pool,
struct ast_sip_subscription sub,
unsigned int  force_full_state 
)
static

Create a resource list body for NOTIFY requests.

Resource list bodies are multipart/related bodies. The first part of the multipart body is an RLMI body that describes the rest of the parts to come. The other parts of the body convey state of individual subscribed resources.

Parameters
poolPJLIB allocation pool
subSubscription details from which to generate body
force_full_stateIf true, ignore resource list settings and send a full state notification
Returns
The generated multipart/related body

Definition at line 2578 of file res_pjsip_pubsub.c.

2580{
2581 int i;
2582 pjsip_multipart_part *rlmi_part;
2583 pjsip_msg_body *multipart;
2584 struct body_part_list body_parts;
2585 unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
2586
2587 if (AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children))) {
2588 return NULL;
2589 }
2590
2591 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2592 build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
2593 }
2594
2595 /* This can happen if issuing partial state and no children of the list have changed state */
2596 if (AST_VECTOR_SIZE(&body_parts) == 0) {
2597 free_body_parts(&body_parts);
2598 return NULL;
2599 }
2600
2601 multipart = create_multipart_body(pool);
2602
2603 rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
2604 if (!rlmi_part) {
2605 free_body_parts(&body_parts);
2606 return NULL;
2607 }
2608 pjsip_multipart_add_part(pool, multipart, rlmi_part);
2609
2610 for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
2611 pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
2612 }
2613
2614 free_body_parts(&body_parts);
2615 return multipart;
2616}
static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *parts, unsigned int use_full_state)
Create a multipart body part for a subscribed resource.
static void free_body_parts(struct body_part_list *parts)
Destroy a list of body parts.
static pjsip_msg_body * create_multipart_body(pj_pool_t *pool)
Create and initialize the PJSIP multipart body structure for a resource list subscription.
static pjsip_multipart_part * build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub, struct body_part_list *body_parts, unsigned int full_state)
Create an RLMI body part for a multipart resource list body.
Type declaration for container of body part structures.

References AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, build_body_part(), build_rlmi_body(), create_multipart_body(), free_body_parts(), NULL, and sub.

Referenced by generate_notify_body().

◆ generate_notify_body()

static pjsip_msg_body * generate_notify_body ( pj_pool_t *  pool,
struct ast_sip_subscription root,
unsigned int  force_full_state 
)
static

Create the body for a NOTIFY request.

Parameters
poolThe pool used for allocations
rootThe root of the subscription tree
force_full_stateIf true, ignore resource list settings and send a full state notification

Definition at line 2625 of file res_pjsip_pubsub.c.

2627{
2628 pjsip_msg_body *body;
2629
2630 if (AST_VECTOR_SIZE(&root->children) == 0) {
2631 if (force_full_state || root->body_changed) {
2632 /* Not a list. We've already generated the body and saved it on the subscription.
2633 * Use that directly.
2634 */
2635 pj_str_t type;
2636 pj_str_t subtype;
2637 pj_str_t text;
2638
2640 pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
2641 pj_cstr(&text, ast_str_buffer(root->body_text));
2642
2643 body = pjsip_msg_body_create(pool, &type, &subtype, &text);
2644 root->body_changed = 0;
2645 } else {
2646 body = NULL;
2647 }
2648 } else {
2649 body = generate_list_body(pool, root, force_full_state);
2650 }
2651
2652 return body;
2653}
char * text
Definition: app_queue.c:1809
static pjsip_msg_body * generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub, unsigned int force_full_state)
Create a resource list body for NOTIFY requests.
struct ast_str * body_text

References ast_sip_subscription_get_body_subtype(), ast_sip_subscription_get_body_type(), ast_str_buffer(), AST_VECTOR_SIZE, ast_sip_subscription::body_changed, ast_sip_subscription::body_text, ast_sip_subscription::children, generate_list_body(), NULL, text, and type.

Referenced by build_body_part(), and send_notify().

◆ have_visited()

static int have_visited ( const char *  resource,
struct resources visited 
)
static

Determine if this resource has been visited already.

See build_resource_tree for more information

Parameters
resourceThe resource currently being visited
visitedThe resources that have previously been visited

Definition at line 1215 of file res_pjsip_pubsub.c.

1216{
1217 int i;
1218
1219 for (i = 0; i < AST_VECTOR_SIZE(visited); ++i) {
1220 if (!strcmp(resource, AST_VECTOR_GET(visited, i))) {
1221 return 1;
1222 }
1223 }
1224
1225 return 0;
1226}

References AST_VECTOR_GET, AST_VECTOR_SIZE, and tree_node::resource.

Referenced by build_node_children().

◆ initial_notify_task()

static int initial_notify_task ( void *  obj)
static

Definition at line 3201 of file res_pjsip_pubsub.c.

3202{
3203 struct initial_notify_data *ind = obj;
3204
3206 pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE);
3207 } else {
3208 send_notify(ind->sub_tree, 1);
3209 ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
3210 "Resource: %s",
3211 ind->sub_tree->root->resource);
3212 }
3213
3215 char *name = ast_alloca(strlen("->/ ") +
3216 strlen(ind->sub_tree->persistence->endpoint) +
3217 strlen(ind->sub_tree->root->resource) +
3218 strlen(ind->sub_tree->root->handler->event_name) +
3219 ind->sub_tree->dlg->call_id->id.slen + 1);
3220
3221 sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint,
3223 (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr);
3224
3225 ast_debug(3, "Scheduling timer: %s\n", name);
3229 if (!ind->sub_tree->expiration_task) {
3230 ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n",
3231 ind->expires, name);
3232 }
3233 }
3234
3235 ao2_ref(ind->sub_tree, -1);
3236 ast_free(ind);
3237
3238 return 0;
3239}
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.
@ AST_SIP_SCHED_TASK_FIXED
Definition: res_pjsip.h:2194
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition: res_pjsip.h:2217
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: res_pjsip.h:68
static int pubsub_on_refresh_timeout(void *userdata)
struct sip_subscription_tree * sub_tree

References ao2_ref, ast_alloca, ast_debug, ast_free, ast_log, AST_SIP_SCHED_TASK_DATA_AO2, AST_SIP_SCHED_TASK_FIXED, ast_sip_schedule_task(), ast_test_suite_event_notify, sip_subscription_tree::dlg, subscription_persistence::endpoint, ast_sip_subscription_handler::event_name, sip_subscription_tree::evsub, sip_subscription_tree::expiration_task, initial_notify_data::expires, generate_initial_notify(), ast_sip_subscription::handler, LOG_ERROR, name, sip_subscription_tree::persistence, PJSIP_EXPIRES_NOT_SPECIFIED, pubsub_on_refresh_timeout(), ast_sip_subscription::resource, sip_subscription_tree::root, send_notify(), sip_subscription_tree::serializer, and initial_notify_data::sub_tree.

Referenced by pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

◆ item_in_vector()

static int item_in_vector ( const struct resource_list list,
const char *  item 
)
static

Definition at line 5231 of file res_pjsip_pubsub.c.

5232{
5233 int i;
5234
5235 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5236 if (!strcmp(item, AST_VECTOR_GET(&list->items, i))) {
5237 return 1;
5238 }
5239 }
5240
5241 return 0;
5242}
static struct aco_type item
Definition: test_config.c:1463

References AST_VECTOR_GET, AST_VECTOR_SIZE, item, and resource_list::items.

Referenced by list_item_handler().

◆ list_item_handler()

static int list_item_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
)
static

Definition at line 5244 of file res_pjsip_pubsub.c.

5246{
5247 struct resource_list *list = obj;
5248 char *items = ast_strdupa(var->value);
5249 char *item;
5250
5251 while ((item = ast_strip(strsep(&items, ",")))) {
5252 if (ast_strlen_zero(item)) {
5253 continue;
5254 }
5255
5256 if (item_in_vector(list, item)) {
5257 ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);
5258 continue;
5259 }
5260
5261 item = ast_strdup(item);
5262 if (!item || AST_VECTOR_APPEND(&list->items, item)) {
5263 ast_free(item);
5264 return -1;
5265 }
5266 }
5267
5268 return 0;
5269}
#define var
Definition: ast_expr2f.c:605
static int item_in_vector(const struct resource_list *list, const char *item)
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223

References ast_free, ast_log, ast_strdup, ast_strdupa, ast_strip(), ast_strlen_zero(), AST_VECTOR_APPEND, item, item_in_vector(), resource_list::items, LOG_WARNING, strsep(), and var.

Referenced by apply_list_configuration().

◆ list_item_to_str()

static int list_item_to_str ( const void *  obj,
const intptr_t *  args,
char **  buf 
)
static

Definition at line 5271 of file res_pjsip_pubsub.c.

5272{
5273 const struct resource_list *list = obj;
5274 int i;
5275 struct ast_str *str = ast_str_create(32);
5276
5277 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5278 ast_str_append(&str, 0, "%s,", AST_VECTOR_GET(&list->items, i));
5279 }
5280
5281 /* Chop off trailing comma */
5282 ast_str_truncate(str, -1);
5284 ast_free(str);
5285 return 0;
5286}
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786

References ast_free, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_truncate(), ast_strdup, AST_VECTOR_GET, AST_VECTOR_SIZE, buf, resource_list::items, and str.

Referenced by apply_list_configuration().

◆ load_module()

static int load_module ( void  )
static

Definition at line 6013 of file res_pjsip_pubsub.c.

6014{
6015 static const pj_str_t str_PUBLISH = { "PUBLISH", 7 };
6016 struct ast_sorcery *sorcery;
6017
6019
6020 if (!(sched = ast_sched_context_create())) {
6021 ast_log(LOG_ERROR, "Could not create scheduler for publication expiration\n");
6023 }
6024
6026 ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n");
6029 }
6030
6031 ast_sorcery_apply_config(sorcery, "res_pjsip_pubsub");
6032 ast_sorcery_apply_default(sorcery, "subscription_persistence", "astdb", "subscription_persistence");
6034 NULL, NULL)) {
6035 ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
6038 }
6039 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "packet", "", OPT_CHAR_ARRAY_T, 0,
6040 CHARFLDSET(struct subscription_persistence, packet));
6041 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_name", "", OPT_CHAR_ARRAY_T, 0,
6042 CHARFLDSET(struct subscription_persistence, src_name));
6043 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_port", "0", OPT_UINT_T, 0,
6044 FLDSET(struct subscription_persistence, src_port));
6045 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "transport_key", "0", OPT_CHAR_ARRAY_T, 0,
6046 CHARFLDSET(struct subscription_persistence, transport_type));
6047 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_name", "", OPT_CHAR_ARRAY_T, 0,
6048 CHARFLDSET(struct subscription_persistence, local_name));
6049 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_port", "0", OPT_UINT_T, 0,
6050 FLDSET(struct subscription_persistence, local_port));
6051 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "cseq", "0", OPT_UINT_T, 0,
6052 FLDSET(struct subscription_persistence, cseq));
6053 ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "endpoint", "",
6055 ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "tag", "",
6057 ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
6059 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "contact_uri", "", OPT_CHAR_ARRAY_T, 0,
6060 CHARFLDSET(struct subscription_persistence, contact_uri));
6061 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "no", OPT_YESNO_T, 1,
6062 FLDSET(struct subscription_persistence, prune_on_boot));
6063 ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "generator_data", "",
6065
6069 }
6070
6071 ast_sorcery_apply_default(sorcery, "inbound-publication", "config", "pjsip.conf,criteria=type=inbound-publication");
6073 NULL, NULL)) {
6074 ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
6077 }
6078 ast_sorcery_object_field_register(sorcery, "inbound-publication", "type", "", OPT_NOOP_T, 0, 0);
6079 ast_sorcery_object_field_register_custom(sorcery, "inbound-publication", "endpoint", "",
6081 ast_sorcery_object_fields_register(sorcery, "inbound-publication", "^event_", resource_event_handler, NULL);
6082 ast_sorcery_reload_object(sorcery, "inbound-publication");
6083
6085 ast_log(LOG_ERROR, "Could not register pubsub service\n");
6088 }
6089
6090 if (pjsip_evsub_init_module(ast_sip_get_pjsip_endpoint()) != PJ_SUCCESS) {
6091 ast_log(LOG_ERROR, "Could not initialize pjsip evsub module.\n");
6095 }
6096
6097 /* Once pjsip_evsub_init_module succeeds we cannot unload.
6098 * Keep all module_load errors above this point. */
6100
6101 pjsip_media_type_init2(&rlmi_media_type, "application", "rlmi+xml");
6102
6103 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &str_PUBLISH);
6104
6107 } else {
6108 struct stasis_subscription *sub;
6109
6113 }
6114
6119 ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
6121
6123
6125 AST_TEST_REGISTER(complex_resource_tree);
6126 AST_TEST_REGISTER(bad_resource);
6127 AST_TEST_REGISTER(bad_branch);
6128 AST_TEST_REGISTER(duplicate_resource);
6129 AST_TEST_REGISTER(loop);
6130 AST_TEST_REGISTER(bad_event);
6131
6133}
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:454
struct ast_flags ast_options
Definition: options.c:62
@ AST_OPT_FLAG_FULLY_BOOTED
Definition: options.h:59
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
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:478
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:133
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:117
static int subscription_persistence_load(void *data)
Function which loads and recreates persisted subscriptions upon startup when the system is fully boot...
static struct ast_cli_entry cli_commands[]
static int ami_show_resource_lists(struct mansession *s, const struct message *m)
static int resource_event_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static void * subscription_persistence_alloc(const char *name)
Allocator for subscription persistence.
static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
static int persistence_endpoint_struct2str(const void *obj, const intptr_t *args, char **buf)
static void * publication_resource_alloc(const char *name)
Allocator for publication resource.
static int resource_endpoint_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
#define AMI_SHOW_SUBSCRIPTIONS_INBOUND
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND
static int persistence_generator_data_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
static int apply_list_configuration(struct ast_sorcery *sorcery)
static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int persistence_tag_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int persistence_tag_struct2str(const void *obj, const intptr_t *args, char **buf)
static void subscription_persistence_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Event callback which fires subscription persistence recreation when the system is fully booted.
static int persistence_generator_data_struct2str(const void *obj, const intptr_t *args, char **buf)
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:197
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
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 ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:455
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
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:1050
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:1104
#define stasis_subscribe_pool(topic, callback, data)
Definition: stasis.h:680
Full structure for sorcery.
Definition: sorcery.c:230
A resource tree.
Definition: sched.c:76
Structure used for persisting an inbound subscription.
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_flag(p, flag)
Definition: utils.h:63

References ami_show_resource_lists(), ami_show_subscriptions_inbound(), AMI_SHOW_SUBSCRIPTIONS_INBOUND, ami_show_subscriptions_outbound(), AMI_SHOW_SUBSCRIPTIONS_OUTBOUND, apply_list_configuration(), ARRAY_LEN, ast_cli_register_multiple, ast_log, ast_manager_get_generic_type(), ast_manager_get_topic(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_module_shutdown_ref, AST_OPT_FLAG_FULLY_BOOTED, ast_options, ast_sched_context_create(), ast_sched_context_destroy(), ast_sched_start_thread(), ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sip_push_task(), ast_sip_register_service(), ast_sip_unregister_service(), ast_sorcery_apply_config, ast_sorcery_apply_default, ast_sorcery_object_field_register, ast_sorcery_object_field_register_custom, ast_sorcery_object_fields_register(), ast_sorcery_object_register, ast_sorcery_reload_object(), ast_test_flag, AST_TEST_REGISTER, CHARFLDSET, cli_commands, EVENT_FLAG_SYSTEM, FLDSET, LOG_ERROR, NULL, OPT_CHAR_ARRAY_T, OPT_NOOP_T, OPT_UINT_T, OPT_YESNO_T, persistence_endpoint_str2struct(), persistence_endpoint_struct2str(), persistence_expires_str2struct(), persistence_expires_struct2str(), persistence_generator_data_str2struct(), persistence_generator_data_struct2str(), persistence_tag_str2struct(), persistence_tag_struct2str(), publication_resource_alloc(), pubsub_module, resource_endpoint_handler(), resource_event_handler(), rlmi_media_type, ast_module_info::self, sorcery, stasis_subscribe_pool, stasis_subscription_accept_message_type(), STASIS_SUBSCRIPTION_FILTER_SELECTIVE, stasis_subscription_set_filter(), sub, subscription_persistence_alloc(), subscription_persistence_event_cb(), and subscription_persistence_load().

◆ parse_simple_message_summary()

static int parse_simple_message_summary ( char *  body,
struct simple_message_summary summary 
)
static

Definition at line 3859 of file res_pjsip_pubsub.c.

3861{
3862 char *line;
3863 char *buffer;
3864 int found_counts = 0;
3865
3866 if (ast_strlen_zero(body) || !summary) {
3867 return -1;
3868 }
3869
3870 buffer = ast_strdupa(body);
3871 memset(summary, 0, sizeof(*summary));
3872
3873 while ((line = ast_read_line_from_buffer(&buffer))) {
3874 line = ast_str_to_lower(line);
3875
3876 if (sscanf(line, "voice-message: %d/%d (%d/%d)",
3877 &summary->voice_messages_new, &summary->voice_messages_old,
3879 found_counts = 1;
3880 } else {
3881 sscanf(line, "message-account: %s", summary->message_account);
3882 }
3883 }
3884
3885 return !found_counts;
3886}
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition: strings.h:1321
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.
Definition: strings.c:385
char message_account[PJSIP_MAX_URL_SIZE]

References ast_read_line_from_buffer(), ast_str_to_lower(), ast_strdupa, ast_strlen_zero(), simple_message_summary::message_account, simple_message_summary::voice_messages_new, simple_message_summary::voice_messages_old, simple_message_summary::voice_messages_urgent_new, and simple_message_summary::voice_messages_urgent_old.

Referenced by pubsub_on_rx_mwi_notify_request().

◆ persistence_endpoint_str2struct()

static int persistence_endpoint_str2struct ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
)
static

Definition at line 5119 of file res_pjsip_pubsub.c.

5120{
5121 struct subscription_persistence *persistence = obj;
5122
5123 persistence->endpoint = ast_strdup(var->value);
5124 return 0;
5125}

References ast_strdup, subscription_persistence::endpoint, and var.

Referenced by load_module().

◆ persistence_endpoint_struct2str()

static int persistence_endpoint_struct2str ( const void *  obj,
const intptr_t *  args,
char **  buf 
)
static

Definition at line 5127 of file res_pjsip_pubsub.c.

5128{
5129 const struct subscription_persistence *persistence = obj;
5130
5131 *buf = ast_strdup(persistence->endpoint);
5132 return 0;
5133}

References ast_strdup, buf, and subscription_persistence::endpoint.

Referenced by load_module().

◆ persistence_expires_str2struct()

static int persistence_expires_str2struct ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
)
static

Definition at line 5184 of file res_pjsip_pubsub.c.

5185{
5186 struct subscription_persistence *persistence = obj;
5187 return ast_get_timeval(var->value, &persistence->expires, ast_tv(0, 0), NULL);
5188}
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
Parse a time (float) string.
Definition: utils.c:2419
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235

References ast_get_timeval(), ast_tv(), subscription_persistence::expires, NULL, and var.

Referenced by load_module().

◆ persistence_expires_struct2str()

static int persistence_expires_struct2str ( const void *  obj,
const intptr_t *  args,
char **  buf 
)
static

Definition at line 5190 of file res_pjsip_pubsub.c.

5191{
5192 const struct subscription_persistence *persistence = obj;
5193 char secs[AST_TIME_T_LEN];
5194
5195 ast_time_t_to_string(persistence->expires.tv_sec, secs, sizeof(secs));
5196
5197 return (ast_asprintf(buf, "%s", secs) < 0) ? -1 : 0;
5198}
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
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....
Definition: time.c:152
#define AST_TIME_T_LEN
Definition: time.h:45

References ast_asprintf, AST_TIME_T_LEN, ast_time_t_to_string(), buf, and subscription_persistence::expires.

Referenced by load_module().

◆ persistence_generator_data_str2struct()

static int persistence_generator_data_str2struct ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
)
static

Definition at line 5151 of file res_pjsip_pubsub.c.

5152{
5153 struct subscription_persistence *persistence = obj;
5154 struct ast_json_error error;
5155
5156 /* We tolerate a failure of the JSON to load and instead start fresh, since this field
5157 * originates from the persistence code and not a user.
5158 */
5159 persistence->generator_data = ast_json_load_string(var->value, &error);
5160
5161 return 0;
5162}
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
JSON parsing error information.
Definition: json.h:887
int error(const char *format,...)
Definition: utils/frame.c:999

References ast_json_load_string(), error(), subscription_persistence::generator_data, and var.

Referenced by load_module().

◆ persistence_generator_data_struct2str()

static int persistence_generator_data_struct2str ( const void *  obj,
const intptr_t *  args,
char **  buf 
)
static

Definition at line 5164 of file res_pjsip_pubsub.c.

5165{
5166 const struct subscription_persistence *persistence = obj;
5167 char *value;
5168
5169 if (!persistence->generator_data) {
5170 return 0;
5171 }
5172
5174 if (!value) {
5175 return -1;
5176 }
5177
5178 *buf = ast_strdup(value);
5180
5181 return 0;
5182}
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:810

References ast_json_dump_string, ast_json_free(), ast_strdup, buf, subscription_persistence::generator_data, and value.

Referenced by load_module().

◆ persistence_tag_str2struct()

static int persistence_tag_str2struct ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
)
static

Definition at line 5135 of file res_pjsip_pubsub.c.

5136{
5137 struct subscription_persistence *persistence = obj;
5138
5139 persistence->tag = ast_strdup(var->value);
5140 return 0;
5141}

References ast_strdup, subscription_persistence::tag, and var.

Referenced by load_module().

◆ persistence_tag_struct2str()

static int persistence_tag_struct2str ( const void *  obj,
const intptr_t *  args,
char **  buf 
)
static

Definition at line 5143 of file res_pjsip_pubsub.c.

5144{
5145 const struct subscription_persistence *persistence = obj;
5146
5147 *buf = ast_strdup(persistence->tag);
5148 return 0;
5149}

References ast_strdup, buf, and subscription_persistence::tag.

Referenced by load_module().

◆ publication_cmp_fn()

static int publication_cmp_fn ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 2972 of file res_pjsip_pubsub.c.

2973{
2974 const struct ast_sip_publication *publication1 = obj;
2975 const struct ast_sip_publication *publication2 = arg;
2976 const int *entity_tag = arg;
2977
2978 return (publication1->entity_tag == (flags & OBJ_KEY ? *entity_tag : publication2->entity_tag) ?
2979 CMP_MATCH | CMP_STOP : 0);
2980}
@ CMP_MATCH
Definition: astobj2.h:1027
#define OBJ_KEY
Definition: astobj2.h:1151
Structure representing a SIP publication.
int entity_tag
Entity tag for the publication.

References CMP_MATCH, CMP_STOP, ast_sip_publication::entity_tag, and OBJ_KEY.

Referenced by ast_sip_register_publish_handler().

◆ publication_destroy_fn()

static void publication_destroy_fn ( void *  obj)
static

Internal destructor for publications.

Definition at line 3406 of file res_pjsip_pubsub.c.

3407{
3408 struct ast_sip_publication *publication = obj;
3409
3410 ast_debug(3, "Destroying SIP publication\n");
3411
3412 ao2_cleanup(publication->datastores);
3413 ao2_cleanup(publication->endpoint);
3414
3416}
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:483

References ao2_cleanup, ast_debug, ast_module_unref, ast_sip_publication::datastores, ast_sip_publication::endpoint, and ast_module_info::self.

Referenced by sip_create_publication().

◆ publication_hash_fn()

static int publication_hash_fn ( const void *  obj,
const int  flags 
)
static

Definition at line 2964 of file res_pjsip_pubsub.c.

2965{
2966 const struct ast_sip_publication *publication = obj;
2967 const int *entity_tag = obj;
2968
2969 return flags & OBJ_KEY ? *entity_tag : publication->entity_tag;
2970}

References ast_sip_publication::entity_tag, and OBJ_KEY.

Referenced by ast_sip_register_publish_handler().

◆ publication_resource_alloc()

static void * publication_resource_alloc ( const char *  name)
static

Allocator for publication resource.

Definition at line 791 of file res_pjsip_pubsub.c.

792{
794}
static void publication_resource_destroy(void *obj)
Destructor for publication resource.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
Structure representing a publication resource.

References ast_sorcery_generic_alloc(), and publication_resource_destroy().

Referenced by load_module().

◆ publication_resource_destroy()

static void publication_resource_destroy ( void *  obj)
static

Destructor for publication resource.

Definition at line 782 of file res_pjsip_pubsub.c.

783{
784 struct ast_sip_publication_resource *resource = obj;
785
786 ast_free(resource->endpoint);
787 ast_variables_destroy(resource->events);
788}
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
char * endpoint
Optional name of an endpoint that is only allowed to publish to this resource.
struct ast_variable * events
Mapping for event types to configuration.

References ast_free, ast_variables_destroy(), ast_sip_publication_resource::endpoint, and ast_sip_publication_resource::events.

Referenced by publication_resource_alloc().

◆ publish_add_handler()

static void publish_add_handler ( struct ast_sip_publish_handler handler)
static

◆ publish_expire()

static int publish_expire ( const void *  data)
static

Definition at line 3586 of file res_pjsip_pubsub.c.

3587{
3588 struct ast_sip_publication *publication = (struct ast_sip_publication*)data;
3589
3590 ao2_unlink(publication->handler->publications, publication);
3591 publication->sched_id = -1;
3592
3593 if (ast_sip_push_task(NULL, publish_expire_callback, publication)) {
3594 ao2_cleanup(publication);
3595 }
3596
3597 return 0;
3598}
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
static int publish_expire_callback(void *data)
struct ast_sip_publish_handler * handler
Handler for this publication.
int sched_id
Scheduled item for expiration of publication.
char data[0]
Data containing the above.
struct ao2_container * publications
Publications.

References ao2_cleanup, ao2_unlink, ast_sip_push_task(), ast_sip_publication::data, ast_sip_publication::handler, NULL, ast_sip_publish_handler::publications, publish_expire_callback(), and ast_sip_publication::sched_id.

Referenced by pubsub_on_rx_publish_request().

◆ publish_expire_callback()

static int publish_expire_callback ( void *  data)
static

Definition at line 3575 of file res_pjsip_pubsub.c.

3576{
3577 RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
3578
3579 if (publication->handler->publish_expire) {
3580 publication->handler->publish_expire(publication);
3581 }
3582
3583 return 0;
3584}

References ao2_cleanup, and RAII_VAR.

Referenced by publish_expire().

◆ publish_request_initial()

static struct ast_sip_publication * publish_request_initial ( struct ast_sip_endpoint endpoint,
pjsip_rx_data *  rdata,
struct ast_sip_publish_handler handler 
)
static

Definition at line 3487 of file res_pjsip_pubsub.c.

3489{
3490 struct ast_sip_publication *publication;
3491 char *resource_name;
3492 size_t resource_size;
3494 struct ast_variable *event_configuration_name = NULL;
3495 pjsip_uri *request_uri;
3496 int resp;
3497 const pj_str_t *user;
3498
3499 request_uri = rdata->msg_info.msg->line.req.uri;
3500
3501 if (!ast_sip_is_uri_sip_sips(request_uri)) {
3502 char uri_str[PJSIP_MAX_URL_SIZE];
3503
3504 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3505 ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3506 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3507 return NULL;
3508 }
3509
3510 user = ast_sip_pjsip_uri_get_username(request_uri);
3511 resource_size = pj_strlen(user) + 1;
3512 resource_name = ast_alloca(resource_size);
3513 ast_copy_pj_str(resource_name, user, resource_size);
3514
3515 /*
3516 * We may want to match without any user options getting
3517 * in the way.
3518 */
3520
3521 resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
3522 if (!resource) {
3523 ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name);
3524 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3525 return NULL;
3526 }
3527
3528 if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
3529 ast_debug(1, "Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3530 resource_name, resource->endpoint, ast_sorcery_object_get_id(endpoint));
3531 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
3532 return NULL;
3533 }
3534
3535 for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
3536 if (!strcmp(event_configuration_name->name, handler->event_name)) {
3537 break;
3538 }
3539 }
3540
3541 if (!event_configuration_name) {
3542 ast_debug(1, "Event '%s' is not configured for '%s'\n", handler->event_name, resource_name);
3543 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3544 return NULL;
3545 }
3546
3547 resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
3548
3549 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3550 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3551 return NULL;
3552 }
3553
3554 publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
3555
3556 if (!publication) {
3557 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
3558 return NULL;
3559 }
3560
3561 publication->handler = handler;
3562 if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
3564 ast_debug(3, "Publication state change failed\n");
3565 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3566 ao2_cleanup(publication);
3567 return NULL;
3568 }
3569
3570 sip_publication_respond(publication, resp, rdata);
3571
3572 return publication;
3573}
static char user[512]
const pj_str_t * ast_sip_pjsip_uri_get_username(pjsip_uri *uri)
Get the user portion of the pjsip_uri.
Definition: res_pjsip.c:3477
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3504
int ast_sip_is_uri_sip_sips(pjsip_uri *uri)
Check whether a pjsip_uri is SIP/SIPS or not.
Definition: res_pjsip.c:3467
static int sip_publication_respond(struct ast_sip_publication *pub, int status_code, pjsip_rx_data *rdata)
static struct ast_sip_publication * sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, const char *event_configuration_name)
@ AST_SIP_PUBLISH_STATE_INITIALIZED
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
int(* publication_state_change)(struct ast_sip_publication *pub, pjsip_msg_body *body, enum ast_sip_publish_state state)
Published resource has changed states.
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
structure to hold users read from users.conf

References ao2_cleanup, ast_alloca, ast_copy_pj_str(), ast_debug, ast_log, ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sip_is_uri_sip_sips(), ast_sip_pjsip_uri_get_username(), AST_SIP_PUBLISH_STATE_INITIALIZED, AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_id(), ast_strlen_zero(), ast_sip_publication::handler, handler(), LOG_WARNING, ast_variable::name, ast_variable::next, NULL, ast_sip_publish_handler::publication_state_change, RAII_VAR, ast_sip_publication::resource, S_OR, sip_create_publication(), sip_publication_respond(), user, and ast_variable::value.

Referenced by pubsub_on_rx_publish_request().

◆ pubsub_on_client_refresh()

static void pubsub_on_client_refresh ( pjsip_evsub *  sub)
static

Definition at line 4435 of file res_pjsip_pubsub.c.

4436{
4437 struct sip_subscription_tree *sub_tree;
4438
4439 if (!(sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4440 return;
4441 }
4442
4444 ao2_cleanup(sub_tree);
4445 }
4446}
static int serialized_pubsub_on_client_refresh(void *userdata)

References ao2_bump, ao2_cleanup, ast_sip_push_task(), sip_subscription_tree::evsub, pubsub_module, serialized_pubsub_on_client_refresh(), and sip_subscription_tree::serializer.

◆ pubsub_on_evsub_state()

static void pubsub_on_evsub_state ( pjsip_evsub *  evsub,
pjsip_event *  event 
)
static

PJSIP callback when underlying SIP subscription changes state.

Although this function is called for every state change, we only care about the TERMINATED state, and only when we're actually processing the final notify (SIP_SUB_TREE_TERMINATE_IN_PROGRESS) OR when a transmission failure occurs (PJSIP_EVENT_TSX_STATE). In this case, we do all the subscription tree cleanup tasks and decrement the evsub reference.

Definition at line 4129 of file res_pjsip_pubsub.c.

4130{
4131 struct sip_subscription_tree *sub_tree =
4132 pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4133
4134 ast_debug(3, "evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub,
4135 pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree,
4136 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4137
4138 if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
4139 return;
4140 }
4141
4142 /* It's easier to write this as what we WANT to process, then negate it. */
4143 if (!(sub_tree->state == SIP_SUB_TREE_TERMINATE_IN_PROGRESS
4144 || (event->type == PJSIP_EVENT_TSX_STATE && sub_tree->state == SIP_SUB_TREE_NORMAL)
4145 )) {
4146 ast_debug(3, "Do nothing.\n");
4147 return;
4148 }
4149
4150#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
4151 /* This check looks for re-subscribes with an expires of 0. If we receive one of those,
4152 we don't want to clean the evsub because we still need it to send the final NOTIFY.
4153 This was previously handled by pubsub_on_rx_refresh setting:
4154 'sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING' */
4155 if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&
4156 !pjsip_method_cmp(&event->body.tsx_state.tsx->method, &pjsip_subscribe_method) &&
4157 pjsip_evsub_get_expires(evsub) == 0) {
4158 ast_debug(3, "Subscription ending, do nothing.\n");
4159 return;
4160 }
4161#endif
4162 /* If we made it this far, we want to clean the sub tree. For pjproject <2.13, the sub_tree
4163 state check makes sure the evsub is not cleaned at the wrong time */
4165}
static void clean_sub_tree(pjsip_evsub *evsub)
Callback sequence for subscription terminate:
static char * sub_tree_state_description[]

References ast_debug, clean_sub_tree(), sip_subscription_tree::evsub, pubsub_module, SIP_SUB_TREE_NORMAL, SIP_SUB_TREE_TERMINATE_IN_PROGRESS, sip_subscription_tree::state, and sub_tree_state_description.

◆ pubsub_on_refresh_timeout()

static int pubsub_on_refresh_timeout ( void *  userdata)
static

Definition at line 4167 of file res_pjsip_pubsub.c.

4168{
4169 struct sip_subscription_tree *sub_tree = userdata;
4170 pjsip_dialog *dlg = sub_tree->dlg;
4171
4172 ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
4173 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4174
4175 pjsip_dlg_inc_lock(dlg);
4176 if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) {
4177 pjsip_dlg_dec_lock(dlg);
4178 return 0;
4179 }
4180
4181 if (sub_tree->state == SIP_SUB_TREE_TERMINATE_PENDING) {
4183 set_state_terminated(sub_tree->root);
4184 }
4185
4186 if (sub_tree->generate_initial_notify) {
4187 sub_tree->generate_initial_notify = 0;
4188 if (generate_initial_notify(sub_tree->root)) {
4189 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4190 pjsip_dlg_dec_lock(dlg);
4191 return 0;
4192 }
4193 }
4194
4195 send_notify(sub_tree, 1);
4196
4197 ast_test_suite_event_notify(sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ?
4198 "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED",
4199 "Resource: %s", sub_tree->root->resource);
4200
4201 pjsip_dlg_dec_lock(dlg);
4202
4203 return 0;
4204}
static void set_state_terminated(struct ast_sip_subscription *sub)
pjsip_evsub_state subscription_state
unsigned int generate_initial_notify

References ast_debug, ast_test_suite_event_notify, sip_subscription_tree::dlg, sip_subscription_tree::evsub, sip_subscription_tree::generate_initial_notify, generate_initial_notify(), ast_sip_subscription::resource, sip_subscription_tree::root, send_notify(), set_state_terminated(), SIP_SUB_TREE_TERMINATE_IN_PROGRESS, SIP_SUB_TREE_TERMINATE_PENDING, sip_subscription_tree::state, sub_tree_state_description, and ast_sip_subscription::subscription_state.

Referenced by initial_notify_task(), pubsub_on_rx_refresh(), and serialized_pubsub_on_refresh_timeout().

◆ pubsub_on_rx_mwi_notify_request()

static pj_bool_t pubsub_on_rx_mwi_notify_request ( pjsip_rx_data *  rdata)
static

Definition at line 3888 of file res_pjsip_pubsub.c.

3889{
3890 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3891 struct simple_message_summary summary;
3892 const char *endpoint_name;
3893 char *atsign;
3894 char *context;
3895 char *body;
3896 char *mailbox;
3897 int rc;
3898
3899 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3900 if (!endpoint) {
3901 ast_debug(1, "Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3902 rc = 404;
3903 goto error;
3904 }
3905
3906 endpoint_name = ast_sorcery_object_get_id(endpoint);
3907 ast_debug(1, "Incoming MWI: Found endpoint: %s\n", endpoint_name);
3908 if (ast_strlen_zero(endpoint->incoming_mwi_mailbox)) {
3909 ast_debug(1, "Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3910 ast_test_suite_event_notify("PUBSUB_NO_INCOMING_MWI_MAILBOX",
3911 "Endpoint: %s", endpoint_name);
3912 rc = 404;
3913 goto error;
3914 }
3915
3916 mailbox = ast_strdupa(endpoint->incoming_mwi_mailbox);
3917 atsign = strchr(mailbox, '@');
3918 if (!atsign) {
3919 ast_debug(1, "Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3920 endpoint_name, endpoint->incoming_mwi_mailbox);
3921 rc = 404;
3922 goto error;
3923 }
3924
3925 *atsign = '\0';
3926 context = atsign + 1;
3927
3928 body = ast_alloca(rdata->msg_info.msg->body->len + 1);
3929 rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3930 rdata->msg_info.msg->body->len + 1);
3931
3932 if (parse_simple_message_summary(body, &summary) != 0) {
3933 ast_debug(1, "Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3934 ast_sorcery_object_get_id(endpoint), body);
3935 rc = 404;
3936 goto error;
3937 }
3938
3940 summary.voice_messages_new, summary.voice_messages_old)) {
3941 ast_log(LOG_ERROR, "Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
3942 "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3943 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3944 summary.voice_messages_new, summary.voice_messages_old,
3945 summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3946 rc = 404;
3947 } else {
3948 ast_debug(1, "Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3949 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3950 summary.voice_messages_new, summary.voice_messages_old,
3951 summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3952 ast_test_suite_event_notify("PUBSUB_INCOMING_MWI_PUBLISH",
3953 "Endpoint: %s\r\n"
3954 "Mailbox: %s\r\n"
3955 "MessageAccount: %s\r\n"
3956 "VoiceMessagesNew: %d\r\n"
3957 "VoiceMessagesOld: %d\r\n"
3958 "VoiceMessagesUrgentNew: %d\r\n"
3959 "VoiceMessagesUrgentOld: %d",
3960 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3961 summary.voice_messages_new, summary.voice_messages_old,
3962 summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3963 rc = 200;
3964 }
3965
3966error:
3967 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, rc, NULL, NULL, NULL);
3968 return PJ_TRUE;
3969}
#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs)
Publish a MWI state update via stasis.
Definition: mwi.h:378
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
static int parse_simple_message_summary(char *body, struct simple_message_summary *summary)
An entity with which Asterisk communicates.
Definition: res_pjsip.h:1051

References ao2_cleanup, ast_alloca, ast_debug, ast_log, ast_pjsip_rdata_get_endpoint(), ast_publish_mwi_state, ast_sip_get_pjsip_endpoint(), ast_sorcery_object_get_id(), ast_strdupa, ast_strlen_zero(), ast_test_suite_event_notify, voicemailpwcheck::context, error(), LOG_ERROR, voicemailpwcheck::mailbox, simple_message_summary::message_account, NULL, parse_simple_message_summary(), RAII_VAR, simple_message_summary::voice_messages_new, simple_message_summary::voice_messages_old, simple_message_summary::voice_messages_urgent_new, and simple_message_summary::voice_messages_urgent_old.

Referenced by pubsub_on_rx_notify_request().

◆ pubsub_on_rx_notify()

static void pubsub_on_rx_notify ( pjsip_evsub *  sub,
pjsip_rx_data *  rdata,
int *  p_st_code,
pj_str_t **  p_st_text,
pjsip_hdr *  res_hdr,
pjsip_msg_body **  p_body 
)
static

Definition at line 4402 of file res_pjsip_pubsub.c.

4404{
4405 struct ast_sip_subscription *sub;
4406
4407 if (!(sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4408 return;
4409 }
4410
4411 sub->handler->subscriber->state_change(sub, rdata->msg_info.msg->body,
4412 pjsip_evsub_get_state(evsub));
4413}

References pubsub_module, and sub.

◆ pubsub_on_rx_notify_request()

static pj_bool_t pubsub_on_rx_notify_request ( pjsip_rx_data *  rdata)
static

Definition at line 3971 of file res_pjsip_pubsub.c.

3972{
3973 if (rdata->msg_info.msg->body &&
3974 ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type,
3975 "application", "simple-message-summary")) {
3976 return pubsub_on_rx_mwi_notify_request(rdata);
3977 }
3978 return PJ_FALSE;
3979}
int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
Checks if the given content type matches type/subtype.
Definition: res_pjsip.c:2248
static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata)

References ast_sip_is_content_type(), and pubsub_on_rx_mwi_notify_request().

Referenced by pubsub_on_rx_request().

◆ pubsub_on_rx_publish_request()

static pj_bool_t pubsub_on_rx_publish_request ( pjsip_rx_data *  rdata)
static

Definition at line 3600 of file res_pjsip_pubsub.c.

3601{
3602 pjsip_event_hdr *event_header;
3604 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3605 char event[32];
3606 static const pj_str_t str_sip_if_match = { "SIP-If-Match", 12 };
3607 pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
3608 enum sip_publish_type publish_type;
3609 RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
3610 unsigned int expires = 0;
3611 int entity_id, response = 0;
3612
3613 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3614 ast_assert(endpoint != NULL);
3615
3616 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
3617 if (!event_header) {
3618 ast_log(LOG_WARNING, "Incoming PUBLISH request from %s with no Event header\n",
3619 ast_sorcery_object_get_id(endpoint));
3620 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3621 return PJ_TRUE;
3622 }
3623 ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
3624
3626 if (!handler) {
3627 ast_log(LOG_WARNING, "No registered publish handler for event %s from %s\n", event,
3628 ast_sorcery_object_get_id(endpoint));
3629 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3630 return PJ_TRUE;
3631 }
3632
3633 publish_type = determine_sip_publish_type(rdata, etag_hdr, &expires, &entity_id);
3634
3635 /* If this is not an initial publish ensure that a publication is present */
3636 if ((publish_type != SIP_PUBLISH_INITIAL) && (publish_type != SIP_PUBLISH_UNKNOWN)) {
3637 if (!(publication = ao2_find(handler->publications, &entity_id, OBJ_KEY | OBJ_UNLINK))) {
3638 static const pj_str_t str_conditional_request_failed = { "Conditional Request Failed", 26 };
3639
3640 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 412, &str_conditional_request_failed,
3641 NULL, NULL);
3642 return PJ_TRUE;
3643 }
3644
3645 /* Per the RFC every response has to have a new entity tag */
3646 publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
3647
3648 /* Update the expires here so that the created responses will contain the correct value */
3649 publication->expires = expires;
3650 }
3651
3652 switch (publish_type) {
3654 publication = publish_request_initial(endpoint, rdata, handler);
3655 break;
3657 case SIP_PUBLISH_MODIFY:
3658 if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
3660 /* If an error occurs we want to terminate the publication */
3661 expires = 0;
3662 }
3663 response = 200;
3664 break;
3665 case SIP_PUBLISH_REMOVE:
3666 handler->publication_state_change(publication, rdata->msg_info.msg->body,
3668 response = 200;
3669 break;
3671 default:
3672 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3673 break;
3674 }
3675
3676 if (publication) {
3677 if (expires) {
3678 ao2_link(handler->publications, publication);
3679
3680 AST_SCHED_REPLACE_UNREF(publication->sched_id, sched, expires * 1000, publish_expire, publication,
3681 ao2_ref(_data, -1), ao2_ref(publication, -1), ao2_ref(publication, +1));
3682 } else {
3683 AST_SCHED_DEL_UNREF(sched, publication->sched_id, ao2_ref(publication, -1));
3684 }
3685 }
3686
3687 if (response) {
3688 sip_publication_respond(publication, response, rdata);
3689 }
3690
3691 return PJ_TRUE;
3692}
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_UNLINK
Definition: astobj2.h:1039
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:764
sip_publish_type
The types of PUBLISH messages defined in RFC 3903.
static int esc_etag_counter
static const pj_str_t str_event_name
static int publish_expire(const void *data)
static struct ast_sip_publish_handler * find_pub_handler(const char *event)
static enum sip_publish_type determine_sip_publish_type(pjsip_rx_data *rdata, pjsip_generic_string_hdr *etag_hdr, unsigned int *expires, int *entity_id)
static struct ast_sip_publication * publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, struct ast_sip_publish_handler *handler)
@ AST_SIP_PUBLISH_STATE_ACTIVE
@ AST_SIP_PUBLISH_STATE_TERMINATED
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
Definition: sched.h:82
#define AST_SCHED_REPLACE_UNREF(id, sched, when, callback, data, unrefcall, addfailcall, refcall)
Definition: sched.h:152
struct sched_id * sched_id
Definition: sched.c:79

References ao2_cleanup, ao2_find, ao2_link, ao2_ref, ast_assert, ast_atomic_fetchadd_int(), ast_copy_pj_str(), ast_log, ast_pjsip_rdata_get_endpoint(), AST_SCHED_DEL_UNREF, AST_SCHED_REPLACE_UNREF, ast_sip_get_pjsip_endpoint(), AST_SIP_PUBLISH_STATE_ACTIVE, AST_SIP_PUBLISH_STATE_TERMINATED, ast_sorcery_object_get_id(), determine_sip_publish_type(), esc_etag_counter, find_pub_handler(), handler(), LOG_WARNING, NULL, OBJ_KEY, OBJ_UNLINK, publish_expire(), publish_request_initial(), RAII_VAR, sched::sched_id, sip_publication_respond(), SIP_PUBLISH_INITIAL, SIP_PUBLISH_MODIFY, SIP_PUBLISH_REFRESH, SIP_PUBLISH_REMOVE, SIP_PUBLISH_UNKNOWN, and str_event_name.

Referenced by pubsub_on_rx_request().

◆ pubsub_on_rx_refresh()

static void pubsub_on_rx_refresh ( pjsip_evsub *  evsub,
pjsip_rx_data *  rdata,
int *  p_st_code,
pj_str_t **  p_st_text,
pjsip_hdr *  res_hdr,
pjsip_msg_body **  p_body 
)
static

Called whenever an in-dialog SUBSCRIBE is received.

This includes both SUBSCRIBE requests that actually refresh the subscription as well as SUBSCRIBE requests that end the subscription.

In either case we push an appropriate NOTIFY via pubsub_on_refresh_timeout.

Definition at line 4282 of file res_pjsip_pubsub.c.

4284{
4285 struct sip_subscription_tree *sub_tree;
4287
4288 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4289 ast_debug(3, "evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree,
4290 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4291
4292 if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4293 return;
4294 }
4295
4296 if (sub_tree->expiration_task) {
4297 char task_name[256];
4298
4299 ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
4300 ast_debug(3, "Cancelling timer: %s\n", task_name);
4302 ao2_cleanup(sub_tree->expiration_task);
4303 sub_tree->expiration_task = NULL;
4304 }
4305
4306 /* PJSIP will set the evsub's state to terminated before calling into this function
4307 * if the Expires value of the incoming SUBSCRIBE is 0.
4308 */
4309
4310 if (pjsip_evsub_get_state(sub_tree->evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
4312 }
4313
4315
4316 /* If the handler wants a callback on refresh, then do it (some protocols require this). */
4317 if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->root->handler->notifier->refresh_subscribe) {
4318 if (!sub_tree->root->handler->notifier->refresh_subscribe(sub_tree->root, rdata)) {
4319 return; /* If the callback handled it, we're done. */
4320 }
4321 }
4322
4323 if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->is_list) {
4324 /* update RLS */
4325 const char *resource = sub_tree->root->resource;
4326 struct ast_sip_subscription *old_root = sub_tree->root;
4327 struct ast_sip_subscription *new_root = NULL;
4328
4329 struct ast_sip_pubsub_body_generator *generator = NULL;
4330
4331 if (endpoint && (generator = subscription_get_generator_from_rdata(rdata, sub_tree->root->handler))) {
4332
4333 struct resource_tree tree;
4334 int resp;
4335
4336 memset(&tree, 0, sizeof(tree));
4337 resp = build_resource_tree(endpoint, sub_tree->root->handler, resource, &tree,
4339 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
4340 new_root = create_virtual_subscriptions(sub_tree->root->handler, resource, generator, sub_tree, tree.root);
4341 if (new_root) {
4342 if (cmp_subscription_childrens(old_root, new_root)) {
4343 ast_debug(1, "RLS '%s->%s' was modified, regenerate it\n", ast_sorcery_object_get_id(endpoint), old_root->resource);
4344 new_root->version = old_root->version;
4345 sub_tree->root = new_root;
4346 sub_tree->generate_initial_notify = 1;
4347
4348 /* If there is scheduled notification need to delete it to avoid use old subscriptions */
4349 if (sub_tree->notify_sched_id > -1) {
4350 AST_SCHED_DEL_UNREF(sched, sub_tree->notify_sched_id, ao2_ref(sub_tree, -1));
4351 sub_tree->send_scheduled_notify = 0;
4352 }
4353
4354 /* Terminate old subscriptions to stop sending NOTIFY messages on exten/device state changes */
4355 set_state_terminated(old_root);
4356
4357 /* Shutdown old subscriptions to remove exten/device state change callbacks
4358 that can queue tasks for old subscriptions */
4359 shutdown_subscriptions(old_root);
4360
4361 /* Postpone destruction until all already queued tasks that may be using old subscriptions have completed */
4362 if (ast_sip_push_task(sub_tree->serializer, destroy_subscriptions_task, old_root)) {
4363 ast_log(LOG_ERROR, "Failed to push task to destroy old subscriptions for RLS '%s->%s'.\n",
4364 ast_sorcery_object_get_id(endpoint), old_root->resource);
4365 }
4366 } else {
4367 destroy_subscriptions(new_root);
4368 }
4369 }
4370 } else {
4372 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4373 }
4374
4375 resource_tree_destroy(&tree);
4376 }
4377 }
4378
4380
4381#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
4382 /* As of pjsip 2.13, the NOTIFY has to be sent within this function as pjproject now
4383 requires it. Previously this would have caused an early NOTIFY to go out before the
4384 SUBSCRIBE's 200 OK. The previous solution was to push the NOTIFY, but now pjproject
4385 looks for the NOTIFY to be sent from this function and caches it to send after it
4386 auto-replies to the SUBSCRIBE. */
4387 pubsub_on_refresh_timeout(sub_tree);
4388#else
4390 /* If we can't push the NOTIFY refreshing task...we'll just go with it. */
4391 ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n");
4392 sub_tree->state = SIP_SUB_TREE_NORMAL;
4393 ao2_ref(sub_tree, -1);
4394 }
4395#endif
4396
4397 if (sub_tree->is_list) {
4398 pj_list_insert_before(res_hdr, create_require_eventlist(rdata->tp_info.pool));
4399 }
4400}
static int build_resource_tree(struct ast_sip_endpoint *endpoint, const struct ast_sip_subscription_handler *handler, const char *resource, struct resource_tree *tree, int has_eventlist_support, pjsip_rx_data *rdata)
Build a resource tree.
static int serialized_pubsub_on_refresh_timeout(void *userdata)
static pjsip_require_hdr * create_require_eventlist(pj_pool_t *pool)
Shortcut method to create a Require: eventlist header.
static struct ast_sip_pubsub_body_generator * subscription_get_generator_from_rdata(pjsip_rx_data *rdata, const struct ast_sip_subscription_handler *handler)
Retrieve a body generator using the Accept header of an rdata message.
static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
Check if the rdata has a Supported header containing 'eventlist'.
static void subscription_persistence_update(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, enum sip_persistence_update_type type)
Function which updates persistence information of a subscription in sorcery.
static void resource_tree_destroy(struct resource_tree *tree)
Destroy a resource tree.
static int cmp_subscription_childrens(struct ast_sip_subscription *s1, struct ast_sip_subscription *s2)
compares the childrens of two ast_sip_subscription s1 and s2
static int destroy_subscriptions_task(void *obj)
int(* refresh_subscribe)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata)
Called when a SUBSCRIBE arrives for an already active subscription.
struct ast_sip_notifier * notifier
unsigned int send_scheduled_notify

References ao2_bump, ao2_cleanup, ao2_ref, ast_debug, ast_log, ast_pjsip_rdata_get_endpoint(), AST_SCHED_DEL_UNREF, ast_sip_pubsub_has_eventlist_support(), ast_sip_push_task(), ast_sip_sched_task_cancel(), ast_sip_sched_task_get_name(), ast_sorcery_object_get_id(), build_resource_tree(), cmp_subscription_childrens(), create_require_eventlist(), create_virtual_subscriptions(), destroy_subscriptions(), destroy_subscriptions_task(), sip_subscription_tree::endpoint, sip_subscription_tree::evsub, sip_subscription_tree::expiration_task, sip_subscription_tree::generate_initial_notify, ast_sip_subscription::handler, sip_subscription_tree::is_list, LOG_ERROR, ast_sip_subscription_handler::notifier, sip_subscription_tree::notify_sched_id, NULL, pubsub_module, pubsub_on_refresh_timeout(), RAII_VAR, ast_sip_notifier::refresh_subscribe, ast_sip_subscription::resource, resource_tree_destroy(), sip_subscription_tree::root, resource_tree::root, sip_subscription_tree::send_scheduled_notify, serialized_pubsub_on_refresh_timeout(), sip_subscription_tree::serializer, set_state_terminated(), shutdown_subscriptions(), SIP_SUB_TREE_NORMAL, SIP_SUB_TREE_TERMINATE_PENDING, sip_subscription_tree::state, sub_tree_state_description, subscription_get_generator_from_rdata(), SUBSCRIPTION_PERSISTENCE_REFRESHED, subscription_persistence_update(), and ast_sip_subscription::version.

◆ pubsub_on_rx_request()

static pj_bool_t pubsub_on_rx_request ( pjsip_rx_data *  rdata)
static

Opaque structure representing an RFC 3265 SIP subscription.

Definition at line 3981 of file res_pjsip_pubsub.c.

3982{
3983 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3984 return pubsub_on_rx_subscribe_request(rdata);
3985 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
3986 return pubsub_on_rx_publish_request(rdata);
3987 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
3988 return pubsub_on_rx_notify_request(rdata);
3989 }
3990
3991 return PJ_FALSE;
3992}
static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata)
static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
const pjsip_method pjsip_publish_method
Defined method for PUBLISH.

References pjsip_publish_method, pubsub_on_rx_notify_request(), pubsub_on_rx_publish_request(), and pubsub_on_rx_subscribe_request().

◆ pubsub_on_rx_subscribe_request()

static pj_bool_t pubsub_on_rx_subscribe_request ( pjsip_rx_data *  rdata)
static

Definition at line 3241 of file res_pjsip_pubsub.c.

3242{
3243 pjsip_expires_hdr *expires_header;
3245 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3246 struct sip_subscription_tree *sub_tree;
3247 struct ast_sip_pubsub_body_generator *generator;
3248 char *resource;
3249 pjsip_uri *request_uri;
3250 size_t resource_size;
3251 int resp;
3252 struct resource_tree tree;
3253 pj_status_t dlg_status;
3254 const pj_str_t *user;
3255
3256 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3257 ast_assert(endpoint != NULL);
3258
3259 if (!endpoint->subscription.allow) {
3260 ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
3261 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
3262 return PJ_TRUE;
3263 }
3264
3265 request_uri = rdata->msg_info.msg->line.req.uri;
3266
3267 if (!ast_sip_is_uri_sip_sips(request_uri)) {
3268 char uri_str[PJSIP_MAX_URL_SIZE];
3269
3270 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3271 ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3272 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3273 return PJ_TRUE;
3274 }
3275
3276 user = ast_sip_pjsip_uri_get_username(request_uri);
3277 resource_size = pj_strlen(user) + 1;
3278 resource = ast_alloca(resource_size);
3279 ast_copy_pj_str(resource, user, resource_size);
3280
3281 /*
3282 * We may want to match without any user options getting
3283 * in the way.
3284 */
3286
3287 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3288 if (expires_header) {
3289 if (expires_header->ivalue == 0) {
3290 ast_debug(1, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3291 ast_sorcery_object_get_id(endpoint));
3292 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3293 return PJ_TRUE;
3294 }
3295 if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3296 ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3297 expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subscription.minexpiry);
3298 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
3299 return PJ_TRUE;
3300 }
3301 }
3302
3304 if (!handler) {
3305 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3306 return PJ_TRUE;
3307 }
3308
3310 if (!generator) {
3311 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3312 return PJ_TRUE;
3313 }
3314
3315 memset(&tree, 0, sizeof(tree));
3316 resp = build_resource_tree(endpoint, handler, resource, &tree,
3318 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3319 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3320 resource_tree_destroy(&tree);
3321 return PJ_TRUE;
3322 }
3323
3324 sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
3325 if (!sub_tree) {
3326 if (dlg_status != PJ_EEXISTS) {
3327 ast_debug(3, "No dialog exists, rejecting\n");
3328 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3329 }
3330 } else {
3331 struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
3332
3333 if (!ind) {
3334 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3335 resource_tree_destroy(&tree);
3336 return PJ_TRUE;
3337 }
3338
3339 ind->sub_tree = ao2_bump(sub_tree);
3340 /* Since this is a normal subscribe, pjproject takes care of the timer */
3342
3345 sip_subscription_accept(sub_tree, rdata, resp);
3347 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3348 ao2_ref(sub_tree, -1);
3349 ast_free(ind);
3350 }
3351 }
3352
3353 resource_tree_destroy(&tree);
3354 return PJ_TRUE;
3355}
static struct subscription_persistence * subscription_persistence_create(struct sip_subscription_tree *sub_tree)
Function which creates initial persistence information of a subscription in sorcery.
static struct sip_subscription_tree * create_subscription_tree(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree, pj_status_t *dlg_status, struct subscription_persistence *persistence)
Create a subscription tree based on a resource tree.
static int initial_notify_task(void *obj)
static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
static struct ast_sip_subscription_handler * subscription_get_handler_from_rdata(pjsip_rx_data *rdata, const char *endpoint)
Retrieve a handler using the Event header of an rdata message.

References ao2_bump, ao2_cleanup, ao2_ref, ast_alloca, ast_assert, ast_copy_pj_str(), ast_debug, ast_free, ast_log, ast_malloc, ast_pjsip_rdata_get_endpoint(), ast_sip_get_pjsip_endpoint(), ast_sip_is_uri_sip_sips(), ast_sip_pjsip_uri_get_username(), ast_sip_pubsub_has_eventlist_support(), ast_sip_push_task(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_sorcery_object_get_id(), build_resource_tree(), create_subscription_tree(), sip_subscription_tree::evsub, initial_notify_data::expires, handler(), initial_notify_task(), LOG_WARNING, NULL, sip_subscription_tree::persistence, PJSIP_EXPIRES_NOT_SPECIFIED, RAII_VAR, resource_tree_destroy(), sip_subscription_tree::serializer, sip_subscription_accept(), initial_notify_data::sub_tree, subscription_get_generator_from_rdata(), subscription_get_handler_from_rdata(), subscription_persistence_create(), SUBSCRIPTION_PERSISTENCE_CREATED, subscription_persistence_update(), and user.

Referenced by pubsub_on_rx_request().

◆ pubsub_on_server_timeout()

static void pubsub_on_server_timeout ( pjsip_evsub *  sub)
static

Definition at line 4448 of file res_pjsip_pubsub.c.

4449{
4450 struct sip_subscription_tree *sub_tree;
4451
4452 /* PJSIP does not terminate the server timeout timer when a SUBSCRIBE
4453 * with Expires: 0 arrives to end a subscription, nor does it terminate
4454 * this timer when we send a NOTIFY request in response to receiving such
4455 * a SUBSCRIBE. PJSIP does not stop the server timeout timer until the
4456 * NOTIFY transaction has finished (either through receiving a response
4457 * or through a transaction timeout).
4458 *
4459 * Therefore, it is possible that we can be told that a server timeout
4460 * occurred after we already thought that the subscription had been
4461 * terminated. In such a case, we will have already removed the sub_tree
4462 * from the evsub's mod_data array.
4463 */
4464
4465 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4466 if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4467 return;
4468 }
4469
4472 sub_tree->state = SIP_SUB_TREE_NORMAL;
4473 ao2_cleanup(sub_tree);
4474 }
4475}

References ao2_bump, ao2_cleanup, ast_sip_push_task(), sip_subscription_tree::evsub, pubsub_module, serialized_pubsub_on_refresh_timeout(), sip_subscription_tree::serializer, SIP_SUB_TREE_NORMAL, SIP_SUB_TREE_TERMINATE_PENDING, and sip_subscription_tree::state.

◆ remove_subscription()

static void remove_subscription ( struct sip_subscription_tree obj)
static

◆ resource_endpoint_handler()

static int resource_endpoint_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
)
static

Definition at line 5979 of file res_pjsip_pubsub.c.

5980{
5981 struct ast_sip_publication_resource *resource = obj;
5982
5983 ast_free(resource->endpoint);
5984 resource->endpoint = ast_strdup(var->value);
5985
5986 return 0;
5987}

References ast_free, ast_strdup, ast_sip_publication_resource::endpoint, and var.

Referenced by load_module().

◆ resource_event_handler()

static int resource_event_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
)
static

Definition at line 5989 of file res_pjsip_pubsub.c.

5990{
5991 struct ast_sip_publication_resource *resource = obj;
5992 /* The event configuration name starts with 'event_' so skip past it to get the real name */
5993 const char *event = var->name + 6;
5994 struct ast_variable *item;
5995
5996 if (ast_strlen_zero(event) || ast_strlen_zero(var->value)) {
5997 return -1;
5998 }
5999
6000 item = ast_variable_new(event, var->value, "");
6001 if (!item) {
6002 return -1;
6003 }
6004
6005 if (resource->events) {
6006 item->next = resource->events;
6007 }
6008 resource->events = item;
6009
6010 return 0;
6011}
#define ast_variable_new(name, value, filename)

References ast_strlen_zero(), ast_variable_new, ast_sip_publication_resource::events, item, and var.

Referenced by load_module().

◆ resource_list_alloc()

static void * resource_list_alloc ( const char *  name)
static

Definition at line 5214 of file res_pjsip_pubsub.c.

5215{
5216 struct resource_list *list;
5217
5219 if (!list) {
5220 return NULL;
5221 }
5222
5224 ao2_cleanup(list);
5225 return NULL;
5226 }
5227
5228 return list;
5229}
#define RESOURCE_LIST_INIT_SIZE
static void resource_list_destructor(void *obj)

References ao2_cleanup, ast_sorcery_generic_alloc(), AST_VECTOR_INIT, resource_list::items, NULL, resource_list_destructor(), and RESOURCE_LIST_INIT_SIZE.

Referenced by apply_list_configuration().

◆ resource_list_apply_handler()

static int resource_list_apply_handler ( const struct ast_sorcery sorcery,
void *  obj 
)
static

Definition at line 5288 of file res_pjsip_pubsub.c.

5289{
5290 struct resource_list *list = obj;
5291
5292 if (ast_strlen_zero(list->event)) {
5293 ast_log(LOG_WARNING, "Resource list '%s' has no event set\n",
5295 return -1;
5296 }
5297
5298 if (AST_VECTOR_SIZE(&list->items) == 0) {
5299 ast_log(LOG_WARNING, "Resource list '%s' has no list items\n",
5301 return -1;
5302 }
5303
5304 return 0;
5305}

References ast_log, ast_sorcery_object_get_id(), ast_strlen_zero(), AST_VECTOR_SIZE, resource_list::event, resource_list::items, and LOG_WARNING.

Referenced by apply_list_configuration().

◆ resource_list_destructor()

static void resource_list_destructor ( void *  obj)
static

Definition at line 5202 of file res_pjsip_pubsub.c.

5203{
5204 struct resource_list *list = obj;
5205 int i;
5206
5207 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5208 ast_free((char *) AST_VECTOR_GET(&list->items, i));
5209 }
5210
5211 AST_VECTOR_FREE(&list->items);
5212}

References ast_free, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_SIZE, and resource_list::items.

Referenced by resource_list_alloc().

◆ resource_tree_destroy()

static void resource_tree_destroy ( struct resource_tree tree)
static

Destroy a resource tree.

This function makes no assumptions about how the tree itself was allocated and does not attempt to free the tree itself. Callers of this function are responsible for freeing the tree.

Parameters
treeThe tree to destroy.

Definition at line 1343 of file res_pjsip_pubsub.c.

1344{
1345 if (tree) {
1346 tree_node_destroy(tree->root);
1347 }
1348}

References resource_tree::root, and tree_node_destroy().

Referenced by pubsub_on_rx_refresh(), pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

◆ retrieve_resource_list()

static struct resource_list * retrieve_resource_list ( const char *  resource,
const char *  event 
)
static

Helper function for retrieving a resource list for a given event.

This will retrieve a resource list that corresponds to the resource and event provided.

Parameters
resourceThe name of the resource list to retrieve
eventThe expected event name on the resource list

Definition at line 1126 of file res_pjsip_pubsub.c.

1127{
1128 struct resource_list *list;
1129
1130 list = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
1131 if (!list) {
1132 return NULL;
1133 }
1134
1135 if (strcmp(list->event, event)) {
1136 ast_log(LOG_WARNING, "Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
1137 resource, list->event, event);
1138 ao2_cleanup(list);
1139 return NULL;
1140 }
1141
1142 return list;
1143}

References ao2_cleanup, ast_log, ast_sip_get_sorcery(), ast_sorcery_retrieve_by_id(), resource_list::event, LOG_WARNING, and NULL.

Referenced by build_node_children(), and build_resource_tree().

◆ rlmi_clone_data()

static void * rlmi_clone_data ( pj_pool_t *  pool,
const void *  data,
unsigned  len 
)
static

Definition at line 2393 of file res_pjsip_pubsub.c.

2394{
2395 const pj_xml_node *rlmi = data;
2396
2397 return pj_xml_clone(pool, rlmi);
2398}

Referenced by build_rlmi_body().

◆ rlmi_print_body()

static int rlmi_print_body ( struct pjsip_msg_body *  msg_body,
char *  buf,
pj_size_t  size 
)
static

Definition at line 2380 of file res_pjsip_pubsub.c.

2381{
2382 int num_printed;
2383 pj_xml_node *rlmi = msg_body->data;
2384
2385 num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
2386 if (num_printed <= AST_PJSIP_XML_PROLOG_LEN) {
2387 return -1;
2388 }
2389
2390 return num_printed;
2391}
#define AST_PJSIP_XML_PROLOG_LEN
Length of the XML prolog when printing presence or other XML in PJSIP.

References AST_PJSIP_XML_PROLOG_LEN, and buf.

Referenced by build_rlmi_body().

◆ sched_cb()

static int sched_cb ( const void *  data)
static

Definition at line 2771 of file res_pjsip_pubsub.c.

2772{
2773 struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
2774
2775 /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
2776 if (ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree)) {
2777 ao2_cleanup(sub_tree);
2778 }
2779
2780 return 0;
2781}
static int serialized_send_notify(void *userdata)

References ao2_cleanup, ast_sip_push_task(), serialized_send_notify(), and sip_subscription_tree::serializer.

Referenced by schedule_notification().

◆ schedule_notification()

static int schedule_notification ( struct sip_subscription_tree sub_tree)
static

Definition at line 2783 of file res_pjsip_pubsub.c.

2784{
2785 /* There's already a notification scheduled */
2786 if (sub_tree->notify_sched_id > -1) {
2787 return 0;
2788 }
2789
2790 sub_tree->send_scheduled_notify = 1;
2792 if (sub_tree->notify_sched_id < 0) {
2793 ao2_cleanup(sub_tree);
2794 return -1;
2795 }
2796
2797 return 0;
2798}
static int sched_cb(const void *data)
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

References ao2_bump, ao2_cleanup, ast_sched_add(), sip_subscription_tree::notification_batch_interval, sip_subscription_tree::notify_sched_id, sched_cb(), and sip_subscription_tree::send_scheduled_notify.

Referenced by ast_sip_subscription_notify().

◆ send_notify()

static int send_notify ( struct sip_subscription_tree sub_tree,
unsigned int  force_full_state 
)
static

Send a NOTIFY request to a subscriber.

Precondition
sub_tree->dlg is locked
Parameters
sub_treeThe subscription tree representing the subscription
force_full_stateIf true, ignore resource list settings and send full resource list state.
Return values
0Success
non-zeroFailure

Definition at line 2689 of file res_pjsip_pubsub.c.

2690{
2691 pjsip_evsub *evsub = sub_tree->evsub;
2692 pjsip_tx_data *tdata;
2693
2694 if (ast_shutdown_final()
2695 && sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED
2696 && sub_tree->persistence) {
2697 return 0;
2698 }
2699
2700 if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
2701 NULL, NULL, &tdata) != PJ_SUCCESS) {
2702 return -1;
2703 }
2704
2705 tdata->msg->body = generate_notify_body(tdata->pool, sub_tree->root, force_full_state);
2706 if (!tdata->msg->body) {
2707 pjsip_tx_data_dec_ref(tdata);
2708 return -1;
2709 }
2710
2711 if (sub_tree->is_list) {
2712 pjsip_require_hdr *require = create_require_eventlist(tdata->pool);
2713 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2714 }
2715
2716 if (sub_tree->root->handler->notifier->notify_created) {
2717 /* The module for this event wants a callback to the pjsip_tx_data,
2718 * e.g. so it can add custom headers or do something custom to the response. */
2719 sub_tree->root->handler->notifier->notify_created(sub_tree->root, tdata);
2720 }
2721
2722 if (sip_subscription_send_request(sub_tree, tdata)) {
2723 /* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */
2724 return -1;
2725 }
2726
2727 sub_tree->send_scheduled_notify = 0;
2728
2729 return 0;
2730}
int ast_shutdown_final(void)
Definition: asterisk.c:1881
static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
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...

References ast_shutdown_final(), create_require_eventlist(), sip_subscription_tree::evsub, generate_notify_body(), ast_sip_subscription::handler, sip_subscription_tree::is_list, ast_sip_subscription_handler::notifier, ast_sip_notifier::notify_created, NULL, sip_subscription_tree::persistence, sip_subscription_tree::root, sip_subscription_tree::send_scheduled_notify, sip_subscription_send_request(), and ast_sip_subscription::subscription_state.

Referenced by ast_sip_subscription_notify(), initial_notify_task(), pubsub_on_refresh_timeout(), and serialized_send_notify().

◆ serialized_pubsub_on_client_refresh()

static int serialized_pubsub_on_client_refresh ( void *  userdata)
static

Definition at line 4415 of file res_pjsip_pubsub.c.

4416{
4417 struct sip_subscription_tree *sub_tree = userdata;
4418 pjsip_tx_data *tdata;
4419
4420 if (!sub_tree->evsub) {
4421 ao2_cleanup(sub_tree);
4422 return 0;
4423 }
4424
4425 if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
4426 pjsip_evsub_send_request(sub_tree->evsub, tdata);
4427 } else {
4428 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4429 }
4430
4431 ao2_cleanup(sub_tree);
4432 return 0;
4433}

References ao2_cleanup, sip_subscription_tree::evsub, and NULL.

Referenced by pubsub_on_client_refresh().

◆ serialized_pubsub_on_refresh_timeout()

static int serialized_pubsub_on_refresh_timeout ( void *  userdata)
static

Definition at line 4206 of file res_pjsip_pubsub.c.

4207{
4208 struct sip_subscription_tree *sub_tree = userdata;
4209
4210 ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
4211 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4212
4213 pubsub_on_refresh_timeout(userdata);
4214 ao2_cleanup(sub_tree);
4215
4216 return 0;
4217}

References ao2_cleanup, ast_debug, pubsub_on_refresh_timeout(), sip_subscription_tree::state, and sub_tree_state_description.

Referenced by pubsub_on_rx_refresh(), and pubsub_on_server_timeout().

◆ serialized_send_notify()

static int serialized_send_notify ( void *  userdata)
static

Definition at line 2732 of file res_pjsip_pubsub.c.

2733{
2734 struct sip_subscription_tree *sub_tree = userdata;
2735 pjsip_dialog *dlg = sub_tree->dlg;
2736
2737 pjsip_dlg_inc_lock(dlg);
2738
2739 sub_tree->notify_sched_id = -1;
2740
2741 /* It's possible that between when the notification was scheduled
2742 * and now a new SUBSCRIBE arrived requiring full state to be
2743 * sent out in an immediate NOTIFY. It's also possible that we're
2744 * already processing a terminate. If that has happened, we need to
2745 * bail out here instead of sending the batched NOTIFY.
2746 */
2747
2749 || !sub_tree->send_scheduled_notify) {
2750 pjsip_dlg_dec_lock(dlg);
2751 ao2_cleanup(sub_tree);
2752 return 0;
2753 }
2754
2755 if (sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) {
2757 }
2758
2759 send_notify(sub_tree, 0);
2760
2762 sub_tree->state == SIP_SUB_TREE_TERMINATED
2763 ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2764 "Resource: %s", sub_tree->root->resource);
2765
2766 pjsip_dlg_dec_lock(dlg);
2767 ao2_cleanup(sub_tree);
2768 return 0;
2769}

References ao2_cleanup, ast_test_suite_event_notify, sip_subscription_tree::dlg, sip_subscription_tree::notify_sched_id, ast_sip_subscription::resource, sip_subscription_tree::root, send_notify(), sip_subscription_tree::send_scheduled_notify, SIP_SUB_TREE_TERMINATE_IN_PROGRESS, SIP_SUB_TREE_TERMINATED, sip_subscription_tree::state, and ast_sip_subscription::subscription_state.

Referenced by sched_cb().

◆ set_state_terminated()

static void set_state_terminated ( struct ast_sip_subscription sub)
static

Definition at line 2669 of file res_pjsip_pubsub.c.

2670{
2671 int i;
2672
2673 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2674 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2675 set_state_terminated(AST_VECTOR_GET(&sub->children, i));
2676 }
2677}

References AST_VECTOR_GET, AST_VECTOR_SIZE, set_state_terminated(), and sub.

Referenced by pubsub_on_refresh_timeout(), pubsub_on_rx_refresh(), and set_state_terminated().

◆ shutdown_subscriptions()

static void shutdown_subscriptions ( struct ast_sip_subscription sub)
static

Definition at line 1574 of file res_pjsip_pubsub.c.

1575{
1576 int i;
1577
1578 if (!sub) {
1579 return;
1580 }
1581
1582 if (AST_VECTOR_SIZE(&sub->children) > 0) {
1583 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
1585 }
1586 return;
1587 }
1588
1589 /* We notify subscription shutdown only on the tree leaves. */
1590 if (sub->handler->subscription_shutdown) {
1591 sub->handler->subscription_shutdown(sub);
1592 }
1593}

References AST_VECTOR_GET, AST_VECTOR_SIZE, shutdown_subscriptions(), and sub.

Referenced by clean_sub_tree(), pubsub_on_rx_refresh(), and shutdown_subscriptions().

◆ sip_create_publication()

static struct ast_sip_publication * sip_create_publication ( struct ast_sip_endpoint endpoint,
pjsip_rx_data *  rdata,
const char *  resource,
const char *  event_configuration_name 
)
static

Definition at line 3418 of file res_pjsip_pubsub.c.

3420{
3421 struct ast_sip_publication *publication;
3422 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3423 size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
3424 char *dst;
3425
3427
3428 if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
3429 return NULL;
3430 }
3431
3433
3434 if (!(publication->datastores = ast_datastores_alloc())) {
3435 ao2_ref(publication, -1);
3436 return NULL;
3437 }
3438
3440 ao2_ref(endpoint, +1);
3441 publication->endpoint = endpoint;
3442 publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3443 publication->sched_id = -1;
3444 dst = publication->data;
3445 publication->resource = strcpy(dst, resource);
3446 dst += resource_len;
3447 publication->event_configuration_name = strcpy(dst, event_configuration_name);
3448
3449 return publication;
3450}
static void publication_destroy_fn(void *obj)
Internal destructor for publications.
unsigned int expires
Expiration time of the publication.

References ao2_alloc, ao2_ref, ast_assert, ast_atomic_fetchadd_int(), ast_datastores_alloc(), ast_module_ref, ast_sip_publication::data, ast_sip_publication::datastores, DEFAULT_PUBLISH_EXPIRES, ast_sip_publication::endpoint, ast_sip_publication::entity_tag, esc_etag_counter, ast_sip_publication::event_configuration_name, ast_sip_publication::expires, NULL, publication_destroy_fn(), ast_sip_publication::resource, ast_sip_publication::sched_id, and ast_module_info::self.

Referenced by publish_request_initial().

◆ sip_publication_respond()

static int sip_publication_respond ( struct ast_sip_publication pub,
int  status_code,
pjsip_rx_data *  rdata 
)
static

Definition at line 3452 of file res_pjsip_pubsub.c.

3454{
3455 pjsip_tx_data *tdata;
3456 pjsip_transaction *tsx;
3457
3458 if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, status_code, NULL, &tdata) != PJ_SUCCESS) {
3459 return -1;
3460 }
3461
3462 if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3463 char buf[30];
3464
3465 snprintf(buf, sizeof(buf), "%d", pub->entity_tag);
3466 ast_sip_add_header(tdata, "SIP-ETag", buf);
3467
3468 snprintf(buf, sizeof(buf), "%d", pub->expires);
3469 ast_sip_add_header(tdata, "Expires", buf);
3470 }
3471
3472 if (pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3473 pjsip_tx_data_dec_ref(tdata);
3474 return -1;
3475 }
3476
3477 pjsip_tsx_recv_msg(tsx, rdata);
3478
3479 if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3480 pjsip_tx_data_dec_ref(tdata);
3481 return -1;
3482 }
3483
3484 return 0;
3485}
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition: res_pjsip.c:2008

References ast_sip_add_header(), ast_sip_get_pjsip_endpoint(), buf, ast_sip_publication::entity_tag, ast_sip_publication::expires, NULL, and pubsub_module.

Referenced by publish_request_initial(), and pubsub_on_rx_publish_request().

◆ sip_subscription_accept()

static int sip_subscription_accept ( struct sip_subscription_tree sub_tree,
pjsip_rx_data *  rdata,
int  response 
)
static

Definition at line 2877 of file res_pjsip_pubsub.c.

2878{
2879 pjsip_hdr res_hdr;
2880
2881 /* If this is a persistence recreation the subscription has already been accepted */
2882 if (ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_PERSISTENCE)) {
2883 return 0;
2884 }
2885
2886 pj_list_init(&res_hdr);
2887 if (sub_tree->is_list) {
2888 /* If subscribing to a list, our response has to have a Require: eventlist header in it */
2889 pj_list_insert_before(&res_hdr, create_require_eventlist(rdata->tp_info.pool));
2890 }
2891
2892 return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2893}

References ast_sip_mod_data_get, create_require_eventlist(), sip_subscription_tree::evsub, sip_subscription_tree::is_list, MOD_DATA_PERSISTENCE, and pubsub_module.

Referenced by pubsub_on_rx_subscribe_request().

◆ sip_subscription_send_request()

static int sip_subscription_send_request ( struct sip_subscription_tree sub_tree,
pjsip_tx_data *  tdata 
)
static

Definition at line 2237 of file res_pjsip_pubsub.c.

2238{
2239#ifdef TEST_FRAMEWORK
2240 struct ast_sip_endpoint *endpoint = sub_tree->endpoint;
2241 pjsip_evsub *evsub = sub_tree->evsub;
2242#endif
2243 int res;
2244
2245 if (allocate_tdata_buffer(tdata)) {
2246 ast_log(LOG_ERROR, "SIP request %s is too large to send.\n", tdata->info);
2247 pjsip_tx_data_dec_ref(tdata);
2248 return -1;
2249 }
2250
2251 res = pjsip_evsub_send_request(sub_tree->evsub, tdata);
2252
2254
2255 ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
2256 "StateText: %s\r\n"
2257 "Endpoint: %s\r\n",
2258 pjsip_evsub_get_state_name(evsub),
2259 ast_sorcery_object_get_id(endpoint));
2260
2261 return (res == PJ_SUCCESS ? 0 : -1);
2262}
static int allocate_tdata_buffer(pjsip_tx_data *tdata)
Pre-allocate a buffer for the transmission.

References allocate_tdata_buffer(), ast_log, ast_sorcery_object_get_id(), ast_test_suite_event_notify, sip_subscription_tree::endpoint, sip_subscription_tree::evsub, LOG_ERROR, NULL, SUBSCRIPTION_PERSISTENCE_SEND_REQUEST, and subscription_persistence_update().

Referenced by send_notify().

◆ sip_subscription_to_ami()

static void sip_subscription_to_ami ( struct sip_subscription_tree sub_tree,
struct ast_str **  buf 
)
static

Definition at line 2068 of file res_pjsip_pubsub.c.

2070{
2071 char str[256];
2072 struct ast_sip_endpoint_id_configuration *id = &sub_tree->endpoint->id;
2073
2074 ast_str_append(buf, 0, "Role: %s\r\n",
2075 sip_subscription_roles_map[sub_tree->role]);
2076 ast_str_append(buf, 0, "Endpoint: %s\r\n",
2078
2079 if (sub_tree->dlg) {
2080 ast_copy_pj_str(str, &sub_tree->dlg->call_id->id, sizeof(str));
2081 } else {
2082 ast_copy_string(str, "<unknown>", sizeof(str));
2083 }
2084 ast_str_append(buf, 0, "Callid: %s\r\n", str);
2085
2086 ast_str_append(buf, 0, "State: %s\r\n", pjsip_evsub_get_state_name(sub_tree->evsub));
2087
2088 ast_callerid_merge(str, sizeof(str),
2089 S_COR(id->self.name.valid, id->self.name.str, NULL),
2090 S_COR(id->self.number.valid, id->self.number.str, NULL),
2091 "Unknown");
2092
2093 ast_str_append(buf, 0, "Callerid: %s\r\n", str);
2094
2095 /* XXX This needs to be done recursively for lists */
2096 if (sub_tree->root->handler->to_ami) {
2097 sub_tree->root->handler->to_ami(sub_tree->root, buf);
2098 }
2099}
static const char * sip_subscription_roles_map[]
Party identification options for endpoints.
Definition: res_pjsip.h:859
void(* to_ami)(struct ast_sip_subscription *sub, struct ast_str **buf)
Converts the subscriber to AMI.

References ast_callerid_merge(), ast_copy_pj_str(), ast_copy_string(), ast_sorcery_object_get_id(), ast_str_append(), buf, sip_subscription_tree::dlg, sip_subscription_tree::endpoint, sip_subscription_tree::evsub, ast_sip_subscription::handler, id, ast_sip_endpoint::id, NULL, sip_subscription_tree::role, sip_subscription_tree::root, S_COR, sip_subscription_roles_map, str, and ast_sip_subscription_handler::to_ami.

Referenced by ami_subscription_detail(), and cli_show_subscription_common().

◆ sub_add_handler()

static void sub_add_handler ( struct ast_sip_subscription_handler handler)
static

◆ sub_persistence_recreate()

static int sub_persistence_recreate ( void *  obj)
static

Definition at line 1804 of file res_pjsip_pubsub.c.

1805{
1806 struct persistence_recreate_data *recreate_data = obj;
1807 struct subscription_persistence *persistence = recreate_data->persistence;
1808 pjsip_rx_data *rdata = recreate_data->rdata;
1809 struct ast_sip_endpoint *endpoint;
1810 struct sip_subscription_tree *sub_tree;
1811 struct ast_sip_pubsub_body_generator *generator;
1813 char *resource;
1814 size_t resource_size;
1815 int resp;
1816 struct resource_tree tree;
1817 pjsip_expires_hdr *expires_header;
1818 int64_t expires;
1819 const pj_str_t *user;
1820
1821 user = ast_sip_pjsip_uri_get_username(rdata->msg_info.msg->line.req.uri);
1822 resource_size = pj_strlen(user) + 1;
1823 resource = ast_alloca(resource_size);
1824 ast_copy_pj_str(resource, user, resource_size);
1825
1826 /*
1827 * We may want to match without any user options getting
1828 * in the way.
1829 */
1831
1833 if (!handler || !handler->notifier) {
1834 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get subscription handler.\n",
1835 persistence->endpoint);
1837 return 0;
1838 }
1839
1841 if (!generator) {
1842 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Body generator not available.\n",
1843 persistence->endpoint);
1845 return 0;
1846 }
1847
1848 ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data,
1849 pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
1850
1851 /* Getting the endpoint may take some time that can affect the expiration. */
1852 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1853 persistence->endpoint);
1854 if (!endpoint) {
1855 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The endpoint was not found\n",
1856 persistence->endpoint);
1858 return 0;
1859 }
1860
1861 /* Update the expiration header with the new expiration */
1862 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1863 rdata->msg_info.msg->hdr.next);
1864 if (!expires_header) {
1865 expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1866 if (!expires_header) {
1867 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not update expires header.\n",
1868 persistence->endpoint);
1870 ao2_ref(endpoint, -1);
1871 return 0;
1872 }
1873 pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1874 }
1875
1876 expires = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
1877 if (expires <= 0) {
1878 /* The subscription expired since we started recreating the subscription. */
1879 ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1880 persistence->endpoint, persistence->tag);
1882 ao2_ref(endpoint, -1);
1883 return 0;
1884 }
1885 expires_header->ivalue = expires;
1886
1887 memset(&tree, 0, sizeof(tree));
1888 resp = build_resource_tree(endpoint, handler, resource, &tree,
1890 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1891 pj_status_t dlg_status;
1892
1893 sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,
1894 &tree, &dlg_status, persistence);
1895 if (!sub_tree) {
1896 if (dlg_status != PJ_EEXISTS) {
1897 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",
1898 persistence->endpoint);
1900 }
1901 } else {
1902 struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
1903
1904 if (!ind) {
1905 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1906 goto error;
1907 }
1908
1909 ind->sub_tree = ao2_bump(sub_tree);
1910 ind->expires = expires_header->ivalue;
1911
1914 /* Could not send initial subscribe NOTIFY */
1915 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1916 ao2_ref(sub_tree, -1);
1917 ast_free(ind);
1918 }
1919 }
1920 } else {
1922 }
1923
1924error:
1925 resource_tree_destroy(&tree);
1926 ao2_ref(endpoint, -1);
1927
1928 return 0;
1929}
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2238
struct subscription_persistence * persistence

References ao2_bump, ao2_ref, ast_alloca, ast_copy_pj_str(), ast_debug, ast_free, ast_log, ast_malloc, ast_sip_get_sorcery(), ast_sip_mod_data_set, ast_sip_pjsip_uri_get_username(), ast_sip_pubsub_has_eventlist_support(), ast_sip_push_task(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_sorcery_delete(), ast_sorcery_retrieve_by_id(), ast_tvdiff_ms(), ast_tvnow(), build_resource_tree(), create_subscription_tree(), subscription_persistence::endpoint, error(), sip_subscription_tree::evsub, subscription_persistence::expires, initial_notify_data::expires, handler(), initial_notify_task(), LOG_WARNING, MOD_DATA_PERSISTENCE, persistence_recreate_data::persistence, pubsub_module, persistence_recreate_data::rdata, resource_tree_destroy(), sip_subscription_tree::serializer, initial_notify_data::sub_tree, subscription_get_generator_from_rdata(), subscription_get_handler_from_rdata(), SUBSCRIPTION_PERSISTENCE_RECREATED, subscription_persistence_update(), subscription_persistence::tag, and user.

Referenced by subscription_persistence_recreate().

◆ sub_tree_subscription_terminate_cb()

static int sub_tree_subscription_terminate_cb ( void *  data)
static

Definition at line 796 of file res_pjsip_pubsub.c.

797{
798 struct sip_subscription_tree *sub_tree = data;
799
800 if (!sub_tree->evsub) {
801 /* Something else already terminated the subscription. */
802 ao2_ref(sub_tree, -1);
803 return 0;
804 }
805
806 ast_debug(3, "Transport destroyed. Removing subscription '%s->%s' prune on boot: %d\n",
807 sub_tree->persistence->endpoint, sub_tree->root->resource,
808 sub_tree->persistence->prune_on_boot);
809
811 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
812
813 ao2_ref(sub_tree, -1);
814 return 0;
815}

References ao2_ref, ast_debug, subscription_persistence::endpoint, sip_subscription_tree::evsub, sip_subscription_tree::persistence, subscription_persistence::prune_on_boot, ast_sip_subscription::resource, sip_subscription_tree::root, SIP_SUB_TREE_TERMINATE_IN_PROGRESS, and sip_subscription_tree::state.

Referenced by sub_tree_transport_cb().

◆ sub_tree_transport_cb()

static void sub_tree_transport_cb ( void *  data)
static

Definition at line 825 of file res_pjsip_pubsub.c.

826{
827 struct sip_subscription_tree *sub_tree = data;
828
829 /*
830 * Push off the subscription termination to the serializer to
831 * avoid deadlock. Another thread could be trying to send a
832 * message on the subscription that can deadlock with this
833 * thread.
834 */
835 ao2_ref(sub_tree, +1);
837 sub_tree)) {
838 ao2_ref(sub_tree, -1);
839 }
840}
static int sub_tree_subscription_terminate_cb(void *data)

References ao2_ref, ast_sip_push_task(), sip_subscription_tree::serializer, and sub_tree_subscription_terminate_cb().

Referenced by subscription_persistence_remove(), subscription_persistence_update(), and unload_module().

◆ subscription_get_generator_from_rdata()

static struct ast_sip_pubsub_body_generator * subscription_get_generator_from_rdata ( pjsip_rx_data *  rdata,
const struct ast_sip_subscription_handler handler 
)
static

Retrieve a body generator using the Accept header of an rdata message.

Definition at line 1054 of file res_pjsip_pubsub.c.

1056{
1057 pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
1058 char accept[AST_SIP_MAX_ACCEPT][64];
1059 size_t num_accept_headers = 0;
1060
1061 while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
1062 (num_accept_headers < AST_SIP_MAX_ACCEPT)) {
1063 int i;
1064
1065 for (i = 0; i < accept_header->count && num_accept_headers < AST_SIP_MAX_ACCEPT; ++i) {
1066 if (!exceptional_accept(&accept_header->values[i])) {
1067 ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
1068 ++num_accept_headers;
1069 }
1070 }
1071 }
1072
1073 if (num_accept_headers == 0) {
1074 /* If a SUBSCRIBE contains no Accept headers, then we must assume that
1075 * the default accept type for the event package is to be used.
1076 */
1077 ast_copy_string(accept[0], handler->notifier->default_accept, sizeof(accept[0]));
1078 num_accept_headers = 1;
1079 }
1080
1081 return find_body_generator(accept, num_accept_headers, handler->body_type);
1082}
static int exceptional_accept(const pj_str_t *accept)
Is the Accept header from the SUBSCRIBE in the list of exceptions?
static struct ast_sip_pubsub_body_generator * find_body_generator(char accept[AST_SIP_MAX_ACCEPT][64], size_t num_accept, const char *body_type)

References ast_copy_pj_str(), ast_copy_string(), AST_SIP_MAX_ACCEPT, exceptional_accept(), find_body_generator(), handler(), and while().

Referenced by pubsub_on_rx_refresh(), pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

◆ subscription_get_handler_from_rdata()

static struct ast_sip_subscription_handler * subscription_get_handler_from_rdata ( pjsip_rx_data *  rdata,
const char *  endpoint 
)
static

Retrieve a handler using the Event header of an rdata message.

Definition at line 994 of file res_pjsip_pubsub.c.

995{
996 pjsip_event_hdr *event_header;
997 char event[32];
999
1000 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
1001 if (!event_header) {
1002 ast_log(LOG_WARNING, "Incoming SUBSCRIBE request from %s with no Event header\n",
1003 endpoint ? endpoint : "Unknown");
1004 return NULL;
1005 }
1006 ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
1007
1009 if (!handler) {
1010 ast_log(LOG_WARNING, "No registered subscribe handler for event %s from %s\n", event,
1011 endpoint ? endpoint : "Unknown");
1012 }
1013
1014 return handler;
1015}

References ast_copy_pj_str(), ast_log, find_sub_handler_for_event_name(), handler(), LOG_WARNING, NULL, and str_event_name.

Referenced by pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

◆ subscription_persistence_alloc()

static void * subscription_persistence_alloc ( const char *  name)
static

Allocator for subscription persistence.

Definition at line 853 of file res_pjsip_pubsub.c.

854{
856}
static void subscription_persistence_destroy(void *obj)
Destructor for subscription persistence.

References ast_sorcery_generic_alloc(), and subscription_persistence_destroy().

Referenced by load_module().

◆ subscription_persistence_create()

static struct subscription_persistence * subscription_persistence_create ( struct sip_subscription_tree sub_tree)
static

Function which creates initial persistence information of a subscription in sorcery.

Definition at line 859 of file res_pjsip_pubsub.c.

860{
861 char tag[PJ_GUID_STRING_LENGTH + 1];
862
863 /* The id of this persistence object doesn't matter as we keep it on the subscription and don't need to
864 * look it up by id at all.
865 */
867 "subscription_persistence", NULL);
868
869 pjsip_dialog *dlg = sub_tree->dlg;
870
871 if (!persistence) {
872 return NULL;
873 }
874
875 persistence->endpoint = ast_strdup(ast_sorcery_object_get_id(sub_tree->endpoint));
876 ast_copy_pj_str(tag, &dlg->local.info->tag, sizeof(tag));
877 persistence->tag = ast_strdup(tag);
878
880 return persistence;
881}
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
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744

References ast_copy_pj_str(), ast_sip_get_sorcery(), ast_sorcery_alloc(), ast_sorcery_create(), ast_sorcery_object_get_id(), ast_strdup, sip_subscription_tree::dlg, subscription_persistence::endpoint, sip_subscription_tree::endpoint, NULL, and subscription_persistence::tag.

Referenced by pubsub_on_rx_subscribe_request().

◆ subscription_persistence_destroy()

static void subscription_persistence_destroy ( void *  obj)
static

Destructor for subscription persistence.

Definition at line 843 of file res_pjsip_pubsub.c.

844{
845 struct subscription_persistence *persistence = obj;
846
847 ast_free(persistence->endpoint);
848 ast_free(persistence->tag);
849 ast_json_unref(persistence->generator_data);
850}

References ast_free, ast_json_unref(), subscription_persistence::endpoint, subscription_persistence::generator_data, and subscription_persistence::tag.

Referenced by subscription_persistence_alloc().

◆ subscription_persistence_event_cb()

static void subscription_persistence_event_cb ( void *  data,
struct stasis_subscription sub,
struct stasis_message message 
)
static

Event callback which fires subscription persistence recreation when the system is fully booted.

Definition at line 2020 of file res_pjsip_pubsub.c.

2021{
2022 struct ast_json_payload *payload;
2023 const char *type;
2024
2026 return;
2027 }
2028
2029 payload = stasis_message_data(message);
2030 type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
2031
2032 /* This subscription only responds to the FullyBooted event so that all modules have been loaded when we
2033 * recreate SIP subscriptions.
2034 */
2035 if (strcmp(type, "FullyBooted")) {
2036 return;
2037 }
2038
2039 /* This has to be here so the subscription is recreated when the body generator is available */
2041
2042 /* Once the system is fully booted we don't care anymore */
2044}
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:998
struct ast_json * json
Definition: json.h:1083

References ast_json_object_get(), ast_json_string_get(), ast_manager_get_generic_type(), ast_sip_push_task(), ast_json_payload::json, NULL, stasis_message_data(), stasis_message_type(), stasis_unsubscribe(), sub, subscription_persistence_load(), and type.

Referenced by load_module().

◆ subscription_persistence_load()

static int subscription_persistence_load ( void *  data)
static

Function which loads and recreates persisted subscriptions upon startup when the system is fully booted.

Definition at line 1998 of file res_pjsip_pubsub.c.

1999{
2000 struct ao2_container *persisted_subscriptions = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
2001 "subscription_persistence", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
2002 pj_pool_t *pool;
2003
2004 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "rtd%p", PJSIP_POOL_RDATA_LEN,
2005 PJSIP_POOL_RDATA_INC);
2006 if (!pool) {
2007 ast_log(LOG_WARNING, "Could not create a memory pool for recreating SIP subscriptions\n");
2008 return 0;
2009 }
2010
2011 ao2_callback(persisted_subscriptions, OBJ_NODATA, subscription_persistence_recreate, pool);
2012
2013 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
2014
2015 ao2_ref(persisted_subscriptions, -1);
2016 return 0;
2017}
static int subscription_persistence_recreate(void *obj, void *arg, int flags)
Callback function to perform the actual recreation of a subscription.

References ao2_callback, ao2_ref, ast_log, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sorcery_retrieve_by_fields(), LOG_WARNING, NULL, OBJ_NODATA, and subscription_persistence_recreate().

Referenced by load_module(), and subscription_persistence_event_cb().

◆ subscription_persistence_recreate()

static int subscription_persistence_recreate ( void *  obj,
void *  arg,
int  flags 
)
static

Callback function to perform the actual recreation of a subscription.

Definition at line 1932 of file res_pjsip_pubsub.c.

1933{
1934 struct subscription_persistence *persistence = obj;
1935 pj_pool_t *pool = arg;
1937 pjsip_rx_data rdata;
1938 struct persistence_recreate_data recreate_data;
1939
1940 /* If this subscription used a reliable transport it can't be reestablished so remove it */
1942 ast_debug(3, "Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1945 return 0;
1946 }
1947
1948 /* If this subscription has already expired remove it */
1950 ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1953 return 0;
1954 }
1955
1956 memset(&rdata, 0, sizeof(rdata));
1957 pj_pool_reset(pool);
1958 rdata.tp_info.pool = pool;
1959
1963 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n",
1966 return 0;
1967 }
1968
1969 if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1970 ast_log(LOG_NOTICE, "Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1973 return 0;
1974 }
1975
1976 /* Continue the remainder in the distributor serializer */
1978 if (!serializer) {
1979 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1982 return 0;
1983 }
1984 recreate_data.persistence = persistence;
1985 recreate_data.rdata = &rdata;
1987 &recreate_data)) {
1988 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
1991 }
1993
1994 return 0;
1995}
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
#define LOG_NOTICE
int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type, const char *local_name, int local_port, const char *contact_uri)
General purpose method for creating an rdata structure using specific information.
Definition: res_pjsip.c:1214
static int sub_persistence_recreate(void *obj)
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
char src_name[PJ_INET6_ADDRSTRLEN]
char contact_uri[PJSIP_MAX_URL_SIZE]
char packet[PJSIP_MAX_PKT_LEN]
char local_name[PJ_INET6_ADDRSTRLEN]
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.

References ast_debug, ast_log, ast_sip_create_rdata_with_contact(), ast_sip_get_distributor_serializer(), ast_sip_get_sorcery(), ast_sip_push_task_wait_serializer(), ast_sorcery_delete(), ast_taskprocessor_unreference(), ast_tvdiff_ms(), ast_tvnow(), subscription_persistence::contact_uri, subscription_persistence::endpoint, subscription_persistence::expires, subscription_persistence::local_name, subscription_persistence::local_port, LOG_NOTICE, LOG_WARNING, subscription_persistence::packet, persistence_recreate_data::persistence, subscription_persistence::prune_on_boot, persistence_recreate_data::rdata, subscription_persistence::src_name, subscription_persistence::src_port, sub_persistence_recreate(), subscription_persistence::tag, and subscription_persistence::transport_type.

Referenced by subscription_persistence_load().

◆ subscription_persistence_remove()

static void subscription_persistence_remove ( struct sip_subscription_tree sub_tree)
static

Function which removes persistence of a subscription from sorcery.

Definition at line 968 of file res_pjsip_pubsub.c.

969{
970 if (!sub_tree->persistence) {
971 return;
972 }
973
974 if (sub_tree->persistence->prune_on_boot && !ast_strlen_zero(sub_tree->transport_key)) {
975 ast_debug(3, "Unregistering transport monitor on %s '%s->%s'\n",
976 sub_tree->transport_key,
977 sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
978 sub_tree->root ? sub_tree->root->resource : "Unknown");
980 sub_tree_transport_cb, sub_tree, NULL);
981 }
982
984 ao2_ref(sub_tree->persistence, -1);
985 sub_tree->persistence = NULL;
986}
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.
static void sub_tree_transport_cb(void *data)
char transport_key[IP6ADDR_COLON_PORT_BUFLEN]

References ao2_ref, ast_debug, ast_sip_get_sorcery(), ast_sip_transport_monitor_unregister_key(), ast_sorcery_delete(), ast_sorcery_object_get_id(), ast_strlen_zero(), sip_subscription_tree::endpoint, NULL, sip_subscription_tree::persistence, subscription_persistence::prune_on_boot, ast_sip_subscription::resource, sip_subscription_tree::root, sub_tree_transport_cb(), and sip_subscription_tree::transport_key.

Referenced by clean_sub_tree().

◆ subscription_persistence_update()

static void subscription_persistence_update ( struct sip_subscription_tree sub_tree,
pjsip_rx_data *  rdata,
enum sip_persistence_update_type  type 
)
static

Function which updates persistence information of a subscription in sorcery.

Definition at line 884 of file res_pjsip_pubsub.c.

886{
887 pjsip_dialog *dlg;
888
889 if (!sub_tree->persistence) {
890 return;
891 }
892
893 ast_debug(3, "Updating persistence for '%s->%s' prune on boot: %s\n",
894 sub_tree->persistence->endpoint, sub_tree->root->resource,
895 sub_tree->persistence->prune_on_boot ? "yes" : "no");
896
897 dlg = sub_tree->dlg;
898 sub_tree->persistence->cseq = dlg->local.cseq;
899
900 if (rdata) {
901 unsigned int expires;
902 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
903 pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
904
905 expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
906 sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1));
907
908 if (contact_hdr) {
909 if (contact_hdr) {
911 sub_tree->persistence->prune_on_boot =
913 (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
914 sub_tree->endpoint, rdata);
915
916 if (sub_tree->persistence->prune_on_boot) {
917 ast_debug(3, "adding transport monitor on %s for '%s->%s' prune on boot: %d\n",
918 rdata->tp_info.transport->obj_name,
919 sub_tree->persistence->endpoint, sub_tree->root->resource,
920 sub_tree->persistence->prune_on_boot);
921 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(rdata->tp_info.transport,
922 sub_tree->transport_key);
924 sub_tree_transport_cb, sub_tree);
925 /*
926 * FYI: ast_sip_transport_monitor_register holds a reference to the sub_tree
927 */
928 }
929 }
930 }
931
932 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
933 sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri));
934 } else {
935 ast_log(LOG_WARNING, "Contact not updated due to missing contact header\n");
936 }
937
938 /* When receiving a packet on an streaming transport, it's possible to receive more than one SIP
939 * message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf
940 * will always point to the proper SIP message that is to be processed. When updating subscription
941 * persistence that is pulled from persistent storage, though, the rdata->pkt_info.packet will
942 * only ever have a single SIP message on it, and so we base persistence on that.
943 */
946 if (rdata->msg_info.msg_buf) {
947 ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf,
948 MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len + 1));
949 } else {
950 ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
951 sizeof(sub_tree->persistence->packet));
952 }
953 }
954 ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
955 sizeof(sub_tree->persistence->src_name));
956 sub_tree->persistence->src_port = rdata->pkt_info.src_port;
957 ast_copy_string(sub_tree->persistence->transport_type, rdata->tp_info.transport->type_name,
958 sizeof(sub_tree->persistence->transport_type));
959 ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host,
960 sizeof(sub_tree->persistence->local_name));
961 sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port;
962 }
963
965}
int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Definition: res_pjsip.c:525
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.
#define AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(_transport, _dest)
Fill a buffer with a pjsip transport's remote ip address and port.
Definition: res_pjsip.h:91
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2150
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
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
#define MIN(a, b)
Definition: utils.h:231

References ast_copy_pj_str(), ast_copy_string(), ast_debug, ast_log, ast_samp2tv(), ast_sip_get_sorcery(), AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR, ast_sip_transport_monitor_register_key(), ast_sip_will_uri_survive_restart(), ast_sorcery_update(), ast_tvadd(), ast_tvnow(), subscription_persistence::contact_uri, subscription_persistence::cseq, DEFAULT_PUBLISH_EXPIRES, sip_subscription_tree::dlg, subscription_persistence::endpoint, sip_subscription_tree::endpoint, subscription_persistence::expires, subscription_persistence::local_name, subscription_persistence::local_port, LOG_WARNING, MIN, NULL, subscription_persistence::packet, sip_subscription_tree::persistence, subscription_persistence::prune_on_boot, ast_sip_subscription::resource, sip_subscription_tree::root, subscription_persistence::src_name, subscription_persistence::src_port, sub_tree_transport_cb(), SUBSCRIPTION_PERSISTENCE_CREATED, SUBSCRIPTION_PERSISTENCE_RECREATED, sip_subscription_tree::transport_key, subscription_persistence::transport_type, and type.

Referenced by pubsub_on_rx_refresh(), pubsub_on_rx_subscribe_request(), sip_subscription_send_request(), and sub_persistence_recreate().

◆ subscription_setup_dialog()

static void subscription_setup_dialog ( struct sip_subscription_tree sub_tree,
pjsip_dialog *  dlg 
)
static

Definition at line 1643 of file res_pjsip_pubsub.c.

1644{
1645 sub_tree->dlg = dlg;
1647 ast_sip_dialog_set_endpoint(dlg, sub_tree->endpoint);
1648 pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
1649 pjsip_dlg_inc_session(dlg, &pubsub_module);
1650}

References ast_sip_dialog_set_endpoint(), ast_sip_dialog_set_serializer(), sip_subscription_tree::dlg, sip_subscription_tree::endpoint, sip_subscription_tree::evsub, pubsub_module, and sip_subscription_tree::serializer.

Referenced by ast_sip_create_subscription(), and create_subscription_tree().

◆ subscription_tree_destructor()

static void subscription_tree_destructor ( void *  obj)
static

Definition at line 1614 of file res_pjsip_pubsub.c.

1615{
1616 struct sip_subscription_tree *sub_tree = obj;
1617
1618 ast_debug(3, "Destroying subscription tree %p '%s->%s'\n",
1619 sub_tree,
1620 sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
1621 sub_tree->root ? sub_tree->root->resource : "Unknown");
1622
1623 destroy_subscriptions(sub_tree->root);
1624
1625 if (sub_tree->dlg) {
1628 }
1629
1630 ao2_cleanup(sub_tree->endpoint);
1631
1634}
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
static int subscription_unreference_dialog(void *obj)

References ao2_cleanup, ast_debug, ast_module_unref, ast_sip_push_task_wait_servant(), ast_sorcery_object_get_id(), ast_taskprocessor_unreference(), destroy_subscriptions(), sip_subscription_tree::dlg, sip_subscription_tree::endpoint, ast_sip_subscription::resource, sip_subscription_tree::root, ast_module_info::self, sip_subscription_tree::serializer, and subscription_unreference_dialog().

Referenced by allocate_subscription_tree().

◆ subscription_unreference_dialog()

static int subscription_unreference_dialog ( void *  obj)
static

Definition at line 1595 of file res_pjsip_pubsub.c.

1596{
1597 struct sip_subscription_tree *sub_tree = obj;
1598
1599 /* This is why we keep the dialog on the subscription. When the subscription
1600 * is destroyed, there is no guarantee that the underlying dialog is ready
1601 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1602 * either. The dialog could be destroyed before our subscription is. We fix
1603 * this problem by keeping a reference to the dialog until it is time to
1604 * destroy the subscription. We need to have the dialog available when the
1605 * subscription is destroyed so that we can guarantee that our attempt to
1606 * remove the serializer will be successful.
1607 */
1608 pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
1609 sub_tree->dlg = NULL;
1610
1611 return 0;
1612}

References sip_subscription_tree::dlg, NULL, and pubsub_module.

Referenced by subscription_tree_destructor().

◆ tree_node_alloc()

static struct tree_node * tree_node_alloc ( const char *  resource,
struct resources visited,
unsigned int  full_state,
const char *  display_name 
)
static

Allocate a tree node.

In addition to allocating and initializing the tree node, the node is also added to the vector of visited resources. See build_resource_tree for more information on the visited resources.

Parameters
resourceThe name of the resource for this tree node.
visitedThe vector of resources that have been visited.
full_stateif allocating a list, indicate whether full state is requested in notifications.
display_namethe display name to include with this tree node.
Return values
NULLAllocation failure.
non-NULLThe newly-allocated tree_node

Definition at line 1160 of file res_pjsip_pubsub.c.

1161{
1162 struct tree_node *node;
1163
1164 node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
1165 if (!node) {
1166 return NULL;
1167 }
1168
1169 strcpy(node->resource, resource);
1170 if (AST_VECTOR_INIT(&node->children, 4)) {
1171 ast_free(node);
1172 return NULL;
1173 }
1174 node->full_state = full_state;
1175 node->display_name = ast_strdup(display_name);
1176
1177 if (visited) {
1178 AST_VECTOR_APPEND(visited, resource);
1179 }
1180 return node;
1181}
Definition: test_heap.c:38
char * display_name
unsigned int full_state

References ast_calloc, ast_free, ast_strdup, AST_VECTOR_APPEND, AST_VECTOR_INIT, tree_node::display_name, tree_node::full_state, NULL, and tree_node::resource.

Referenced by build_node_children(), and build_resource_tree().

◆ tree_node_destroy()

static void tree_node_destroy ( struct tree_node node)
static

Destructor for a tree node.

This function calls recursively in order to destroy all nodes lower in the tree from the given node in addition to the node itself.

Parameters
nodeThe node to destroy.

Definition at line 1192 of file res_pjsip_pubsub.c.

1193{
1194 int i;
1195 if (!node) {
1196 return;
1197 }
1198
1199 for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
1200 tree_node_destroy(AST_VECTOR_GET(&node->children, i));
1201 }
1202 AST_VECTOR_FREE(&node->children);
1203 ast_free(node->display_name);
1204 ast_free(node);
1205}

References ast_free, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_SIZE, and tree_node_destroy().

Referenced by build_node_children(), resource_tree_destroy(), and tree_node_destroy().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 6135 of file res_pjsip_pubsub.c.

6136{
6138 AST_TEST_UNREGISTER(complex_resource_tree);
6139 AST_TEST_UNREGISTER(bad_resource);
6140 AST_TEST_UNREGISTER(bad_branch);
6141 AST_TEST_UNREGISTER(duplicate_resource);
6142 AST_TEST_UNREGISTER(loop);
6143 AST_TEST_UNREGISTER(bad_event);
6144
6146
6148
6151 ast_manager_unregister("PJSIPShowResourceLists");
6152
6154 if (sched) {
6156 }
6157
6158 return 0;
6159}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
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.
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References AMI_SHOW_SUBSCRIPTIONS_INBOUND, AMI_SHOW_SUBSCRIPTIONS_OUTBOUND, ARRAY_LEN, ast_cli_unregister_multiple(), ast_manager_unregister(), ast_sched_context_destroy(), ast_sip_transport_monitor_unregister_all(), ast_sip_unregister_service(), AST_TEST_UNREGISTER, cli_commands, NULL, pubsub_module, and sub_tree_transport_cb().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "PJSIP event resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, .requires = "res_pjsip", }
static

Definition at line 6167 of file res_pjsip_pubsub.c.

◆ accept_exceptions

const char* accept_exceptions[]
Initial value:
= {
"multipart/related",
"application/rlmi+xml",
}

Accept headers that are exceptions to the rule.

Typically, when a SUBSCRIBE arrives, we attempt to find a body generator that matches one of the Accept headers in the request. When subscribing to a single resource, this works great. However, when subscribing to a list, things work differently. Most Accept header values are fine, but there are a couple that are endemic to resource lists that need to be ignored when searching for a body generator to use for the individual resources of the subscription.

Definition at line 1029 of file res_pjsip_pubsub.c.

Referenced by exceptional_accept().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 6167 of file res_pjsip_pubsub.c.

◆ body_generators

struct body_generators body_generators = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }

◆ body_supplements

struct body_supplements body_supplements = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }

◆ cli_commands

struct ast_cli_entry cli_commands[]
static
Initial value:
= {
{ .handler = cli_list_subscriptions_inout , .summary = "List active inbound/outbound subscriptions" ,},
{ .handler = cli_show_subscription_inout , .summary = "Show active subscription details" ,},
{ .handler = cli_show_subscriptions_inout , .summary = "Show active inbound/outbound subscriptions" ,},
}
static char * cli_show_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_list_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_show_subscription_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 5113 of file res_pjsip_pubsub.c.

Referenced by load_module(), and unload_module().

◆ esc_etag_counter

int esc_etag_counter
static

Used to create new entity IDs by ESCs.

Definition at line 558 of file res_pjsip_pubsub.c.

Referenced by pubsub_on_rx_publish_request(), and sip_create_publication().

◆ pjsip_publish_method

const pjsip_method pjsip_publish_method
Initial value:
=
{
PJSIP_OTHER_METHOD,
{ "PUBLISH", 7 }
}

Defined method for PUBLISH.

Definition at line 472 of file res_pjsip_pubsub.c.

Referenced by pubsub_on_rx_request().

◆ publish_handlers

struct publish_handlers publish_handlers = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }

◆ pubsub_cb

pjsip_evsub_user pubsub_cb
static

Definition at line 773 of file res_pjsip_pubsub.c.

Referenced by ast_sip_create_subscription(), and create_subscription_tree().

◆ pubsub_module

struct pjsip_module pubsub_module
static

◆ rlmi_media_type

pjsip_media_type rlmi_media_type
static

Definition at line 763 of file res_pjsip_pubsub.c.

Referenced by build_rlmi_body(), and load_module().

◆ sched

struct ast_sched_context* sched
static

Scheduler used for automatically expiring publications.

Definition at line 457 of file res_pjsip_pubsub.c.

◆ sip_subscription_roles_map

const char* sip_subscription_roles_map[]
static
Initial value:
= {
[AST_SIP_SUBSCRIBER] = "Subscriber",
[AST_SIP_NOTIFIER] = "Notifier"
}

Definition at line 742 of file res_pjsip_pubsub.c.

Referenced by sip_subscription_to_ami().

◆ str_event_name

const pj_str_t str_event_name = { "Event", 5 }
static

◆ sub_tree_state_description

char* sub_tree_state_description[]
static

◆ subscription_handlers

struct subscription_handlers subscription_handlers = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }

◆ subscriptions

struct subscriptions subscriptions = { .first = NULL, .last = NULL, .lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} } , }