Asterisk - The Open Source Telephony Project GIT-master-7e7a603
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 4374 of file res_pjsip_pubsub.c.

◆ AMI_SHOW_SUBSCRIPTIONS_OUTBOUND

#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND   "PJSIPShowSubscriptionsOutbound"

Definition at line 4375 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 4761 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 4760 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 4618 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 4613 of file res_pjsip_pubsub.c.

◆ DATASTORE_BUCKETS

#define DATASTORE_BUCKETS   53

Number of buckets for subscription datastore.

Definition at line 259 of file res_pjsip_pubsub.c.

◆ DEFAULT_EXPIRES

#define DEFAULT_EXPIRES   3600

Default expiration for subscriptions.

Definition at line 262 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 256 of file res_pjsip_pubsub.c.

◆ MAX_REGEX_ERROR_LEN

#define MAX_REGEX_ERROR_LEN   128

Definition at line 4377 of file res_pjsip_pubsub.c.

◆ MOD_DATA_MSG

#define MOD_DATA_MSG   "sub_msg"

Definition at line 245 of file res_pjsip_pubsub.c.

◆ MOD_DATA_PERSISTENCE

#define MOD_DATA_PERSISTENCE   "sub_persistence"

Definition at line 244 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 1021 of file res_pjsip_pubsub.c.

◆ PUBLICATIONS_BUCKETS

#define PUBLICATIONS_BUCKETS   37

Number of buckets for publications (on a per handler)

Definition at line 253 of file res_pjsip_pubsub.c.

◆ RESOURCE_LIST_INIT_SIZE

#define RESOURCE_LIST_INIT_SIZE   4

Definition at line 4993 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 1839 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 540 of file res_pjsip_pubsub.c.

540 {
541 /*! Called from send request */
543 /*! Subscription created from initial client request */
545 /*! Subscription recreated by asterisk on startup */
547 /*! Subscription created from client refresh */
549};
@ 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 274 of file res_pjsip_pubsub.c.

274 {
275 /*!
276 * \brief Unknown
277 *
278 * \details
279 * This actually is not defined in RFC 3903. We use this as a constant
280 * to indicate that an incoming PUBLISH does not fit into any of the
281 * other categories and is thus invalid.
282 */
284
285 /*!
286 * \brief Initial
287 *
288 * \details
289 * The first PUBLISH sent. This will contain a non-zero Expires header
290 * as well as a body that indicates the current state of the endpoint
291 * that has sent the message. The initial PUBLISH is the only type
292 * of PUBLISH to not contain a Sip-If-Match header in it.
293 */
295
296 /*!
297 * \brief Refresh
298 *
299 * \details
300 * Used to keep a published state from expiring. This will contain a
301 * non-zero Expires header but no body since its purpose is not to
302 * update state.
303 */
305
306 /*!
307 * \brief Modify
308 *
309 * \details
310 * Used to change state from its previous value. This will contain
311 * a body updating the published state. May or may not contain an
312 * Expires header.
313 */
315
316 /*!
317 * \brief Remove
318 *
319 * \details
320 * Used to remove published state from an ESC. This will contain
321 * an Expires header set to 0 and likely no body.
322 */
324};
@ 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 415 of file res_pjsip_pubsub.c.

415 {
416 /*! Normal operation */
418 /*! A terminate has been requested by Asterisk, the client, or pjproject */
420 /*! The terminate is in progress */
422 /*! The terminate process has finished and the subscription tree is no longer valid */
424};
@ 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 5960 of file res_pjsip_pubsub.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 5960 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 2071 of file res_pjsip_pubsub.c.

2073{
2074 static pj_str_t cid_name = { "cid", 3 };
2075 pj_xml_node *resource;
2076 pj_xml_node *name;
2077 pj_xml_node *instance;
2078 pj_xml_attr *cid_attr;
2079 char id[6];
2080 char uri[PJSIP_MAX_URL_SIZE];
2081 char name_sanitized[PJSIP_MAX_URL_SIZE];
2082
2083 /* This creates a string representing the Content-ID without the enclosing < > */
2084 const pj_str_t cid_stripped = {
2085 .ptr = cid->hvalue.ptr + 1,
2086 .slen = cid->hvalue.slen - 2,
2087 };
2088
2089 resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
2090 name = ast_sip_presence_xml_create_node(pool, resource, "name");
2091 instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
2092
2093 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
2094 ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
2095
2096 ast_sip_sanitize_xml(resource_name, name_sanitized, sizeof(name_sanitized));
2097 pj_strdup2(pool, &name->content, name_sanitized);
2098
2099 ast_generate_random_string(id, sizeof(id));
2100
2101 ast_sip_presence_xml_create_attr(pool, instance, "id", id);
2102 ast_sip_presence_xml_create_attr(pool, instance, "state",
2103 state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
2104
2105 /* Use the PJLIB-util XML library directly here since we are using a
2106 * pj_str_t
2107 */
2108
2109 cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2110 pj_xml_add_attr(instance, cid_attr);
2111}
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 1204 of file res_pjsip_pubsub.c.

1205{
1209}
#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 2279 of file res_pjsip_pubsub.c.

2280{
2281 struct body_part *bp;
2282
2283 bp = ast_calloc(1, sizeof(*bp));
2284 if (!bp) {
2285 return NULL;
2286 }
2287
2288 bp->cid = generate_content_id_hdr(pool, sub);
2289 bp->resource = sub->resource;
2290 bp->state = sub->subscription_state;
2291 bp->uri = sub->uri;
2292 bp->display_name = sub->display_name;
2293
2294 return bp;
2295}
#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 1263 of file res_pjsip_pubsub.c.

1265{
1266 struct ast_sip_subscription *sub;
1267 pjsip_msg *msg;
1268 pjsip_sip_uri *request_uri;
1269
1271 if (!msg) {
1272 ast_log(LOG_ERROR, "No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n", resource);
1273 return NULL;
1274 }
1275
1276 sub = ast_calloc(1, sizeof(*sub) + strlen(resource) + 1);
1277 if (!sub) {
1278 return NULL;
1279 }
1280 strcpy(sub->resource, resource); /* Safe */
1281
1282 sub->display_name = ast_strdup(display_name);
1283
1284 sub->datastores = ast_datastores_alloc();
1285 if (!sub->datastores) {
1287 return NULL;
1288 }
1289
1290 sub->body_text = ast_str_create(128);
1291 if (!sub->body_text) {
1293 return NULL;
1294 }
1295
1296 sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
1297 request_uri = pjsip_uri_get_uri(msg->line.req.uri);
1298 pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, request_uri);
1299 pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
1300
1301 /* If there is any persistence information available for this subscription that was persisted
1302 * then make it available so that the NOTIFY has the correct state.
1303 */
1304
1307 }
1308
1309 sub->handler = handler;
1310 sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1311 sub->tree = ao2_bump(tree);
1312
1313 return sub;
1314}
#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:2948
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 1445 of file res_pjsip_pubsub.c.

1446{
1447 struct sip_subscription_tree *sub_tree;
1448
1449 sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
1450 if (!sub_tree) {
1451 return NULL;
1452 }
1453
1455
1456 if (rdata) {
1457 /*
1458 * We must continue using the serializer that the original
1459 * SUBSCRIBE came in on for the dialog. There may be
1460 * retransmissions already enqueued in the original
1461 * serializer that can result in reentrancy and message
1462 * sequencing problems.
1463 */
1465 } else {
1466 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1467
1468 /* Create name with seq number appended. */
1469 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s",
1471
1472 sub_tree->serializer = ast_sip_create_serializer(tps_name);
1473 }
1474 if (!sub_tree->serializer) {
1475 ao2_ref(sub_tree, -1);
1476 return NULL;
1477 }
1478
1479 sub_tree->endpoint = ao2_bump(endpoint);
1480 sub_tree->notify_sched_id = -1;
1481
1482 return sub_tree;
1483}
#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:443
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:342
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 2008 of file res_pjsip_pubsub.c.

2009{
2010 int buf_size;
2011 int size = -1;
2012 char *buf;
2013
2014 for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
2015 buf = pj_pool_alloc(tdata->pool, buf_size);
2016 size = pjsip_msg_print(tdata->msg, buf, buf_size);
2017 }
2018
2019 if (size == -1) {
2020 return -1;
2021 }
2022
2023 tdata->buf.start = buf;
2024 tdata->buf.cur = tdata->buf.start;
2025 tdata->buf.end = tdata->buf.start + buf_size;
2026
2027 return 0;
2028}
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 4351 of file res_pjsip_pubsub.c.

4352{
4353 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4354 struct ao2_container *lists;
4355
4356 lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
4358
4359 if (!lists || !ao2_container_count(lists)) {
4360 astman_send_error(s, m, "No resource lists found\n");
4361 return 0;
4362 }
4363
4364 astman_send_listack(s, m, "A listing of resource lists follows, presented as ResourceListDetail events",
4365 "start");
4366
4368
4369 astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count);
4371 return 0;
4372}
#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:3423
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3381
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:3459
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3042
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3467
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:3047
struct mansession * s
Definition: res_pjsip.h:3049
const struct message * m
Definition: res_pjsip.h:3051

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 4301 of file res_pjsip_pubsub.c.

4302{
4303 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4304
4305 astman_send_listack(s, m, "Following are Events for each inbound Subscription",
4306 "start");
4307
4309
4310 astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count);
4312 return 0;
4313}
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 4315 of file res_pjsip_pubsub.c.

4316{
4317 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4318
4319 astman_send_listack(s, m, "Following are Events for each outbound Subscription",
4320 "start");
4321
4323
4324 astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count);
4326 return 0;
4327}
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 4270 of file res_pjsip_pubsub.c.

4273{
4274 struct ast_str *buf;
4275
4277 if (!buf) {
4278 return -1;
4279 }
4280
4281 sip_subscription_to_ami(sub_tree, &buf);
4282 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4283 ast_free(buf);
4284
4285 ++ami->count;
4286 return 0;
4287}
#define ast_free(a)
Definition: astmm.h:180
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3302
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 4289 of file res_pjsip_pubsub.c.

4290{
4291 return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
4292 sub_tree, arg, "InboundSubscriptionDetail") : 0;
4293}
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 4295 of file res_pjsip_pubsub.c.

4296{
4297 return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
4298 sub_tree, arg, "OutboundSubscriptionDetail") : 0;
4299}
@ 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 5100 of file res_pjsip_pubsub.c.

5101{
5102 ast_sorcery_apply_default(sorcery, "resource_list", "config",
5103 "pjsip.conf,criteria=type=resource_list");
5106 return -1;
5107 }
5108
5109 ast_sorcery_object_field_register(sorcery, "resource_list", "type", "",
5110 OPT_NOOP_T, 0, 0);
5111 ast_sorcery_object_field_register(sorcery, "resource_list", "event", "",
5113 ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "no",
5114 OPT_BOOL_T, 1, FLDSET(struct resource_list, full_state));
5115 ast_sorcery_object_field_register(sorcery, "resource_list", "notification_batch_interval",
5116 "0", OPT_UINT_T, 0, FLDSET(struct resource_list, notification_batch_interval));
5117 ast_sorcery_object_field_register_custom(sorcery, "resource_list", "list_item",
5119 ast_sorcery_object_field_register(sorcery, "resource_list", "resource_display_name", "no",
5120 OPT_BOOL_T, 1, FLDSET(struct resource_list, resource_display_name));
5121
5122 ast_sorcery_reload_object(sorcery, "resource_list");
5123
5124 return 0;
5125}
#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 5960 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 1909 of file res_pjsip_pubsub.c.

1911{
1912 struct ast_sip_subscription *sub;
1913 pjsip_dialog *dlg;
1914 struct ast_sip_contact *contact;
1915 pj_str_t event;
1916 pjsip_tx_data *tdata;
1917 pjsip_evsub *evsub;
1918 struct sip_subscription_tree *sub_tree = NULL;
1919
1921 if (!sub_tree) {
1922 return NULL;
1923 }
1924
1925 sub = allocate_subscription(handler, resource, NULL, sub_tree);
1926 if (!sub) {
1927 ao2_cleanup(sub_tree);
1928 return NULL;
1929 }
1930
1932 if (!contact || ast_strlen_zero(contact->uri)) {
1933 ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
1935 ao2_ref(sub_tree, -1);
1936 ao2_cleanup(contact);
1937 return NULL;
1938 }
1939
1941 ao2_cleanup(contact);
1942 if (!dlg) {
1943 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1944 ao2_ref(sub_tree, -1);
1945 return NULL;
1946 }
1947
1948 pj_cstr(&event, handler->event_name);
1949 pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub_tree->evsub);
1950 subscription_setup_dialog(sub_tree, dlg);
1951
1952 evsub = sub_tree->evsub;
1953
1954 if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
1955 pjsip_evsub_send_request(sub_tree->evsub, tdata);
1956 } else {
1957 /* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
1958 * being called and terminating the subscription. Therefore, we don't
1959 * need to decrease the reference count of sub here.
1960 */
1961 pjsip_evsub_terminate(evsub, PJ_TRUE);
1962 ao2_ref(sub_tree, -1);
1963 return NULL;
1964 }
1965
1966 add_subscription(sub_tree);
1967
1968 return sub;
1969}
#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:392
const ast_string_field uri
Definition: res_pjsip.h:414
const ast_string_field aors
Definition: res_pjsip.h:992

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 2713 of file res_pjsip_pubsub.c.

2714{
2715 return ast_datastores_add(publication->datastores, datastore);
2716}
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 2718 of file res_pjsip_pubsub.c.

2719{
2720 return ast_datastores_find(publication->datastores, name);
2721}
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 2728 of file res_pjsip_pubsub.c.

2729{
2730 return publication->datastores;
2731}

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 3487 of file res_pjsip_pubsub.c.

3488{
3489 return pub->endpoint;
3490}
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 3497 of file res_pjsip_pubsub.c.

3498{
3499 return pub->event_configuration_name;
3500}
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 3492 of file res_pjsip_pubsub.c.

3493{
3494 return pub->resource;
3495}
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 2723 of file res_pjsip_pubsub.c.

2724{
2725 ast_datastores_remove(publication->datastores, name);
2726}
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 3586 of file res_pjsip_pubsub.c.

