Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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 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 , 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)
 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)
 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 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 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)
 Callback sequence for subscription terminate: 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 4270 of file res_pjsip_pubsub.c.

◆ AMI_SHOW_SUBSCRIPTIONS_OUTBOUND

#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND   "PJSIPShowSubscriptionsOutbound"

Definition at line 4271 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 4657 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 4656 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 4514 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 4509 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 4273 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.

◆ 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 4889 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 1831 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.

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

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

2065 {
2066  static pj_str_t cid_name = { "cid", 3 };
2067  pj_xml_node *resource;
2068  pj_xml_node *name;
2069  pj_xml_node *instance;
2070  pj_xml_attr *cid_attr;
2071  char id[6];
2072  char uri[PJSIP_MAX_URL_SIZE];
2073 
2074  /* This creates a string representing the Content-ID without the enclosing < > */
2075  const pj_str_t cid_stripped = {
2076  .ptr = cid->hvalue.ptr + 1,
2077  .slen = cid->hvalue.slen - 2,
2078  };
2079 
2080  resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
2081  name = ast_sip_presence_xml_create_node(pool, resource, "name");
2082  instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
2083 
2084  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
2085  ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
2086 
2087  pj_strdup2(pool, &name->content, resource_name);
2088 
2089  ast_generate_random_string(id, sizeof(id));
2090 
2091  ast_sip_presence_xml_create_attr(pool, instance, "id", id);
2092  ast_sip_presence_xml_create_attr(pool, instance, "state",
2093  state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
2094 
2095  /* Use the PJLIB-util XML library directly here since we are using a
2096  * pj_str_t
2097  */
2098 
2099  cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2100  pj_xml_add_attr(instance, cid_attr);
2101 }
static char cid_name[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:168
static const char name[]
Definition: format_mp3.c:68
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:227

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

Referenced by build_rlmi_body().

◆ add_subscription()

static void add_subscription ( struct sip_subscription_tree obj)
static

Definition at line 1197 of file res_pjsip_pubsub.c.

1198 {
1202 }
#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 2269 of file res_pjsip_pubsub.c.

2270 {
2271  struct body_part *bp;
2272 
2273  bp = ast_calloc(1, sizeof(*bp));
2274  if (!bp) {
2275  return NULL;
2276  }
2277 
2278  bp->cid = generate_content_id_hdr(pool, sub);
2279  bp->resource = sub->resource;
2280  bp->state = sub->subscription_state;
2281  bp->uri = sub->uri;
2282  bp->display_name = sub->display_name;
2283 
2284  return bp;
2285 }
#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 1256 of file res_pjsip_pubsub.c.

1258 {
1259  struct ast_sip_subscription *sub;
1260  pjsip_msg *msg;
1261  pjsip_sip_uri *request_uri;
1262 
1263  msg = ast_sip_mod_data_get(tree->dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1264  if (!msg) {
1265  ast_log(LOG_ERROR, "No dialog message saved for SIP subscription. Cannot allocate subscription for resource %s\n", resource);
1266  return NULL;
1267  }
1268 
1269  sub = ast_calloc(1, sizeof(*sub) + strlen(resource) + 1);
1270  if (!sub) {
1271  return NULL;
1272  }
1273  strcpy(sub->resource, resource); /* Safe */
1274 
1275  sub->display_name = ast_strdup(display_name);
1276 
1277  sub->datastores = ast_datastores_alloc();
1278  if (!sub->datastores) {
1280  return NULL;
1281  }
1282 
1283  sub->body_text = ast_str_create(128);
1284  if (!sub->body_text) {
1286  return NULL;
1287  }
1288 
1289  sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
1290  request_uri = pjsip_uri_get_uri(msg->line.req.uri);
1291  pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, request_uri);
1292  pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
1293 
1294  /* If there is any persistence information available for this subscription that was persisted
1295  * then make it available so that the NOTIFY has the correct state.
1296  */
1297 
1300  }
1301 
1302  sub->handler = handler;
1303  sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1304  sub->tree = ao2_bump(tree);
1305 
1306  return sub;
1307 }
#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:95
#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:397
#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:2720
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:640
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 1437 of file res_pjsip_pubsub.c.

1438 {
1439  struct sip_subscription_tree *sub_tree;
1440 
1441  sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
1442  if (!sub_tree) {
1443  return NULL;
1444  }
1445 
1447 
1448  if (rdata) {
1449  /*
1450  * We must continue using the serializer that the original
1451  * SUBSCRIBE came in on for the dialog. There may be
1452  * retransmissions already enqueued in the original
1453  * serializer that can result in reentrancy and message
1454  * sequencing problems.
1455  */
1457  } else {
1458  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1459 
1460  /* Create name with seq number appended. */
1461  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s",
1463 
1464  sub_tree->serializer = ast_sip_create_serializer(tps_name);
1465  }
1466  if (!sub_tree->serializer) {
1467  ao2_ref(sub_tree, -1);
1468  return NULL;
1469  }
1470 
1471  sub_tree->endpoint = ao2_bump(endpoint);
1472  sub_tree->notify_sched_id = -1;
1473 
1474  return sub_tree;
1475 }
#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:1928
#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:2312
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 2000 of file res_pjsip_pubsub.c.

2001 {
2002  int buf_size;
2003  int size = -1;
2004  char *buf;
2005 
2006  for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
2007  buf = pj_pool_alloc(tdata->pool, buf_size);
2008  size = pjsip_msg_print(tdata->msg, buf, buf_size);
2009  }
2010 
2011  if (size == -1) {
2012  return -1;
2013  }
2014 
2015  tdata->buf.start = buf;
2016  tdata->buf.cur = tdata->buf.start;
2017  tdata->buf.end = tdata->buf.start + buf_size;
2018 
2019  return 0;
2020 }
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 4247 of file res_pjsip_pubsub.c.

4248 {
4249  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4250  struct ao2_container *lists;
4251 
4252  lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
4254 
4255  if (!lists || !ao2_container_count(lists)) {
4256  astman_send_error(s, m, "No resource lists found\n");
4257  return 0;
4258  }
4259 
4260  astman_send_listack(s, m, "A listing of resource lists follows, presented as ResourceListDetail events",
4261  "start");
4262 
4264 
4265  astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count);
4267  return 0;
4268 }
#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:3208
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3166
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:3244
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3252
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:2827
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:2819
struct mansession * s
Definition: res_pjsip.h:2821
const struct message * m
Definition: res_pjsip.h:2823

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