3588{
3589 struct ast_sip_pubsub_body_supplement *supplement;
3590 struct ast_sip_pubsub_body_generator *generator;
3591 int res = 0;
3592 void *body;
3593
3595 if (!generator) {
3596 ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
3597 type, subtype);
3598 return -1;
3599 }
3600
3601 if (strcmp(data->body_type, generator->body_type)) {
3602 ast_log(LOG_WARNING, "%s/%s body generator does not accept the type of data provided\n",
3603 type, subtype);
3604 return -1;
3605 }
3606
3607 body = generator->allocate_body(data->body_data);
3608 if (!body) {
3609 ast_log(LOG_WARNING, "%s/%s body generator could not to allocate a body\n",
3610 type, subtype);
3611 return -1;
3612 }
3613
3614 if (generator->generate_body_content(body, data->body_data)) {
3615 res = -1;
3616 goto end;
3617 }
3618
3621 if (!strcmp(generator->type, supplement->type) &&
3622 !strcmp(generator->subtype, supplement->subtype)) {
3623 res = supplement->supplement_body(body, data->body_data);
3624 if (res) {
3625 break;
3626 }
3627 }
3628 }
3630
3631 if (!res) {
3632 generator->to_string(body, str);
3633 }
3634
3635end:
3636 if (generator->destroy_body) {
3637 generator->destroy_body(body);
3638 }
3639
3640 return res;
3641}
const char * str
Definition: app_jack.c:147
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.
void(* destroy_body)(void *body)
Deallocate resources created for the body.
struct ast_sip_pubsub_body_generator::@261 list
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 882 of file res_pjsip_pubsub.c.

883{
884 pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
885
886 while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
887 int i;
888
889 for (i = 0; i < supported_header->count; i++) {
890 if (!pj_stricmp2(&supported_header->values[i], "eventlist")) {
891 return 1;
892 }
893 }
894 }
895
896 return 0;
897}
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 3502 of file res_pjsip_pubsub.c.

3503{
3504 return !!find_body_generator_type_subtype(type, subtype);
3505}

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 3507 of file res_pjsip_pubsub.c.

3508{
3509 struct ast_sip_pubsub_body_generator *existing;
3510 pj_str_t accept;
3511 pj_size_t accept_len;
3512
3514 existing = find_body_generator_type_subtype_nolock(generator->type, generator->subtype);
3515 if (existing) {
3517 ast_log(LOG_WARNING, "A body generator for %s/%s is already registered.\n",
3518 generator->type, generator->subtype);
3519 return -1;
3520 }
3523
3524 /* Lengths of type and subtype plus a slash. */
3525 accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
3526
3527 /* Add room for null terminator that sprintf() will set. */
3528 pj_strset(&accept, ast_alloca(accept_len + 1), accept_len);
3529 sprintf((char *) pj_strbuf(&accept), "%s/%s", generator->type, generator->subtype);/* Safe */
3530
3531 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
3532 PJSIP_H_ACCEPT, NULL, 1, &accept);
3533
3534 return 0;
3535}
#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 3552 of file res_pjsip_pubsub.c.

3553{
3555 AST_RWLIST_INSERT_TAIL(&body_supplements, supplement, list);
3557
3558 return 0;
3559}

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 3537 of file res_pjsip_pubsub.c.

3538{
3539 struct ast_sip_pubsub_body_generator *iter;
3540
3543 if (iter == generator) {
3545 break;
3546 }
3547 }
3550}
#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 3561 of file res_pjsip_pubsub.c.

3562{
3563 struct ast_sip_pubsub_body_supplement *iter;
3564
3567 if (iter == supplement) {
3569 break;
3570 }
3571 }
3574}
struct ast_sip_pubsub_body_supplement::@262 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 2782 of file res_pjsip_pubsub.c.

2783{
2784 if (ast_strlen_zero(handler->event_name)) {
2785 ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
2786 return -1;
2787 }
2788
2791 if (!handler->publications) {
2792 ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
2793 handler->event_name);
2794 return -1;
2795 }
2796
2798
2799 return 0;
2800}
@ 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 2841 of file res_pjsip_pubsub.c.

2842{
2843 pj_str_t event;
2844 pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
2845 struct ast_sip_subscription_handler *existing;
2846 int i = 0;
2847
2848 if (ast_strlen_zero(handler->event_name)) {
2849 ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
2850 return -1;
2851 }
2852
2853 existing = find_sub_handler_for_event_name(handler->event_name);
2854 if (existing) {
2856 "Unable to register subscription handler for event %s. A handler is already registered\n",
2857 handler->event_name);
2858 return -1;
2859 }
2860
2861 for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
2862 pj_cstr(&accept[i], handler->accept[i]);
2863 }
2864
2865 pj_cstr(&event, handler->event_name);
2866
2867 pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
2868
2870
2871 return 0;
2872}
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 2693 of file res_pjsip_pubsub.c.

2694{
2695 return ast_datastores_add(subscription->datastores, datastore);
2696}
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 2688 of file res_pjsip_pubsub.c.

2689{
2691}
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 1429 of file res_pjsip_pubsub.c.

1430{
1431 ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1432 sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree);
1433 ao2_cleanup(sub->tree);
1434}
#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 3581 of file res_pjsip_pubsub.c.

3582{
3583 return sub->body_generator->subtype;
3584}

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 3576 of file res_pjsip_pubsub.c.

3577{
3578 return sub->body_generator->type;
3579}

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 2698 of file res_pjsip_pubsub.c.

2699{
2700 return ast_datastores_find(subscription->datastores, name);
2701}

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 2708 of file res_pjsip_pubsub.c.

2709{
2710 return subscription->datastores;
2711}

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 1971 of file res_pjsip_pubsub.c.

1972{
1973 ast_assert(sub->tree->dlg != NULL);
1974 return sub->tree->dlg;
1975}
#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 1977 of file res_pjsip_pubsub.c.

1978{
1979 ast_assert(sub->tree->endpoint != NULL);
1980 return ao2_bump(sub->tree->endpoint);
1981}

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 1895 of file res_pjsip_pubsub.c.

1896{
1897 pjsip_dialog *dlg;
1898 pjsip_msg *msg;
1899 pj_str_t name;
1900
1901 dlg = sub->tree->dlg;
1902 msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1903 pj_cstr(&name, header);
1904
1905 return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
1906}

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 2642 of file res_pjsip_pubsub.c.

2643{
2644 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2645}

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 2750 of file res_pjsip_pubsub.c.

2751{
2752 return subscription->persistence_data;
2753}
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 2647 of file res_pjsip_pubsub.c.

2648{
2649 pjsip_dialog *dlg;
2650 pjsip_sip_uri *uri;
2651
2652 dlg = sub->tree->dlg;
2653 uri = pjsip_uri_get_uri(dlg->remote.info->uri);
2654
2655 if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
2656 *buf = '\0';
2657 }
2658}

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 2660 of file res_pjsip_pubsub.c.

2661{
2662 return sub->resource;
2663}

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 1983 of file res_pjsip_pubsub.c.

1984{
1985 ast_assert(sub->tree->serializer != NULL);
1986 return sub->tree->serializer;
1987}

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 2637 of file res_pjsip_pubsub.c.

2638{
2639 return sub->uri;
2640}

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 2665 of file res_pjsip_pubsub.c.

2666{
2667 return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2668}

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 2593 of file res_pjsip_pubsub.c.

2595{
2596 int res;
2597 pjsip_dialog *dlg = sub->tree->dlg;
2598
2599 pjsip_dlg_inc_lock(dlg);
2600
2601 if (sub->tree->state != SIP_SUB_TREE_NORMAL) {
2602 pjsip_dlg_dec_lock(dlg);
2603 return 0;
2604 }
2605
2608 pjsip_dlg_dec_lock(dlg);
2609 return -1;
2610 }
2611
2612 sub->body_changed = 1;
2613 if (terminate) {
2614 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2615 sub->tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
2616 }
2617
2618 if (sub->tree->notification_batch_interval) {
2619 res = schedule_notification(sub->tree);
2620 } else {
2621 /* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */
2622 ao2_ref(sub->tree, +1);
2623 if (terminate) {
2625 }
2626 res = send_notify(sub->tree, 0);
2627 ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2628 "Resource: %s",
2629 sub->tree->root->resource);
2630 ao2_ref(sub->tree, -1);
2631 }
2632
2633 pjsip_dlg_dec_lock(dlg);
2634 return res;
2635}
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 2703 of file res_pjsip_pubsub.c.

2704{
2705 ast_datastores_remove(subscription->datastores, name);
2706}

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 2733 of file res_pjsip_pubsub.c.

2734{
2735 ast_json_unref(subscription->persistence_data);
2736 subscription->persistence_data = persistence_data;
2737
2738 if (subscription->tree->persistence) {
2739 if (!subscription->tree->persistence->generator_data) {
2741 if (!subscription->tree->persistence->generator_data) {
2742 return;
2743 }
2744 }
2745 ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
2746 ast_json_ref(persistence_data));
2747 }
2748}
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 2802 of file res_pjsip_pubsub.c.

2803{
2804 struct ast_sip_publish_handler *iter;
2805
2808 if (handler == iter) {
2810 ao2_cleanup(handler->publications);
2811 break;
2812 }
2813 }
2816}
#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 2305 of file res_pjsip_pubsub.c.

2307{
2308 struct body_part *bp;
2309 pjsip_msg_body *body;
2310
2311 bp = allocate_body_part(pool, sub);
2312 if (!bp) {
2313 return;
2314 }
2315
2316 body = generate_notify_body(pool, sub, use_full_state);
2317 if (!body) {
2318 /* Partial state was requested and the resource has not changed state */
2319 ast_free(bp);
2320 return;
2321 }
2322
2323 bp->part = pjsip_multipart_create_part(pool);
2324 bp->part->body = body;
2325 pj_list_insert_before(&bp->part->hdr, bp->cid);
2326
2327 if (AST_VECTOR_APPEND(parts, bp)) {
2328 ast_free(bp);
2329 }
2330}
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 1044 of file res_pjsip_pubsub.c.

1046{
1047 int i;
1048
1049 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
1050 struct tree_node *current;
1051 struct resource_list *child_list;
1052 const char *resource = AST_VECTOR_GET(&list->items, i);
1053
1054 if (have_visited(resource, visited)) {
1055 ast_debug(1, "Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1056 continue;
1057 }
1058
1059 child_list = retrieve_resource_list(resource, list->event);
1060 if (!child_list) {
1061 int resp = NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
1062 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1063 char display_name[AST_MAX_EXTENSION] = "";
1064 if (list->resource_display_name && handler->notifier->get_resource_display_name) {
1065 handler->notifier->get_resource_display_name(endpoint, resource, display_name, sizeof(display_name));
1066 }
1067 current = tree_node_alloc(resource, visited, 0, ast_strlen_zero(display_name) ? NULL : display_name);
1068 if (!current) {
1069 ast_debug(1,
1070 "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1071 resource);
1072 continue;
1073 }
1074 ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1075 resource, parent->resource);
1076 if (AST_VECTOR_APPEND(&parent->children, current)) {
1078 }
1079 } else {
1080 ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n",
1081 resource, resp);
1082 }
1083 } else {
1084 ast_debug(2, "Resource %s (child of %s) is a list\n", resource, parent->resource);
1085 current = tree_node_alloc(resource, visited, child_list->full_state, NULL);
1086 if (!current) {
1087 ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
1088 continue;
1089 }
1090 build_node_children(endpoint, handler, child_list, current, visited, rdata);
1091 if (AST_VECTOR_SIZE(&current->children) > 0) {
1092 ast_debug(1, "List %s had no successful children.\n", resource);
1093 if (AST_VECTOR_APPEND(&parent->children, current)) {
1095 }
1096 } else {
1097 ast_debug(2, "List %s had successful children. Adding to parent %s\n",
1098 resource, parent->resource);
1100 }
1101 ao2_cleanup(child_list);
1102 }
1103 }
1104}
#define AST_MAX_EXTENSION
Definition: channel.h:134
size_t current
Definition: main/cli.c:113
#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::@464 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 1162 of file res_pjsip_pubsub.c.

1164{
1165 RAII_VAR(struct resource_list *, list, NULL, ao2_cleanup);
1166 struct resources visited;
1167
1168 int not_eventlist_but_needs_children = !strcmp(handler->body_type, AST_SIP_DEVICE_FEATURE_SYNC_DATA);
1169
1170 if ((!has_eventlist_support && !not_eventlist_but_needs_children) || !(list = retrieve_resource_list(resource, handler->event_name))) {
1171 ast_debug(2, "Subscription '%s->%s' is not to a list\n",
1172 ast_sorcery_object_get_id(endpoint), resource);
1173 tree->root = tree_node_alloc(resource, NULL, 0, NULL);
1174 if (!tree->root) {
1175 return 500;
1176 }
1177 return NEW_SUBSCRIBE(handler->notifier, endpoint, resource, rdata);
1178 }
1179
1180 ast_debug(2, "Subscription '%s->%s' is a list\n",
1181 ast_sorcery_object_get_id(endpoint), resource);
1182 if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
1183 return 500;
1184 }
1185
1186 tree->root = tree_node_alloc(resource, &visited, list->full_state, NULL);
1187 if (!tree->root) {
1188 AST_VECTOR_FREE(&visited);
1189 return 500;
1190 }
1191
1192 tree->notification_batch_interval = list->notification_batch_interval;
1193
1194 build_node_children(endpoint, handler, list, tree->root, &visited, rdata);
1195 AST_VECTOR_FREE(&visited);
1196
1197 if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
1198 return 200;
1199 } else {
1200 return 500;
1201 }
1202}
#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 2208 of file res_pjsip_pubsub.c.

2210{
2211 pj_xml_node *rlmi;
2212 pj_xml_node *name;
2213 pjsip_multipart_part *rlmi_part;
2214 char version_str[32];
2215 char uri[PJSIP_MAX_URL_SIZE];
2216 pjsip_generic_string_hdr *cid;
2217 int i;
2218
2219 rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
2220 ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
2221
2222 ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
2223 ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
2224
2225 snprintf(version_str, sizeof(version_str), "%u", sub->version++);
2226 ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
2227 ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
2228
2229 name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
2230 pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
2231
2232 for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
2233 const struct body_part *part = AST_VECTOR_GET(body_parts, i);
2234
2235 add_rlmi_resource(pool, rlmi, part->cid, S_OR(part->display_name, part->resource), part->uri, part->state);
2236 }
2237
2238 rlmi_part = pjsip_multipart_create_part(pool);
2239
2240 rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2241 pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &rlmi_media_type);
2242
2243 rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2244 rlmi_part->body->clone_data = rlmi_clone_data;
2245 rlmi_part->body->print_body = rlmi_print_body;
2246
2248 pj_list_insert_before(&rlmi_part->hdr, cid);
2249
2250 return rlmi_part;
2251}
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 3869 of file res_pjsip_pubsub.c.

3870{
3871
3872 struct sip_subscription_tree *sub_tree;
3873 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3874
3875 ast_debug(3, "Cleaning subscription %p\n", evsub);
3876
3877 if (sub_tree->expiration_task) {
3878 char task_name[256];
3879
3880 ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
3881 ast_debug(3, "Cancelling timer: %s\n", task_name);
3883 ao2_cleanup(sub_tree->expiration_task);
3884 sub_tree->expiration_task = NULL;
3885 }
3886
3887 remove_subscription(sub_tree);
3888
3889 pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
3890
3891#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
3892 pjsip_evsub_dec_ref(sub_tree->evsub);
3893#endif
3894
3895 sub_tree->evsub = NULL;
3896
3899
3901 shutdown_subscriptions(sub_tree->root);
3902
3903 sub_tree->state = SIP_SUB_TREE_TERMINATED;
3904 /* Remove evsub's reference to the sub_tree */
3905 ao2_ref(sub_tree, -1);
3906}
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 4432 of file res_pjsip_pubsub.c.