4198 {
4199  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4200 
4201  astman_send_listack(s, m, "Following are Events for each inbound Subscription",
4202  "start");
4203 
4205 
4206  astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count);
4208  return 0;
4209 }
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 4211 of file res_pjsip_pubsub.c.

4212 {
4213  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4214 
4215  astman_send_listack(s, m, "Following are Events for each outbound Subscription",
4216  "start");
4217 
4219 
4220  astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count);
4222  return 0;
4223 }
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 4166 of file res_pjsip_pubsub.c.

4169 {
4170  struct ast_str *buf;
4171 
4173  if (!buf) {
4174  return -1;
4175  }
4176 
4177  sip_subscription_to_ami(sub_tree, &buf);
4178  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4179  ast_free(buf);
4180 
4181  ++ami->count;
4182  return 0;
4183 }
#define ast_free(a)
Definition: astmm.h:180
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3087
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:739
Support for dynamic strings.
Definition: strings.h:604
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 4185 of file res_pjsip_pubsub.c.

4186 {
4187  return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
4188  sub_tree, arg, "InboundSubscriptionDetail") : 0;
4189 }
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 4191 of file res_pjsip_pubsub.c.

4192 {
4193  return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
4194  sub_tree, arg, "OutboundSubscriptionDetail") : 0;
4195 }
@ 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 4996 of file res_pjsip_pubsub.c.

4997 {
4998  ast_sorcery_apply_default(sorcery, "resource_list", "config",
4999  "pjsip.conf,criteria=type=resource_list");
5002  return -1;
5003  }
5004 
5005  ast_sorcery_object_field_register(sorcery, "resource_list", "type", "",
5006  OPT_NOOP_T, 0, 0);
5007  ast_sorcery_object_field_register(sorcery, "resource_list", "event", "",
5009  ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "no",
5010  OPT_BOOL_T, 1, FLDSET(struct resource_list, full_state));
5011  ast_sorcery_object_field_register(sorcery, "resource_list", "notification_batch_interval",
5012  "0", OPT_UINT_T, 0, FLDSET(struct resource_list, notification_batch_interval));
5013  ast_sorcery_object_field_register_custom(sorcery, "resource_list", "list_item",
5015  ast_sorcery_object_field_register(sorcery, "resource_list", "resource_display_name", "no",
5016  OPT_BOOL_T, 1, FLDSET(struct resource_list, resource_display_name));
5017 
5018  ast_sorcery_reload_object(sorcery, "resource_list");
5019 
5020  return 0;
5021 }
#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 5855 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 1901 of file res_pjsip_pubsub.c.

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

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, and subscription_setup_dialog().

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

2688 {
2689  return ast_datastores_add(publication->datastores, datastore);
2690 }
int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore)
Add a data store to a container.
Definition: datastore.c:101
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 2692 of file res_pjsip_pubsub.c.

2693 {
2694  return ast_datastores_find(publication->datastores, name);
2695 }
struct ast_datastore * ast_datastores_find(struct ao2_container *datastores, const char *name)
Find a data store in a container.
Definition: datastore.c:119

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

2703 {
2704  return publication->datastores;
2705 }

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

3459 {
3460  return pub->endpoint;
3461 }
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 3468 of file res_pjsip_pubsub.c.

3469 {
3470  return pub->event_configuration_name;
3471 }
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 3463 of file res_pjsip_pubsub.c.

3464 {
3465  return pub->resource;
3466 }
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 2697 of file res_pjsip_pubsub.c.

2698 {
2699  ast_datastores_remove(publication->datastores, name);
2700 }
void ast_datastores_remove(struct ao2_container *datastores, const char *name)
Remove a data store from a container.
Definition: datastore.c:114

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

3559 {
3560  struct ast_sip_pubsub_body_supplement *supplement;
3561  struct ast_sip_pubsub_body_generator *generator;
3562  int res = 0;
3563  void *body;
3564 
3566  if (!generator) {
3567  ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
3568  type, subtype);
3569  return -1;
3570  }
3571 
3572  if (strcmp(data->body_type, generator->body_type)) {
3573  ast_log(LOG_WARNING, "%s/%s body generator does not accept the type of data provided\n",
3574  type, subtype);
3575  return -1;
3576  }
3577 
3578  body = generator->allocate_body(data->body_data);
3579  if (!body) {
3580  ast_log(LOG_WARNING, "%s/%s body generator could not to allocate a body\n",
3581  type, subtype);
3582  return -1;
3583  }
3584 
3585  if (generator->generate_body_content(body, data->body_data)) {
3586  res = -1;
3587  goto end;
3588  }
3589 
3591  AST_RWLIST_TRAVERSE(&body_supplements, supplement, list) {
3592  if (!strcmp(generator->type, supplement->type) &&
3593  !strcmp(generator->subtype, supplement->subtype)) {
3594  res = supplement->supplement_body(body, data->body_data);
3595  if (res) {
3596  break;
3597  }
3598  }
3599  }
3601 
3602  if (!res) {
3603  generator->to_string(body, str);
3604  }
3605 
3606 end:
3607  if (generator->destroy_body) {
3608  generator->destroy_body(body);
3609  }
3610 
3611  return res;
3612 }
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 *(* allocate_body)(void *data)
allocate body structure.
void(* destroy_body)(void *body)
Deallocate resources created for the body.
struct ast_sip_pubsub_body_generator::@291 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.
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 881 of file res_pjsip_pubsub.c.

882 {
883  pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
884 
885  while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
886  int i;
887 
888  for (i = 0; i < supported_header->count; i++) {
889  if (!pj_stricmp2(&supported_header->values[i], "eventlist")) {
890  return 1;
891  }
892  }
893  }
894 
895  return 0;
896 }
while(1)
Definition: ast_expr2f.c:894

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

3474 {
3475  return !!find_body_generator_type_subtype(type, subtype);
3476 }

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

3479 {
3480  struct ast_sip_pubsub_body_generator *existing;
3481  pj_str_t accept;
3482  pj_size_t accept_len;
3483 
3485  existing = find_body_generator_type_subtype_nolock(generator->type, generator->subtype);
3486  if (existing) {
3488  ast_log(LOG_WARNING, "A body generator for %s/%s is already registered.\n",
3489  generator->type, generator->subtype);
3490  return -1;
3491  }
3494 
3495  /* Lengths of type and subtype plus a slash. */
3496  accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
3497 
3498  /* Add room for null terminator that sprintf() will set. */
3499  pj_strset(&accept, ast_alloca(accept_len + 1), accept_len);
3500  sprintf((char *) pj_strbuf(&accept), "%s/%s", generator->type, generator->subtype);/* Safe */
3501 
3502  pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
3503  PJSIP_H_ACCEPT, NULL, 1, &accept);
3504 
3505  return 0;
3506 }
#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:513
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 3523 of file res_pjsip_pubsub.c.