4433{
4435 on_subscription_t on_subscription;
4436
4437 if (a->pos != 4) {
4438 return NULL;
4439 }
4440
4441 if (!strcasecmp(a->argv[3], "inbound")) {
4442 on_subscription = cli_complete_subscription_inbound;
4443 } else if (!strcasecmp(a->argv[3], "outbound")) {
4444 on_subscription = cli_complete_subscription_outbound;
4445 } else {
4446 /* Should never get here */
4447 ast_assert(0);
4448 return NULL;
4449 }
4450
4451 cli.a = a;
4452 cli.callid = NULL;
4453 cli.wordlen = strlen(a->word);
4454 cli.which = 0;
4455 for_each_subscription(on_subscription, &cli);
4456
4457 return cli.callid;
4458}
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 4399 of file res_pjsip_pubsub.c.

4400{
4401 pj_str_t *callid;
4402
4403 if (!sub_tree->dlg) {
4404 return 0;
4405 }
4406
4407 callid = &sub_tree->dlg->call_id->id;
4408 if (cli->wordlen <= pj_strlen(callid)
4409 && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
4410 && (++cli->which > cli->a->n)) {
4411 cli->callid = ast_malloc(pj_strlen(callid) + 1);
4412 if (cli->callid) {
4413 ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
4414 }
4415 return -1;
4416 }
4417 return 0;
4418}
#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 4420 of file res_pjsip_pubsub.c.

4421{
4422 return sub_tree->role == AST_SIP_NOTIFIER
4423 ? cli_complete_subscription_common(sub_tree, arg) : 0;
4424}
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 4426 of file res_pjsip_pubsub.c.

4427{
4428 return sub_tree->role == AST_SIP_SUBSCRIBER
4429 ? cli_complete_subscription_common(sub_tree, arg) : 0;
4430}

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 4763 of file res_pjsip_pubsub.c.

4764{
4765 char ep_cid_buf[50];
4766 char res_evt_buf[50];
4767 char callid[256];
4768
4769 /* Endpoint/CID column */
4770 snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s",
4772 S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str,
4773 S_COR(sub_tree->endpoint->id.self.number.valid,
4774 sub_tree->endpoint->id.self.number.str, "<none>")));
4775
4776 /* Resource/Event column */
4777 snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s",
4778 sub_tree->root->resource,
4779 sub_tree->root->handler->event_name);
4780
4781 /* Call-id column */
4782 if (sub_tree->dlg) {
4783 ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4784 } else {
4785 ast_copy_string(callid, "<unknown>", sizeof(callid));
4786 }
4787
4789 ep_cid_buf,
4790 res_evt_buf,
4791 cli_subscription_expiry(sub_tree),
4792 callid);
4793
4794 if (cli->like) {
4795 if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4796 /* Output line did not match the regex */
4797 return 0;
4798 }
4799 }
4800
4801 ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4802 ++cli->count;
4803
4804 return 0;
4805}
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:340
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
char * str
Subscriber name (Malloced)
Definition: channel.h:264
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
struct ast_party_id self
Definition: res_pjsip.h:772
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:1002
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 4807 of file res_pjsip_pubsub.c.

4808{
4809 return sub_tree->role == AST_SIP_NOTIFIER
4810 ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4811}
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 4819 of file res_pjsip_pubsub.c.

4820{
4821 on_subscription_t on_subscription;
4822 struct cli_sub_parms cli;
4823 regex_t like;
4824 const char *regex;
4825
4826 switch (cmd) {
4827 case CLI_INIT:
4828 e->command = "pjsip list subscriptions {inbound|outbound} [like]";
4829 e->usage = "Usage:\n"
4830 " pjsip list subscriptions inbound [like <regex>]\n"
4831 " List active inbound subscriptions\n"
4832 " pjsip list subscriptions outbound [like <regex>]\n"
4833 " List active outbound subscriptions\n"
4834 "\n"
4835 " The regex selects output lines that match.\n";
4836 return NULL;
4837 case CLI_GENERATE:
4838 return NULL;
4839 }
4840
4841 if (a->argc != 4 && a->argc != 6) {
4842 return CLI_SHOWUSAGE;
4843 }
4844 if (!strcasecmp(a->argv[3], "inbound")) {
4845 on_subscription = cli_list_subscriptions_inbound;
4846 } else if (!strcasecmp(a->argv[3], "outbound")) {
4847 on_subscription = cli_list_subscriptions_outbound;
4848 } else {
4849 /* Should never get here */
4850 ast_assert(0);
4851 return CLI_SHOWUSAGE;
4852 }
4853 if (a->argc == 6) {
4854 int rc;
4855
4856 if (strcasecmp(a->argv[4], "like")) {
4857 return CLI_SHOWUSAGE;
4858 }
4859
4860 /* Setup regular expression */
4861 memset(&like, 0, sizeof(like));
4862 cli.like = &like;
4863 regex = a->argv[5];
4864 rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4865 if (rc) {
4866 char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4867
4868 regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4869 ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4870 regex, regerr);
4871 return CLI_FAILURE;
4872 }
4873 } else {
4874 cli.like = NULL;
4875 regex = NULL;
4876 }
4877
4878 cli.a = a;
4879 cli.e = e;
4880 cli.count = 0;
4881 cli.buf = ast_str_create(256);
4882 if (!cli.buf) {
4883 if (cli.like) {
4884 regfree(cli.like);
4885 }
4886 return CLI_FAILURE;
4887 }
4888
4890 "Endpoint/CLI", "Resource/Event", "Expiry", "Call-id");
4891 for_each_subscription(on_subscription, &cli);
4892 ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n",
4893 cli.count,
4894 regex ? " matched \"" : "",
4895 regex ?: "",
4896 regex ? "\"" : "");
4897
4898 ast_free(cli.buf);
4899 if (cli.like) {
4900 regfree(cli.like);
4901 }
4902
4903 return CLI_SUCCESS;
4904}
#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 4813 of file res_pjsip_pubsub.c.

4814{
4815 return sub_tree->role == AST_SIP_SUBSCRIBER
4816 ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4817}

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 4474 of file res_pjsip_pubsub.c.

4475{
4476 const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
4477 pj_str_t *sub_callid;
4478 struct ast_str *buf;
4479 char *src;
4480 char *dest;
4481 char *key;
4482 char *value;
4483 char *value_end;
4484 int key_len;
4485 int key_filler_width;
4486 int value_len;
4487
4488 if (!sub_tree->dlg) {
4489 return 0;
4490 }
4491 sub_callid = &sub_tree->dlg->call_id->id;
4492 if (pj_strcmp2(sub_callid, callid)) {
4493 return 0;
4494 }
4495
4496 buf = ast_str_create(512);
4497 if (!buf) {
4498 return -1;
4499 }
4500
4501 ast_cli(cli->a->fd,
4502 "%-20s: %s\n"
4503 "===========================================================================\n",
4504 "ParameterName", "ParameterValue");
4505
4506 ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
4507 ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
4508 ast_str_append(&buf, 0, "Expiry: %u\n", cli_subscription_expiry(sub_tree));
4509
4510 sip_subscription_to_ami(sub_tree, &buf);
4511
4512 /* Convert AMI \r\n to \n line terminators. */
4513 src = strchr(ast_str_buffer(buf), '\r');
4514 if (src) {
4515 dest = src;
4516 ++src;
4517 while (*src) {
4518 if (*src == '\r') {
4519 ++src;
4520 continue;
4521 }
4522 *dest++ = *src++;
4523 }
4524 *dest = '\0';
4526 }
4527
4528 /* Reformat AMI key value pairs to pretty columns */
4529 key = ast_str_buffer(buf);
4530 do {
4531 value = strchr(key, ':');
4532 if (!value) {
4533 break;
4534 }
4535 value_end = strchr(value, '\n');
4536 if (!value_end) {
4537 break;
4538 }
4539
4540 /* Calculate field lengths */
4541 key_len = value - key;
4542 key_filler_width = 20 - key_len;
4543 if (key_filler_width < 0) {
4544 key_filler_width = 0;
4545 }
4546 value_len = value_end - value;
4547
4548 ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
4549 key_len, key, key_filler_width, "",
4550 value_len, value);
4551
4552 key = value_end + 1;
4553 } while (*key);
4554 ast_cli(cli->a->fd, "\n");
4555
4556 ast_free(buf);
4557
4558 return -1;
4559}
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 4561 of file res_pjsip_pubsub.c.

4562{
4563 return sub_tree->role == AST_SIP_NOTIFIER
4564 ? cli_show_subscription_common(sub_tree, arg) : 0;
4565}
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 4573 of file res_pjsip_pubsub.c.

4574{
4575 on_subscription_t on_subscription;
4576 struct cli_sub_parms cli;
4577
4578 switch (cmd) {
4579 case CLI_INIT:
4580 e->command = "pjsip show subscription {inbound|outbound}";
4581 e->usage = "Usage:\n"
4582 " pjsip show subscription inbound <call-id>\n"
4583 " pjsip show subscription outbound <call-id>\n"
4584 " Show active subscription with the dialog call-id\n";
4585 return NULL;
4586 case CLI_GENERATE:
4588 }
4589
4590 if (a->argc != 5) {
4591 return CLI_SHOWUSAGE;
4592 }
4593
4594 if (!strcasecmp(a->argv[3], "inbound")) {
4595 on_subscription = cli_show_subscription_inbound;
4596 } else if (!strcasecmp(a->argv[3], "outbound")) {
4597 on_subscription = cli_show_subscription_outbound;
4598 } else {
4599 /* Should never get here */
4600 ast_assert(0);
4601 return NULL;
4602 }
4603
4604 /* Find the subscription with the specified call-id */
4605 cli.a = a;
4606 cli.e = e;
4607 cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */
4608 for_each_subscription(on_subscription, &cli);
4609
4610 return CLI_SUCCESS;
4611}
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 4567 of file res_pjsip_pubsub.c.

4568{
4569 return sub_tree->role == AST_SIP_SUBSCRIBER
4570 ? cli_show_subscription_common(sub_tree, arg) : 0;
4571}

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 4623 of file res_pjsip_pubsub.c.

4624{
4625 char caller_id[256];
4626 char callid[256];
4627
4628 ast_callerid_merge(caller_id, sizeof(caller_id),
4629 S_COR(sub_tree->endpoint->id.self.name.valid,
4630 sub_tree->endpoint->id.self.name.str, NULL),
4631 S_COR(sub_tree->endpoint->id.self.number.valid,
4632 sub_tree->endpoint->id.self.number.str, NULL),
4633 "<none>");
4634
4635 /* Call-id */
4636 if (sub_tree->dlg) {
4637 ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4638 } else {
4639 ast_copy_string(callid, "<unknown>", sizeof(callid));
4640 }
4641
4643 ast_sorcery_object_get_id(sub_tree->endpoint), caller_id,
4644 sub_tree->root->resource, sub_tree->root->handler->event_name,
4645 cli_subscription_expiry(sub_tree), callid);
4646
4647 if (cli->like) {
4648 if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4649 /* Output line did not match the regex */
4650 return 0;
4651 }
4652 }
4653
4654 ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4655 ++cli->count;
4656
4657 return 0;
4658}
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 4660 of file res_pjsip_pubsub.c.

4661{
4662 return sub_tree->role == AST_SIP_NOTIFIER
4663 ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4664}
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 4672 of file res_pjsip_pubsub.c.

4673{
4674 on_subscription_t on_subscription;
4675 struct cli_sub_parms cli;
4676 regex_t like;
4677 const char *regex;
4678
4679 switch (cmd) {
4680 case CLI_INIT:
4681 e->command = "pjsip show subscriptions {inbound|outbound} [like]";
4682 e->usage = "Usage:\n"
4683 " pjsip show subscriptions inbound [like <regex>]\n"
4684 " Show active inbound subscriptions\n"
4685 " pjsip show subscriptions outbound [like <regex>]\n"
4686 " Show active outbound subscriptions\n"
4687 "\n"
4688 " The regex selects a subscriptions output that matches.\n"
4689 " i.e., All output lines for a subscription are checked\n"
4690 " as a block by the regex.\n";
4691 return NULL;
4692 case CLI_GENERATE:
4693 return NULL;
4694 }
4695
4696 if (a->argc != 4 && a->argc != 6) {
4697 return CLI_SHOWUSAGE;
4698 }
4699 if (!strcasecmp(a->argv[3], "inbound")) {
4700 on_subscription = cli_show_subscriptions_inbound;
4701 } else if (!strcasecmp(a->argv[3], "outbound")) {
4702 on_subscription = cli_show_subscriptions_outbound;
4703 } else {
4704 /* Should never get here */
4705 ast_assert(0);
4706 return CLI_SHOWUSAGE;
4707 }
4708 if (a->argc == 6) {
4709 int rc;
4710
4711 if (strcasecmp(a->argv[4], "like")) {
4712 return CLI_SHOWUSAGE;
4713 }
4714
4715 /* Setup regular expression */
4716 memset(&like, 0, sizeof(like));
4717 cli.like = &like;
4718 regex = a->argv[5];
4719 rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4720 if (rc) {
4721 char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4722
4723 regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4724 ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4725 regex, regerr);
4726 return CLI_FAILURE;
4727 }
4728 } else {
4729 cli.like = NULL;
4730 regex = NULL;
4731 }
4732
4733 cli.a = a;
4734 cli.e = e;
4735 cli.count = 0;
4736 cli.buf = ast_str_create(256);
4737 if (!cli.buf) {
4738 if (cli.like) {
4739 regfree(cli.like);
4740 }
4741 return CLI_FAILURE;
4742 }
4743
4745 for_each_subscription(on_subscription, &cli);
4746 ast_cli(a->fd, "%d active subscriptions%s%s%s\n",
4747 cli.count,
4748 regex ? " matched \"" : "",
4749 regex ?: "",
4750 regex ? "\"" : "");
4751
4752 ast_free(cli.buf);
4753 if (cli.like) {
4754 regfree(cli.like);
4755 }
4756
4757 return CLI_SUCCESS;
4758}
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 4666 of file res_pjsip_pubsub.c.

4667{
4668 return sub_tree->role == AST_SIP_SUBSCRIBER
4669 ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4670}

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 4460 of file res_pjsip_pubsub.c.

4461{
4462 int expiry;
4463
4464 expiry = sub_tree->persistence
4465 ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
4466 : 0;
4467 if (expiry < 0) {
4468 /* Subscription expired */
4469 expiry = 0;
4470 }
4471 return expiry;
4472}
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 4021 of file res_pjsip_pubsub.c.