3524 {
3526  AST_RWLIST_INSERT_TAIL(&body_supplements, supplement, list);
3528 
3529  return 0;
3530 }

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

3509 {
3510  struct ast_sip_pubsub_body_generator *iter;
3511 
3514  if (iter == generator) {
3516  break;
3517  }
3518  }
3521 }
#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 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 3532 of file res_pjsip_pubsub.c.

3533 {
3534  struct ast_sip_pubsub_body_supplement *iter;
3535 
3538  if (iter == supplement) {
3540  break;
3541  }
3542  }
3545 }
struct ast_sip_pubsub_body_supplement::@292 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.

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

2757 {
2758  if (ast_strlen_zero(handler->event_name)) {
2759  ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
2760  return -1;
2761  }
2762 
2765  if (!handler->publications) {
2766  ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
2767  handler->event_name);
2768  return -1;
2769  }
2770 
2772 
2773  return 0;
2774 }
@ 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 2815 of file res_pjsip_pubsub.c.

2816 {
2817  pj_str_t event;
2818  pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
2819  struct ast_sip_subscription_handler *existing;
2820  int i = 0;
2821 
2822  if (ast_strlen_zero(handler->event_name)) {
2823  ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
2824  return -1;
2825  }
2826 
2827  existing = find_sub_handler_for_event_name(handler->event_name);
2828  if (existing) {
2830  "Unable to register subscription handler for event %s. A handler is already registered\n",
2831  handler->event_name);
2832  return -1;
2833  }
2834 
2835  for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
2836  pj_cstr(&accept[i], handler->accept[i]);
2837  }
2838 
2839  pj_cstr(&event, handler->event_name);
2840 
2841  pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
2842 
2844 
2845  return 0;
2846 }
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().

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

2668 {
2669  return ast_datastores_add(subscription->datastores, datastore);
2670 }
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 2662 of file res_pjsip_pubsub.c.

2663 {
2664  return ast_datastores_alloc_datastore(info, uid);
2665 }
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:138
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 1421 of file res_pjsip_pubsub.c.

1422 {
1423  ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1424  sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree);
1425  ao2_cleanup(sub->tree);
1426 }
#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 3552 of file res_pjsip_pubsub.c.

3553 {
3554  return sub->body_generator->subtype;
3555 }

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

3548 {
3549  return sub->body_generator->type;
3550 }

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

2673 {
2674  return ast_datastores_find(subscription->datastores, name);
2675 }

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

2683 {
2684  return subscription->datastores;
2685 }

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

1964 {
1965  ast_assert(sub->tree->dlg != NULL);
1966  return sub->tree->dlg;
1967 }
#define ast_assert(a)
Definition: utils.h:734

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

1970 {
1971  ast_assert(sub->tree->endpoint != NULL);
1972  return ao2_bump(sub->tree->endpoint);
1973 }

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

1888 {
1889  pjsip_dialog *dlg;
1890  pjsip_msg *msg;
1891  pj_str_t name;
1892 
1893  dlg = sub->tree->dlg;
1894  msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1895  pj_cstr(&name, header);
1896 
1897  return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
1898 }

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

2617 {
2618  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2619 }

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

2725 {
2726  return subscription->persistence_data;
2727 }
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 2621 of file res_pjsip_pubsub.c.

2622 {
2623  pjsip_dialog *dlg;
2624  pjsip_sip_uri *uri;
2625 
2626  dlg = sub->tree->dlg;
2627  uri = pjsip_uri_get_uri(dlg->remote.info->uri);
2628 
2629  if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
2630  *buf = '\0';
2631  }
2632 }

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

2635 {
2636  return sub->resource;
2637 }

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

1976 {
1977  ast_assert(sub->tree->serializer != NULL);
1978  return sub->tree->serializer;
1979 }

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

2612 {
2613  return sub->uri;
2614 }

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

2640 {
2641  return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2642 }

References sub.

Referenced by notify_task().

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

2569 {
2570  int res;
2571  pjsip_dialog *dlg = sub->tree->dlg;
2572 
2573  pjsip_dlg_inc_lock(dlg);
2574 
2575  if (sub->tree->state != SIP_SUB_TREE_NORMAL) {
2576  pjsip_dlg_dec_lock(dlg);
2577  return 0;
2578  }
2579 
2582  pjsip_dlg_dec_lock(dlg);
2583  return -1;
2584  }
2585 
2586  sub->body_changed = 1;
2587  if (terminate) {
2588  sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2589  sub->tree->state = SIP_SUB_TREE_TERMINATE_PENDING;
2590  }
2591 
2592  if (sub->tree->notification_batch_interval) {
2593  res = schedule_notification(sub->tree);
2594  } else {
2595  /* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */
2596  ao2_ref(sub->tree, +1);
2597  if (terminate) {
2598  sub->tree->state = SIP_SUB_TREE_TERMINATE_IN_PROGRESS;
2599  }
2600  res = send_notify(sub->tree, 0);
2601  ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2602  "Resource: %s",
2603  sub->tree->root->resource);
2604  ao2_ref(sub->tree, -1);
2605  }
2606 
2607  pjsip_dlg_dec_lock(dlg);
2608  return res;
2609 }
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 2677 of file res_pjsip_pubsub.c.

2678 {
2679  ast_datastores_remove(subscription->datastores, name);
2680 }

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

2708 {
2709  ast_json_unref(subscription->persistence_data);
2710  subscription->persistence_data = persistence_data;
2711 
2712  if (subscription->tree->persistence) {
2713  if (!subscription->tree->persistence->generator_data) {
2715  if (!subscription->tree->persistence->generator_data) {
2716  return;
2717  }
2718  }
2719  ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
2720  ast_json_ref(persistence_data));
2721  }
2722 }
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:389
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:404

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

2777 {
2778  struct ast_sip_publish_handler *iter;
2779 
2782  if (handler == iter) {
2784  ao2_cleanup(handler->publications);
2785  break;
2786  }
2787  }
2790 }
#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().

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

2297 {
2298  struct body_part *bp;
2299  pjsip_msg_body *body;
2300 
2301  bp = allocate_body_part(pool, sub);
2302  if (!bp) {
2303  return;
2304  }
2305 
2306  body = generate_notify_body(pool, sub, use_full_state);
2307  if (!body) {
2308  /* Partial state was requested and the resource has not changed state */
2309  ast_free(bp);
2310  return;
2311  }
2312 
2313  bp->part = pjsip_multipart_create_part(pool);
2314  bp->part->body = body;
2315  pj_list_insert_before(&bp->part->hdr, bp->cid);
2316 
2317  if (AST_VECTOR_APPEND(parts, bp)) {
2318  ast_free(bp);
2319  }
2320 }
static struct body_part * allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
Allocate and initialize a body part structure.
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.
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 
)
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 1039 of file res_pjsip_pubsub.c.

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