4022{
4023 if (!ast_strlen_zero(s1) && !ast_strlen_zero(s2)) {
4024 return strcmp(s1, s2);
4025 }
4026
4027 return ast_strlen_zero(s1) == ast_strlen_zero(s2) ? 0 : 1;
4028}

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 4036 of file res_pjsip_pubsub.c.

4037{
4038 int i;
4039
4040 if (AST_VECTOR_SIZE(&s1->children) != AST_VECTOR_SIZE(&s2->children)) {
4041 return 1;
4042 }
4043
4044 for (i = 0; i < AST_VECTOR_SIZE(&s1->children); ++i) {
4045 struct ast_sip_subscription *c1 = AST_VECTOR_GET(&s1->children, i);
4046 struct ast_sip_subscription *c2 = AST_VECTOR_GET(&s2->children, i);
4047
4048 if (cmp_strings(c1->resource, c2->resource)
4049 || cmp_strings(c1->display_name, c2->display_name)) {
4050
4051 return 1;
4052 }
4053 }
4054
4055 return 0;
4056}
static int cmp_strings(char *s1, char *s2)
Compare strings for equality checking for NULL.
struct ast_sip_subscription::@463 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 2338 of file res_pjsip_pubsub.c.

2339{
2340 pjsip_media_type media_type;
2341 pjsip_param *media_type_param;
2342 char boundary[6];
2343 pj_str_t pj_boundary;
2344
2345 pjsip_media_type_init2(&media_type, "multipart", "related");
2346
2347 media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
2348 pj_list_init(media_type_param);
2349
2350 pj_strdup2(pool, &media_type_param->name, "type");
2351 pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
2352
2353 pj_list_insert_before(&media_type.param, media_type_param);
2354
2355 pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
2356 return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2357}

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 2451 of file res_pjsip_pubsub.c.

2452{
2453 pjsip_require_hdr *require;
2454
2455 require = pjsip_require_hdr_create(pool);
2456 pj_strdup2(pool, &require->values[0], "eventlist");
2457 require->count = 1;
2458
2459 return require;
2460}

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 1506 of file res_pjsip_pubsub.c.

1510{
1511 struct sip_subscription_tree *sub_tree;
1512 pjsip_dialog *dlg;
1513
1514 sub_tree = allocate_subscription_tree(endpoint, rdata);
1515 if (!sub_tree) {
1516 *dlg_status = PJ_ENOMEM;
1517 return NULL;
1518 }
1519 sub_tree->role = AST_SIP_NOTIFIER;
1520
1521 dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, dlg_status);
1522 if (!dlg) {
1523 if (*dlg_status != PJ_EEXISTS) {
1524 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1525 }
1526 ao2_ref(sub_tree, -1);
1527 return NULL;
1528 }
1529
1530 persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
1532 if (persistence) {
1533 /* Update the created dialog with the persisted information */
1534 pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
1535 pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->tag);
1536 dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
1537 pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
1538 dlg->local.cseq = persistence->cseq;
1539 }
1540
1541 pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
1542
1543 subscription_setup_dialog(sub_tree, dlg);
1544
1545 /*
1546 * The evsub and subscription setup both add dialog refs, so the dialog ref that
1547 * was added when the dialog was created (see ast_sip_create_dialog_uas_lock) can
1548 * now be removed. The lock should no longer be needed so can be removed too.
1549 */
1550 pjsip_dlg_dec_lock(dlg);
1551
1552#ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
1553 pjsip_evsub_add_ref(sub_tree->evsub);
1554#endif
1555
1557 pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
1558
1560
1561 /* Persistence information needs to be available for all the subscriptions */
1562 sub_tree->persistence = ao2_bump(persistence);
1563
1564 sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
1565 if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
1566 sub_tree->is_list = 1;
1567 }
1568
1569 add_subscription(sub_tree);
1570
1571 return sub_tree;
1572}
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:2980
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 1325 of file res_pjsip_pubsub.c.

1328{
1329 int i;
1330 struct ast_sip_subscription *sub;
1331
1333 if (!sub) {
1334 return NULL;
1335 }
1336
1337 sub->full_state = current->full_state;
1338 sub->body_generator = generator;
1339 AST_VECTOR_INIT(&sub->children, AST_VECTOR_SIZE(&current->children));
1340
1341 for (i = 0; i < AST_VECTOR_SIZE(&current->children); ++i) {
1342 struct ast_sip_subscription *child;
1343 struct tree_node *child_node = AST_VECTOR_GET(&current->children, i);
1344
1345 child = create_virtual_subscriptions(handler, child_node->resource, generator,
1346 tree, child_node);
1347
1348 if (!child) {
1349 ast_debug(1, "Child subscription to resource %s could not be created\n",
1350 child_node->resource);
1351 continue;
1352 }
1353
1354 if (AST_VECTOR_APPEND(&sub->children, child)) {
1355 ast_debug(1, "Child subscription to resource %s could not be appended\n",
1356 child_node->resource);
1357 destroy_subscription(child);
1358 /* Have to release tree here too because a ref was added
1359 * to child that destroy_subscription() doesn't release. */
1360 ao2_cleanup(tree);
1361 }
1362 }
1363
1364 return sub;
1365}

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 1230 of file res_pjsip_pubsub.c.

1231{
1232 ast_debug(3, "Destroying SIP subscription from '%s->%s'\n",
1233 sub->tree && sub->tree->endpoint ? ast_sorcery_object_get_id(sub->tree->endpoint) : "Unknown",
1234 sub->resource);
1235
1236 ast_free(sub->body_text);
1237
1238 AST_VECTOR_FREE(&sub->children);
1239 ao2_cleanup(sub->datastores);
1240 ast_json_unref(sub->persistence_data);
1241 ast_free(sub->display_name);
1242 ast_free(sub);
1243}

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 1245 of file res_pjsip_pubsub.c.

1246{
1247 int i;
1248
1249 if (!root) {
1250 return;
1251 }
1252
1253 for (i = 0; i < AST_VECTOR_SIZE(&root->children); ++i) {
1254 struct ast_sip_subscription *child;
1255
1256 child = AST_VECTOR_GET(&root->children, i);
1257 destroy_subscriptions(child);
1258 }
1259
1261}
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 4058 of file res_pjsip_pubsub.c.

4059{
4060 struct ast_sip_subscription *sub = (struct ast_sip_subscription *) obj;
4061
4063
4064 return 0;
4065}

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 3168 of file res_pjsip_pubsub.c.

3170{
3171 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3172
3173 if (etag_hdr) {
3174 char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3175
3176 ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
3177
3178 if (sscanf(etag, "%30d", entity_id) != 1) {
3179 return SIP_PUBLISH_UNKNOWN;
3180 }
3181 }
3182
3183 *expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3184
3185 if (!(*expires)) {
3186 return SIP_PUBLISH_REMOVE;
3187 } else if (!etag_hdr && rdata->msg_info.msg->body) {
3188 return SIP_PUBLISH_INITIAL;
3189 } else if (etag_hdr && !rdata->msg_info.msg->body) {
3190 return SIP_PUBLISH_REFRESH;
3191 } else if (etag_hdr && rdata->msg_info.msg->body) {
3192 return SIP_PUBLISH_MODIFY;
3193 }
3194
3195 return SIP_PUBLISH_UNKNOWN;
3196}
#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 833 of file res_pjsip_pubsub.c.

834{
835 int i;
836
837 for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
838 if (!pj_strcmp2(accept, accept_exceptions[i])) {
839 return 1;
840 }
841 }
842
843 return 0;
844}
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 2926 of file res_pjsip_pubsub.c.

2928{
2929 int i;
2930 struct ast_sip_pubsub_body_generator *generator = NULL;
2931
2932 for (i = 0; i < num_accept; ++i) {
2933 generator = find_body_generator_accept(accept[i]);
2934 if (generator) {
2935 ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
2936 if (strcmp(generator->body_type, body_type)) {
2937 ast_log(LOG_WARNING, "Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
2938 generator->type, generator->subtype, generator);
2939 generator = NULL;
2940 continue;
2941 }
2942 break;
2943 } else {
2944 ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
2945 }
2946 }
2947
2948 return generator;
2949}
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 2913 of file res_pjsip_pubsub.c.

2914{
2915 char *accept_copy = ast_strdupa(accept);
2916 char *subtype = accept_copy;
2917 char *type = strsep(&subtype, "/");
2918
2919 if (ast_strlen_zero(type) || ast_strlen_zero(subtype)) {
2920 return NULL;
2921 }
2922
2923 return find_body_generator_type_subtype(type, subtype);
2924}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
char * strsep(char **str, const char *delims)

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 2889 of file res_pjsip_pubsub.c.

2890{
2892
2894 if (!strcmp(gen->type, type)
2895 && !strcmp(gen->subtype, subtype)) {
2896 break;
2897 }
2898 }
2899
2900 return gen;
2901}
#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 3150 of file res_pjsip_pubsub.c.

3151{
3152 struct ast_sip_publish_handler *iter = NULL;
3153
3156 if (strcmp(event, iter->event_name)) {
3157 ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
3158 continue;
3159 }
3160 ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
3161 break;
3162 }
3164
3165 return iter;
3166}
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 1841 of file res_pjsip_pubsub.c.

1842{
1843 int num = 0;
1844 struct sip_subscription_tree *i;
1845
1846 if (!on_subscription) {
1847 return num;
1848 }
1849
1852 if (on_subscription(i, arg)) {
1853 break;
1854 }
1855 ++num;
1856 }
1858 return num;
1859}
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 4329 of file res_pjsip_pubsub.c.

4330{
4331 struct resource_list *list = obj;
4332 struct ast_sip_ami *ami = arg;
4333 struct ast_str *buf;
4334
4335 buf = ast_sip_create_ami_event("ResourceListDetail", ami);
4336 if (!buf) {
4337 return CMP_STOP;
4338 }
4339
4340 if (ast_sip_sorcery_object_to_ami(list, &buf)) {
4341 ast_free(buf);
4342 return CMP_STOP;
4343 }
4344 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4345 ast_free(buf);
4346
4347 ++ami->count;
4348 return 0;
4349}
@ 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:3055

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 2261 of file res_pjsip_pubsub.c.

2262{
2263 int i;
2264
2265 for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
2266 struct body_part *part = AST_VECTOR_GET(parts, i);
2267 ast_free(part);
2268 }
2269
2270 AST_VECTOR_FREE(parts);
2271}

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 2153 of file res_pjsip_pubsub.c.

2155{
2156 static const pj_str_t cid_name = { "Content-ID", 10 };
2157 pjsip_generic_string_hdr *cid;
2158 char id[6];
2159 size_t alloc_size;
2160 pj_str_t cid_value;
2161
2162 /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
2163 alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
2164 cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2165 cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
2166 ast_generate_random_string(id, sizeof(id)),
2167 (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
2168 cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2169
2170 return cid;
2171}
enum queue_result id
Definition: app_queue.c:1638

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 2951 of file res_pjsip_pubsub.c.

2952{
2953 void *notify_data;
2954 int res;
2955 struct ast_sip_body_data data = {
2956 .body_type = sub->handler->body_type,
2957 };
2958
2959 if (AST_VECTOR_SIZE(&sub->children) > 0) {
2960 int i;
2961
2962 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2963 if (generate_initial_notify(AST_VECTOR_GET(&sub->children, i))) {
2964 return -1;
2965 }
2966 }
2967
2968 return 0;
2969 }
2970
2971 /* We notify subscription establishment only on the tree leaves. */
2972 if (sub->handler->notifier->subscription_established(sub)) {
2973 return -1;
2974 }
2975
2976 notify_data = sub->handler->notifier->get_notify_data(sub);
2977 if (!notify_data) {
2978 ast_debug(3, "No notify data, not generating any body content\n");
2979 return -1;
2980 }
2981
2982 data.body_data = notify_data;
2983
2985 ast_sip_subscription_get_body_subtype(sub), &data, &sub->body_text);
2986
2988
2989 return res;
2990}
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 2371 of file res_pjsip_pubsub.c.

2373{
2374 int i;
2375 pjsip_multipart_part *rlmi_part;
2376 pjsip_msg_body *multipart;
2377 struct body_part_list body_parts;
2378 unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
2379
2380 if (AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children))) {
2381 return NULL;
2382 }
2383
2384 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2385 build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
2386 }
2387
2388 /* This can happen if issuing partial state and no children of the list have changed state */
2389 if (AST_VECTOR_SIZE(&body_parts) == 0) {
2390 free_body_parts(&body_parts);
2391 return NULL;
2392 }
2393
2394 multipart = create_multipart_body(pool);
2395
2396 rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
2397 if (!rlmi_part) {
2398 free_body_parts(&body_parts);
2399 return NULL;
2400 }
2401 pjsip_multipart_add_part(pool, multipart, rlmi_part);
2402
2403 for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
2404 pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
2405 }
2406
2407 free_body_parts(&body_parts);
2408 return multipart;
2409}
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 2418 of file res_pjsip_pubsub.c.

2420{
2421 pjsip_msg_body *body;
2422
2423 if (AST_VECTOR_SIZE(&root->children) == 0) {
2424 if (force_full_state || root->body_changed) {
2425 /* Not a list. We've already generated the body and saved it on the subscription.
2426 * Use that directly.
2427 */
2428 pj_str_t type;
2429 pj_str_t subtype;
2430 pj_str_t text;
2431
2433 pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
2434 pj_cstr(&text, ast_str_buffer(root->body_text));
2435
2436 body = pjsip_msg_body_create(pool, &type, &subtype, &text);
2437 root->body_changed = 0;
2438 } else {
2439 body = NULL;
2440 }
2441 } else {
2442 body = generate_list_body(pool, root, force_full_state);
2443 }
2444
2445 return body;
2446}
char * text
Definition: app_queue.c:1639
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 1008 of file res_pjsip_pubsub.c.

1009{
1010 int i;
1011
1012 for (i = 0; i < AST_VECTOR_SIZE(visited); ++i) {
1013 if (!strcmp(resource, AST_VECTOR_GET(visited, i))) {
1014 return 1;
1015 }
1016 }
1017
1018 return 0;
1019}

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 2994 of file res_pjsip_pubsub.c.

2995{
2996 struct initial_notify_data *ind = obj;
2997
2999 pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE);
3000 } else {
3001 send_notify(ind->sub_tree, 1);
3002 ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
3003 "Resource: %s",
3004 ind->sub_tree->root->resource);
3005 }
3006
3008 char *name = ast_alloca(strlen("->/ ") +
3009 strlen(ind->sub_tree->persistence->endpoint) +
3010 strlen(ind->sub_tree->root->resource) +
3011 strlen(ind->sub_tree->root->handler->event_name) +
3012 ind->sub_tree->dlg->call_id->id.slen + 1);
3013
3014 sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint,
3016 (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr);
3017
3018 ast_debug(3, "Scheduling timer: %s\n", name);
3022 if (!ind->sub_tree->expiration_task) {
3023 ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n",
3024 ind->expires, name);
3025 }
3026 }
3027
3028 ao2_ref(ind->sub_tree, -1);
3029 ast_free(ind);
3030
3031 return 0;
3032}
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:2075
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition: res_pjsip.h:2098
#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 5024 of file res_pjsip_pubsub.c.

5025{
5026 int i;
5027
5028 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5029 if (!strcmp(item, AST_VECTOR_GET(&list->items, i))) {
5030 return 1;
5031 }
5032 }
5033
5034 return 0;
5035}
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 5037 of file res_pjsip_pubsub.c.

5039{
5040 struct resource_list *list = obj;
5041 char *items = ast_strdupa(var->value);
5042 char *item;
5043
5044 while ((item = ast_strip(strsep(&items, ",")))) {
5045 if (ast_strlen_zero(item)) {
5046 continue;
5047 }
5048
5049 if (item_in_vector(list, item)) {
5050 ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);
5051 continue;
5052 }
5053
5054 item = ast_strdup(item);
5055 if (!item || AST_VECTOR_APPEND(&list->items, item)) {
5056 ast_free(item);
5057 return -1;
5058 }
5059 }
5060
5061 return 0;
5062}
#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 5064 of file res_pjsip_pubsub.c.

5065{
5066 const struct resource_list *list = obj;
5067 int i;
5068 struct ast_str *str = ast_str_create(32);
5069
5070 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5071 ast_str_append(&str, 0, "%s,", AST_VECTOR_GET(&list->items, i));
5072 }
5073
5074 /* Chop off trailing comma */
5075 ast_str_truncate(str, -1);
5077 ast_free(str);
5078 return 0;
5079}
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 5806 of file res_pjsip_pubsub.c.

5807{
5808 static const pj_str_t str_PUBLISH = { "PUBLISH", 7 };
5809 struct ast_sorcery *sorcery;
5810
5812
5813 if (!(sched = ast_sched_context_create())) {
5814 ast_log(LOG_ERROR, "Could not create scheduler for publication expiration\n");
5816 }
5817
5819 ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n");
5822 }
5823
5824 ast_sorcery_apply_config(sorcery, "res_pjsip_pubsub");
5825 ast_sorcery_apply_default(sorcery, "subscription_persistence", "astdb", "subscription_persistence");
5827 NULL, NULL)) {
5828 ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
5831 }
5832 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "packet", "", OPT_CHAR_ARRAY_T, 0,
5833 CHARFLDSET(struct subscription_persistence, packet));
5834 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_name", "", OPT_CHAR_ARRAY_T, 0,
5835 CHARFLDSET(struct subscription_persistence, src_name));
5836 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_port", "0", OPT_UINT_T, 0,
5837 FLDSET(struct subscription_persistence, src_port));
5838 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "transport_key", "0", OPT_CHAR_ARRAY_T, 0,
5839 CHARFLDSET(struct subscription_persistence, transport_type));
5840 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_name", "", OPT_CHAR_ARRAY_T, 0,
5841 CHARFLDSET(struct subscription_persistence, local_name));
5842 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_port", "0", OPT_UINT_T, 0,
5843 FLDSET(struct subscription_persistence, local_port));
5844 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "cseq", "0", OPT_UINT_T, 0,
5845 FLDSET(struct subscription_persistence, cseq));
5846 ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "endpoint", "",
5848 ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "tag", "",
5850 ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
5852 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "contact_uri", "", OPT_CHAR_ARRAY_T, 0,
5853 CHARFLDSET(struct subscription_persistence, contact_uri));
5854 ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "no", OPT_YESNO_T, 1,
5855 FLDSET(struct subscription_persistence, prune_on_boot));
5856 ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "generator_data", "",
5858
5862 }
5863
5864 ast_sorcery_apply_default(sorcery, "inbound-publication", "config", "pjsip.conf,criteria=type=inbound-publication");
5866 NULL, NULL)) {
5867 ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
5870 }
5871 ast_sorcery_object_field_register(sorcery, "inbound-publication", "type", "", OPT_NOOP_T, 0, 0);
5872 ast_sorcery_object_field_register_custom(sorcery, "inbound-publication", "endpoint", "",
5874 ast_sorcery_object_fields_register(sorcery, "inbound-publication", "^event_", resource_event_handler, NULL);
5875 ast_sorcery_reload_object(sorcery, "inbound-publication");
5876
5878 ast_log(LOG_ERROR, "Could not register pubsub service\n");
5881 }
5882
5883 if (pjsip_evsub_init_module(ast_sip_get_pjsip_endpoint()) != PJ_SUCCESS) {
5884 ast_log(LOG_ERROR, "Could not initialize pjsip evsub module.\n");
5888 }
5889
5890 /* Once pjsip_evsub_init_module succeeds we cannot unload.
5891 * Keep all module_load errors above this point. */
5893
5894 pjsip_media_type_init2(&rlmi_media_type, "application", "rlmi+xml");
5895
5896 pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &str_PUBLISH);
5897
5900 } else {
5901 struct stasis_subscription *sub;
5902
5906 }
5907
5912 ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
5914
5916
5918 AST_TEST_REGISTER(complex_resource_tree);
5919 AST_TEST_REGISTER(bad_resource);
5920 AST_TEST_REGISTER(bad_branch);
5921 AST_TEST_REGISTER(duplicate_resource);
5922 AST_TEST_REGISTER(loop);
5923 AST_TEST_REGISTER(bad_event);
5924
5926}
#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:1872
struct ast_flags ast_options
Definition: options.c:61
@ AST_OPT_FLAG_FULLY_BOOTED
Definition: options.h:58
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:191
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:464
@ 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:1023
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1077
#define 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 3652 of file res_pjsip_pubsub.c.

3654{
3655 char *line;
3656 char *buffer;
3657 int found_counts = 0;
3658
3659 if (ast_strlen_zero(body) || !summary) {
3660 return -1;
3661 }
3662
3663 buffer = ast_strdupa(body);
3664 memset(summary, 0, sizeof(*summary));
3665
3666 while ((line = ast_read_line_from_buffer(&buffer))) {
3667 line = ast_str_to_lower(line);
3668
3669 if (sscanf(line, "voice-message: %d/%d (%d/%d)",
3670 &summary->voice_messages_new, &summary->voice_messages_old,
3672 found_counts = 1;
3673 } else {
3674 sscanf(line, "message-account: %s", summary->message_account);
3675 }
3676 }
3677
3678 return !found_counts;
3679}
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:371
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 4912 of file res_pjsip_pubsub.c.

4913{
4914 struct subscription_persistence *persistence = obj;
4915
4916 persistence->endpoint = ast_strdup(var->value);
4917 return 0;
4918}

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 4920 of file res_pjsip_pubsub.c.

4921{
4922 const struct subscription_persistence *persistence = obj;
4923
4924 *buf = ast_strdup(persistence->endpoint);
4925 return 0;
4926}

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 4977 of file res_pjsip_pubsub.c.

4978{
4979 struct subscription_persistence *persistence = obj;
4980 return ast_get_timeval(var->value, &persistence->expires, ast_tv(0, 0), NULL);
4981}
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 4983 of file res_pjsip_pubsub.c.

4984{
4985 const struct subscription_persistence *persistence = obj;
4986 char secs[AST_TIME_T_LEN];
4987
4988 ast_time_t_to_string(persistence->expires.tv_sec, secs, sizeof(secs));
4989
4990 return (ast_asprintf(buf, "%s", secs) < 0) ? -1 : 0;
4991}
#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 4944 of file res_pjsip_pubsub.c.

4945{
4946 struct subscription_persistence *persistence = obj;
4947 struct ast_json_error error;
4948
4949 /* We tolerate a failure of the JSON to load and instead start fresh, since this field
4950 * originates from the persistence code and not a user.
4951 */
4952 persistence->generator_data = ast_json_load_string(var->value, &error);
4953
4954 return 0;
4955}
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 4957 of file res_pjsip_pubsub.c.

4958{
4959 const struct subscription_persistence *persistence = obj;
4960 char *value;
4961
4962 if (!persistence->generator_data) {
4963 return 0;
4964 }
4965
4967 if (!value) {
4968 return -1;
4969 }
4970
4971 *buf = ast_strdup(value);
4973
4974 return 0;
4975}
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 4928 of file res_pjsip_pubsub.c.

4929{
4930 struct subscription_persistence *persistence = obj;
4931
4932 persistence->tag = ast_strdup(var->value);
4933 return 0;
4934}

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 4936 of file res_pjsip_pubsub.c.

4937{
4938 const struct subscription_persistence *persistence = obj;
4939
4940 *buf = ast_strdup(persistence->tag);
4941 return 0;
4942}

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 2765 of file res_pjsip_pubsub.c.

2766{
2767 const struct ast_sip_publication *publication1 = obj;
2768 const struct ast_sip_publication *publication2 = arg;
2769 const int *entity_tag = arg;
2770
2771 return (publication1->entity_tag == (flags & OBJ_KEY ? *entity_tag : publication2->entity_tag) ?
2772 CMP_MATCH | CMP_STOP : 0);
2773}
@ 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 3199 of file res_pjsip_pubsub.c.

3200{
3201 struct ast_sip_publication *publication = obj;
3202
3203 ast_debug(3, "Destroying SIP publication\n");
3204
3205 ao2_cleanup(publication->datastores);
3206 ao2_cleanup(publication->endpoint);
3207
3209}
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469

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 2757 of file res_pjsip_pubsub.c.

2758{
2759 const struct ast_sip_publication *publication = obj;
2760 const int *entity_tag = obj;
2761
2762 return flags & OBJ_KEY ? *entity_tag : publication->entity_tag;
2763}

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 584 of file res_pjsip_pubsub.c.

585{
587}
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 575 of file res_pjsip_pubsub.c.

576{
577 struct ast_sip_publication_resource *resource = obj;
578
579 ast_free(resource->endpoint);
580 ast_variables_destroy(resource->events);
581}
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 3379 of file res_pjsip_pubsub.c.

3380{
3381 struct ast_sip_publication *publication = (struct ast_sip_publication*)data;
3382
3383 ao2_unlink(publication->handler->publications, publication);
3384 publication->sched_id = -1;
3385
3386 if (ast_sip_push_task(NULL, publish_expire_callback, publication)) {
3387 ao2_cleanup(publication);
3388 }
3389
3390 return 0;
3391}
#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 3368 of file res_pjsip_pubsub.c.

3369{
3370 RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
3371
3372 if (publication->handler->publish_expire) {
3373 publication->handler->publish_expire(publication);
3374 }
3375
3376 return 0;
3377}

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 3280 of file res_pjsip_pubsub.c.

3282{
3283 struct ast_sip_publication *publication;
3284 char *resource_name;
3285 size_t resource_size;
3287 struct ast_variable *event_configuration_name = NULL;
3288 pjsip_uri *request_uri;
3289 int resp;
3290 const pj_str_t *user;
3291
3292 request_uri = rdata->msg_info.msg->line.req.uri;
3293
3294 if (!ast_sip_is_uri_sip_sips(request_uri)) {
3295 char uri_str[PJSIP_MAX_URL_SIZE];
3296
3297 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3298 ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3299 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3300 return NULL;
3301 }
3302
3303 user = ast_sip_pjsip_uri_get_username(request_uri);
3304 resource_size = pj_strlen(user) + 1;
3305 resource_name = ast_alloca(resource_size);
3306 ast_copy_pj_str(resource_name, user, resource_size);
3307
3308 /*
3309 * We may want to match without any user options getting
3310 * in the way.
3311 */
3313
3314 resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
3315 if (!resource) {
3316 ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name);
3317 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3318 return NULL;
3319 }
3320
3321 if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
3322 ast_debug(1, "Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3323 resource_name, resource->endpoint, ast_sorcery_object_get_id(endpoint));
3324 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
3325 return NULL;
3326 }
3327
3328 for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
3329 if (!strcmp(event_configuration_name->name, handler->event_name)) {
3330 break;
3331 }
3332 }
3333
3334 if (!event_configuration_name) {
3335 ast_debug(1, "Event '%s' is not configured for '%s'\n", handler->event_name, resource_name);
3336 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3337 return NULL;
3338 }
3339
3340 resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
3341
3342 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3343 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3344 return NULL;
3345 }
3346
3347 publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
3348
3349 if (!publication) {
3350 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
3351 return NULL;
3352 }
3353
3354 publication->handler = handler;
3355 if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
3357 ast_debug(3, "Publication state change failed\n");
3358 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3359 ao2_cleanup(publication);
3360 return NULL;
3361 }
3362
3363 sip_publication_respond(publication, resp, rdata);
3364
3365 return publication;
3366}
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:3351
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 4228 of file res_pjsip_pubsub.c.

4229{
4230 struct sip_subscription_tree *sub_tree;
4231
4232 if (!(sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4233 return;
4234 }
4235
4237 ao2_cleanup(sub_tree);
4238 }
4239}
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 3922 of file res_pjsip_pubsub.c.

3923{
3924 struct sip_subscription_tree *sub_tree =
3925 pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3926
3927 ast_debug(3, "evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub,
3928 pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree,
3929 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3930
3931 if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
3932 return;
3933 }
3934
3935 /* It's easier to write this as what we WANT to process, then negate it. */
3936 if (!(sub_tree->state == SIP_SUB_TREE_TERMINATE_IN_PROGRESS
3937 || (event->type == PJSIP_EVENT_TSX_STATE && sub_tree->state == SIP_SUB_TREE_NORMAL)
3938 )) {
3939 ast_debug(3, "Do nothing.\n");
3940 return;
3941 }
3942
3943#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
3944 /* This check looks for re-subscribes with an expires of 0. If we receive one of those,
3945 we don't want to clean the evsub because we still need it to send the final NOTIFY.
3946 This was previously handled by pubsub_on_rx_refresh setting:
3947 'sub_tree->state = SIP_SUB_TREE_TERMINATE_PENDING' */
3948 if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&
3949 !pjsip_method_cmp(&event->body.tsx_state.tsx->method, &pjsip_subscribe_method) &&
3950 pjsip_evsub_get_expires(evsub) == 0) {
3951 ast_debug(3, "Subscription ending, do nothing.\n");
3952 return;
3953 }
3954#endif
3955 /* If we made it this far, we want to clean the sub tree. For pjproject <2.13, the sub_tree
3956 state check makes sure the evsub is not cleaned at the wrong time */
3958}
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 3960 of file res_pjsip_pubsub.c.