Referenced by 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 
)
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 1157 of file res_pjsip_pubsub.c.

1159 {
1160  RAII_VAR(struct resource_list *, list, NULL, ao2_cleanup);
1161  struct resources visited;
1162 
1163  if (!has_eventlist_support || !(list = retrieve_resource_list(resource, handler->event_name))) {
1164  ast_debug(2, "Subscription '%s->%s' is not to a list\n",
1165  ast_sorcery_object_get_id(endpoint), resource);
1166  tree->root = tree_node_alloc(resource, NULL, 0, NULL);
1167  if (!tree->root) {
1168  return 500;
1169  }
1170  return handler->notifier->new_subscribe(endpoint, resource);
1171  }
1172 
1173  ast_debug(2, "Subscription '%s->%s' is a list\n",
1174  ast_sorcery_object_get_id(endpoint), resource);
1175  if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
1176  return 500;
1177  }
1178 
1179  tree->root = tree_node_alloc(resource, &visited, list->full_state, NULL);
1180  if (!tree->root) {
1181  AST_VECTOR_FREE(&visited);
1182  return 500;
1183  }
1184 
1185  tree->notification_batch_interval = list->notification_batch_interval;
1186 
1187  build_node_children(endpoint, handler, list, tree->root, &visited);
1188  AST_VECTOR_FREE(&visited);
1189 
1190  if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
1191  return 200;
1192  } else {
1193  return 500;
1194  }
1195 }
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:936
#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_sorcery_object_get_id(), AST_VECTOR_FREE, AST_VECTOR_INIT, AST_VECTOR_SIZE, build_node_children(), tree_node::children, handler(), 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 2198 of file res_pjsip_pubsub.c.

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

◆ cli_complete_subscription_callid()

static char* cli_complete_subscription_callid ( struct ast_cli_args a)
static

Definition at line 4328 of file res_pjsip_pubsub.c.

4329 {
4330  struct cli_sub_complete_parms cli;
4331  on_subscription_t on_subscription;
4332 
4333  if (a->pos != 4) {
4334  return NULL;
4335  }
4336 
4337  if (!strcasecmp(a->argv[3], "inbound")) {
4338  on_subscription = cli_complete_subscription_inbound;
4339  } else if (!strcasecmp(a->argv[3], "outbound")) {
4340  on_subscription = cli_complete_subscription_outbound;
4341  } else {
4342  /* Should never get here */
4343  ast_assert(0);
4344  return NULL;
4345  }
4346 
4347  cli.a = a;
4348  cli.callid = NULL;
4349  cli.wordlen = strlen(a->word);
4350  cli.which = 0;
4351  for_each_subscription(on_subscription, &cli);
4352 
4353  return cli.callid;
4354 }
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 4295 of file res_pjsip_pubsub.c.

4296 {
4297  pj_str_t *callid;
4298 
4299  if (!sub_tree->dlg) {
4300  return 0;
4301  }
4302 
4303  callid = &sub_tree->dlg->call_id->id;
4304  if (cli->wordlen <= pj_strlen(callid)
4305  && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
4306  && (++cli->which > cli->a->n)) {
4307  cli->callid = ast_malloc(pj_strlen(callid) + 1);
4308  if (cli->callid) {
4309  ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
4310  }
4311  return -1;
4312  }
4313  return 0;
4314 }
#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:2035

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

4317 {
4318  return sub_tree->role == AST_SIP_NOTIFIER
4319  ? cli_complete_subscription_common(sub_tree, arg) : 0;
4320 }
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 4322 of file res_pjsip_pubsub.c.

4323 {
4324  return sub_tree->role == AST_SIP_SUBSCRIBER
4325  ? cli_complete_subscription_common(sub_tree, arg) : 0;
4326 }

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

4660 {
4661  char ep_cid_buf[50];
4662  char res_evt_buf[50];
4663  char callid[256];
4664 
4665  /* Endpoint/CID column */
4666  snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s",
4668  S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str,
4669  S_COR(sub_tree->endpoint->id.self.number.valid,
4670  sub_tree->endpoint->id.self.number.str, "<none>")));
4671 
4672  /* Resource/Event column */
4673  snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s",
4674  sub_tree->root->resource,
4675  sub_tree->root->handler->event_name);
4676 
4677  /* Call-id column */
4678  if (sub_tree->dlg) {
4679  ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4680  } else {
4681  ast_copy_string(callid, "<unknown>", sizeof(callid));
4682  }
4683 
4685  ep_cid_buf,
4686  res_evt_buf,
4687  cli_subscription_expiry(sub_tree),
4688  callid);
4689 
4690  if (cli->like) {
4691  if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4692  /* Output line did not match the regex */
4693  return 0;
4694  }
4695  }
4696 
4697  ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4698  ++cli->count;
4699 
4700  return 0;
4701 }
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:1091
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
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:663
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:893
const struct ast_sip_subscription_handler * handler
struct ast_sip_subscription * root

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

4704 {
4705  return sub_tree->role == AST_SIP_NOTIFIER
4706  ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4707 }
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.

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

4716 {
4717  on_subscription_t on_subscription;
4718  struct cli_sub_parms cli;
4719  regex_t like;
4720  const char *regex;
4721 
4722  switch (cmd) {
4723  case CLI_INIT:
4724  e->command = "pjsip list subscriptions {inbound|outbound} [like]";
4725  e->usage = "Usage:\n"
4726  " pjsip list subscriptions inbound [like <regex>]\n"
4727  " List active inbound subscriptions\n"
4728  " pjsip list subscriptions outbound [like <regex>]\n"
4729  " List active outbound subscriptions\n"
4730  "\n"
4731  " The regex selects output lines that match.\n";
4732  return NULL;
4733  case CLI_GENERATE:
4734  return NULL;
4735  }
4736 
4737  if (a->argc != 4 && a->argc != 6) {
4738  return CLI_SHOWUSAGE;
4739  }
4740  if (!strcasecmp(a->argv[3], "inbound")) {
4741  on_subscription = cli_list_subscriptions_inbound;
4742  } else if (!strcasecmp(a->argv[3], "outbound")) {
4743  on_subscription = cli_list_subscriptions_outbound;
4744  } else {
4745  /* Should never get here */
4746  ast_assert(0);
4747  return CLI_SHOWUSAGE;
4748  }
4749  if (a->argc == 6) {
4750  int rc;
4751 
4752  if (strcasecmp(a->argv[4], "like")) {
4753  return CLI_SHOWUSAGE;
4754  }
4755 
4756  /* Setup regular expression */
4757  memset(&like, 0, sizeof(like));
4758  cli.like = &like;
4759  regex = a->argv[5];
4760  rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4761  if (rc) {
4762  char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4763 
4764  regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4765  ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4766  regex, regerr);
4767  return CLI_FAILURE;
4768  }
4769  } else {
4770  cli.like = NULL;
4771  regex = NULL;
4772  }
4773 
4774  cli.a = a;
4775  cli.e = e;
4776  cli.count = 0;
4777  cli.buf = ast_str_create(256);
4778  if (!cli.buf) {
4779  if (cli.like) {
4780  regfree(cli.like);
4781  }
4782  return CLI_FAILURE;
4783  }
4784 
4786  "Endpoint/CLI", "Resource/Event", "Expiry", "Call-id");
4787  for_each_subscription(on_subscription, &cli);
4788  ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n",
4789  cli.count,
4790  regex ? " matched \"" : "",
4791  regex ?: "",
4792  regex ? "\"" : "");
4793 
4794  ast_free(cli.buf);
4795  if (cli.like) {
4796  regfree(cli.like);
4797  }
4798 
4799  return CLI_SUCCESS;
4800 }
#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

◆ cli_list_subscriptions_outbound()

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

Definition at line 4709 of file res_pjsip_pubsub.c.

4710 {
4711  return sub_tree->role == AST_SIP_SUBSCRIBER
4712  ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4713 }

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

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

4371 {
4372  const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
4373  pj_str_t *sub_callid;
4374  struct ast_str *buf;
4375  char *src;
4376  char *dest;
4377  char *key;
4378  char *value;
4379  char *value_end;
4380  int key_len;
4381  int key_filler_width;
4382  int value_len;
4383 
4384  if (!sub_tree->dlg) {
4385  return 0;
4386  }
4387  sub_callid = &sub_tree->dlg->call_id->id;
4388  if (pj_strcmp2(sub_callid, callid)) {
4389  return 0;
4390  }
4391 
4392  buf = ast_str_create(512);
4393  if (!buf) {
4394  return -1;
4395  }
4396 
4397  ast_cli(cli->a->fd,
4398  "%-20s: %s\n"
4399  "===========================================================================\n",
4400  "ParameterName", "ParameterValue");
4401 
4402  ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
4403  ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
4404  ast_str_append(&buf, 0, "Expiry: %u\n", cli_subscription_expiry(sub_tree));
4405 
4406  sip_subscription_to_ami(sub_tree, &buf);
4407 
4408  /* Convert AMI \r\n to \n line terminators. */
4409  src = strchr(ast_str_buffer(buf), '\r');
4410  if (src) {
4411  dest = src;
4412  ++src;
4413  while (*src) {
4414  if (*src == '\r') {
4415  ++src;
4416  continue;
4417  }
4418  *dest++ = *src++;
4419  }
4420  *dest = '\0';
4422  }
4423 
4424  /* Reformat AMI key value pairs to pretty columns */
4425  key = ast_str_buffer(buf);
4426  do {
4427  value = strchr(key, ':');
4428  if (!value) {
4429  break;
4430  }
4431  value_end = strchr(value, '\n');
4432  if (!value_end) {
4433  break;
4434  }
4435 
4436  /* Calculate field lengths */
4437  key_len = value - key;
4438  key_filler_width = 20 - key_len;
4439  if (key_filler_width < 0) {
4440  key_filler_width = 0;
4441  }
4442  value_len = value_end - value;
4443 
4444  ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
4445  key_len, key, key_filler_width, "",
4446  value_len, value);
4447 
4448  key = value_end + 1;
4449  } while (*key);
4450  ast_cli(cli->a->fd, "\n");
4451 
4452  ast_free(buf);
4453 
4454  return -1;
4455 }
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
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:1117
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:684
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 4457 of file res_pjsip_pubsub.c.

4458 {
4459  return sub_tree->role == AST_SIP_NOTIFIER
4460  ? cli_show_subscription_common(sub_tree, arg) : 0;
4461 }
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 4469 of file res_pjsip_pubsub.c.

4470 {
4471  on_subscription_t on_subscription;
4472  struct cli_sub_parms cli;
4473 
4474  switch (cmd) {
4475  case CLI_INIT:
4476  e->command = "pjsip show subscription {inbound|outbound}";
4477  e->usage = "Usage:\n"
4478  " pjsip show subscription inbound <call-id>\n"
4479  " pjsip show subscription outbound <call-id>\n"
4480  " Show active subscription with the dialog call-id\n";
4481  return NULL;
4482  case CLI_GENERATE:
4484  }
4485 
4486  if (a->argc != 5) {
4487  return CLI_SHOWUSAGE;
4488  }
4489 
4490  if (!strcasecmp(a->argv[3], "inbound")) {
4491  on_subscription = cli_show_subscription_inbound;
4492  } else if (!strcasecmp(a->argv[3], "outbound")) {
4493  on_subscription = cli_show_subscription_outbound;
4494  } else {
4495  /* Should never get here */
4496  ast_assert(0);
4497  return NULL;
4498  }
4499 
4500  /* Find the subscription with the specified call-id */
4501  cli.a = a;
4502  cli.e = e;
4503  cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */
4504  for_each_subscription(on_subscription, &cli);
4505 
4506  return CLI_SUCCESS;
4507 }
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 4463 of file res_pjsip_pubsub.c.

4464 {
4465  return sub_tree->role == AST_SIP_SUBSCRIBER
4466  ? cli_show_subscription_common(sub_tree, arg) : 0;
4467 }

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

4520 {
4521  char caller_id[256];
4522  char callid[256];
4523 
4524  ast_callerid_merge(caller_id, sizeof(caller_id),
4525  S_COR(sub_tree->endpoint->id.self.name.valid,
4526  sub_tree->endpoint->id.self.name.str, NULL),
4527  S_COR(sub_tree->endpoint->id.self.number.valid,
4528  sub_tree->endpoint->id.self.number.str, NULL),
4529  "<none>");
4530 
4531  /* Call-id */
4532  if (sub_tree->dlg) {
4533  ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4534  } else {
4535  ast_copy_string(callid, "<unknown>", sizeof(callid));
4536  }
4537 
4539  ast_sorcery_object_get_id(sub_tree->endpoint), caller_id,
4540  sub_tree->root->resource, sub_tree->root->handler->event_name,
4541  cli_subscription_expiry(sub_tree), callid);
4542 
4543  if (cli->like) {
4544  if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4545  /* Output line did not match the regex */
4546  return 0;
4547  }
4548  }
4549 
4550  ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4551  ++cli->count;
4552 
4553  return 0;
4554 }
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1073
#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 4556 of file res_pjsip_pubsub.c.