3961{
3962 struct sip_subscription_tree *sub_tree = userdata;
3963 pjsip_dialog *dlg = sub_tree->dlg;
3964
3965 ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
3966 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3967
3968 pjsip_dlg_inc_lock(dlg);
3969 if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) {
3970 pjsip_dlg_dec_lock(dlg);
3971 return 0;
3972 }
3973
3974 if (sub_tree->state == SIP_SUB_TREE_TERMINATE_PENDING) {
3976 set_state_terminated(sub_tree->root);
3977 }
3978
3979 if (sub_tree->generate_initial_notify) {
3980 sub_tree->generate_initial_notify = 0;
3981 if (generate_initial_notify(sub_tree->root)) {
3982 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3983 pjsip_dlg_dec_lock(dlg);
3984 return 0;
3985 }
3986 }
3987
3988 send_notify(sub_tree, 1);
3989
3990 ast_test_suite_event_notify(sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ?
3991 "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED",
3992 "Resource: %s", sub_tree->root->resource);
3993
3994 pjsip_dlg_dec_lock(dlg);
3995
3996 return 0;
3997}
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 3681 of file res_pjsip_pubsub.c.

3682{
3683 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3684 struct simple_message_summary summary;
3685 const char *endpoint_name;
3686 char *atsign;
3687 char *context;
3688 char *body;
3689 char *mailbox;
3690 int rc;
3691
3692 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3693 if (!endpoint) {
3694 ast_debug(1, "Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3695 rc = 404;
3696 goto error;
3697 }
3698
3699 endpoint_name = ast_sorcery_object_get_id(endpoint);
3700 ast_debug(1, "Incoming MWI: Found endpoint: %s\n", endpoint_name);
3701 if (ast_strlen_zero(endpoint->incoming_mwi_mailbox)) {
3702 ast_debug(1, "Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3703 ast_test_suite_event_notify("PUBSUB_NO_INCOMING_MWI_MAILBOX",
3704 "Endpoint: %s", endpoint_name);
3705 rc = 404;
3706 goto error;
3707 }
3708
3709 mailbox = ast_strdupa(endpoint->incoming_mwi_mailbox);
3710 atsign = strchr(mailbox, '@');
3711 if (!atsign) {
3712 ast_debug(1, "Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3713 endpoint_name, endpoint->incoming_mwi_mailbox);
3714 rc = 404;
3715 goto error;
3716 }
3717
3718 *atsign = '\0';
3719 context = atsign + 1;
3720
3721 body = ast_alloca(rdata->msg_info.msg->body->len + 1);
3722 rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3723 rdata->msg_info.msg->body->len + 1);
3724
3725 if (parse_simple_message_summary(body, &summary) != 0) {
3726 ast_debug(1, "Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3727 ast_sorcery_object_get_id(endpoint), body);
3728 rc = 404;
3729 goto error;
3730 }
3731
3733 summary.voice_messages_new, summary.voice_messages_old)) {
3734 ast_log(LOG_ERROR, "Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
3735 "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3736 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3737 summary.voice_messages_new, summary.voice_messages_old,
3738 summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3739 rc = 404;
3740 } else {
3741 ast_debug(1, "Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3742 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3743 summary.voice_messages_new, summary.voice_messages_old,
3744 summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3745 ast_test_suite_event_notify("PUBSUB_INCOMING_MWI_PUBLISH",
3746 "Endpoint: %s\r\n"
3747 "Mailbox: %s\r\n"
3748 "MessageAccount: %s\r\n"
3749 "VoiceMessagesNew: %d\r\n"
3750 "VoiceMessagesOld: %d\r\n"
3751 "VoiceMessagesUrgentNew: %d\r\n"
3752 "VoiceMessagesUrgentOld: %d",
3753 endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3754 summary.voice_messages_new, summary.voice_messages_old,
3755 summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3756 rc = 200;
3757 }
3758
3759error:
3760 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, rc, NULL, NULL, NULL);
3761 return PJ_TRUE;
3762}
#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:963

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 4195 of file res_pjsip_pubsub.c.

4197{
4198 struct ast_sip_subscription *sub;
4199
4200 if (!(sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
4201 return;
4202 }
4203
4204 sub->handler->subscriber->state_change(sub, rdata->msg_info.msg->body,
4205 pjsip_evsub_get_state(evsub));
4206}

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 3764 of file res_pjsip_pubsub.c.

3765{
3766 if (rdata->msg_info.msg->body &&
3767 ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type,
3768 "application", "simple-message-summary")) {
3769 return pubsub_on_rx_mwi_notify_request(rdata);
3770 }
3771 return PJ_FALSE;
3772}
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 3393 of file res_pjsip_pubsub.c.

3394{
3395 pjsip_event_hdr *event_header;
3397 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3398 char event[32];
3399 static const pj_str_t str_sip_if_match = { "SIP-If-Match", 12 };
3400 pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
3401 enum sip_publish_type publish_type;
3402 RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
3403 unsigned int expires = 0;
3404 int entity_id, response = 0;
3405
3406 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3407 ast_assert(endpoint != NULL);
3408
3409 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
3410 if (!event_header) {
3411 ast_log(LOG_WARNING, "Incoming PUBLISH request from %s with no Event header\n",
3412 ast_sorcery_object_get_id(endpoint));
3413 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3414 return PJ_TRUE;
3415 }
3416 ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
3417
3419 if (!handler) {
3420 ast_log(LOG_WARNING, "No registered publish handler for event %s from %s\n", event,
3421 ast_sorcery_object_get_id(endpoint));
3422 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3423 return PJ_TRUE;
3424 }
3425
3426 publish_type = determine_sip_publish_type(rdata, etag_hdr, &expires, &entity_id);
3427
3428 /* If this is not an initial publish ensure that a publication is present */
3429 if ((publish_type != SIP_PUBLISH_INITIAL) && (publish_type != SIP_PUBLISH_UNKNOWN)) {
3430 if (!(publication = ao2_find(handler->publications, &entity_id, OBJ_KEY | OBJ_UNLINK))) {
3431 static const pj_str_t str_conditional_request_failed = { "Conditional Request Failed", 26 };
3432
3433 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 412, &str_conditional_request_failed,
3434 NULL, NULL);
3435 return PJ_TRUE;
3436 }
3437
3438 /* Per the RFC every response has to have a new entity tag */
3439 publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
3440
3441 /* Update the expires here so that the created responses will contain the correct value */
3442 publication->expires = expires;
3443 }
3444
3445 switch (publish_type) {
3447 publication = publish_request_initial(endpoint, rdata, handler);
3448 break;
3450 case SIP_PUBLISH_MODIFY:
3451 if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
3453 /* If an error occurs we want to terminate the publication */
3454 expires = 0;
3455 }
3456 response = 200;
3457 break;
3458 case SIP_PUBLISH_REMOVE:
3459 handler->publication_state_change(publication, rdata->msg_info.msg->body,
3461 response = 200;
3462 break;
3464 default:
3465 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3466 break;
3467 }
3468
3469 if (publication) {
3470 if (expires) {
3471 ao2_link(handler->publications, publication);
3472
3473 AST_SCHED_REPLACE_UNREF(publication->sched_id, sched, expires * 1000, publish_expire, publication,
3474 ao2_ref(_data, -1), ao2_ref(publication, -1), ao2_ref(publication, +1));
3475 } else {
3476 AST_SCHED_DEL_UNREF(sched, publication->sched_id, ao2_ref(publication, -1));
3477 }
3478 }
3479
3480 if (response) {
3481 sip_publication_respond(publication, response, rdata);
3482 }
3483
3484 return PJ_TRUE;
3485}
#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:757
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 4075 of file res_pjsip_pubsub.c.

4077{
4078 struct sip_subscription_tree *sub_tree;
4080
4081 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4082 ast_debug(3, "evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree,
4083 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4084
4085 if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4086 return;
4087 }
4088
4089 if (sub_tree->expiration_task) {
4090 char task_name[256];
4091
4092 ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
4093 ast_debug(3, "Cancelling timer: %s\n", task_name);
4095 ao2_cleanup(sub_tree->expiration_task);
4096 sub_tree->expiration_task = NULL;
4097 }
4098
4099 /* PJSIP will set the evsub's state to terminated before calling into this function
4100 * if the Expires value of the incoming SUBSCRIBE is 0.
4101 */
4102
4103 if (pjsip_evsub_get_state(sub_tree->evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
4105 }
4106
4108
4109 /* If the handler wants a callback on refresh, then do it (some protocols require this). */
4110 if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->root->handler->notifier->refresh_subscribe) {
4111 if (!sub_tree->root->handler->notifier->refresh_subscribe(sub_tree->root, rdata)) {
4112 return; /* If the callback handled it, we're done. */
4113 }
4114 }
4115
4116 if (sub_tree->state == SIP_SUB_TREE_NORMAL && sub_tree->is_list) {
4117 /* update RLS */
4118 const char *resource = sub_tree->root->resource;
4119 struct ast_sip_subscription *old_root = sub_tree->root;
4120 struct ast_sip_subscription *new_root = NULL;
4121
4122 struct ast_sip_pubsub_body_generator *generator = NULL;
4123
4124 if (endpoint && (generator = subscription_get_generator_from_rdata(rdata, sub_tree->root->handler))) {
4125
4126 struct resource_tree tree;
4127 int resp;
4128
4129 memset(&tree, 0, sizeof(tree));
4130 resp = build_resource_tree(endpoint, sub_tree->root->handler, resource, &tree,
4132 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
4133 new_root = create_virtual_subscriptions(sub_tree->root->handler, resource, generator, sub_tree, tree.root);
4134 if (new_root) {
4135 if (cmp_subscription_childrens(old_root, new_root)) {
4136 ast_debug(1, "RLS '%s->%s' was modified, regenerate it\n", ast_sorcery_object_get_id(endpoint), old_root->resource);
4137 new_root->version = old_root->version;
4138 sub_tree->root = new_root;
4139 sub_tree->generate_initial_notify = 1;
4140
4141 /* If there is scheduled notification need to delete it to avoid use old subscriptions */
4142 if (sub_tree->notify_sched_id > -1) {
4143 AST_SCHED_DEL_UNREF(sched, sub_tree->notify_sched_id, ao2_ref(sub_tree, -1));
4144 sub_tree->send_scheduled_notify = 0;
4145 }
4146
4147 /* Terminate old subscriptions to stop sending NOTIFY messages on exten/device state changes */
4148 set_state_terminated(old_root);
4149
4150 /* Shutdown old subscriptions to remove exten/device state change callbacks
4151 that can queue tasks for old subscriptions */
4152 shutdown_subscriptions(old_root);
4153
4154 /* Postpone destruction until all already queued tasks that may be using old subscriptions have completed */
4155 if (ast_sip_push_task(sub_tree->serializer, destroy_subscriptions_task, old_root)) {
4156 ast_log(LOG_ERROR, "Failed to push task to destroy old subscriptions for RLS '%s->%s'.\n",
4157 ast_sorcery_object_get_id(endpoint), old_root->resource);
4158 }
4159 } else {
4160 destroy_subscriptions(new_root);
4161 }
4162 }
4163 } else {
4165 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4166 }
4167
4168 resource_tree_destroy(&tree);
4169 }
4170 }
4171
4173
4174#ifdef HAVE_PJSIP_EVSUB_PENDING_NOTIFY
4175 /* As of pjsip 2.13, the NOTIFY has to be sent within this function as pjproject now
4176 requires it. Previously this would have caused an early NOTIFY to go out before the
4177 SUBSCRIBE's 200 OK. The previous solution was to push the NOTIFY, but now pjproject
4178 looks for the NOTIFY to be sent from this function and caches it to send after it
4179 auto-replies to the SUBSCRIBE. */
4180 pubsub_on_refresh_timeout(sub_tree);
4181#else
4183 /* If we can't push the NOTIFY refreshing task...we'll just go with it. */
4184 ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n");
4185 sub_tree->state = SIP_SUB_TREE_NORMAL;
4186 ao2_ref(sub_tree, -1);
4187 }
4188#endif
4189
4190 if (sub_tree->is_list) {
4191 pj_list_insert_before(res_hdr, create_require_eventlist(rdata->tp_info.pool));
4192 }
4193}
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 3774 of file res_pjsip_pubsub.c.

3775{
3776 if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3777 return pubsub_on_rx_subscribe_request(rdata);
3778 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
3779 return pubsub_on_rx_publish_request(rdata);
3780 } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
3781 return pubsub_on_rx_notify_request(rdata);
3782 }
3783
3784 return PJ_FALSE;
3785}
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 3034 of file res_pjsip_pubsub.c.

3035{
3036 pjsip_expires_hdr *expires_header;
3038 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3039 struct sip_subscription_tree *sub_tree;
3040 struct ast_sip_pubsub_body_generator *generator;
3041 char *resource;
3042 pjsip_uri *request_uri;
3043 size_t resource_size;
3044 int resp;
3045 struct resource_tree tree;
3046 pj_status_t dlg_status;
3047 const pj_str_t *user;
3048
3049 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3050 ast_assert(endpoint != NULL);
3051
3052 if (!endpoint->subscription.allow) {
3053 ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
3054 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
3055 return PJ_TRUE;
3056 }
3057
3058 request_uri = rdata->msg_info.msg->line.req.uri;
3059
3060 if (!ast_sip_is_uri_sip_sips(request_uri)) {
3061 char uri_str[PJSIP_MAX_URL_SIZE];
3062
3063 pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3064 ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3065 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3066 return PJ_TRUE;
3067 }
3068
3069 user = ast_sip_pjsip_uri_get_username(request_uri);
3070 resource_size = pj_strlen(user) + 1;
3071 resource = ast_alloca(resource_size);
3072 ast_copy_pj_str(resource, user, resource_size);
3073
3074 /*
3075 * We may want to match without any user options getting
3076 * in the way.
3077 */
3079
3080 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3081 if (expires_header) {
3082 if (expires_header->ivalue == 0) {
3083 ast_debug(1, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3084 ast_sorcery_object_get_id(endpoint));
3085 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3086 return PJ_TRUE;
3087 }
3088 if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3089 ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3090 expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subscription.minexpiry);
3091 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
3092 return PJ_TRUE;
3093 }
3094 }
3095
3097 if (!handler) {
3098 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3099 return PJ_TRUE;
3100 }
3101
3103 if (!generator) {
3104 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3105 return PJ_TRUE;
3106 }
3107
3108 memset(&tree, 0, sizeof(tree));
3109 resp = build_resource_tree(endpoint, handler, resource, &tree,
3111 if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3112 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3113 resource_tree_destroy(&tree);
3114 return PJ_TRUE;
3115 }
3116
3117 sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
3118 if (!sub_tree) {
3119 if (dlg_status != PJ_EEXISTS) {
3120 ast_debug(3, "No dialog exists, rejecting\n");
3121 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3122 }
3123 } else {
3124 struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
3125
3126 if (!ind) {
3127 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3128 resource_tree_destroy(&tree);
3129 return PJ_TRUE;
3130 }
3131
3132 ind->sub_tree = ao2_bump(sub_tree);
3133 /* Since this is a normal subscribe, pjproject takes care of the timer */
3135
3138 sip_subscription_accept(sub_tree, rdata, resp);
3140 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3141 ao2_ref(sub_tree, -1);
3142 ast_free(ind);
3143 }
3144 }
3145
3146 resource_tree_destroy(&tree);
3147 return PJ_TRUE;
3148}
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 4241 of file res_pjsip_pubsub.c.