4557 {
4558  return sub_tree->role == AST_SIP_NOTIFIER
4559  ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4560 }
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 4568 of file res_pjsip_pubsub.c.

4569 {
4570  on_subscription_t on_subscription;
4571  struct cli_sub_parms cli;
4572  regex_t like;
4573  const char *regex;
4574 
4575  switch (cmd) {
4576  case CLI_INIT:
4577  e->command = "pjsip show subscriptions {inbound|outbound} [like]";
4578  e->usage = "Usage:\n"
4579  " pjsip show subscriptions inbound [like <regex>]\n"
4580  " Show active inbound subscriptions\n"
4581  " pjsip show subscriptions outbound [like <regex>]\n"
4582  " Show active outbound subscriptions\n"
4583  "\n"
4584  " The regex selects a subscriptions output that matches.\n"
4585  " i.e., All output lines for a subscription are checked\n"
4586  " as a block by the regex.\n";
4587  return NULL;
4588  case CLI_GENERATE:
4589  return NULL;
4590  }
4591 
4592  if (a->argc != 4 && a->argc != 6) {
4593  return CLI_SHOWUSAGE;
4594  }
4595  if (!strcasecmp(a->argv[3], "inbound")) {
4596  on_subscription = cli_show_subscriptions_inbound;
4597  } else if (!strcasecmp(a->argv[3], "outbound")) {
4598  on_subscription = cli_show_subscriptions_outbound;
4599  } else {
4600  /* Should never get here */
4601  ast_assert(0);
4602  return CLI_SHOWUSAGE;
4603  }
4604  if (a->argc == 6) {
4605  int rc;
4606 
4607  if (strcasecmp(a->argv[4], "like")) {
4608  return CLI_SHOWUSAGE;
4609  }
4610 
4611  /* Setup regular expression */
4612  memset(&like, 0, sizeof(like));
4613  cli.like = &like;
4614  regex = a->argv[5];
4615  rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4616  if (rc) {
4617  char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4618 
4619  regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4620  ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4621  regex, regerr);
4622  return CLI_FAILURE;
4623  }
4624  } else {
4625  cli.like = NULL;
4626  regex = NULL;
4627  }
4628 
4629  cli.a = a;
4630  cli.e = e;
4631  cli.count = 0;
4632  cli.buf = ast_str_create(256);
4633  if (!cli.buf) {
4634  if (cli.like) {
4635  regfree(cli.like);
4636  }
4637  return CLI_FAILURE;
4638  }
4639 
4641  for_each_subscription(on_subscription, &cli);
4642  ast_cli(a->fd, "%d active subscriptions%s%s%s\n",
4643  cli.count,
4644  regex ? " matched \"" : "",
4645  regex ?: "",
4646  regex ? "\"" : "");
4647 
4648  ast_free(cli.buf);
4649  if (cli.like) {
4650  regfree(cli.like);
4651  }
4652 
4653  return CLI_SUCCESS;
4654 }
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 4562 of file res_pjsip_pubsub.c.

4563 {
4564  return sub_tree->role == AST_SIP_SUBSCRIBER
4565  ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4566 }

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

4357 {
4358  int expiry;
4359 
4360  expiry = sub_tree->persistence
4361  ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
4362  : 0;
4363  if (expiry < 0) {
4364  /* Subscription expired */
4365  expiry = 0;
4366  }
4367  return expiry;
4368 }
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:105
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:157

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

3959 {
3960  if (!ast_strlen_zero(s1) && !ast_strlen_zero(s2)) {
3961  return strcmp(s1, s2);
3962  }
3963 
3964  return ast_strlen_zero(s1) == ast_strlen_zero(s2) ? 0 : 1;
3965 }

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

3974 {
3975  int i;
3976 
3977  if (AST_VECTOR_SIZE(&s1->children) != AST_VECTOR_SIZE(&s2->children)) {
3978  return 1;
3979  }
3980 
3981  for (i = 0; i < AST_VECTOR_SIZE(&s1->children); ++i) {
3982  struct ast_sip_subscription *c1 = AST_VECTOR_GET(&s1->children, i);
3983  struct ast_sip_subscription *c2 = AST_VECTOR_GET(&s2->children, i);
3984 
3985  if (cmp_strings(c1->resource, c2->resource)
3986  || cmp_strings(c1->display_name, c2->display_name)) {
3987 
3988  return 1;
3989  }
3990  }
3991 
3992  return 0;
3993 }
static int cmp_strings(char *s1, char *s2)
Compare strings for equality checking for NULL.
struct ast_sip_subscription::@491 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 2328 of file res_pjsip_pubsub.c.

2329 {
2330  pjsip_media_type media_type;
2331  pjsip_param *media_type_param;
2332  char boundary[6];
2333  pj_str_t pj_boundary;
2334 
2335  pjsip_media_type_init2(&media_type, "multipart", "related");
2336 
2337  media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
2338  pj_list_init(media_type_param);
2339 
2340  pj_strdup2(pool, &media_type_param->name, "type");
2341  pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
2342 
2343  pj_list_insert_before(&media_type.param, media_type_param);
2344 
2345  pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
2346  return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2347 }
media_type
Media types generate different "dummy answers" for not accepting the offer of a media stream....
Definition: sip.h:486

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

2442 {
2443  pjsip_require_hdr *require;
2444 
2445  require = pjsip_require_hdr_create(pool);
2446  pj_strdup2(pool, &require->values[0], "eventlist");
2447  require->count = 1;
2448 
2449  return require;
2450 }

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

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

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

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

Referenced by create_subscription_tree(), and pubsub_on_rx_refresh().

◆ destroy_subscription()

static void destroy_subscription ( struct ast_sip_subscription sub)
static

Definition at line 1223 of file res_pjsip_pubsub.c.

1224 {
1225  ast_debug(3, "Destroying SIP subscription from '%s->%s'\n",
1226  sub->tree && sub->tree->endpoint ? ast_sorcery_object_get_id(sub->tree->endpoint) : "Unknown",
1227  sub->resource);
1228 
1229  ast_free(sub->body_text);
1230 
1231  AST_VECTOR_FREE(&sub->children);
1232  ao2_cleanup(sub->datastores);
1233  ast_json_unref(sub->persistence_data);
1234  ast_free(sub->display_name);
1235  ast_free(sub);
1236 }

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

1239 {
1240  int i;
1241 
1242  if (!root) {
1243  return;
1244  }
1245 
1246  for (i = 0; i < AST_VECTOR_SIZE(&root->children); ++i) {
1247  struct ast_sip_subscription *child;
1248 
1249  child = AST_VECTOR_GET(&root->children, i);
1250  destroy_subscriptions(child);
1251  }
1252 
1253  destroy_subscription(root);
1254 }
static void destroy_subscriptions(struct ast_sip_subscription *root)

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

Referenced by pubsub_on_rx_refresh(), and subscription_tree_destructor().

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

3142 {
3143  pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3144 
3145  if (etag_hdr) {
3146  char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3147 
3148  ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
3149 
3150  if (sscanf(etag, "%30d", entity_id) != 1) {
3151  return SIP_PUBLISH_UNKNOWN;
3152  }
3153  }
3154 
3155  *expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3156 
3157  if (!(*expires)) {
3158  return SIP_PUBLISH_REMOVE;
3159  } else if (!etag_hdr && rdata->msg_info.msg->body) {
3160  return SIP_PUBLISH_INITIAL;
3161  } else if (etag_hdr && !rdata->msg_info.msg->body) {
3162  return SIP_PUBLISH_REFRESH;
3163  } else if (etag_hdr && rdata->msg_info.msg->body) {
3164  return SIP_PUBLISH_MODIFY;
3165  }
3166 
3167  return SIP_PUBLISH_UNKNOWN;
3168 }
#define DEFAULT_PUBLISH_EXPIRES
Default expiration time for PUBLISH if one is not specified.

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().

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

833 {
834  int i;
835 
836  for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
837  if (!pj_strcmp2(accept, accept_exceptions[i])) {
838  return 1;
839  }
840  }
841 
842  return 0;
843 }
const char * accept_exceptions[]
Accept headers that are exceptions to the rule.
#define ARRAY_LEN(a)
Definition: utils.h:661

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

2902 {
2903  int i;
2904  struct ast_sip_pubsub_body_generator *generator = NULL;
2905 
2906  for (i = 0; i < num_accept; ++i) {
2907  generator = find_body_generator_accept(accept[i]);
2908  if (generator) {
2909  ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
2910  if (strcmp(generator->body_type, body_type)) {
2911  ast_log(LOG_WARNING, "Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
2912  generator->type, generator->subtype, generator);
2913  generator = NULL;
2914  continue;
2915  }
2916  break;
2917  } else {
2918  ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
2919  }
2920  }
2921 
2922  return generator;
2923 }
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 2887 of file res_pjsip_pubsub.c.

2888 {
2889  char *accept_copy = ast_strdupa(accept);
2890  char *subtype = accept_copy;
2891  char *type = strsep(&subtype, "/");
2892 
2893  if (ast_strlen_zero(type) || ast_strlen_zero(subtype)) {
2894  return NULL;
2895  }
2896 
2897  return find_body_generator_type_subtype(type, subtype);
2898 }
#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 2863 of file res_pjsip_pubsub.c.

2864 {
2866 
2868  if (!strcmp(gen->type, type)
2869  && !strcmp(gen->subtype, subtype)) {
2870  break;
2871  }
2872  }
2873 
2874  return gen;
2875 }
#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 3122 of file res_pjsip_pubsub.c.

3123 {
3124  struct ast_sip_publish_handler *iter = NULL;
3125 
3128  if (strcmp(event, iter->event_name)) {
3129  ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
3130  continue;
3131  }
3132  ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
3133  break;
3134  }
3136 
3137  return iter;
3138 }
const char * event_name
The name of the event this handler deals with.

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

1834 {
1835  int num = 0;
1836  struct sip_subscription_tree *i;
1837 
1838  if (!on_subscription) {
1839  return num;
1840  }
1841 
1844  if (on_subscription(i, arg)) {
1845  break;
1846  }
1847  ++num;
1848  }
1850  return num;
1851 }
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_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 4225 of file res_pjsip_pubsub.c.

4226 {
4227  struct resource_list *list = obj;
4228  struct ast_sip_ami *ami = arg;
4229  struct ast_str *buf;
4230 
4231  buf = ast_sip_create_ami_event("ResourceListDetail", ami);
4232  if (!buf) {
4233  return CMP_STOP;
4234  }
4235 
4236  if (ast_sip_sorcery_object_to_ami(list, &buf)) {
4237  ast_free(buf);
4238  return CMP_STOP;
4239  }
4240  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4241  ast_free(buf);
4242 
4243  ++ami->count;
4244  return 0;
4245 }
@ 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:2827

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

2252 {
2253  int i;
2254 
2255  for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
2256  struct body_part *part = AST_VECTOR_GET(parts, i);
2257  ast_free(part);
2258  }
2259 
2260  AST_VECTOR_FREE(parts);
2261 }

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

2145 {
2146  static const pj_str_t cid_name = { "Content-ID", 10 };
2147  pjsip_generic_string_hdr *cid;
2148  char id[6];
2149  size_t alloc_size;
2150  pj_str_t cid_value;
2151 
2152  /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
2153  alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
2154  cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2155  cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
2156  ast_generate_random_string(id, sizeof(id)),
2157  (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
2158  cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2159 
2160  return cid;
2161 }
enum queue_result id
Definition: app_queue.c:1640

References ast_generate_random_string(), cid_name, 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 2925 of file res_pjsip_pubsub.c.

2926 {
2927  void *notify_data;
2928  int res;
2929  struct ast_sip_body_data data = {
2930  .body_type = sub->handler->body_type,
2931  };
2932 
2933  if (AST_VECTOR_SIZE(&sub->children) > 0) {
2934  int i;
2935 
2936  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2937  if (generate_initial_notify(AST_VECTOR_GET(&sub->children, i))) {
2938  return -1;
2939  }
2940  }
2941 
2942  return 0;
2943  }
2944 
2945  /* We notify subscription establishment only on the tree leaves. */
2946  if (sub->handler->notifier->subscription_established(sub)) {
2947  return -1;
2948  }
2949 
2950  notify_data = sub->handler->notifier->get_notify_data(sub);
2951  if (!notify_data) {
2952  return -1;
2953  }
2954 
2955  data.body_data = notify_data;
2956 
2958  ast_sip_subscription_get_body_subtype(sub), &data, &sub->body_text);
2959 
2961 
2962  return res;
2963 }
static int generate_initial_notify(struct ast_sip_subscription *sub)
Data used to create bodies for NOTIFY/PUBLISH requests.