4242{
4243 struct sip_subscription_tree *sub_tree;
4244
4245 /* PJSIP does not terminate the server timeout timer when a SUBSCRIBE
4246 * with Expires: 0 arrives to end a subscription, nor does it terminate
4247 * this timer when we send a NOTIFY request in response to receiving such
4248 * a SUBSCRIBE. PJSIP does not stop the server timeout timer until the
4249 * NOTIFY transaction has finished (either through receiving a response
4250 * or through a transaction timeout).
4251 *
4252 * Therefore, it is possible that we can be told that a server timeout
4253 * occurred after we already thought that the subscription had been
4254 * terminated. In such a case, we will have already removed the sub_tree
4255 * from the evsub's mod_data array.
4256 */
4257
4258 sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4259 if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4260 return;
4261 }
4262
4265 sub_tree->state = SIP_SUB_TREE_NORMAL;
4266 ao2_cleanup(sub_tree);
4267 }
4268}

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 5772 of file res_pjsip_pubsub.c.

5773{
5774 struct ast_sip_publication_resource *resource = obj;
5775
5776 ast_free(resource->endpoint);
5777 resource->endpoint = ast_strdup(var->value);
5778
5779 return 0;
5780}

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 5782 of file res_pjsip_pubsub.c.

5783{
5784 struct ast_sip_publication_resource *resource = obj;
5785 /* The event configuration name starts with 'event_' so skip past it to get the real name */
5786 const char *event = var->name + 6;
5787 struct ast_variable *item;
5788
5789 if (ast_strlen_zero(event) || ast_strlen_zero(var->value)) {
5790 return -1;
5791 }
5792
5793 item = ast_variable_new(event, var->value, "");
5794 if (!item) {
5795 return -1;
5796 }
5797
5798 if (resource->events) {
5799 item->next = resource->events;
5800 }
5801 resource->events = item;
5802
5803 return 0;
5804}
#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 5007 of file res_pjsip_pubsub.c.

5008{
5009 struct resource_list *list;
5010
5012 if (!list) {
5013 return NULL;
5014 }
5015
5017 ao2_cleanup(list);
5018 return NULL;
5019 }
5020
5021 return list;
5022}
#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 5081 of file res_pjsip_pubsub.c.

5082{
5083 struct resource_list *list = obj;
5084
5085 if (ast_strlen_zero(list->event)) {
5086 ast_log(LOG_WARNING, "Resource list '%s' has no event set\n",
5088 return -1;
5089 }
5090
5091 if (AST_VECTOR_SIZE(&list->items) == 0) {
5092 ast_log(LOG_WARNING, "Resource list '%s' has no list items\n",
5094 return -1;
5095 }
5096
5097 return 0;
5098}

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 4995 of file res_pjsip_pubsub.c.

4996{
4997 struct resource_list *list = obj;
4998 int i;
4999
5000 for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
5001 ast_free((char *) AST_VECTOR_GET(&list->items, i));
5002 }
5003
5004 AST_VECTOR_FREE(&list->items);
5005}

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 1136 of file res_pjsip_pubsub.c.

1137{
1138 if (tree) {
1139 tree_node_destroy(tree->root);
1140 }
1141}

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 919 of file res_pjsip_pubsub.c.

920{
921 struct resource_list *list;
922
923 list = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
924 if (!list) {
925 return NULL;
926 }
927
928 if (strcmp(list->event, event)) {
929 ast_log(LOG_WARNING, "Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
930 resource, list->event, event);
931 ao2_cleanup(list);
932 return NULL;
933 }
934
935 return list;
936}

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 2186 of file res_pjsip_pubsub.c.

2187{
2188 const pj_xml_node *rlmi = data;
2189
2190 return pj_xml_clone(pool, rlmi);
2191}

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 2173 of file res_pjsip_pubsub.c.

2174{
2175 int num_printed;
2176 pj_xml_node *rlmi = msg_body->data;
2177
2178 num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
2179 if (num_printed <= AST_PJSIP_XML_PROLOG_LEN) {
2180 return -1;
2181 }
2182
2183 return num_printed;
2184}
#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 2564 of file res_pjsip_pubsub.c.

2565{
2566 struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
2567
2568 /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
2569 if (ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree)) {
2570 ao2_cleanup(sub_tree);
2571 }
2572
2573 return 0;
2574}
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 2576 of file res_pjsip_pubsub.c.

2577{
2578 /* There's already a notification scheduled */
2579 if (sub_tree->notify_sched_id > -1) {
2580 return 0;
2581 }
2582
2583 sub_tree->send_scheduled_notify = 1;
2585 if (sub_tree->notify_sched_id < 0) {
2586 ao2_cleanup(sub_tree);
2587 return -1;
2588 }
2589
2590 return 0;
2591}
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 2482 of file res_pjsip_pubsub.c.

2483{
2484 pjsip_evsub *evsub = sub_tree->evsub;
2485 pjsip_tx_data *tdata;
2486
2487 if (ast_shutdown_final()
2488 && sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED
2489 && sub_tree->persistence) {
2490 return 0;
2491 }
2492
2493 if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
2494 NULL, NULL, &tdata) != PJ_SUCCESS) {
2495 return -1;
2496 }
2497
2498 tdata->msg->body = generate_notify_body(tdata->pool, sub_tree->root, force_full_state);
2499 if (!tdata->msg->body) {
2500 pjsip_tx_data_dec_ref(tdata);
2501 return -1;
2502 }
2503
2504 if (sub_tree->is_list) {
2505 pjsip_require_hdr *require = create_require_eventlist(tdata->pool);
2506 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2507 }
2508
2509 if (sub_tree->root->handler->notifier->notify_created) {
2510 /* The module for this event wants a callback to the pjsip_tx_data,
2511 * e.g. so it can add custom headers or do something custom to the response. */
2512 sub_tree->root->handler->notifier->notify_created(sub_tree->root, tdata);
2513 }
2514
2515 if (sip_subscription_send_request(sub_tree, tdata)) {
2516 /* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */
2517 return -1;
2518 }
2519
2520 sub_tree->send_scheduled_notify = 0;
2521
2522 return 0;
2523}
int ast_shutdown_final(void)
Definition: asterisk.c:1867
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 4208 of file res_pjsip_pubsub.c.

4209{
4210 struct sip_subscription_tree *sub_tree = userdata;
4211 pjsip_tx_data *tdata;
4212
4213 if (!sub_tree->evsub) {
4214 ao2_cleanup(sub_tree);
4215 return 0;
4216 }
4217
4218 if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
4219 pjsip_evsub_send_request(sub_tree->evsub, tdata);
4220 } else {
4221 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
4222 }
4223
4224 ao2_cleanup(sub_tree);
4225 return 0;
4226}

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 3999 of file res_pjsip_pubsub.c.

4000{
4001 struct sip_subscription_tree *sub_tree = userdata;
4002
4003 ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
4004 (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
4005
4006 pubsub_on_refresh_timeout(userdata);
4007 ao2_cleanup(sub_tree);
4008
4009 return 0;
4010}

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 2525 of file res_pjsip_pubsub.c.

2526{
2527 struct sip_subscription_tree *sub_tree = userdata;
2528 pjsip_dialog *dlg = sub_tree->dlg;
2529
2530 pjsip_dlg_inc_lock(dlg);
2531
2532 sub_tree->notify_sched_id = -1;
2533
2534 /* It's possible that between when the notification was scheduled
2535 * and now a new SUBSCRIBE arrived requiring full state to be
2536 * sent out in an immediate NOTIFY. It's also possible that we're
2537 * already processing a terminate. If that has happened, we need to
2538 * bail out here instead of sending the batched NOTIFY.
2539 */
2540
2542 || !sub_tree->send_scheduled_notify) {
2543 pjsip_dlg_dec_lock(dlg);
2544 ao2_cleanup(sub_tree);
2545 return 0;
2546 }
2547
2548 if (sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) {
2550 }
2551
2552 send_notify(sub_tree, 0);
2553
2555 sub_tree->state == SIP_SUB_TREE_TERMINATED
2556 ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2557 "Resource: %s", sub_tree->root->resource);
2558
2559 pjsip_dlg_dec_lock(dlg);
2560 ao2_cleanup(sub_tree);
2561 return 0;
2562}

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 2462 of file res_pjsip_pubsub.c.

2463{
2464 int i;
2465
2466 sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2467 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2468 set_state_terminated(AST_VECTOR_GET(&sub->children, i));
2469 }
2470}

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 1367 of file res_pjsip_pubsub.c.

1368{
1369 int i;
1370
1371 if (!sub) {
1372 return;
1373 }
1374
1375 if (AST_VECTOR_SIZE(&sub->children) > 0) {
1376 for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
1378 }
1379 return;
1380 }
1381
1382 /* We notify subscription shutdown only on the tree leaves. */
1383 if (sub->handler->subscription_shutdown) {
1384 sub->handler->subscription_shutdown(sub);
1385 }
1386}

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 3211 of file res_pjsip_pubsub.c.

3213{
3214 struct ast_sip_publication *publication;
3215 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3216 size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
3217 char *dst;
3218
3220
3221 if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
3222 return NULL;
3223 }
3224
3226
3227 if (!(publication->datastores = ast_datastores_alloc())) {
3228 ao2_ref(publication, -1);
3229 return NULL;
3230 }
3231
3233 ao2_ref(endpoint, +1);
3234 publication->endpoint = endpoint;
3235 publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3236 publication->sched_id = -1;
3237 dst = publication->data;
3238 publication->resource = strcpy(dst, resource);
3239 dst += resource_len;
3240 publication->event_configuration_name = strcpy(dst, event_configuration_name);
3241
3242 return publication;
3243}
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 3245 of file res_pjsip_pubsub.c.

3247{
3248 pjsip_tx_data *tdata;
3249 pjsip_transaction *tsx;
3250
3251 if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, status_code, NULL, &tdata) != PJ_SUCCESS) {
3252 return -1;
3253 }
3254
3255 if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3256 char buf[30];
3257
3258 snprintf(buf, sizeof(buf), "%d", pub->entity_tag);
3259 ast_sip_add_header(tdata, "SIP-ETag", buf);
3260
3261 snprintf(buf, sizeof(buf), "%d", pub->expires);
3262 ast_sip_add_header(tdata, "Expires", buf);
3263 }
3264
3265 if (pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3266 pjsip_tx_data_dec_ref(tdata);
3267 return -1;
3268 }
3269
3270 pjsip_tsx_recv_msg(tsx, rdata);
3271
3272 if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3273 pjsip_tx_data_dec_ref(tdata);
3274 return -1;
3275 }
3276
3277 return 0;
3278}
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 2670 of file res_pjsip_pubsub.c.

2671{
2672 pjsip_hdr res_hdr;
2673
2674 /* If this is a persistence recreation the subscription has already been accepted */
2675 if (ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_PERSISTENCE)) {
2676 return 0;
2677 }
2678
2679 pj_list_init(&res_hdr);
2680 if (sub_tree->is_list) {
2681 /* If subscribing to a list, our response has to have a Require: eventlist header in it */
2682 pj_list_insert_before(&res_hdr, create_require_eventlist(rdata->tp_info.pool));
2683 }
2684
2685 return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2686}

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 2030 of file res_pjsip_pubsub.c.

2031{
2032#ifdef TEST_FRAMEWORK
2033 struct ast_sip_endpoint *endpoint = sub_tree->endpoint;
2034 pjsip_evsub *evsub = sub_tree->evsub;
2035#endif
2036 int res;
2037
2038 if (allocate_tdata_buffer(tdata)) {
2039 ast_log(LOG_ERROR, "SIP request %s is too large to send.\n", tdata->info);
2040 pjsip_tx_data_dec_ref(tdata);
2041 return -1;
2042 }
2043
2044 res = pjsip_evsub_send_request(sub_tree->evsub, tdata);
2045
2047
2048 ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
2049 "StateText: %s\r\n"
2050 "Endpoint: %s\r\n",
2051 pjsip_evsub_get_state_name(evsub),
2052 ast_sorcery_object_get_id(endpoint));
2053
2054 return (res == PJ_SUCCESS ? 0 : -1);
2055}
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 1861 of file res_pjsip_pubsub.c.

1863{
1864 char str[256];
1865 struct ast_sip_endpoint_id_configuration *id = &sub_tree->endpoint->id;
1866
1867 ast_str_append(buf, 0, "Role: %s\r\n",
1868 sip_subscription_roles_map[sub_tree->role]);
1869 ast_str_append(buf, 0, "Endpoint: %s\r\n",
1871
1872 if (sub_tree->dlg) {
1873 ast_copy_pj_str(str, &sub_tree->dlg->call_id->id, sizeof(str));
1874 } else {
1875 ast_copy_string(str, "<unknown>", sizeof(str));
1876 }
1877 ast_str_append(buf, 0, "Callid: %s\r\n", str);
1878
1879 ast_str_append(buf, 0, "State: %s\r\n", pjsip_evsub_get_state_name(sub_tree->evsub));
1880
1881 ast_callerid_merge(str, sizeof(str),
1882 S_COR(id->self.name.valid, id->self.name.str, NULL),
1883 S_COR(id->self.number.valid, id->self.number.str, NULL),
1884 "Unknown");
1885
1886 ast_str_append(buf, 0, "Callerid: %s\r\n", str);
1887
1888 /* XXX This needs to be done recursively for lists */
1889 if (sub_tree->root->handler->to_ami) {
1890 sub_tree->root->handler->to_ami(sub_tree->root, buf);
1891 }
1892}
static const char * sip_subscription_roles_map[]
Party identification options for endpoints.
Definition: res_pjsip.h:771
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 1597 of file res_pjsip_pubsub.c.

1598{
1599 struct persistence_recreate_data *recreate_data = obj;
1600 struct subscription_persistence *persistence = recreate_data->persistence;
1601 pjsip_rx_data *rdata = recreate_data->rdata;
1602 struct ast_sip_endpoint *endpoint;
1603 struct sip_subscription_tree *sub_tree;
1604 struct ast_sip_pubsub_body_generator *generator;
1606 char *resource;
1607 size_t resource_size;
1608 int resp;
1609 struct resource_tree tree;
1610 pjsip_expires_hdr *expires_header;
1611 int64_t expires;
1612 const pj_str_t *user;
1613
1614 user = ast_sip_pjsip_uri_get_username(rdata->msg_info.msg->line.req.uri);
1615 resource_size = pj_strlen(user) + 1;
1616 resource = ast_alloca(resource_size);
1617 ast_copy_pj_str(resource, user, resource_size);
1618
1619 /*
1620 * We may want to match without any user options getting
1621 * in the way.
1622 */
1624
1626 if (!handler || !handler->notifier) {
1627 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get subscription handler.\n",
1628 persistence->endpoint);
1630 return 0;
1631 }
1632
1634 if (!generator) {
1635 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Body generator not available.\n",
1636 persistence->endpoint);
1638 return 0;
1639 }
1640
1641 ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data,
1642 pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
1643
1644 /* Getting the endpoint may take some time that can affect the expiration. */
1645 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1646 persistence->endpoint);
1647 if (!endpoint) {
1648 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The endpoint was not found\n",
1649 persistence->endpoint);
1651 return 0;
1652 }
1653
1654 /* Update the expiration header with the new expiration */
1655 expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1656 rdata->msg_info.msg->hdr.next);
1657 if (!expires_header) {
1658 expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1659 if (!expires_header) {
1660 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not update expires header.\n",
1661 persistence->endpoint);
1663 ao2_ref(endpoint, -1);
1664 return 0;
1665 }
1666 pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1667 }
1668
1669 expires = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
1670 if (expires <= 0) {
1671 /* The subscription expired since we started recreating the subscription. */
1672 ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1673 persistence->endpoint, persistence->tag);
1675 ao2_ref(endpoint, -1);
1676 return 0;
1677 }
1678 expires_header->ivalue = expires;
1679
1680 memset(&tree, 0, sizeof(tree));
1681 resp = build_resource_tree(endpoint, handler, resource, &tree,
1683 if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1684 pj_status_t dlg_status;
1685
1686 sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,
1687 &tree, &dlg_status, persistence);
1688 if (!sub_tree) {
1689 if (dlg_status != PJ_EEXISTS) {
1690 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",
1691 persistence->endpoint);
1693 }
1694 } else {
1695 struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
1696
1697 if (!ind) {
1698 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1699 goto error;
1700 }
1701
1702 ind->sub_tree = ao2_bump(sub_tree);
1703 ind->expires = expires_header->ivalue;
1704
1707 /* Could not send initial subscribe NOTIFY */
1708 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1709 ao2_ref(sub_tree, -1);
1710 ast_free(ind);
1711 }
1712 }
1713 } else {
1715 }
1716
1717error:
1718 resource_tree_destroy(&tree);
1719 ao2_ref(endpoint, -1);
1720
1721 return 0;
1722}
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 589 of file res_pjsip_pubsub.c.

590{
591 struct sip_subscription_tree *sub_tree = data;
592
593 if (!sub_tree->evsub) {
594 /* Something else already terminated the subscription. */
595 ao2_ref(sub_tree, -1);
596 return 0;
597 }
598
599 ast_debug(3, "Transport destroyed. Removing subscription '%s->%s' prune on boot: %d\n",
600 sub_tree->persistence->endpoint, sub_tree->root->resource,
601 sub_tree->persistence->prune_on_boot);
602
604 pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
605
606 ao2_ref(sub_tree, -1);
607 return 0;
608}

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 618 of file res_pjsip_pubsub.c.

619{
620 struct sip_subscription_tree *sub_tree = data;
621
622 /*
623 * Push off the subscription termination to the serializer to
624 * avoid deadlock. Another thread could be trying to send a
625 * message on the subscription that can deadlock with this
626 * thread.
627 */
628 ao2_ref(sub_tree, +1);
630 sub_tree)) {
631 ao2_ref(sub_tree, -1);
632 }
633}
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 847 of file res_pjsip_pubsub.c.

849{
850 pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
851 char accept[AST_SIP_MAX_ACCEPT][64];
852 size_t num_accept_headers = 0;
853
854 while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
855 (num_accept_headers < AST_SIP_MAX_ACCEPT)) {
856 int i;
857
858 for (i = 0; i < accept_header->count && num_accept_headers < AST_SIP_MAX_ACCEPT; ++i) {
859 if (!exceptional_accept(&accept_header->values[i])) {
860 ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
861 ++num_accept_headers;
862 }
863 }
864 }
865
866 if (num_accept_headers == 0) {
867 /* If a SUBSCRIBE contains no Accept headers, then we must assume that
868 * the default accept type for the event package is to be used.
869 */
870 ast_copy_string(accept[0], handler->notifier->default_accept, sizeof(accept[0]));
871 num_accept_headers = 1;
872 }
873
874 return find_body_generator(accept, num_accept_headers, handler->body_type);
875}
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 787 of file res_pjsip_pubsub.c.

788{
789 pjsip_event_hdr *event_header;
790 char event[32];
792
793 event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
794 if (!event_header) {
795 ast_log(LOG_WARNING, "Incoming SUBSCRIBE request from %s with no Event header\n",
796 endpoint ? endpoint : "Unknown");
797 return NULL;
798 }
799 ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
800
802 if (!handler) {
803 ast_log(LOG_WARNING, "No registered subscribe handler for event %s from %s\n", event,
804 endpoint ? endpoint : "Unknown");
805 }
806
807 return handler;
808}

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 646 of file res_pjsip_pubsub.c.

647{
649}
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 652 of file res_pjsip_pubsub.c.

653{
654 char tag[PJ_GUID_STRING_LENGTH + 1];
655
656 /* The id of this persistence object doesn't matter as we keep it on the subscription and don't need to
657 * look it up by id at all.
658 */
660 "subscription_persistence", NULL);
661
662 pjsip_dialog *dlg = sub_tree->dlg;
663
664 if (!persistence) {
665 return NULL;
666 }
667
668 persistence->endpoint = ast_strdup(ast_sorcery_object_get_id(sub_tree->endpoint));
669 ast_copy_pj_str(tag, &dlg->local.info->tag, sizeof(tag));
670 persistence->tag = ast_strdup(tag);
671
673 return persistence;
674}
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 636 of file res_pjsip_pubsub.c.

637{
638 struct subscription_persistence *persistence = obj;
639
640 ast_free(persistence->endpoint);
641 ast_free(persistence->tag);
642 ast_json_unref(persistence->generator_data);
643}

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 1813 of file res_pjsip_pubsub.c.

1814{
1815 struct ast_json_payload *payload;
1816 const char *type;
1817
1819 return;
1820 }
1821
1822 payload = stasis_message_data(message);
1823 type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1824
1825 /* This subscription only responds to the FullyBooted event so that all modules have been loaded when we
1826 * recreate SIP subscriptions.
1827 */
1828 if (strcmp(type, "FullyBooted")) {
1829 return;
1830 }
1831
1832 /* This has to be here so the subscription is recreated when the body generator is available */
1834
1835 /* Once the system is fully booted we don't care anymore */
1837}
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:971
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 1791 of file res_pjsip_pubsub.c.

1792{
1793 struct ao2_container *persisted_subscriptions = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
1794 "subscription_persistence", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1795 pj_pool_t *pool;
1796
1797 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "rtd%p", PJSIP_POOL_RDATA_LEN,
1798 PJSIP_POOL_RDATA_INC);
1799 if (!pool) {
1800 ast_log(LOG_WARNING, "Could not create a memory pool for recreating SIP subscriptions\n");
1801 return 0;
1802 }
1803
1804 ao2_callback(persisted_subscriptions, OBJ_NODATA, subscription_persistence_recreate, pool);
1805
1806 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1807
1808 ao2_ref(persisted_subscriptions, -1);
1809 return 0;
1810}
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 1725 of file res_pjsip_pubsub.c.

1726{
1727 struct subscription_persistence *persistence = obj;
1728 pj_pool_t *pool = arg;
1730 pjsip_rx_data rdata;
1731 struct persistence_recreate_data recreate_data;
1732
1733 /* If this subscription used a reliable transport it can't be reestablished so remove it */
1735 ast_debug(3, "Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1738 return 0;
1739 }
1740
1741 /* If this subscription has already expired remove it */
1743 ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1746 return 0;
1747 }
1748
1749 memset(&rdata, 0, sizeof(rdata));
1750 pj_pool_reset(pool);
1751 rdata.tp_info.pool = pool;
1752
1756 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n",
1759 return 0;
1760 }
1761
1762 if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1763 ast_log(LOG_NOTICE, "Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1766 return 0;
1767 }
1768
1769 /* Continue the remainder in the distributor serializer */
1771 if (!serializer) {
1772 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1775 return 0;
1776 }
1777 recreate_data.persistence = persistence;
1778 recreate_data.rdata = &rdata;
1780 &recreate_data)) {
1781 ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
1784 }
1786
1787 return 0;
1788}
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 761 of file res_pjsip_pubsub.c.

762{
763 if (!sub_tree->persistence) {
764 return;
765 }
766
767 if (sub_tree->persistence->prune_on_boot && !ast_strlen_zero(sub_tree->transport_key)) {
768 ast_debug(3, "Unregistering transport monitor on %s '%s->%s'\n",
769 sub_tree->transport_key,
770 sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
771 sub_tree->root ? sub_tree->root->resource : "Unknown");
773 sub_tree_transport_cb, sub_tree, NULL);
774 }
775
777 ao2_ref(sub_tree->persistence, -1);
778 sub_tree->persistence = NULL;
779}
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 677 of file res_pjsip_pubsub.c.

679{
680 pjsip_dialog *dlg;
681
682 if (!sub_tree->persistence) {
683 return;
684 }
685
686 ast_debug(3, "Updating persistence for '%s->%s' prune on boot: %s\n",
687 sub_tree->persistence->endpoint, sub_tree->root->resource,
688 sub_tree->persistence->prune_on_boot ? "yes" : "no");
689
690 dlg = sub_tree->dlg;
691 sub_tree->persistence->cseq = dlg->local.cseq;
692
693 if (rdata) {
694 unsigned int expires;
695 pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
696 pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
697
698 expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
699 sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1));
700
701 if (contact_hdr) {
702 if (contact_hdr) {
704 sub_tree->persistence->prune_on_boot =
706 (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
707 sub_tree->endpoint, rdata);
708
709 if (sub_tree->persistence->prune_on_boot) {
710 ast_debug(3, "adding transport monitor on %s for '%s->%s' prune on boot: %d\n",
711 rdata->tp_info.transport->obj_name,
712 sub_tree->persistence->endpoint, sub_tree->root->resource,
713 sub_tree->persistence->prune_on_boot);
714 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(rdata->tp_info.transport,
715 sub_tree->transport_key);
717 sub_tree_transport_cb, sub_tree);
718 /*
719 * FYI: ast_sip_transport_monitor_register holds a reference to the sub_tree
720 */
721 }
722 }
723 }
724
725 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
726 sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri));
727 } else {
728 ast_log(LOG_WARNING, "Contact not updated due to missing contact header\n");
729 }
730
731 /* When receiving a packet on an streaming transport, it's possible to receive more than one SIP
732 * message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf
733 * will always point to the proper SIP message that is to be processed. When updating subscription
734 * persistence that is pulled from persistent storage, though, the rdata->pkt_info.packet will
735 * only ever have a single SIP message on it, and so we base persistence on that.
736 */
739 if (rdata->msg_info.msg_buf) {
740 ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf,
741 MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len + 1));
742 } else {
743 ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
744 sizeof(sub_tree->persistence->packet));
745 }
746 }
747 ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
748 sizeof(sub_tree->persistence->src_name));
749 sub_tree->persistence->src_port = rdata->pkt_info.src_port;
750 ast_copy_string(sub_tree->persistence->transport_type, rdata->tp_info.transport->type_name,
751 sizeof(sub_tree->persistence->transport_type));
752 ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host,
753 sizeof(sub_tree->persistence->local_name));
754 sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port;
755 }
756
758}
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:90
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 1436 of file res_pjsip_pubsub.c.

1437{
1438 sub_tree->dlg = dlg;
1440 ast_sip_dialog_set_endpoint(dlg, sub_tree->endpoint);
1441 pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
1442 pjsip_dlg_inc_session(dlg, &pubsub_module);
1443}

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 1407 of file res_pjsip_pubsub.c.

1408{
1409 struct sip_subscription_tree *sub_tree = obj;
1410
1411 ast_debug(3, "Destroying subscription tree %p '%s->%s'\n",
1412 sub_tree,
1413 sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
1414 sub_tree->root ? sub_tree->root->resource : "Unknown");
1415
1416 destroy_subscriptions(sub_tree->root);
1417
1418 if (sub_tree->dlg) {
1421 }
1422
1423 ao2_cleanup(sub_tree->endpoint);
1424
1427}
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 1388 of file res_pjsip_pubsub.c.

1389{
1390 struct sip_subscription_tree *sub_tree = obj;
1391
1392 /* This is why we keep the dialog on the subscription. When the subscription
1393 * is destroyed, there is no guarantee that the underlying dialog is ready
1394 * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1395 * either. The dialog could be destroyed before our subscription is. We fix
1396 * this problem by keeping a reference to the dialog until it is time to
1397 * destroy the subscription. We need to have the dialog available when the
1398 * subscription is destroyed so that we can guarantee that our attempt to
1399 * remove the serializer will be successful.
1400 */
1401 pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
1402 sub_tree->dlg = NULL;
1403
1404 return 0;
1405}

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 953 of file res_pjsip_pubsub.c.

954{
955 struct tree_node *node;
956
957 node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
958 if (!node) {
959 return NULL;
960 }
961
962 strcpy(node->resource, resource);
963 if (AST_VECTOR_INIT(&node->children, 4)) {
964 ast_free(node);
965 return NULL;
966 }
967 node->full_state = full_state;
968 node->display_name = ast_strdup(display_name);
969
970 if (visited) {
971 AST_VECTOR_APPEND(visited, resource);
972 }
973 return node;
974}
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 985 of file res_pjsip_pubsub.c.

986{
987 int i;
988 if (!node) {
989 return;
990 }
991
992 for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
993 tree_node_destroy(AST_VECTOR_GET(&node->children, i));
994 }
995 AST_VECTOR_FREE(&node->children);
996 ast_free(node->display_name);
997 ast_free(node);
998}

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 5928 of file res_pjsip_pubsub.c.

5929{
5931 AST_TEST_UNREGISTER(complex_resource_tree);
5932 AST_TEST_UNREGISTER(bad_resource);
5933 AST_TEST_UNREGISTER(bad_branch);
5934 AST_TEST_UNREGISTER(duplicate_resource);
5935 AST_TEST_UNREGISTER(loop);
5936 AST_TEST_UNREGISTER(bad_event);
5937
5939
5941
5944 ast_manager_unregister("PJSIPShowResourceLists");
5945
5947 if (sched) {
5949 }
5950
5951 return 0;
5952}
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:8041
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 5960 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 822 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 5960 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 4906 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 351 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 265 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 566 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 556 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 250 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 535 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} } , }