References ao2_cleanup, 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, and sub.

Referenced by 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 2361 of file res_pjsip_pubsub.c.

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

2410 {
2411  pjsip_msg_body *body;
2412 
2413  if (AST_VECTOR_SIZE(&root->children) == 0) {
2414  if (force_full_state || root->body_changed) {
2415  /* Not a list. We've already generated the body and saved it on the subscription.
2416  * Use that directly.
2417  */
2418  pj_str_t type;
2419  pj_str_t subtype;
2420  pj_str_t text;
2421 
2422  pj_cstr(&type, ast_sip_subscription_get_body_type(root));
2423  pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
2424  pj_cstr(&text, ast_str_buffer(root->body_text));
2425 
2426  body = pjsip_msg_body_create(pool, &type, &subtype, &text);
2427  root->body_changed = 0;
2428  } else {
2429  body = NULL;
2430  }
2431  } else {
2432  body = generate_list_body(pool, root, force_full_state);
2433  }
2434 
2435  return body;
2436 }
char * text
Definition: app_queue.c:1641
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 1005 of file res_pjsip_pubsub.c.

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

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

2968 {
2969  struct initial_notify_data *ind = obj;
2970 
2971  if (generate_initial_notify(ind->sub_tree->root)) {
2972  pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE);
2973  } else {
2974  send_notify(ind->sub_tree, 1);
2975  ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
2976  "Resource: %s",
2977  ind->sub_tree->root->resource);
2978  }
2979 
2980  if (ind->expires != PJSIP_EXPIRES_NOT_SPECIFIED) {
2981  char *name = ast_alloca(strlen("->/ ") +
2982  strlen(ind->sub_tree->persistence->endpoint) +
2983  strlen(ind->sub_tree->root->resource) +
2984  strlen(ind->sub_tree->root->handler->event_name) +
2985  ind->sub_tree->dlg->call_id->id.slen + 1);
2986 
2987  sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint,
2989  (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr);
2990 
2991  ast_debug(3, "Scheduling timer: %s\n", name);
2993  ind->expires * 1000, pubsub_on_refresh_timeout, name,
2995  if (!ind->sub_tree->expiration_task) {
2996  ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n",
2997  ind->expires, name);
2998  }
2999  }
3000 
3001  ao2_ref(ind->sub_tree, -1);
3002  ast_free(ind);
3003 
3004  return 0;
3005 }
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:1858
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition: res_pjsip.h:1881
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: res_pjsip.h:63
static int pubsub_on_refresh_timeout(void *userdata)
struct sip_subscription_tree * sub_tree
struct ast_sip_sched_task * expiration_task

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

4921 {
4922  int i;
4923 
4924  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
4925  if (!strcmp(item, AST_VECTOR_GET(&list->items, i))) {
4926  return 1;
4927  }
4928  }
4929 
4930  return 0;
4931 }
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 4933 of file res_pjsip_pubsub.c.

4935 {
4936  struct resource_list *list = obj;
4937  char *items = ast_strdupa(var->value);
4938  char *item;
4939 
4940  while ((item = ast_strip(strsep(&items, ",")))) {
4941  if (ast_strlen_zero(item)) {
4942  continue;
4943  }
4944 
4945  if (item_in_vector(list, item)) {
4946  ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);
4947  continue;
4948  }
4949 
4950  item = ast_strdup(item);
4951  if (!item || AST_VECTOR_APPEND(&list->items, item)) {
4952  ast_free(item);
4953  return -1;
4954  }
4955  }
4956 
4957  return 0;
4958 }
#define var
Definition: ast_expr2f.c:614
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 4960 of file res_pjsip_pubsub.c.

4961 {
4962  const struct resource_list *list = obj;
4963  int i;
4964  struct ast_str *str = ast_str_create(32);
4965 
4966  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
4967  ast_str_append(&str, 0, "%s,", AST_VECTOR_GET(&list->items, i));
4968  }
4969 
4970  /* Chop off trailing comma */
4971  ast_str_truncate(str, -1);
4973  ast_free(str);
4974  return 0;
4975 }
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:764

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

5702 {
5703  static const pj_str_t str_PUBLISH = { "PUBLISH", 7 };
5704  struct ast_sorcery *sorcery;
5705 
5707 
5708  if (!(sched = ast_sched_context_create())) {
5709  ast_log(LOG_ERROR, "Could not create scheduler for publication expiration\n");
5710  return AST_MODULE_LOAD_DECLINE;
5711  }
5712 
5714  ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n");
5716  return AST_MODULE_LOAD_DECLINE;
5717  }
5718 
5719  ast_sorcery_apply_config(sorcery, "res_pjsip_pubsub");
5720  ast_sorcery_apply_default(sorcery, "subscription_persistence", "astdb", "subscription_persistence");
5721  if (ast_sorcery_object_register(sorcery, "subscription_persistence", subscription_persistence_alloc,
5722  NULL, NULL)) {
5723  ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
5725  return AST_MODULE_LOAD_DECLINE;
5726  }
5727  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "packet", "", OPT_CHAR_ARRAY_T, 0,
5728  CHARFLDSET(struct subscription_persistence, packet));
5729  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_name", "", OPT_CHAR_ARRAY_T, 0,
5730  CHARFLDSET(struct subscription_persistence, src_name));
5731  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_port", "0", OPT_UINT_T, 0,
5732  FLDSET(struct subscription_persistence, src_port));
5733  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "transport_key", "0", OPT_CHAR_ARRAY_T, 0,
5734  CHARFLDSET(struct subscription_persistence, transport_key));
5735  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_name", "", OPT_CHAR_ARRAY_T, 0,
5736  CHARFLDSET(struct subscription_persistence, local_name));
5737  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_port", "0", OPT_UINT_T, 0,
5738  FLDSET(struct subscription_persistence, local_port));
5739  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "cseq", "0", OPT_UINT_T, 0,
5740  FLDSET(struct subscription_persistence, cseq));
5741  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "endpoint", "",
5743  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "tag", "",
5745  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
5747  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "contact_uri", "", OPT_CHAR_ARRAY_T, 0,
5748  CHARFLDSET(struct subscription_persistence, contact_uri));
5749  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "no", OPT_YESNO_T, 1,
5750  FLDSET(struct subscription_persistence, prune_on_boot));
5751  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "generator_data", "",
5753 
5756  return AST_MODULE_LOAD_DECLINE;
5757  }
5758 
5759  ast_sorcery_apply_default(sorcery, "inbound-publication", "config", "pjsip.conf,criteria=type=inbound-publication");
5761  NULL, NULL)) {
5762  ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
5763