Asterisk - The Open Source Telephony Project  18.5.0
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_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  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, 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...
 
 AST_TEST_DEFINE (resource_tree)
 
 AST_TEST_DEFINE (complex_resource_tree)
 
 AST_TEST_DEFINE (bad_resource)
 
 AST_TEST_DEFINE (bad_branch)
 
 AST_TEST_DEFINE (duplicate_resource)
 
 AST_TEST_DEFINE (loop)
 
 AST_TEST_DEFINE (bad_event)
 
 AST_VECTOR (resources, const char *)
 A vector of strings commonly used throughout this module. More...
 
 AST_VECTOR (body_part_list, struct body_part *)
 Type declaration for container of body part structures. 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 int check_node (struct ast_test *test, struct tree_node *node, const char **resources, size_t num_resources)
 Check the integrity of a tree node against a set of resources. More...
 
static void cleanup_resource_list (struct resource_list *list)
 RAII callback to destroy a resource list. 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 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 resource_listcreate_resource_list (struct ast_test *test, const char *list_name, const char *event, const char **resources, size_t num_resources)
 allocate a resource list, store it in sorcery, and set its details 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 ineligible_configuration (void)
 
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 populate_list (struct resource_list *list, const char *event, const char **resources, size_t num_resources)
 Set properties on an allocated resource list. More...
 
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 int test_new_subscribe (struct ast_sip_endpoint *endpoint, const char *resource)
 new_subscribe callback for unit tests More...
 
static void test_resource_tree_destroy (struct resource_tree *tree)
 RAII_VAR callback to destroy an allocated resource tree. More...
 
static struct tree_nodetree_node_alloc (const char *resource, struct resources *visited, unsigned int full_state)
 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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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
 
const char * bad_resources []
 "bad" resources More...
 
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} } , }
 
struct ast_sip_subscription_handler test_handler
 Subscription handler for unit tests. More...
 
struct ast_sip_notifier test_notifier
 Subscription notifier for unit tests. More...
 

Macro Definition Documentation

◆ AMI_SHOW_SUBSCRIPTIONS_INBOUND

#define AMI_SHOW_SUBSCRIPTIONS_INBOUND   "PJSIPShowSubscriptionsInbound"

Definition at line 4135 of file res_pjsip_pubsub.c.

Referenced by load_module(), and unload_module().

◆ AMI_SHOW_SUBSCRIPTIONS_OUTBOUND

#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND   "PJSIPShowSubscriptionsOutbound"

Definition at line 4136 of file res_pjsip_pubsub.c.

Referenced by load_module(), and unload_module().

◆ CLI_LIST_SUB_FORMAT_ENTRY

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

Definition at line 4522 of file res_pjsip_pubsub.c.

Referenced by cli_list_subscriptions_detail().

◆ CLI_LIST_SUB_FORMAT_HEADER

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

Definition at line 4521 of file res_pjsip_pubsub.c.

Referenced by cli_list_subscriptions_inout().

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

Referenced by cli_show_subscriptions_detail().

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

Referenced by cli_show_subscriptions_inout().

◆ DATASTORE_BUCKETS

#define DATASTORE_BUCKETS   53

Number of buckets for subscription datastore.

Definition at line 250 of file res_pjsip_pubsub.c.

◆ DEFAULT_EXPIRES

#define DEFAULT_EXPIRES   3600

Default expiration for subscriptions.

Definition at line 253 of file res_pjsip_pubsub.c.

Referenced by ast_sip_register_subscription_handler().

◆ DEFAULT_PUBLISH_EXPIRES

#define DEFAULT_PUBLISH_EXPIRES   3600

Default expiration time for PUBLISH if one is not specified.

Definition at line 247 of file res_pjsip_pubsub.c.

Referenced by determine_sip_publish_type(), sip_create_publication(), and subscription_persistence_update().

◆ MAX_REGEX_ERROR_LEN

#define MAX_REGEX_ERROR_LEN   128

◆ MOD_DATA_MSG

#define MOD_DATA_MSG   "sub_msg"

◆ MOD_DATA_PERSISTENCE

#define MOD_DATA_PERSISTENCE   "sub_persistence"

◆ PUBLICATIONS_BUCKETS

#define PUBLICATIONS_BUCKETS   37

Number of buckets for publications (on a per handler)

Definition at line 244 of file res_pjsip_pubsub.c.

Referenced by ast_sip_register_publish_handler().

◆ RESOURCE_LIST_INIT_SIZE

#define RESOURCE_LIST_INIT_SIZE   4

Definition at line 4750 of file res_pjsip_pubsub.c.

Referenced by resource_list_alloc().

Typedef Documentation

◆ on_subscription_t

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

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

523  {
524  /*! Called from send request */
526  /*! Subscription created from initial client request */
528  /*! Subscription recreated by asterisk on startup */
530  /*! Subscription created from client refresh */
532 };

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

265  {
266  /*!
267  * \brief Unknown
268  *
269  * \details
270  * This actually is not defined in RFC 3903. We use this as a constant
271  * to indicate that an incoming PUBLISH does not fit into any of the
272  * other categories and is thus invalid.
273  */
275 
276  /*!
277  * \brief Initial
278  *
279  * \details
280  * The first PUBLISH sent. This will contain a non-zero Expires header
281  * as well as a body that indicates the current state of the endpoint
282  * that has sent the message. The initial PUBLISH is the only type
283  * of PUBLISH to not contain a Sip-If-Match header in it.
284  */
286 
287  /*!
288  * \brief Refresh
289  *
290  * \details
291  * Used to keep a published state from expiring. This will contain a
292  * non-zero Expires header but no body since its purpose is not to
293  * update state.
294  */
296 
297  /*!
298  * \brief Modify
299  *
300  * \details
301  * Used to change state from its previous value. This will contain
302  * a body updating the published state. May or may not contain an
303  * Expires header.
304  */
306 
307  /*!
308  * \brief Remove
309  *
310  * \details
311  * Used to remove published state from an ESC. This will contain
312  * an Expires header set to 0 and likely no body.
313  */
315 };

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

404  {
405  /*! Normal operation */
407  /*! A terminate has been requested by Asterisk, the client, or pjproject */
409  /*! The terminate is in progress */
411  /*! The terminate process has finished and the subscription tree is no longer valid */
413 };

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 5714 of file res_pjsip_pubsub.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 5714 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
cidContent-ID header of the resource
resource_nameName of the resource
resource_uriURI of the resource
stateState of the subscribed resource

Definition at line 2029 of file res_pjsip_pubsub.c.

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

2031 {
2032  static pj_str_t cid_name = { "cid", 3 };
2033  pj_xml_node *resource;
2034  pj_xml_node *name;
2035  pj_xml_node *instance;
2036  pj_xml_attr *cid_attr;
2037  char id[6];
2038  char uri[PJSIP_MAX_URL_SIZE];
2039 
2040  /* This creates a string representing the Content-ID without the enclosing < > */
2041  const pj_str_t cid_stripped = {
2042  .ptr = cid->hvalue.ptr + 1,
2043  .slen = cid->hvalue.slen - 2,
2044  };
2045 
2046  resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
2047  name = ast_sip_presence_xml_create_node(pool, resource, "name");
2048  instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
2049 
2050  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
2051  ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
2052 
2053  pj_strdup2(pool, &name->content, resource_name);
2054 
2055  ast_generate_random_string(id, sizeof(id));
2056 
2057  ast_sip_presence_xml_create_attr(pool, instance, "id", id);
2058  ast_sip_presence_xml_create_attr(pool, instance, "state",
2059  state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
2060 
2061  /* Use the PJLIB-util XML library directly here since we are using a
2062  * pj_str_t
2063  */
2064 
2065  cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
2066  pj_xml_add_attr(instance, cid_attr);
2067 }
static pj_pool_t * pool
Global memory pool for configuration and timers.
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
static const char name[]
Definition: cdr_mysql.c:74
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
static char cid_name[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:165

◆ add_subscription()

static void add_subscription ( struct sip_subscription_tree obj)
static

Definition at line 1175 of file res_pjsip_pubsub.c.

References AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by ast_sip_create_subscription(), and create_subscription_tree().

1176 {
1180 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:740

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

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

Referenced by build_body_part().

2234 {
2235  struct body_part *bp;
2236 
2237  bp = ast_calloc(1, sizeof(*bp));
2238  if (!bp) {
2239  return NULL;
2240  }
2241 
2242  bp->cid = generate_content_id_hdr(pool, sub);
2243  bp->resource = sub->resource;
2244  bp->state = sub->subscription_state;
2245  bp->uri = sub->uri;
2246 
2247  return bp;
2248 }
A multipart body part and meta-information.
static pj_pool_t * pool
Global memory pool for configuration and timers.
const char * resource
#define NULL
Definition: resample.c:96
pjsip_sip_uri * uri
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
pjsip_generic_string_hdr * cid
static pjsip_generic_string_hdr * generate_content_id_hdr(pj_pool_t *pool, const struct ast_sip_subscription *sub)
Create a Content-ID header.
pjsip_evsub_state state

◆ allocate_subscription()

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

Definition at line 1233 of file res_pjsip_pubsub.c.

References ao2_bump, ast_calloc, ast_datastores_alloc(), ast_json_object_get(), ast_json_ref(), ast_str_create, ast_sip_subscription::datastores, destroy_subscription(), sip_subscription_tree::dlg, subscription_persistence::generator_data, handler(), ast_sip_subscription::handler, NULL, sip_subscription_tree::persistence, sub, and ast_sip_subscription::tree.

Referenced by ast_sip_create_subscription(), and create_virtual_subscriptions().

1235 {
1236  struct ast_sip_subscription *sub;
1237  pjsip_sip_uri *contact_uri;
1238 
1239  sub = ast_calloc(1, sizeof(*sub) + strlen(resource) + 1);
1240  if (!sub) {
1241  return NULL;
1242  }
1243  strcpy(sub->resource, resource); /* Safe */
1244 
1246  if (!sub->datastores) {
1247  destroy_subscription(sub);
1248  return NULL;
1249  }
1250 
1251  sub->body_text = ast_str_create(128);
1252  if (!sub->body_text) {
1253  destroy_subscription(sub);
1254  return NULL;
1255  }
1256 
1257  sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
1258  contact_uri = pjsip_uri_get_uri(tree->dlg->local.contact->uri);
1259  pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, contact_uri);
1260  pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
1261 
1262  /* If there is any persistence information available for this subscription that was persisted
1263  * then make it available so that the NOTIFY has the correct state.
1264  */
1265 
1266  if (tree->persistence && tree->persistence->generator_data) {
1267  sub->persistence_data = ast_json_ref(ast_json_object_get(tree->persistence->generator_data, resource));
1268  }
1269 
1270  sub->handler = handler;
1271  sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
1272  sub->tree = ao2_bump(tree);
1273 
1274  return sub;
1275 }
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
struct sip_subscription_tree * tree
#define NULL
Definition: resample.c:96
struct subscription_persistence * persistence
struct ao2_container * ast_datastores_alloc(void)
Allocate a specialized data stores container.
Definition: datastore.c:95
#define ao2_bump(obj)
Definition: astobj2.h:491
struct ao2_container * datastores
const struct ast_sip_subscription_handler * handler
Structure representing a "virtual" SIP subscription.
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
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
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
struct stasis_forward * sub
Definition: res_corosync.c:240
static void destroy_subscription(struct ast_sip_subscription *sub)
struct ast_json * generator_data
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ allocate_subscription_tree()

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

Definition at line 1405 of file res_pjsip_pubsub.c.

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

1406 {
1407  struct sip_subscription_tree *sub_tree;
1408 
1409  sub_tree = ao2_alloc(sizeof *sub_tree, subscription_tree_destructor);
1410  if (!sub_tree) {
1411  return NULL;
1412  }
1413 
1415 
1416  if (rdata) {
1417  /*
1418  * We must continue using the serializer that the original
1419  * SUBSCRIBE came in on for the dialog. There may be
1420  * retransmissions already enqueued in the original
1421  * serializer that can result in reentrancy and message
1422  * sequencing problems.
1423  */
1425  } else {
1426  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1427 
1428  /* Create name with seq number appended. */
1429  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/pubsub/%s",
1430  ast_sorcery_object_get_id(endpoint));
1431 
1432  sub_tree->serializer = ast_sip_create_serializer(tps_name);
1433  }
1434  if (!sub_tree->serializer) {
1435  ao2_ref(sub_tree, -1);
1436  return NULL;
1437  }
1438 
1439  sub_tree->endpoint = ao2_bump(endpoint);
1440  sub_tree->notify_sched_id = -1;
1441 
1442  return sub_tree;
1443 }
static void subscription_tree_destructor(void *obj)
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
struct ast_sip_endpoint * endpoint
#define NULL
Definition: resample.c:96
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:60
#define ao2_bump(obj)
Definition: astobj2.h:491
struct ast_module * self
Definition: module.h:342
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:5133
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
struct ast_taskprocessor * serializer
A tree of SIP subscriptions.
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443

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

References buf.

Referenced by sip_subscription_send_request().

1968 {
1969  int buf_size;
1970  int size = -1;
1971  char *buf;
1972 
1973  for (buf_size = PJSIP_MAX_PKT_LEN; size == -1 && buf_size < (PJSIP_MAX_PKT_LEN * 2); buf_size *= 2) {
1974  buf = pj_pool_alloc(tdata->pool, buf_size);
1975  size = pjsip_msg_print(tdata->msg, buf, buf_size);
1976  }
1977 
1978  if (size == -1) {
1979  return -1;
1980  }
1981 
1982  tdata->buf.start = buf;
1983  tdata->buf.cur = tdata->buf.start;
1984  tdata->buf.end = tdata->buf.start + buf_size;
1985 
1986  return 0;
1987 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66

◆ ami_show_resource_lists()

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

Definition at line 4112 of file res_pjsip_pubsub.c.

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

4113 {
4114  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4115  struct ao2_container *lists;
4116 
4117  lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
4119 
4120  if (!lists || !ao2_container_count(lists)) {
4121  astman_send_error(s, m, "No resource lists found\n");
4122  return 0;
4123  }
4124 
4125  astman_send_listack(s, m, "A listing of resource lists follows, presented as ResourceListDetail events",
4126  "start");
4127 
4129 
4130  astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count);
4132  return 0;
4133 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
const struct message * m
Definition: res_pjsip.h:2741
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:3237
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
AMI variable container.
Definition: res_pjsip.h:2737
static int format_ami_resource_lists(void *obj, void *arg, int flags)
Perform no matching, return all objects.
Definition: sorcery.h:123
Return all matching objects.
Definition: sorcery.h:120
#define NULL
Definition: resample.c:96
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
struct mansession * s
Definition: res_pjsip.h:2739
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
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
Generic container type.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
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:3201

◆ ami_show_subscriptions_inbound()

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

Definition at line 4062 of file res_pjsip_pubsub.c.

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

4063 {
4064  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4065 
4066  astman_send_listack(s, m, "Following are Events for each inbound Subscription",
4067  "start");
4068 
4070 
4071  astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count);
4073  return 0;
4074 }
static int ami_subscription_detail_inbound(struct sip_subscription_tree *sub_tree, void *arg)
const struct message * m
Definition: res_pjsip.h:2741
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:3237
AMI variable container.
Definition: res_pjsip.h:2737
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
static int for_each_subscription(on_subscription_t on_subscription, void *arg)
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
struct mansession * s
Definition: res_pjsip.h:2739
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:3201

◆ ami_show_subscriptions_outbound()

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

Definition at line 4076 of file res_pjsip_pubsub.c.

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

4077 {
4078  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
4079 
4080  astman_send_listack(s, m, "Following are Events for each outbound Subscription",
4081  "start");
4082 
4084 
4085  astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count);
4087  return 0;
4088 }
const struct message * m
Definition: res_pjsip.h:2741
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:3237
AMI variable container.
Definition: res_pjsip.h:2737
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tree, void *arg)
static int for_each_subscription(on_subscription_t on_subscription, void *arg)
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
struct mansession * s
Definition: res_pjsip.h:2739
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:3201

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

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

4034 {
4035  struct ast_str *buf;
4036 
4037  buf = ast_sip_create_ami_event(event, ami);
4038  if (!buf) {
4039  return -1;
4040  }
4041 
4042  sip_subscription_to_ami(sub_tree, &buf);
4043  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4044  ast_free(buf);
4045 
4046  ++ami->count;
4047  return 0;
4048 }
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
Definition: astman.c:222
static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree, struct ast_str **buf)
struct mansession * s
Definition: res_pjsip.h:2739
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ast_free(a)
Definition: astmm.h:182
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.

◆ ami_subscription_detail_inbound()

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

Definition at line 4050 of file res_pjsip_pubsub.c.

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

Referenced by ami_show_subscriptions_inbound().

4051 {
4052  return sub_tree->role == AST_SIP_NOTIFIER ? ami_subscription_detail(
4053  sub_tree, arg, "InboundSubscriptionDetail") : 0;
4054 }
enum ast_sip_subscription_role role
static int ami_subscription_detail(struct sip_subscription_tree *sub_tree, struct ast_sip_ami *ami, const char *event)

◆ ami_subscription_detail_outbound()

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

Definition at line 4056 of file res_pjsip_pubsub.c.

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

Referenced by ami_show_subscriptions_outbound().

4057 {
4058  return sub_tree->role == AST_SIP_SUBSCRIBER ? ami_subscription_detail(
4059  sub_tree, arg, "OutboundSubscriptionDetail") : 0;
4060 }
enum ast_sip_subscription_role role
static int ami_subscription_detail(struct sip_subscription_tree *sub_tree, struct ast_sip_ami *ami, const char *event)

◆ apply_list_configuration()

static int apply_list_configuration ( struct ast_sorcery sorcery)
static

Definition at line 4857 of file res_pjsip_pubsub.c.

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

Referenced by load_module().

4858 {
4859  ast_sorcery_apply_default(sorcery, "resource_list", "config",
4860  "pjsip.conf,criteria=type=resource_list");
4861  if (ast_sorcery_object_register(sorcery, "resource_list", resource_list_alloc,
4863  return -1;
4864  }
4865 
4866  ast_sorcery_object_field_register(sorcery, "resource_list", "type", "",
4867  OPT_NOOP_T, 0, 0);
4868  ast_sorcery_object_field_register(sorcery, "resource_list", "event", "",
4870  ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "no",
4871  OPT_BOOL_T, 1, FLDSET(struct resource_list, full_state));
4872  ast_sorcery_object_field_register(sorcery, "resource_list", "notification_batch_interval",
4873  "0", OPT_UINT_T, 0, FLDSET(struct resource_list, notification_batch_interval));
4874  ast_sorcery_object_field_register_custom(sorcery, "resource_list", "list_item",
4876 
4877  ast_sorcery_reload_object(sorcery, "resource_list");
4878 
4879  return 0;
4880 }
#define CHARFLDSET(type, field)
A helper macro to pass the appropriate arguments to aco_option_register for OPT_CHAR_ARRAY_T.
Type for a default handler that should do nothing.
Definition: astman.c:222
#define NULL
Definition: resample.c:96
Resource list configuration item.
static void * resource_list_alloc(const char *name)
Type for default option handler for character array strings.
#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 FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
Type for default option handler for unsigned integers.
static int list_item_to_str(const void *obj, const intptr_t *args, char **buf)
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:838
Type for default option handler for bools (ast_true/ast_false)
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:477
static int list_item_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
static int resource_list_apply_handler(const struct ast_sorcery *sorcery, void *obj)
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

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 5714 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
subscriberThe 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 1868 of file res_pjsip_pubsub.c.

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, resource_list::event, ast_sip_subscription_handler::event_name, sip_subscription_tree::evsub, LOG_WARNING, NULL, pubsub_cb, sub, subscription_setup_dialog(), and ast_sip_contact::uri.

1870 {
1871  struct ast_sip_subscription *sub;
1872  pjsip_dialog *dlg;
1873  struct ast_sip_contact *contact;
1874  pj_str_t event;
1875  pjsip_tx_data *tdata;
1876  pjsip_evsub *evsub;
1877  struct sip_subscription_tree *sub_tree = NULL;
1878 
1879  sub_tree = allocate_subscription_tree(endpoint, NULL);
1880  if (!sub_tree) {
1881  return NULL;
1882  }
1883 
1884  sub = allocate_subscription(handler, resource, sub_tree);
1885  if (!sub) {
1886  ao2_cleanup(sub_tree);
1887  return NULL;
1888  }
1889 
1891  if (!contact || ast_strlen_zero(contact->uri)) {
1892  ast_log(LOG_WARNING, "No contacts configured for endpoint %s. Unable to create SIP subsription\n",
1893  ast_sorcery_object_get_id(endpoint));
1894  ao2_ref(sub_tree, -1);
1895  ao2_cleanup(contact);
1896  return NULL;
1897  }
1898 
1899  dlg = ast_sip_create_dialog_uac(endpoint, contact->uri, NULL);
1900  ao2_cleanup(contact);
1901  if (!dlg) {
1902  ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1903  ao2_ref(sub_tree, -1);
1904  return NULL;
1905  }
1906 
1907  pj_cstr(&event, handler->event_name);
1908  pjsip_evsub_create_uac(dlg, &pubsub_cb, &event, 0, &sub_tree->evsub);
1909  subscription_setup_dialog(sub_tree, dlg);
1910 
1911  evsub = sub_tree->evsub;
1912 
1913  if (pjsip_evsub_initiate(evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
1914  pjsip_evsub_send_request(sub_tree->evsub, tdata);
1915  } else {
1916  /* pjsip_evsub_terminate will result in pubsub_on_evsub_state,
1917  * being called and terminating the subscription. Therefore, we don't
1918  * need to decrease the reference count of sub here.
1919  */
1920  pjsip_evsub_terminate(evsub, PJ_TRUE);
1921  ao2_ref(sub_tree, -1);
1922  return NULL;
1923  }
1924 
1925  add_subscription(sub_tree);
1926 
1927  return sub;
1928 }
static void add_subscription(struct sip_subscription_tree *obj)
#define LOG_WARNING
Definition: logger.h:274
Definition: astman.c:222
static pjsip_evsub_user pubsub_cb
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
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
Structure representing a "virtual" SIP subscription.
static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
Contact associated with an address of record.
Definition: res_pjsip.h:281
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ast_sip_subscription * allocate_subscription(const struct ast_sip_subscription_handler *handler, const char *resource, struct sip_subscription_tree *tree)
struct stasis_forward * sub
Definition: res_corosync.c:240
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:4028
const ast_string_field aors
Definition: res_pjsip.h:821
const ast_string_field uri
Definition: res_pjsip.h:303
A tree of SIP subscriptions.
static struct sip_subscription_tree * allocate_subscription_tree(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)

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

References ast_datastores_add(), and ast_sip_publication::datastores.

2650 {
2651  return ast_datastores_add(publication->datastores, datastore);
2652 }
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

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

References ast_datastores_find(), and ast_sip_publication::datastores.

2655 {
2656  return ast_datastores_find(publication->datastores, name);
2657 }
struct ast_datastore * ast_datastores_find(struct ao2_container *datastores, const char *name)
Find a data store in a container.
Definition: datastore.c:119
struct ao2_container * datastores
static const char name[]
Definition: cdr_mysql.c:74

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

References ast_sip_publication::datastores.

2665 {
2666  return publication->datastores;
2667 }
struct ao2_container * 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 3420 of file res_pjsip_pubsub.c.

References ast_sip_publication::endpoint.

3421 {
3422  return pub->endpoint;
3423 }
struct ast_sip_endpoint * endpoint
The endpoint with which the subscription is communicating.

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

References ast_sip_publication::event_configuration_name.

Referenced by asterisk_publication_devicestate_state_change(), and asterisk_publication_mwi_state_change().

3431 {
3432  return pub->event_configuration_name;
3433 }
char * event_configuration_name
The name of the event type configuration.

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

References ast_sip_publication::resource.

3426 {
3427  return pub->resource;
3428 }
char * resource
The resource the publication is to.

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

References ast_datastores_remove(), and ast_sip_publication::datastores.

2660 {
2661  ast_datastores_remove(publication->datastores, name);
2662 }
struct ao2_container * datastores
static const char name[]
Definition: cdr_mysql.c:74
void ast_datastores_remove(struct ao2_container *datastores, const char *name)
Remove a data store from a container.
Definition: datastore.c:114

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

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, generator, ast_sip_pubsub_body_generator::list, LOG_WARNING, 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, 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().

3521 {
3522  struct ast_sip_pubsub_body_supplement *supplement;
3524  int res = 0;
3525  void *body;
3526 
3528  if (!generator) {
3529  ast_log(LOG_WARNING, "Unable to find a body generator for %s/%s\n",
3530  type, subtype);
3531  return -1;
3532  }
3533 
3534  if (strcmp(data->body_type, generator->body_type)) {
3535  ast_log(LOG_WARNING, "%s/%s body generator does not accept the type of data provided\n",
3536  type, subtype);
3537  return -1;
3538  }
3539 
3540  body = generator->allocate_body(data->body_data);
3541  if (!body) {
3542  ast_log(LOG_WARNING, "%s/%s body generator could not to allocate a body\n",
3543  type, subtype);
3544  return -1;
3545  }
3546 
3547  if (generator->generate_body_content(body, data->body_data)) {
3548  res = -1;
3549  goto end;
3550  }
3551 
3553  AST_RWLIST_TRAVERSE(&body_supplements, supplement, list) {
3554  if (!strcmp(generator->type, supplement->type) &&
3555  !strcmp(generator->subtype, supplement->subtype)) {
3556  res = supplement->supplement_body(body, data->body_data);
3557  if (res) {
3558  break;
3559  }
3560  }
3561  }
3563 
3564  if (!res) {
3565  generator->to_string(body, str);
3566  }
3567 
3568 end:
3569  if (generator->destroy_body) {
3570  generator->destroy_body(body);
3571  }
3572 
3573  return res;
3574 }
void(* to_string)(void *body, struct ast_str **str)
Convert the body to a string.
static const char type[]
Definition: chan_ooh323.c:109
Pubsub body generator.
const char * type
Content type In "plain/text", "plain" is the type.
const char * body_type
#define LOG_WARNING
Definition: logger.h:274
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
const char * type
Content type In "plain/text", "plain" is the type.
char * end
Definition: eagi_proxy.c:73
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
#define ast_log
Definition: astobj2.c:42
void *(* allocate_body)(void *data)
allocate body structure.
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype(const char *type, const char *subtype)
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
struct ast_sip_pubsub_body_generator::@306 list
static struct ast_generator generator
Definition: app_fax.c:359
void(* destroy_body)(void *body)
Deallocate resources created for the body.
int(* supplement_body)(void *body, void *data)
Add additional content to a SIP request body.
int(* generate_body_content)(void *body, void *data)
Add content to the body of a SIP request.

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

References while().

Referenced by pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

867 {
868  pjsip_supported_hdr *supported_header = (pjsip_supported_hdr *) &rdata->msg_info.msg->hdr;
869 
870  while ((supported_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, supported_header->next))) {
871  int i;
872 
873  for (i = 0; i < supported_header->count; i++) {
874  if (!pj_stricmp2(&supported_header->values[i], "eventlist")) {
875  return 1;
876  }
877  }
878  }
879 
880  return 0;
881 }
while(1)
Definition: ast_expr2f.c:894

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

References find_body_generator_type_subtype().

Referenced by publisher_start().

3436 {
3438 }
static const char type[]
Definition: chan_ooh323.c:109
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype(const char *type, const char *subtype)
const char * subtype
Content subtype In "plain/text", "text" is the subtype.

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

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

3441 {
3442  struct ast_sip_pubsub_body_generator *existing;
3443  pj_str_t accept;
3444  pj_size_t accept_len;
3445 
3447  existing = find_body_generator_type_subtype_nolock(generator->type, generator->subtype);
3448  if (existing) {
3450  ast_log(LOG_WARNING, "A body generator for %s/%s is already registered.\n",
3451  generator->type, generator->subtype);
3452  return -1;
3453  }
3456 
3457  /* Lengths of type and subtype plus a slash. */
3458  accept_len = strlen(generator->type) + strlen(generator->subtype) + 1;
3459 
3460  /* Add room for null terminator that sprintf() will set. */
3461  pj_strset(&accept, ast_alloca(accept_len + 1), accept_len);
3462  sprintf((char *) pj_strbuf(&accept), "%s/%s", generator->type, generator->subtype);/* Safe */
3463 
3464  pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), &pubsub_module,
3465  PJSIP_H_ACCEPT, NULL, 1, &accept);
3466 
3467  return 0;
3468 }
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype_nolock(const char *type, const char *subtype)
static struct pjsip_module pubsub_module
Pubsub body generator.
const char * type
Content type In "plain/text", "plain" is the type.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define LOG_WARNING
Definition: logger.h:274
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
struct ast_sip_pubsub_body_generator::@306 list
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718

◆ 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
generatorBody generator to register
Return values
0Success
-1Failure

Definition at line 3485 of file res_pjsip_pubsub.c.

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

Referenced by load_module().

3486 {
3490 
3491  return 0;
3492 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
struct ast_sip_pubsub_body_generator::@306 list
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:740

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

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

Referenced by unload_module(), and unregister_all().

3471 {
3472  struct ast_sip_pubsub_body_generator *iter;
3473 
3476  if (iter == generator) {
3478  break;
3479  }
3480  }
3483 }
Pubsub body generator.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
struct ast_sip_pubsub_body_generator::@306 list
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616

◆ 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
generatorBody generator to unregister

Definition at line 3494 of file res_pjsip_pubsub.c.

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

Referenced by unload_module().

3495 {
3496  struct ast_sip_pubsub_body_supplement *iter;
3497 
3500  if (iter == supplement) {
3502  break;
3503  }
3504  }
3507 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
struct ast_sip_pubsub_body_supplement::@307 list
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616

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

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ast_log, ast_strlen_zero, ast_sip_publish_handler::event_name, LOG_ERROR, NULL, publication_cmp_fn(), publication_hash_fn(), ast_sip_publish_handler::publications, PUBLICATIONS_BUCKETS, and publish_add_handler().

Referenced by load_module().

2719 {
2720  if (ast_strlen_zero(handler->event_name)) {
2721  ast_log(LOG_ERROR, "No event package specified for publish handler. Cannot register\n");
2722  return -1;
2723  }
2724 
2727  if (!handler->publications) {
2728  ast_log(LOG_ERROR, "Could not allocate publications container for event '%s'\n",
2729  handler->event_name);
2730  return -1;
2731  }
2732 
2733  publish_add_handler(handler);
2734 
2735  return 0;
2736 }
const char * event_name
The name of the event this handler deals with.
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define PUBLICATIONS_BUCKETS
Number of buckets for publications (on a per handler)
static void publish_add_handler(struct ast_sip_publish_handler *handler)
static int publication_hash_fn(const void *obj, const int flags)
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
static int publication_cmp_fn(void *obj, void *arg, int flags)
struct ao2_container * publications
Publications.

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

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

Referenced by load_module().

2778 {
2779  pj_str_t event;
2780  pj_str_t accept[AST_SIP_MAX_ACCEPT] = { {0, }, };
2781  struct ast_sip_subscription_handler *existing;
2782  int i = 0;
2783 
2784  if (ast_strlen_zero(handler->event_name)) {
2785  ast_log(LOG_ERROR, "No event package specified for subscription handler. Cannot register\n");
2786  return -1;
2787  }
2788 
2789  existing = find_sub_handler_for_event_name(handler->event_name);
2790  if (existing) {
2792  "Unable to register subscription handler for event %s. A handler is already registered\n",
2793  handler->event_name);
2794  return -1;
2795  }
2796 
2797  for (i = 0; i < AST_SIP_MAX_ACCEPT && !ast_strlen_zero(handler->accept[i]); ++i) {
2798  pj_cstr(&accept[i], handler->accept[i]);
2799  }
2800 
2801  pj_cstr(&event, handler->event_name);
2802 
2803  pjsip_evsub_register_pkg(&pubsub_module, &event, DEFAULT_EXPIRES, i, accept);
2804 
2805  sub_add_handler(handler);
2806 
2807  return 0;
2808 }
static struct pjsip_module pubsub_module
const char * accept[AST_SIP_MAX_ACCEPT]
#define DEFAULT_EXPIRES
Default expiration for subscriptions.
Definition: astman.c:222
static void sub_add_handler(struct ast_sip_subscription_handler *handler)
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define AST_SIP_MAX_ACCEPT
#define LOG_ERROR
Definition: logger.h:285
static struct ast_sip_subscription_handler * find_sub_handler_for_event_name(const char *event_name)

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

References ast_datastores_add(), and ast_sip_subscription::datastores.

Referenced by add_datastore(), and add_mwi_datastore().

2630 {
2631  return ast_datastores_add(subscription->datastores, datastore);
2632 }
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

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

References ast_datastores_alloc_datastore().

Referenced by add_datastore(), and add_mwi_datastore().

2625 {
2626  return ast_datastores_alloc_datastore(info, uid);
2627 }
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

◆ 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
Returns
Nothing

Definition at line 1389 of file res_pjsip_pubsub.c.

References ao2_cleanup, ast_debug, ast_sorcery_object_get_id(), sip_subscription_tree::endpoint, and ast_sip_subscription::tree.

Referenced by exten_state_subscription_destructor(), and mwi_subscription_destructor().

1390 {
1391  ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n",
1392  sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree);
1393  ao2_cleanup(sub->tree);
1394 }
struct sip_subscription_tree * tree
struct ast_sip_endpoint * endpoint
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

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

References ast_sip_subscription::body_generator, and ast_sip_pubsub_body_generator::subtype.

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

3515 {
3516  return sub->body_generator->subtype;
3517 }
struct ast_sip_pubsub_body_generator * body_generator
const char * subtype
Content subtype In "plain/text", "text" is the subtype.

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

References ast_sip_subscription::body_generator, and ast_sip_pubsub_body_generator::type.

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

3510 {
3511  return sub->body_generator->type;
3512 }
const char * type
Content type In "plain/text", "plain" is the type.
struct ast_sip_pubsub_body_generator * body_generator

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

References ast_datastores_find(), and ast_sip_subscription::datastores.

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

2635 {
2636  return ast_datastores_find(subscription->datastores, name);
2637 }
struct ast_datastore * ast_datastores_find(struct ao2_container *datastores, const char *name)
Find a data store in a container.
Definition: datastore.c:119
struct ao2_container * datastores
static const char name[]
Definition: cdr_mysql.c:74

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

References ast_sip_subscription::datastores.

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

2645 {
2646  return subscription->datastores;
2647 }
struct ao2_container * datastores

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

References ast_assert, sip_subscription_tree::dlg, NULL, and ast_sip_subscription::tree.

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

1931 {
1932  ast_assert(sub->tree->dlg != NULL);
1933  return sub->tree->dlg;
1934 }
struct sip_subscription_tree * tree
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96

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

References ao2_bump, ast_assert, sip_subscription_tree::endpoint, NULL, and ast_sip_subscription::tree.

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

1937 {
1938  ast_assert(sub->tree->endpoint != NULL);
1939  return ao2_bump(sub->tree->endpoint);
1940 }
struct sip_subscription_tree * tree
struct ast_sip_endpoint * endpoint
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491

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

References ast_sip_mod_data_get, sip_subscription_tree::dlg, MOD_DATA_MSG, name, NULL, pubsub_module, and ast_sip_subscription::tree.

Referenced by get_user_agent().

1855 {
1856  pjsip_dialog *dlg;
1857  pjsip_msg *msg;
1858  pj_str_t name;
1859 
1860  dlg = sub->tree->dlg;
1861  msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
1862  pj_cstr(&name, header);
1863 
1864  return pjsip_msg_find_hdr_by_name(msg, &name, NULL);
1865 }
struct sip_subscription_tree * tree
static struct pjsip_module pubsub_module
#define NULL
Definition: resample.c:96
#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:2638
static const char name[]
Definition: cdr_mysql.c:74
#define MOD_DATA_MSG

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

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

2579 {
2580  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
2581 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66

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

Referenced by dialog_info_generate_body_content().

2687 {
2688  return subscription->persistence_data;
2689 }

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

References sip_subscription_tree::dlg, and ast_sip_subscription::tree.

Referenced by exten_state_data_alloc(), and notify_task().

2584 {
2585  pjsip_dialog *dlg;
2586  pjsip_sip_uri *uri;
2587 
2588  dlg = sub->tree->dlg;
2589  uri = pjsip_uri_get_uri(dlg->remote.info->uri);
2590 
2591  if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
2592  *buf = '\0';
2593  }
2594 }
struct sip_subscription_tree * tree
char buf[BUFSIZE]
Definition: eagi_proxy.c:66

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

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

2597 {
2598  return sub->resource;
2599 }

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

References ast_assert, NULL, sip_subscription_tree::serializer, and ast_sip_subscription::tree.

Referenced by exten_state_subscription_alloc(), and send_notify().

1943 {
1944  ast_assert(sub->tree->serializer != NULL);
1945  return sub->tree->serializer;
1946 }
struct sip_subscription_tree * tree
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
struct ast_taskprocessor * serializer

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

Referenced by mwi_get_notify_data(), and send_mwi_notify().

2574 {
2575  return sub->uri;
2576 }

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

Referenced by notify_task().

2602 {
2603  return sub->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ? 1 : 0;
2604 }

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

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, sip_subscription_tree::notification_batch_interval, sip_subscription_tree::root, schedule_notification(), send_notify(), SIP_SUB_TREE_NORMAL, SIP_SUB_TREE_TERMINATE_IN_PROGRESS, SIP_SUB_TREE_TERMINATE_PENDING, sip_subscription_tree::state, and ast_sip_subscription::tree.

Referenced by notify_task(), and send_mwi_notify().

2531 {
2532  int res;
2533  pjsip_dialog *dlg = sub->tree->dlg;
2534 
2535  pjsip_dlg_inc_lock(dlg);
2536 
2537  if (sub->tree->state != SIP_SUB_TREE_NORMAL) {
2538  pjsip_dlg_dec_lock(dlg);
2539  return 0;
2540  }
2541 
2543  ast_sip_subscription_get_body_subtype(sub), notify_data, &sub->body_text)) {
2544  pjsip_dlg_dec_lock(dlg);
2545  return -1;
2546  }
2547 
2548  sub->body_changed = 1;
2549  if (terminate) {
2550  sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
2552  }
2553 
2554  if (sub->tree->notification_batch_interval) {
2555  res = schedule_notification(sub->tree);
2556  } else {
2557  /* See the note in pubsub_on_rx_refresh() for why sub->tree is refbumped here */
2558  ao2_ref(sub->tree, +1);
2559  if (terminate) {
2561  }
2562  res = send_notify(sub->tree, 0);
2563  ast_test_suite_event_notify(terminate ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2564  "Resource: %s",
2565  sub->tree->root->resource);
2566  ao2_ref(sub->tree, -1);
2567  }
2568 
2569  pjsip_dlg_dec_lock(dlg);
2570  return res;
2571 }
struct ast_sip_subscription * root
struct sip_subscription_tree * tree
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.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
enum sip_subscription_tree_state state
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
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.
const char * ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
Get the body type 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.
unsigned int notification_batch_interval

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

References ast_datastores_remove(), and ast_sip_subscription::datastores.

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

2640 {
2641  ast_datastores_remove(subscription->datastores, name);
2642 }
struct ao2_container * datastores
static const char name[]
Definition: cdr_mysql.c:74
void ast_datastores_remove(struct ao2_container *datastores, const char *name)
Remove a data store from a container.
Definition: datastore.c:114

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

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

Referenced by dialog_info_generate_body_content().

2670 {
2671  ast_json_unref(subscription->persistence_data);
2672  subscription->persistence_data = persistence_data;
2673 
2674  if (subscription->tree->persistence) {
2675  if (!subscription->tree->persistence->generator_data) {
2677  if (!subscription->tree->persistence->generator_data) {
2678  return;
2679  }
2680  }
2681  ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
2682  ast_json_ref(persistence_data));
2683  }
2684 }
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
struct sip_subscription_tree * tree
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct subscription_persistence * persistence
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
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:389
struct ast_json * generator_data

◆ ast_sip_unregister_publish_handler()

void ast_sip_unregister_publish_handler ( struct ast_sip_publish_handler handler)

Unregister a publish handler.

Definition at line 2738 of file res_pjsip_pubsub.c.

References ao2_cleanup, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sip_publish_handler::next, and ast_sip_publish_handler::publications.

Referenced by load_module(), and unload_module().

2739 {
2740  struct ast_sip_publish_handler *iter;
2741 
2744  if (handler == iter) {
2746  ao2_cleanup(handler->publications);
2747  break;
2748  }
2749  }
2752 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
struct ast_sip_publish_handler * next
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:569
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
Callbacks that publication handlers will define.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ao2_container * publications
Publications.
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616

◆ ast_sip_unregister_subscription_handler()

void ast_sip_unregister_subscription_handler ( struct ast_sip_subscription_handler handler)

Unregister a subscription handler.

Definition at line 2810 of file res_pjsip_pubsub.c.

References AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_sip_subscription_handler::next.

Referenced by unload_module().

2811 {
2812  struct ast_sip_subscription_handler *iter;
2813 
2816  if (handler == iter) {
2818  break;
2819  }
2820  }
2823 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:569
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
struct ast_sip_subscription_handler * next
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616

◆ AST_TEST_DEFINE() [1/7]

AST_TEST_DEFINE ( resource_tree  )

Definition at line 5078 of file res_pjsip_pubsub.c.

References ARRAY_LEN, ast_calloc, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, build_resource_tree(), check_node(), cleanup_resource_list(), create_resource_list(), ineligible_configuration(), sip_to_pjsip::info(), NULL, RAII_VAR, TEST_EXECUTE, TEST_INIT, and test_resource_tree_destroy().

5079 {
5082  const char *resources[] = {
5083  "huey",
5084  "dewey",
5085  "louie",
5086  };
5087  int resp;
5088 
5089  switch (cmd) {
5090  case TEST_INIT:
5091  info->name = "resource_tree";
5092  info->category = "/res/res_pjsip_pubsub/";
5093  info->summary = "Basic resource tree integrity check";
5094  info->description =
5095  "Create a resource list and ensure that our attempt to build a tree works as expected.";
5096  return AST_TEST_NOT_RUN;
5097  case TEST_EXECUTE:
5098  break;
5099  }
5100 
5101  if (ineligible_configuration()) {
5102  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5103  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5104  return AST_TEST_NOT_RUN;
5105  }
5106 
5107  list = create_resource_list(test, "foo", "test", resources, ARRAY_LEN(resources));
5108  if (!list) {
5109  return AST_TEST_FAIL;
5110  }
5111 
5112  tree = ast_calloc(1, sizeof(*tree));
5113  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
5114  if (resp != 200) {
5115  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5116  return AST_TEST_FAIL;
5117  }
5118 
5119  if (!tree->root) {
5120  ast_test_status_update(test, "Resource tree has no root\n");
5121  return AST_TEST_FAIL;
5122  }
5123 
5124  if (check_node(test, tree->root, resources, ARRAY_LEN(resources))) {
5125  return AST_TEST_FAIL;
5126  }
5127 
5128  return AST_TEST_PASS;
5129 }
static struct resource_list * create_resource_list(struct ast_test *test, const char *list_name, const char *event, const char **resources, size_t num_resources)
allocate a resource list, store it in sorcery, and set its details
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define NULL
Definition: resample.c:96
struct ast_sip_subscription_handler test_handler
Subscription handler for unit tests.
Resource list configuration item.
A resource tree.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void cleanup_resource_list(struct resource_list *list)
RAII callback to destroy a resource list.
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.
static int check_node(struct ast_test *test, struct tree_node *node, const char **resources, size_t num_resources)
Check the integrity of a tree node against a set of resources.
def info(msg)
static int ineligible_configuration(void)
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static void test_resource_tree_destroy(struct resource_tree *tree)
RAII_VAR callback to destroy an allocated resource tree.

◆ AST_TEST_DEFINE() [2/7]

AST_TEST_DEFINE ( complex_resource_tree  )

Definition at line 5131 of file res_pjsip_pubsub.c.

References ARRAY_LEN, ast_calloc, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, AST_VECTOR_GET, build_resource_tree(), check_node(), cleanup_resource_list(), create_resource_list(), ineligible_configuration(), sip_to_pjsip::info(), NULL, RAII_VAR, TEST_EXECUTE, TEST_INIT, and test_resource_tree_destroy().

5132 {
5133  RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
5134  RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
5136  const char *resources_1[] = {
5137  "huey",
5138  "dewey",
5139  "louie",
5140  "dwarves",
5141  };
5142  const char *resources_2[] = {
5143  "happy",
5144  "grumpy",
5145  "doc",
5146  "bashful",
5147  "dopey",
5148  "sneezy",
5149  "sleepy",
5150  };
5151  int resp;
5152  struct tree_node *node;
5153 
5154  switch (cmd) {
5155  case TEST_INIT:
5156  info->name = "complex_resource_tree";
5157  info->category = "/res/res_pjsip_pubsub/";
5158  info->summary = "Complex resource tree integrity check";
5159  info->description =
5160  "Create a complex resource list and ensure that our attempt to build a tree works as expected.";
5161  return AST_TEST_NOT_RUN;
5162  case TEST_EXECUTE:
5163  break;
5164  }
5165 
5166  if (ineligible_configuration()) {
5167  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5168  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5169  return AST_TEST_NOT_RUN;
5170  }
5171 
5172  list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
5173  if (!list_1) {
5174  return AST_TEST_FAIL;
5175  }
5176 
5177  list_2 = create_resource_list(test, "dwarves", "test", resources_2, ARRAY_LEN(resources_2));
5178  if (!list_2) {
5179  return AST_TEST_FAIL;
5180  }
5181 
5182  tree = ast_calloc(1, sizeof(*tree));
5183  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
5184  if (resp != 200) {
5185  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5186  return AST_TEST_FAIL;
5187  }
5188 
5189  if (!tree->root) {
5190  ast_test_status_update(test, "Resource tree has no root\n");
5191  return AST_TEST_FAIL;
5192  }
5193 
5194  node = tree->root;
5195  if (check_node(test, node, resources_1, ARRAY_LEN(resources_1))) {
5196  return AST_TEST_FAIL;
5197  }
5198 
5199  /* The embedded list is at index 3 in the root node's children */
5200  node = AST_VECTOR_GET(&node->children, 3);
5201  if (check_node(test, node, resources_2, ARRAY_LEN(resources_2))) {
5202  return AST_TEST_FAIL;
5203  }
5204 
5205  return AST_TEST_PASS;
5206 }
Definition: test_heap.c:38
static struct resource_list * create_resource_list(struct ast_test *test, const char *list_name, const char *event, const char **resources, size_t num_resources)
allocate a resource list, store it in sorcery, and set its details
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define NULL
Definition: resample.c:96
A node for a resource tree.
struct ast_sip_subscription_handler test_handler
Subscription handler for unit tests.
Resource list configuration item.
A resource tree.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void cleanup_resource_list(struct resource_list *list)
RAII callback to destroy a resource list.
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.
static int check_node(struct ast_test *test, struct tree_node *node, const char **resources, size_t num_resources)
Check the integrity of a tree node against a set of resources.
def info(msg)
static int ineligible_configuration(void)
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static void test_resource_tree_destroy(struct resource_tree *tree)
RAII_VAR callback to destroy an allocated resource tree.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682

◆ AST_TEST_DEFINE() [3/7]

AST_TEST_DEFINE ( bad_resource  )

Definition at line 5208 of file res_pjsip_pubsub.c.

References ARRAY_LEN, ast_calloc, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, build_resource_tree(), check_node(), cleanup_resource_list(), create_resource_list(), ineligible_configuration(), sip_to_pjsip::info(), NULL, RAII_VAR, TEST_EXECUTE, TEST_INIT, and test_resource_tree_destroy().

5209 {
5212  const char *resources[] = {
5213  "huey",
5214  "dewey",
5215  "louie",
5216  "coconut", /* A "bad" resource */
5217  };
5218  int resp;
5219 
5220  switch (cmd) {
5221  case TEST_INIT:
5222  info->name = "bad_resource";
5223  info->category = "/res/res_pjsip_pubsub/";
5224  info->summary = "Ensure bad resources do not end up in the tree";
5225  info->description =
5226  "Create a resource list with a single bad resource. Ensure the bad resource does not end up in the tree.";
5227  return AST_TEST_NOT_RUN;
5228  case TEST_EXECUTE:
5229  break;
5230  }
5231 
5232  if (ineligible_configuration()) {
5233  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5234  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5235  return AST_TEST_NOT_RUN;
5236  }
5237 
5238  list = create_resource_list(test, "foo", "test", resources, ARRAY_LEN(resources));
5239  if (!list) {
5240  return AST_TEST_FAIL;
5241  }
5242 
5243  tree = ast_calloc(1, sizeof(*tree));
5244  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
5245  if (resp != 200) {
5246  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5247  return AST_TEST_FAIL;
5248  }
5249 
5250  if (!tree->root) {
5251  ast_test_status_update(test, "Resource tree has no root\n");
5252  return AST_TEST_FAIL;
5253  }
5254 
5255  /* We check against all but the final resource since we expect it not to be in the tree */
5256  if (check_node(test, tree->root, resources, ARRAY_LEN(resources) - 1)) {
5257  return AST_TEST_FAIL;
5258  }
5259 
5260  return AST_TEST_PASS;
5261 
5262 }
static struct resource_list * create_resource_list(struct ast_test *test, const char *list_name, const char *event, const char **resources, size_t num_resources)
allocate a resource list, store it in sorcery, and set its details
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define NULL
Definition: resample.c:96
struct ast_sip_subscription_handler test_handler
Subscription handler for unit tests.
Resource list configuration item.
A resource tree.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void cleanup_resource_list(struct resource_list *list)
RAII callback to destroy a resource list.
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.
static int check_node(struct ast_test *test, struct tree_node *node, const char **resources, size_t num_resources)
Check the integrity of a tree node against a set of resources.
def info(msg)
static int ineligible_configuration(void)
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static void test_resource_tree_destroy(struct resource_tree *tree)
RAII_VAR callback to destroy an allocated resource tree.

◆ AST_TEST_DEFINE() [4/7]

AST_TEST_DEFINE ( bad_branch  )

Definition at line 5264 of file res_pjsip_pubsub.c.

References ARRAY_LEN, ast_calloc, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, build_resource_tree(), check_node(), cleanup_resource_list(), create_resource_list(), ineligible_configuration(), sip_to_pjsip::info(), NULL, RAII_VAR, TEST_EXECUTE, TEST_INIT, and test_resource_tree_destroy().

5265 {
5266  RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
5267  RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
5269  const char *resources_1[] = {
5270  "huey",
5271  "dewey",
5272  "louie",
5273  "gross",
5274  };
5275  /* This list has nothing but bad resources */
5276  const char *resources_2[] = {
5277  "coconut",
5278  "cilantro",
5279  "olive",
5280  "cheese",
5281  };
5282  int resp;
5283 
5284  switch (cmd) {
5285  case TEST_INIT:
5286  info->name = "bad_branch";
5287  info->category = "/res/res_pjsip_pubsub/";
5288  info->summary = "Ensure bad branches are pruned from the tree";
5289  info->description =
5290  "Create a resource list that makes a tree with an entire branch of bad resources.\n"
5291  "Ensure the bad branch is pruned from the tree.";
5292  return AST_TEST_NOT_RUN;
5293  case TEST_EXECUTE:
5294  break;
5295  }
5296 
5297  if (ineligible_configuration()) {
5298  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5299  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5300  return AST_TEST_NOT_RUN;
5301  }
5302 
5303  list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
5304  if (!list_1) {
5305  return AST_TEST_FAIL;
5306  }
5307  list_2 = create_resource_list(test, "gross", "test", resources_2, ARRAY_LEN(resources_2));
5308  if (!list_2) {
5309  return AST_TEST_FAIL;
5310  }
5311 
5312  tree = ast_calloc(1, sizeof(*tree));
5313  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
5314  if (resp != 200) {
5315  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5316  return AST_TEST_FAIL;
5317  }
5318 
5319  if (!tree->root) {
5320  ast_test_status_update(test, "Resource tree has no root\n");
5321  return AST_TEST_FAIL;
5322  }
5323 
5324  /* We check against all but the final resource of the list since the entire branch should
5325  * be pruned from the tree
5326  */
5327  if (check_node(test, tree->root, resources_1, ARRAY_LEN(resources_1) - 1)) {
5328  return AST_TEST_FAIL;
5329  }
5330 
5331  return AST_TEST_PASS;
5332 
5333 }
static struct resource_list * create_resource_list(struct ast_test *test, const char *list_name, const char *event, const char **resources, size_t num_resources)
allocate a resource list, store it in sorcery, and set its details
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define NULL
Definition: resample.c:96
struct ast_sip_subscription_handler test_handler
Subscription handler for unit tests.
Resource list configuration item.
A resource tree.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void cleanup_resource_list(struct resource_list *list)
RAII callback to destroy a resource list.
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.
static int check_node(struct ast_test *test, struct tree_node *node, const char **resources, size_t num_resources)
Check the integrity of a tree node against a set of resources.
def info(msg)
static int ineligible_configuration(void)
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static void test_resource_tree_destroy(struct resource_tree *tree)
RAII_VAR callback to destroy an allocated resource tree.

◆ AST_TEST_DEFINE() [5/7]

AST_TEST_DEFINE ( duplicate_resource  )

Definition at line 5335 of file res_pjsip_pubsub.c.

References ARRAY_LEN, ast_calloc, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, AST_VECTOR_GET, build_resource_tree(), check_node(), cleanup_resource_list(), create_resource_list(), ineligible_configuration(), sip_to_pjsip::info(), NULL, RAII_VAR, TEST_EXECUTE, TEST_INIT, and test_resource_tree_destroy().

5336 {
5337  RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
5338  RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
5340  const char *resources_1[] = {
5341  "huey",
5342  "ducks",
5343  "dewey",
5344  "louie",
5345  };
5346  const char *resources_2[] = {
5347  "donald",
5348  "daisy",
5349  "scrooge",
5350  "dewey",
5351  "louie",
5352  "huey",
5353  };
5354  int resp;
5355  struct tree_node *node;
5356 
5357  switch (cmd) {
5358  case TEST_INIT:
5359  info->name = "duplicate_resource";
5360  info->category = "/res/res_pjsip_pubsub/";
5361  info->summary = "Ensure duplicated resources do not end up in the tree";
5362  info->description =
5363  "Create a resource list with a single duplicated resource. Ensure the duplicated resource does not end up in the tree.";
5364  return AST_TEST_NOT_RUN;
5365  case TEST_EXECUTE:
5366  break;
5367  }
5368 
5369  if (ineligible_configuration()) {
5370  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5371  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5372  return AST_TEST_NOT_RUN;
5373  }
5374 
5375  list_1 = create_resource_list(test, "foo", "test", resources_1, ARRAY_LEN(resources_1));
5376  if (!list_1) {
5377  return AST_TEST_FAIL;
5378  }
5379 
5380  list_2 = create_resource_list(test, "ducks", "test", resources_2, ARRAY_LEN(resources_2));
5381  if (!list_2) {
5382  return AST_TEST_FAIL;
5383  }
5384 
5385  tree = ast_calloc(1, sizeof(*tree));
5386  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
5387  if (resp != 200) {
5388  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5389  return AST_TEST_FAIL;
5390  }
5391 
5392  if (!tree->root) {
5393  ast_test_status_update(test, "Resource tree has no root\n");
5394  return AST_TEST_FAIL;
5395  }
5396 
5397  node = tree->root;
5398  /* This node should have "huey" and "ducks". "dewey" and "louie" should not
5399  * be present since they were found in the "ducks" list.
5400  */
5401  if (check_node(test, node, resources_1, ARRAY_LEN(resources_1) - 2)) {
5402  return AST_TEST_FAIL;
5403  }
5404 
5405  /* This node should have "donald", "daisy", "scrooge", "dewey", and "louie".
5406  * "huey" is not here since that was already encountered in the parent list
5407  */
5408  node = AST_VECTOR_GET(&node->children, 1);
5409  if (check_node(test, node, resources_2, ARRAY_LEN(resources_2) - 1)) {
5410  return AST_TEST_FAIL;
5411  }
5412 
5413  return AST_TEST_PASS;
5414 }
Definition: test_heap.c:38
static struct resource_list * create_resource_list(struct ast_test *test, const char *list_name, const char *event, const char **resources, size_t num_resources)
allocate a resource list, store it in sorcery, and set its details
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define NULL
Definition: resample.c:96
A node for a resource tree.
struct ast_sip_subscription_handler test_handler
Subscription handler for unit tests.
Resource list configuration item.
A resource tree.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void cleanup_resource_list(struct resource_list *list)
RAII callback to destroy a resource list.
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.
static int check_node(struct ast_test *test, struct tree_node *node, const char **resources, size_t num_resources)
Check the integrity of a tree node against a set of resources.
def info(msg)
static int ineligible_configuration(void)
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static void test_resource_tree_destroy(struct resource_tree *tree)
RAII_VAR callback to destroy an allocated resource tree.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682

◆ AST_TEST_DEFINE() [6/7]

AST_TEST_DEFINE ( loop  )

Definition at line 5416 of file res_pjsip_pubsub.c.

References ARRAY_LEN, ast_calloc, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, build_resource_tree(), cleanup_resource_list(), create_resource_list(), ineligible_configuration(), sip_to_pjsip::info(), NULL, RAII_VAR, TEST_EXECUTE, TEST_INIT, and test_resource_tree_destroy().

5417 {
5418  RAII_VAR(struct resource_list *, list_1, NULL, cleanup_resource_list);
5419  RAII_VAR(struct resource_list *, list_2, NULL, cleanup_resource_list);
5421  const char *resources_1[] = {
5422  "derp",
5423  };
5424  const char *resources_2[] = {
5425  "herp",
5426  };
5427  int resp;
5428 
5429  switch (cmd) {
5430  case TEST_INIT:
5431  info->name = "loop";
5432  info->category = "/res/res_pjsip_pubsub/";
5433  info->summary = "Test that loops are properly detected.";
5434  info->description =
5435  "Create two resource lists that refer to each other. Ensure that attempting to build a tree\n"
5436  "results in an empty tree.";
5437  return AST_TEST_NOT_RUN;
5438  case TEST_EXECUTE:
5439  break;
5440  }
5441 
5442  if (ineligible_configuration()) {
5443  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5444  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5445  return AST_TEST_NOT_RUN;
5446  }
5447 
5448  list_1 = create_resource_list(test, "herp", "test", resources_1, ARRAY_LEN(resources_1));
5449  if (!list_1) {
5450  return AST_TEST_FAIL;
5451  }
5452  list_2 = create_resource_list(test, "derp", "test", resources_2, ARRAY_LEN(resources_2));
5453  if (!list_2) {
5454  return AST_TEST_FAIL;
5455  }
5456 
5457  tree = ast_calloc(1, sizeof(*tree));
5458  resp = build_resource_tree(NULL, &test_handler, "herp", tree, 1);
5459  if (resp == 200) {
5460  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5461  return AST_TEST_FAIL;
5462  }
5463 
5464  return AST_TEST_PASS;
5465 }
static struct resource_list * create_resource_list(struct ast_test *test, const char *list_name, const char *event, const char **resources, size_t num_resources)
allocate a resource list, store it in sorcery, and set its details
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define NULL
Definition: resample.c:96
struct ast_sip_subscription_handler test_handler
Subscription handler for unit tests.
Resource list configuration item.
A resource tree.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void cleanup_resource_list(struct resource_list *list)
RAII callback to destroy a resource list.
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.
def info(msg)
static int ineligible_configuration(void)
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static void test_resource_tree_destroy(struct resource_tree *tree)
RAII_VAR callback to destroy an allocated resource tree.

◆ AST_TEST_DEFINE() [7/7]

AST_TEST_DEFINE ( bad_event  )

Definition at line 5467 of file res_pjsip_pubsub.c.

References ARRAY_LEN, ast_calloc, AST_TEST_FAIL, AST_TEST_NOT_RUN, AST_TEST_PASS, ast_test_status_update, build_resource_tree(), cleanup_resource_list(), create_resource_list(), ineligible_configuration(), sip_to_pjsip::info(), NULL, RAII_VAR, TEST_EXECUTE, TEST_INIT, and test_resource_tree_destroy().

5468 {
5471  const char *resources[] = {
5472  "huey",
5473  "dewey",
5474  "louie",
5475  };
5476  int resp;
5477 
5478  switch (cmd) {
5479  case TEST_INIT:
5480  info->name = "bad_event";
5481  info->category = "/res/res_pjsip_pubsub/";
5482  info->summary = "Ensure that list with wrong event specified is not retrieved";
5483  info->description =
5484  "Create a simple resource list for event 'tsetse'. Ensure that trying to retrieve the list for event 'test' fails.";
5485  return AST_TEST_NOT_RUN;
5486  case TEST_EXECUTE:
5487  break;
5488  }
5489 
5490  if (ineligible_configuration()) {
5491  ast_test_status_update(test, "Ineligible configuration for this test. Please add a "
5492  "'res_pjsip_pubsub' section to sorcery.conf, and set 'resource_list=memory'\n");
5493  return AST_TEST_NOT_RUN;
5494  }
5495 
5496  list = create_resource_list(test, "foo", "tsetse", resources, ARRAY_LEN(resources));
5497  if (!list) {
5498  return AST_TEST_FAIL;
5499  }
5500 
5501  tree = ast_calloc(1, sizeof(*tree));
5502  /* Since the test_handler is for event "test", this should not build a list, but
5503  * instead result in a single resource being created, called "foo"
5504  */
5505  resp = build_resource_tree(NULL, &test_handler, "foo", tree, 1);
5506  if (resp != 200) {
5507  ast_test_status_update(test, "Unexpected response %d when building resource tree\n", resp);
5508  return AST_TEST_FAIL;
5509  }
5510 
5511  if (!tree->root) {
5512  ast_test_status_update(test, "Resource tree has no root\n");
5513  return AST_TEST_FAIL;
5514  }
5515 
5516  if (strcmp(tree->root->resource, "foo")) {
5517  ast_test_status_update(test, "Unexpected resource %s found in tree\n", tree->root->resource);
5518  return AST_TEST_FAIL;
5519  }
5520 
5521  return AST_TEST_PASS;
5522 }
static struct resource_list * create_resource_list(struct ast_test *test, const char *list_name, const char *event, const char **resources, size_t num_resources)
allocate a resource list, store it in sorcery, and set its details
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define NULL
Definition: resample.c:96
struct ast_sip_subscription_handler test_handler
Subscription handler for unit tests.
Resource list configuration item.
A resource tree.
#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:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void cleanup_resource_list(struct resource_list *list)
RAII callback to destroy a resource list.
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.
def info(msg)
static int ineligible_configuration(void)
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static void test_resource_tree_destroy(struct resource_tree *tree)
RAII_VAR callback to destroy an allocated resource tree.

◆ AST_VECTOR() [1/2]

AST_VECTOR ( resources  ,
const char *   
)

A vector of strings commonly used throughout this module.

◆ AST_VECTOR() [2/2]

AST_VECTOR ( body_part_list  ,
struct body_part  
)

Type declaration for container of body part structures.

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

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

Referenced by generate_list_body().

2260 {
2261  struct body_part *bp;
2262  pjsip_msg_body *body;
2263 
2264  bp = allocate_body_part(pool, sub);
2265  if (!bp) {
2266  return;
2267  }
2268 
2269  body = generate_notify_body(pool, sub, use_full_state);
2270  if (!body) {
2271  /* Partial state was requested and the resource has not changed state */
2272  ast_free(bp);
2273  return;
2274  }
2275 
2276  bp->part = pjsip_multipart_create_part(pool);
2277  bp->part->body = body;
2278  pj_list_insert_before(&bp->part->hdr, bp->cid);
2279 
2280  if (AST_VECTOR_APPEND(parts, bp)) {
2281  ast_free(bp);
2282  }
2283 }
A multipart body part and meta-information.
static pj_pool_t * pool
Global memory pool for configuration and timers.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
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.
#define ast_free(a)
Definition: astmm.h:182
pjsip_generic_string_hdr * cid
pjsip_multipart_part * part

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

References ao2_cleanup, ast_debug, AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_SIZE, resource_list::event, resource_list::full_state, have_visited(), resource_list::items, ast_sip_notifier::new_subscribe, ast_sip_subscription_handler::notifier, retrieve_resource_list(), tree_node_alloc(), and tree_node_destroy().

Referenced by build_resource_tree().

1023 {
1024  int i;
1025 
1026  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
1027  struct tree_node *current;
1028  struct resource_list *child_list;
1029  const char *resource = AST_VECTOR_GET(&list->items, i);
1030 
1031  if (have_visited(resource, visited)) {
1032  ast_debug(1, "Already visited resource %s. Avoiding duplicate resource or potential loop.\n", resource);
1033  continue;
1034  }
1035 
1036  child_list = retrieve_resource_list(resource, list->event);
1037  if (!child_list) {
1038  int resp = handler->notifier->new_subscribe(endpoint, resource);
1039  if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1040  current = tree_node_alloc(resource, visited, 0);
1041  if (!current) {
1042  ast_debug(1,
1043  "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
1044  resource);
1045  continue;
1046  }
1047  ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
1048  resource, parent->resource);
1049  if (AST_VECTOR_APPEND(&parent->children, current)) {
1050  tree_node_destroy(current);
1051  }
1052  } else {
1053  ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n",
1054  resource, resp);
1055  }
1056  } else {
1057  ast_debug(2, "Resource %s (child of %s) is a list\n", resource, parent->resource);
1058  current = tree_node_alloc(resource, visited, child_list->full_state);
1059  if (!current) {
1060  ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
1061  continue;
1062  }
1063  build_node_children(endpoint, handler, child_list, current, visited);
1064  if (AST_VECTOR_SIZE(&current->children) > 0) {
1065  ast_debug(1, "List %s had no successful children.\n", resource);
1066  if (AST_VECTOR_APPEND(&parent->children, current)) {
1067  tree_node_destroy(current);
1068  }
1069  } else {
1070  ast_debug(2, "List %s had successful children. Adding to parent %s\n",
1071  resource, parent->resource);
1072  tree_node_destroy(current);
1073  }
1074  ao2_cleanup(child_list);
1075  }
1076  }
1077 }
static struct tree_node * tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state)
Allocate a tree node.
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.
struct ast_sip_notifier * notifier
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
static struct resource_list * retrieve_resource_list(const char *resource, const char *event)
Helper function for retrieving a resource list for a given event.
A node for a resource tree.
Resource list configuration item.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int(* new_subscribe)(struct ast_sip_endpoint *endpoint, const char *resource)
Called when a SUBSCRIBE arrives attempting to establish a new subscription.
struct resources items
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static int have_visited(const char *resource, struct resources *visited)
Determine if this resource has been visited already.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
unsigned int full_state
static void tree_node_destroy(struct tree_node *node)
Destructor for a tree node.

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

References ao2_cleanup, ast_debug, ast_sorcery_object_get_id(), AST_VECTOR_FREE, AST_VECTOR_INIT, AST_VECTOR_SIZE, build_node_children(), ast_sip_subscription_handler::event_name, ast_sip_notifier::new_subscribe, resource_tree::notification_batch_interval, ast_sip_subscription_handler::notifier, NULL, RAII_VAR, retrieve_resource_list(), resource_tree::root, and tree_node_alloc().

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

1137 {
1138  RAII_VAR(struct resource_list *, list, NULL, ao2_cleanup);
1139  struct resources visited;
1140 
1141  if (!has_eventlist_support || !(list = retrieve_resource_list(resource, handler->event_name))) {
1142  ast_debug(2, "Subscription '%s->%s' is not to a list\n",
1143  ast_sorcery_object_get_id(endpoint), resource);
1144  tree->root = tree_node_alloc(resource, NULL, 0);
1145  if (!tree->root) {
1146  return 500;
1147  }
1148  return handler->notifier->new_subscribe(endpoint, resource);
1149  }
1150 
1151  ast_debug(2, "Subscription '%s->%s' is a list\n",
1152  ast_sorcery_object_get_id(endpoint), resource);
1153  if (AST_VECTOR_INIT(&visited, AST_VECTOR_SIZE(&list->items))) {
1154  return 500;
1155  }
1156 
1157  tree->root = tree_node_alloc(resource, &visited, list->full_state);
1158  if (!tree->root) {
1159  AST_VECTOR_FREE(&visited);
1160  return 500;
1161  }
1162 
1163  tree->notification_batch_interval = list->notification_batch_interval;
1164 
1165  build_node_children(endpoint, handler, list, tree->root, &visited);
1166  AST_VECTOR_FREE(&visited);
1167 
1168  if (AST_VECTOR_SIZE(&tree->root->children) > 0) {
1169  return 200;
1170  } else {
1171  return 500;
1172  }
1173 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
static struct tree_node * tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state)
Allocate a tree node.
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.
struct ast_sip_notifier * notifier
struct tree_node * root
static struct resource_list * retrieve_resource_list(const char *resource, const char *event)
Helper function for retrieving a resource list for a given event.
#define NULL
Definition: resample.c:96
Resource list configuration item.
unsigned int notification_batch_interval
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#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:911
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
int(* new_subscribe)(struct ast_sip_endpoint *endpoint, const char *resource)
Called when a SUBSCRIBE arrives attempting to establish a new subscription.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

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

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(), generate_notify_body(), name, NULL, body_part::part, pool, body_part::resource, rlmi_clone_data(), rlmi_media_type, rlmi_print_body(), body_part::state, and body_part::uri.

Referenced by generate_list_body().

2164 {
2165  pj_xml_node *rlmi;
2166  pj_xml_node *name;
2167  pjsip_multipart_part *rlmi_part;
2168  char version_str[32];
2169  char uri[PJSIP_MAX_URL_SIZE];
2170  pjsip_generic_string_hdr *cid;
2171  int i;
2172 
2173  rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
2174  ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
2175 
2176  ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
2177  ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
2178 
2179  snprintf(version_str, sizeof(version_str), "%u", sub->version++);
2180  ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
2181  ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
2182 
2183  name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
2184  pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
2185 
2186  for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
2187  const struct body_part *part = AST_VECTOR_GET(body_parts, i);
2188 
2189  add_rlmi_resource(pool, rlmi, part->cid, part->resource, part->uri, part->state);
2190  }
2191 
2192  rlmi_part = pjsip_multipart_create_part(pool);
2193 
2194  rlmi_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
2195  pjsip_media_type_cp(pool, &rlmi_part->body->content_type, &rlmi_media_type);
2196 
2197  rlmi_part->body->data = pj_xml_clone(pool, rlmi);
2198  rlmi_part->body->clone_data = rlmi_clone_data;
2199  rlmi_part->body->print_body = rlmi_print_body;
2200 
2201  cid = generate_content_id_hdr(pool, sub);
2202  pj_list_insert_before(&rlmi_part->hdr, cid);
2203 
2204  return rlmi_part;
2205 }
static pjsip_media_type rlmi_media_type
static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t size)
A multipart body part and meta-information.
static pj_pool_t * pool
Global memory pool for configuration and timers.
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
const char * resource
#define NULL
Definition: resample.c:96
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.
pjsip_sip_uri * 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.
const char * ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
Get the name of the subscribed resource.
static const char name[]
Definition: cdr_mysql.c:74
pjsip_generic_string_hdr * cid
static void * rlmi_clone_data(pj_pool_t *pool, const void *data, unsigned len)
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
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
pjsip_multipart_part * part
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 AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
pjsip_evsub_state state

◆ check_node()

static int check_node ( struct ast_test test,
struct tree_node node,
const char **  resources,
size_t  num_resources 
)
static

Check the integrity of a tree node against a set of resources.

The tree node's resources must be in the same order as the resources in the supplied resources array. Because of this constraint, tests can misrepresent the size of the resources array as being smaller than it really is if resources at the end of the array should not be present in the tree node.

Parameters
testThe unit test. Used for printing status messages.
nodeThe constructed tree node whose integrity is under question.
resourcesArray of expected resource values
num_resourcesThe number of resources to check in the array.

Definition at line 5022 of file res_pjsip_pubsub.c.

References ast_test_status_update, AST_VECTOR_GET, and AST_VECTOR_SIZE.

Referenced by AST_TEST_DEFINE().

5024 {
5025  int i;
5026 
5027  if (AST_VECTOR_SIZE(&node->children) != num_resources) {
5028  ast_test_status_update(test, "Unexpected number of resources in tree. Expected %zu, got %zu\n",
5029  num_resources, AST_VECTOR_SIZE(&node->children));
5030  return -1;
5031  }
5032 
5033  for (i = 0; i < num_resources; ++i) {
5034  if (strcmp(resources[i], AST_VECTOR_GET(&node->children, i)->resource)) {
5035  ast_test_status_update(test, "Mismatched resources. Expected '%s' but got '%s'\n",
5036  resources[i], AST_VECTOR_GET(&node->children, i)->resource);
5037  return -1;
5038  }
5039  }
5040 
5041  return 0;
5042 }
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ cleanup_resource_list()

static void cleanup_resource_list ( struct resource_list list)
static

RAII callback to destroy a resource list.

Definition at line 4962 of file res_pjsip_pubsub.c.

References ao2_cleanup, ast_sip_get_sorcery(), and ast_sorcery_delete().

Referenced by AST_TEST_DEFINE(), and create_resource_list().

4963 {
4964  if (!list) {
4965  return;
4966  }
4967 
4969  ao2_cleanup(list);
4970 }
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2233
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ cli_complete_subscription_callid()

static char* cli_complete_subscription_callid ( struct ast_cli_args a)
static

Definition at line 4193 of file res_pjsip_pubsub.c.

References a, cli_sub_complete_parms::a, ast_cli_args::argv, ast_assert, cli_sub_complete_parms::callid, cli_complete_subscription_inbound(), cli_complete_subscription_outbound(), for_each_subscription(), NULL, ast_cli_args::pos, cli_sub_complete_parms::which, ast_cli_args::word, and cli_sub_complete_parms::wordlen.

Referenced by cli_show_subscription_inout().

4194 {
4195  struct cli_sub_complete_parms cli;
4196  on_subscription_t on_subscription;
4197 
4198  if (a->pos != 4) {
4199  return NULL;
4200  }
4201 
4202  if (!strcasecmp(a->argv[3], "inbound")) {
4203  on_subscription = cli_complete_subscription_inbound;
4204  } else if (!strcasecmp(a->argv[3], "outbound")) {
4205  on_subscription = cli_complete_subscription_outbound;
4206  } else {
4207  /* Should never get here */
4208  ast_assert(0);
4209  return NULL;
4210  }
4211 
4212  cli.a = a;
4213  cli.callid = NULL;
4214  cli.wordlen = strlen(a->word);
4215  cli.which = 0;
4216  for_each_subscription(on_subscription, &cli);
4217 
4218  return cli.callid;
4219 }
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
static int for_each_subscription(on_subscription_t on_subscription, void *arg)
int(* on_subscription_t)(struct sip_subscription_tree *sub, void *arg)
const char *const * argv
Definition: cli.h:161
static struct ast_cli_entry cli[]
Definition: codec_dahdi.c:265
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)
const char * word
Definition: cli.h:163
const int pos
Definition: cli.h:164
static struct test_val a

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

References cli_sub_complete_parms::a, ast_copy_pj_str(), ast_malloc, cli_sub_complete_parms::callid, sip_subscription_tree::dlg, ast_cli_args::n, cli_sub_complete_parms::which, ast_cli_args::word, and cli_sub_complete_parms::wordlen.

Referenced by cli_complete_subscription_inbound(), and cli_complete_subscription_outbound().

4161 {
4162  pj_str_t *callid;
4163 
4164  if (!sub_tree->dlg) {
4165  return 0;
4166  }
4167 
4168  callid = &sub_tree->dlg->call_id->id;
4169  if (cli->wordlen <= pj_strlen(callid)
4170  && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
4171  && (++cli->which > cli->a->n)) {
4172  cli->callid = ast_malloc(pj_strlen(callid) + 1);
4173  if (cli->callid) {
4174  ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
4175  }
4176  return -1;
4177  }
4178  return 0;
4179 }
struct ast_cli_args * a
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:5240
const int n
Definition: cli.h:165
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
const char * word
Definition: cli.h:163

◆ cli_complete_subscription_inbound()

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

Definition at line 4181 of file res_pjsip_pubsub.c.

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

Referenced by cli_complete_subscription_callid().

4182 {
4183  return sub_tree->role == AST_SIP_NOTIFIER
4184  ? cli_complete_subscription_common(sub_tree, arg) : 0;
4185 }
enum ast_sip_subscription_role role
static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)

◆ cli_complete_subscription_outbound()

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

Definition at line 4187 of file res_pjsip_pubsub.c.

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

Referenced by cli_complete_subscription_callid().

4188 {
4189  return sub_tree->role == AST_SIP_SUBSCRIBER
4190  ? cli_complete_subscription_common(sub_tree, arg) : 0;
4191 }
enum ast_sip_subscription_role role
static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)

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

References cli_sub_parms::a, ast_cli(), ast_copy_pj_str(), ast_copy_string(), ast_sorcery_object_get_id(), ast_str_buffer(), ast_str_set(), cli_sub_parms::buf, CLI_LIST_SUB_FORMAT_ENTRY, cli_subscription_expiry(), cli_sub_parms::count, sip_subscription_tree::dlg, sip_subscription_tree::endpoint, ast_sip_subscription_handler::event_name, ast_cli_args::fd, ast_sip_subscription::handler, ast_sip_endpoint::id, cli_sub_parms::like, ast_party_id::name, NULL, ast_party_id::number, 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().

4525 {
4526  char ep_cid_buf[50];
4527  char res_evt_buf[50];
4528  char callid[256];
4529 
4530  /* Endpoint/CID column */
4531  snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s",
4533  S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str,
4534  S_COR(sub_tree->endpoint->id.self.number.valid,
4535  sub_tree->endpoint->id.self.number.str, "<none>")));
4536 
4537  /* Resource/Event column */
4538  snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s",
4539  sub_tree->root->resource,
4540  sub_tree->root->handler->event_name);
4541 
4542  /* Call-id column */
4543  if (sub_tree->dlg) {
4544  ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4545  } else {
4546  ast_copy_string(callid, "<unknown>", sizeof(callid));
4547  }
4548 
4550  ep_cid_buf,
4551  res_evt_buf,
4552  cli_subscription_expiry(sub_tree),
4553  callid);
4554 
4555  if (cli->like) {
4556  if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4557  /* Output line did not match the regex */
4558  return 0;
4559  }
4560  }
4561 
4562  ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4563  ++cli->count;
4564 
4565  return 0;
4566 }
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
struct ast_sip_subscription * root
struct ast_sip_endpoint * endpoint
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define CLI_LIST_SUB_FORMAT_ENTRY
char * str
Subscriber name (Malloced)
Definition: channel.h:265
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:5240
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
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:1065
const int fd
Definition: cli.h:159
const struct ast_sip_subscription_handler * handler
struct ast_cli_args * a
#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:85
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:847
struct ast_party_id self
Definition: res_pjsip.h:629
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
struct ast_str * buf
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343

◆ cli_list_subscriptions_inbound()

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

Definition at line 4568 of file res_pjsip_pubsub.c.

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

Referenced by cli_list_subscriptions_inout().

4569 {
4570  return sub_tree->role == AST_SIP_NOTIFIER
4571  ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4572 }
enum ast_sip_subscription_role role
static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

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

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

4581 {
4582  on_subscription_t on_subscription;
4583  struct cli_sub_parms cli;
4584  regex_t like;
4585  const char *regex;
4586 
4587  switch (cmd) {
4588  case CLI_INIT:
4589  e->command = "pjsip list subscriptions {inbound|outbound} [like]";
4590  e->usage = "Usage:\n"
4591  " pjsip list subscriptions inbound [like <regex>]\n"
4592  " List active inbound subscriptions\n"
4593  " pjsip list subscriptions outbound [like <regex>]\n"
4594  " List active outbound subscriptions\n"
4595  "\n"
4596  " The regex selects output lines that match.\n";
4597  return NULL;
4598  case CLI_GENERATE:
4599  return NULL;
4600  }
4601 
4602  if (a->argc != 4 && a->argc != 6) {
4603  return CLI_SHOWUSAGE;
4604  }
4605  if (!strcasecmp(a->argv[3], "inbound")) {
4606  on_subscription = cli_list_subscriptions_inbound;
4607  } else if (!strcasecmp(a->argv[3], "outbound")) {
4608  on_subscription = cli_list_subscriptions_outbound;
4609  } else {
4610  /* Should never get here */
4611  ast_assert(0);
4612  return CLI_SHOWUSAGE;
4613  }
4614  if (a->argc == 6) {
4615  int rc;
4616 
4617  if (strcasecmp(a->argv[4], "like")) {
4618  return CLI_SHOWUSAGE;
4619  }
4620 
4621  /* Setup regular expression */
4622  memset(&like, 0, sizeof(like));
4623  cli.like = &like;
4624  regex = a->argv[5];
4625  rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4626  if (rc) {
4627  char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4628 
4629  regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4630  ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4631  regex, regerr);
4632  return CLI_FAILURE;
4633  }
4634  } else {
4635  cli.like = NULL;
4636  regex = NULL;
4637  }
4638 
4639  cli.a = a;
4640  cli.e = e;
4641  cli.count = 0;
4642  cli.buf = ast_str_create(256);
4643  if (!cli.buf) {
4644  if (cli.like) {
4645  regfree(cli.like);
4646  }
4647  return CLI_FAILURE;
4648  }
4649 
4651  "Endpoint/CLI", "Resource/Event", "Expiry", "Call-id");
4652  for_each_subscription(on_subscription, &cli);
4653  ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n",
4654  cli.count,
4655  regex ? " matched \"" : "",
4656  regex ?: "",
4657  regex ? "\"" : "");
4658 
4659  ast_free(cli.buf);
4660  if (cli.like) {
4661  regfree(cli.like);
4662  }
4663 
4664  return CLI_SUCCESS;
4665 }
struct ast_cli_entry * e
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define CLI_LIST_SUB_FORMAT_HEADER
#define ast_assert(a)
Definition: utils.h:695
static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define MAX_REGEX_ERROR_LEN
static int for_each_subscription(on_subscription_t on_subscription, void *arg)
int(* on_subscription_t)(struct sip_subscription_tree *sub, void *arg)
const int fd
Definition: cli.h:159
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
const char *const * argv
Definition: cli.h:161
static struct ast_cli_entry cli[]
Definition: codec_dahdi.c:265
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:948
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
static struct test_val a

◆ cli_list_subscriptions_outbound()

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

Definition at line 4574 of file res_pjsip_pubsub.c.

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

Referenced by cli_list_subscriptions_inout().

4575 {
4576  return sub_tree->role == AST_SIP_SUBSCRIBER
4577  ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
4578 }
enum ast_sip_subscription_role role
static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

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

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

Referenced by cli_show_subscription_inbound(), and cli_show_subscription_outbound().

4236 {
4237  const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
4238  pj_str_t *sub_callid;
4239  struct ast_str *buf;
4240  char *src;
4241  char *dest;
4242  char *key;
4243  char *value;
4244  char *value_end;
4245  int key_len;
4246  int key_filler_width;
4247  int value_len;
4248 
4249  if (!sub_tree->dlg) {
4250  return 0;
4251  }
4252  sub_callid = &sub_tree->dlg->call_id->id;
4253  if (pj_strcmp2(sub_callid, callid)) {
4254  return 0;
4255  }
4256 
4257  buf = ast_str_create(512);
4258  if (!buf) {
4259  return -1;
4260  }
4261 
4262  ast_cli(cli->a->fd,
4263  "%-20s: %s\n"
4264  "===========================================================================\n",
4265  "ParameterName", "ParameterValue");
4266 
4267  ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
4268  ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
4269  ast_str_append(&buf, 0, "Expiry: %u\n", cli_subscription_expiry(sub_tree));
4270 
4271  sip_subscription_to_ami(sub_tree, &buf);
4272 
4273  /* Convert AMI \r\n to \n line terminators. */
4274  src = strchr(ast_str_buffer(buf), '\r');
4275  if (src) {
4276  dest = src;
4277  ++src;
4278  while (*src) {
4279  if (*src == '\r') {
4280  ++src;
4281  continue;
4282  }
4283  *dest++ = *src++;
4284  }
4285  *dest = '\0';
4287  }
4288 
4289  /* Reformat AMI key value pairs to pretty columns */
4290  key = ast_str_buffer(buf);
4291  do {
4292  value = strchr(key, ':');
4293  if (!value) {
4294  break;
4295  }
4296  value_end = strchr(value, '\n');
4297  if (!value_end) {
4298  break;
4299  }
4300 
4301  /* Calculate field lengths */
4302  key_len = value - key;
4303  key_filler_width = 20 - key_len;
4304  if (key_filler_width < 0) {
4305  key_filler_width = 0;
4306  }
4307  value_len = value_end - value;
4308 
4309  ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
4310  key_len, key, key_filler_width, "",
4311  value_len, value);
4312 
4313  key = value_end + 1;
4314  } while (*key);
4315  ast_cli(cli->a->fd, "\n");
4316 
4317  ast_free(buf);
4318 
4319  return -1;
4320 }
struct ast_sip_subscription * root
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
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:1091
int value
Definition: syslog.c:37
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
static void sip_subscription_to_ami(struct sip_subscription_tree *sub_tree, struct ast_str **buf)
const int fd
Definition: cli.h:159
const struct ast_sip_subscription_handler * handler
struct ast_cli_args * a
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ast_free(a)
Definition: astmm.h:182
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:663
struct ast_str * buf
static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ cli_show_subscription_inbound()

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

Definition at line 4322 of file res_pjsip_pubsub.c.

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

Referenced by cli_show_subscription_inout().

4323 {
4324  return sub_tree->role == AST_SIP_NOTIFIER
4325  ? cli_show_subscription_common(sub_tree, arg) : 0;
4326 }
enum ast_sip_subscription_role role
static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

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

References a, cli_sub_parms::a, ast_cli_args::argc, ast_cli_args::argv, ast_assert, cli_sub_parms::buf, 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.

4335 {
4336  on_subscription_t on_subscription;
4337  struct cli_sub_parms cli;
4338 
4339  switch (cmd) {
4340  case CLI_INIT:
4341  e->command = "pjsip show subscription {inbound|outbound}";
4342  e->usage = "Usage:\n"
4343  " pjsip show subscription inbound <call-id>\n"
4344  " pjsip show subscription outbound <call-id>\n"
4345  " Show active subscription with the dialog call-id\n";
4346  return NULL;
4347  case CLI_GENERATE:
4349  }
4350 
4351  if (a->argc != 5) {
4352  return CLI_SHOWUSAGE;
4353  }
4354 
4355  if (!strcasecmp(a->argv[3], "inbound")) {
4356  on_subscription = cli_show_subscription_inbound;
4357  } else if (!strcasecmp(a->argv[3], "outbound")) {
4358  on_subscription = cli_show_subscription_outbound;
4359  } else {
4360  /* Should never get here */
4361  ast_assert(0);
4362  return NULL;
4363  }
4364 
4365  /* Find the subscription with the specified call-id */
4366  cli.a = a;
4367  cli.e = e;
4368  cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */
4369  for_each_subscription(on_subscription, &cli);
4370 
4371  return CLI_SUCCESS;
4372 }
struct ast_cli_entry * e
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
static int for_each_subscription(on_subscription_t on_subscription, void *arg)
int(* on_subscription_t)(struct sip_subscription_tree *sub, void *arg)
const char *const * argv
Definition: cli.h:161
static struct ast_cli_entry cli[]
Definition: codec_dahdi.c:265
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)
#define CLI_SHOWUSAGE
Definition: cli.h:45
static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
static struct test_val a

◆ cli_show_subscription_outbound()

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

Definition at line 4328 of file res_pjsip_pubsub.c.

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

Referenced by cli_show_subscription_inout().

4329 {
4330  return sub_tree->role == AST_SIP_SUBSCRIBER
4331  ? cli_show_subscription_common(sub_tree, arg) : 0;
4332 }
enum ast_sip_subscription_role role
static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

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

References cli_sub_parms::a, ast_callerid_merge(), ast_cli(), ast_copy_pj_str(), ast_copy_string(), ast_sorcery_object_get_id(), ast_str_buffer(), ast_str_set(), cli_sub_parms::buf, CLI_SHOW_SUB_FORMAT_ENTRY, cli_subscription_expiry(), cli_sub_parms::count, sip_subscription_tree::dlg, sip_subscription_tree::endpoint, ast_sip_subscription_handler::event_name, ast_cli_args::fd, ast_sip_subscription::handler, ast_sip_endpoint::id, cli_sub_parms::like, ast_party_id::name, NULL, ast_party_id::number, 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().

4385 {
4386  char caller_id[256];
4387  char callid[256];
4388 
4389  ast_callerid_merge(caller_id, sizeof(caller_id),
4390  S_COR(sub_tree->endpoint->id.self.name.valid,
4391  sub_tree->endpoint->id.self.name.str, NULL),
4392  S_COR(sub_tree->endpoint->id.self.number.valid,
4393  sub_tree->endpoint->id.self.number.str, NULL),
4394  "<none>");
4395 
4396  /* Call-id */
4397  if (sub_tree->dlg) {
4398  ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
4399  } else {
4400  ast_copy_string(callid, "<unknown>", sizeof(callid));
4401  }
4402 
4404  ast_sorcery_object_get_id(sub_tree->endpoint), caller_id,
4405  sub_tree->root->resource, sub_tree->root->handler->event_name,
4406  cli_subscription_expiry(sub_tree), callid);
4407 
4408  if (cli->like) {
4409  if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
4410  /* Output line did not match the regex */
4411  return 0;
4412  }
4413  }
4414 
4415  ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
4416  ++cli->count;
4417 
4418  return 0;
4419 }
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
struct ast_sip_subscription * root
#define CLI_SHOW_SUB_FORMAT_ENTRY
struct ast_sip_endpoint * endpoint
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
char * str
Subscriber name (Malloced)
Definition: channel.h:265
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:5240
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
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:1065
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1073
const int fd
Definition: cli.h:159
const struct ast_sip_subscription_handler * handler
struct ast_cli_args * a
#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:85
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:847
struct ast_party_id self
Definition: res_pjsip.h:629
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
struct ast_str * buf
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
static unsigned int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343

◆ cli_show_subscriptions_inbound()

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

Definition at line 4421 of file res_pjsip_pubsub.c.

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

Referenced by cli_show_subscriptions_inout().

4422 {
4423  return sub_tree->role == AST_SIP_NOTIFIER
4424  ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4425 }
enum ast_sip_subscription_role role
static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

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

References a, cli_sub_parms::a, ast_cli_args::argc, ast_cli_args::argv, ast_alloca, ast_assert, ast_cli(), ast_free, ast_str_create, cli_sub_parms::buf, 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::count, cli_sub_parms::e, ast_cli_args::fd, for_each_subscription(), cli_sub_parms::like, MAX_REGEX_ERROR_LEN, NULL, regex(), and ast_cli_entry::usage.

4434 {
4435  on_subscription_t on_subscription;
4436  struct cli_sub_parms cli;
4437  regex_t like;
4438  const char *regex;
4439 
4440  switch (cmd) {
4441  case CLI_INIT:
4442  e->command = "pjsip show subscriptions {inbound|outbound} [like]";
4443  e->usage = "Usage:\n"
4444  " pjsip show subscriptions inbound [like <regex>]\n"
4445  " Show active inbound subscriptions\n"
4446  " pjsip show subscriptions outbound [like <regex>]\n"
4447  " Show active outbound subscriptions\n"
4448  "\n"
4449  " The regex selects a subscriptions output that matches.\n"
4450  " i.e., All output lines for a subscription are checked\n"
4451  " as a block by the regex.\n";
4452  return NULL;
4453  case CLI_GENERATE:
4454  return NULL;
4455  }
4456 
4457  if (a->argc != 4 && a->argc != 6) {
4458  return CLI_SHOWUSAGE;
4459  }
4460  if (!strcasecmp(a->argv[3], "inbound")) {
4461  on_subscription = cli_show_subscriptions_inbound;
4462  } else if (!strcasecmp(a->argv[3], "outbound")) {
4463  on_subscription = cli_show_subscriptions_outbound;
4464  } else {
4465  /* Should never get here */
4466  ast_assert(0);
4467  return CLI_SHOWUSAGE;
4468  }
4469  if (a->argc == 6) {
4470  int rc;
4471 
4472  if (strcasecmp(a->argv[4], "like")) {
4473  return CLI_SHOWUSAGE;
4474  }
4475 
4476  /* Setup regular expression */
4477  memset(&like, 0, sizeof(like));
4478  cli.like = &like;
4479  regex = a->argv[5];
4480  rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
4481  if (rc) {
4482  char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
4483 
4484  regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
4485  ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
4486  regex, regerr);
4487  return CLI_FAILURE;
4488  }
4489  } else {
4490  cli.like = NULL;
4491  regex = NULL;
4492  }
4493 
4494  cli.a = a;
4495  cli.e = e;
4496  cli.count = 0;
4497  cli.buf = ast_str_create(256);
4498  if (!cli.buf) {
4499  if (cli.like) {
4500  regfree(cli.like);
4501  }
4502  return CLI_FAILURE;
4503  }
4504 
4506  for_each_subscription(on_subscription, &cli);
4507  ast_cli(a->fd, "%d active subscriptions%s%s%s\n",
4508  cli.count,
4509  regex ? " matched \"" : "",
4510  regex ?: "",
4511  regex ? "\"" : "");
4512 
4513  ast_free(cli.buf);
4514  if (cli.like) {
4515  regfree(cli.like);
4516  }
4517 
4518  return CLI_SUCCESS;
4519 }
struct ast_cli_entry * e
static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define MAX_REGEX_ERROR_LEN
static int for_each_subscription(on_subscription_t on_subscription, void *arg)
#define CLI_SHOW_SUB_FORMAT_HEADER
int(* on_subscription_t)(struct sip_subscription_tree *sub, void *arg)
const int fd
Definition: cli.h:159
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
const char *const * argv
Definition: cli.h:161
static struct ast_cli_entry cli[]
Definition: codec_dahdi.c:265
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_FAILURE
Definition: cli.h:46
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:948
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
static struct test_val a

◆ cli_show_subscriptions_outbound()

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

Definition at line 4427 of file res_pjsip_pubsub.c.

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

Referenced by cli_show_subscriptions_inout().

4428 {
4429  return sub_tree->role == AST_SIP_SUBSCRIBER
4430  ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
4431 }
enum ast_sip_subscription_role role
static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)

◆ cli_subscription_expiry()

static unsigned int cli_subscription_expiry ( struct sip_subscription_tree sub_tree)
static

Definition at line 4221 of file res_pjsip_pubsub.c.

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

4222 {
4223  int expiry;
4224 
4225  expiry = sub_tree->persistence
4226  ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
4227  : 0;
4228  if (expiry < 0) {
4229  /* Subscription expired */
4230  expiry = 0;
4231  }
4232  return expiry;
4233 }
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
struct subscription_persistence * persistence

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

References ast_generate_random_string().

Referenced by generate_list_body().

2292 {
2293  pjsip_media_type media_type;
2294  pjsip_param *media_type_param;
2295  char boundary[6];
2296  pj_str_t pj_boundary;
2297 
2298  pjsip_media_type_init2(&media_type, "multipart", "related");
2299 
2300  media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
2301  pj_list_init(media_type_param);
2302 
2303  pj_strdup2(pool, &media_type_param->name, "type");
2304  pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
2305 
2306  pj_list_insert_before(&media_type.param, media_type_param);
2307 
2308  pj_cstr(&pj_boundary, ast_generate_random_string(boundary, sizeof(boundary)));
2309  return pjsip_multipart_create(pool, &media_type, &pj_boundary);
2310 }
media_type
Media types generate different "dummy answers" for not accepting the offer of a media stream...
Definition: sip.h:489
static pj_pool_t * pool
Global memory pool for configuration and timers.
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
Definition: strings.c:227

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

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

2405 {
2406  pjsip_require_hdr *require;
2407 
2408  require = pjsip_require_hdr_create(pool);
2409  pj_strdup2(pool, &require->values[0], "eventlist");
2410  require->count = 1;
2411 
2412  return require;
2413 }
static pj_pool_t * pool
Global memory pool for configuration and timers.

◆ create_resource_list()

static struct resource_list* create_resource_list ( struct ast_test test,
const char *  list_name,
const char *  event,
const char **  resources,
size_t  num_resources 
)
static

allocate a resource list, store it in sorcery, and set its details

Parameters
testThe unit test. Used for logging status messages.
list_nameThe name of the list to create.
eventThe event the list services
resourcesArray of resources to apply to the list
num_resourcesThe number of resources in the array
Return values
NULLFailed to allocate or populate list
non-NULLThe created list

Definition at line 4983 of file res_pjsip_pubsub.c.

References ao2_cleanup, ast_sip_get_sorcery(), ast_sorcery_alloc(), ast_sorcery_create(), ast_test_status_update, cleanup_resource_list(), NULL, and populate_list().

Referenced by AST_TEST_DEFINE().

4985 {
4986  struct resource_list *list;
4987 
4988  list = ast_sorcery_alloc(ast_sip_get_sorcery(), "resource_list", list_name);
4989  if (!list) {
4990  ast_test_status_update(test, "Could not allocate resource list in sorcery\n");
4991  return NULL;
4992  }
4993 
4994  if (ast_sorcery_create(ast_sip_get_sorcery(), list)) {
4995  ast_test_status_update(test, "Could not store the resource list in sorcery\n");
4996  ao2_cleanup(list);
4997  return NULL;
4998  }
4999 
5000  if (populate_list(list, event, resources, num_resources)) {
5001  ast_test_status_update(test, "Could not add resources to the resource list\n");
5002  cleanup_resource_list(list);
5003  return NULL;
5004  }
5005 
5006  return list;
5007 }
Definition: astman.c:222
#define NULL
Definition: resample.c:96
Resource list configuration item.
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2057
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
static void cleanup_resource_list(struct resource_list *list)
RAII callback to destroy a resource list.
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static int populate_list(struct resource_list *list, const char *event, const char **resources, size_t num_resources)
Set properties on an allocated resource list.

◆ 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
dlg_status[out]The result of attempting to create a dialog.
Return values
NULLCould not create the subscription tree
non-NULLThe root of the created subscription tree

Definition at line 1465 of file res_pjsip_pubsub.c.

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, create_virtual_subscriptions(), subscription_persistence::cseq, sip_subscription_tree::dlg, sip_subscription_tree::evsub, 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().

1469 {
1470  struct sip_subscription_tree *sub_tree;
1471  pjsip_dialog *dlg;
1472 
1473  sub_tree = allocate_subscription_tree(endpoint, rdata);
1474  if (!sub_tree) {
1475  *dlg_status = PJ_ENOMEM;
1476  return NULL;
1477  }
1478  sub_tree->role = AST_SIP_NOTIFIER;
1479 
1480  dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, dlg_status);
1481  if (!dlg) {
1482  if (*dlg_status != PJ_EEXISTS) {
1483  ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
1484  }
1485  ao2_ref(sub_tree, -1);
1486  return NULL;
1487  }
1488 
1489  persistence = ast_sip_mod_data_get(rdata->endpt_info.mod_data,
1491  if (persistence) {
1492  /* Update the created dialog with the persisted information */
1493  pjsip_ua_unregister_dlg(pjsip_ua_instance(), dlg);
1494  pj_strdup2(dlg->pool, &dlg->local.info->tag, persistence->tag);
1495  dlg->local.tag_hval = pj_hash_calc_tolower(0, NULL, &dlg->local.info->tag);
1496  pjsip_ua_register_dlg(pjsip_ua_instance(), dlg);
1497  dlg->local.cseq = persistence->cseq;
1498  }
1499 
1500  pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
1501 
1502  subscription_setup_dialog(sub_tree, dlg);
1503 
1504  /*
1505  * The evsub and subscription setup both add dialog refs, so the dialog ref that
1506  * was added when the dialog was created (see ast_sip_create_dialog_uas_lock) can
1507  * now be removed. The lock should no longer be needed so can be removed too.
1508  */
1509  pjsip_dlg_dec_lock(dlg);
1510 
1511 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
1512  pjsip_evsub_add_ref(sub_tree->evsub);
1513 #endif
1514 
1515  ast_sip_mod_data_set(dlg->pool, dlg->mod_data, pubsub_module.id, MOD_DATA_MSG,
1516  pjsip_msg_clone(dlg->pool, rdata->msg_info.msg));
1517 
1519 
1520  /* Persistence information needs to be available for all the subscriptions */
1521  sub_tree->persistence = ao2_bump(persistence);
1522 
1523  sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
1524  if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
1525  sub_tree->is_list = 1;
1526  }
1527 
1528  add_subscription(sub_tree);
1529 
1530  return sub_tree;
1531 }
struct ast_sip_subscription * root
static struct pjsip_module pubsub_module
static void add_subscription(struct sip_subscription_tree *obj)
#define LOG_WARNING
Definition: logger.h:274
struct tree_node * root
static pjsip_evsub_user pubsub_cb
#define NULL
Definition: resample.c:96
struct subscription_persistence * persistence
enum ast_sip_subscription_role role
unsigned int notification_batch_interval
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_log
Definition: astobj2.c:42
#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:2670
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#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:2638
static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)
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:4249
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.
unsigned int notification_batch_interval
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
#define MOD_DATA_PERSISTENCE
A tree of SIP subscriptions.
static struct sip_subscription_tree * allocate_subscription_tree(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
#define MOD_DATA_MSG

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

References allocate_subscription(), ao2_cleanup, ast_debug, AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, ast_sip_subscription::body_generator, destroy_subscription(), generator, NULL, and sub.

Referenced by create_subscription_tree().

1289 {
1290  int i;
1291  struct ast_sip_subscription *sub;
1292 
1293  sub = allocate_subscription(handler, resource, tree);
1294  if (!sub) {
1295  return NULL;
1296  }
1297 
1298  sub->full_state = current->full_state;
1299  sub->body_generator = generator;
1300  AST_VECTOR_INIT(&sub->children, AST_VECTOR_SIZE(&current->children));
1301 
1302  for (i = 0; i < AST_VECTOR_SIZE(&current->children); ++i) {
1303  struct ast_sip_subscription *child;
1304  struct tree_node *child_node = AST_VECTOR_GET(&current->children, i);
1305 
1306  child = create_virtual_subscriptions(handler, child_node->resource, generator,
1307  tree, child_node);
1308 
1309  if (!child) {
1310  ast_debug(1, "Child subscription to resource %s could not be created\n",
1311  child_node->resource);
1312  continue;
1313  }
1314 
1315  if (AST_VECTOR_APPEND(&sub->children, child)) {
1316  ast_debug(1, "Child subscription to resource %s could not be appended\n",
1317  child_node->resource);
1318  destroy_subscription(child);
1319  /* Have to release tree here too because a ref was added
1320  * to child that destroy_subscription() doesn't release. */
1321  ao2_cleanup(tree);
1322  }
1323  }
1324 
1325  return sub;
1326 }
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define NULL
Definition: resample.c:96
A node for a resource tree.
struct ast_sip_pubsub_body_generator * body_generator
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
Structure representing a "virtual" SIP subscription.
static struct ast_generator generator
Definition: app_fax.c:359
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 AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static struct ast_sip_subscription * allocate_subscription(const struct ast_sip_subscription_handler *handler, const char *resource, struct sip_subscription_tree *tree)
struct stasis_forward * sub
Definition: res_corosync.c:240
static void destroy_subscription(struct ast_sip_subscription *sub)
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ destroy_subscription()

static void destroy_subscription ( struct ast_sip_subscription sub)
static

Definition at line 1201 of file res_pjsip_pubsub.c.

References ao2_cleanup, ast_debug, ast_free, ast_json_unref(), ast_sorcery_object_get_id(), AST_VECTOR_FREE, ast_sip_subscription::datastores, sip_subscription_tree::endpoint, and ast_sip_subscription::tree.

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

1202 {
1203  ast_debug(3, "Destroying SIP subscription from '%s->%s'\n",
1204  sub->tree && sub->tree->endpoint ? ast_sorcery_object_get_id(sub->tree->endpoint) : "Unknown",
1205  sub->resource);
1206 
1207  ast_free(sub->body_text);
1208 
1209  AST_VECTOR_FREE(&sub->children);
1210  ao2_cleanup(sub->datastores);
1211  ast_json_unref(sub->persistence_data);
1212  ast_free(sub);
1213 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct sip_subscription_tree * tree
struct ast_sip_endpoint * endpoint
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct ao2_container * datastores
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#define ast_free(a)
Definition: astmm.h:182
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ destroy_subscriptions()

static void destroy_subscriptions ( struct ast_sip_subscription root)
static

Definition at line 1215 of file res_pjsip_pubsub.c.

References AST_VECTOR_GET, AST_VECTOR_SIZE, and destroy_subscription().

Referenced by subscription_tree_destructor().

1216 {
1217  int i;
1218 
1219  if (!root) {
1220  return;
1221  }
1222 
1223  for (i = 0; i < AST_VECTOR_SIZE(&root->children); ++i) {
1224  struct ast_sip_subscription *child;
1225 
1226  child = AST_VECTOR_GET(&root->children, i);
1227  destroy_subscriptions(child);
1228  }
1229 
1230  destroy_subscription(root);
1231 }
static void destroy_subscriptions(struct ast_sip_subscription *root)
Structure representing a "virtual" SIP subscription.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
static void destroy_subscription(struct ast_sip_subscription *sub)
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

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

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

Referenced by pubsub_on_rx_publish_request().

3104 {
3105  pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3106 
3107  if (etag_hdr) {
3108  char etag[pj_strlen(&etag_hdr->hvalue) + 1];
3109 
3110  ast_copy_pj_str(etag, &etag_hdr->hvalue, sizeof(etag));
3111 
3112  if (sscanf(etag, "%30d", entity_id) != 1) {
3113  return SIP_PUBLISH_UNKNOWN;
3114  }
3115  }
3116 
3117  *expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3118 
3119  if (!(*expires)) {
3120  return SIP_PUBLISH_REMOVE;
3121  } else if (!etag_hdr && rdata->msg_info.msg->body) {
3122  return SIP_PUBLISH_INITIAL;
3123  } else if (etag_hdr && !rdata->msg_info.msg->body) {
3124  return SIP_PUBLISH_REFRESH;
3125  } else if (etag_hdr && rdata->msg_info.msg->body) {
3126  return SIP_PUBLISH_MODIFY;
3127  }
3128 
3129  return SIP_PUBLISH_UNKNOWN;
3130 }
#define DEFAULT_PUBLISH_EXPIRES
Default expiration time for PUBLISH if one is not specified.
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:5240
#define NULL
Definition: resample.c:96

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

References accept_exceptions, and ARRAY_LEN.

Referenced by subscription_get_generator_from_rdata().

818 {
819  int i;
820 
821  for (i = 0; i < ARRAY_LEN(accept_exceptions); ++i) {
822  if (!pj_strcmp2(accept, accept_exceptions[i])) {
823  return 1;
824  }
825  }
826 
827  return 0;
828 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
const char * accept_exceptions[]
Accept headers that are exceptions to the rule.

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

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

Referenced by subscription_get_generator_from_rdata(), and subscription_persistence_remove().

2864 {
2865  int i;
2867 
2868  for (i = 0; i < num_accept; ++i) {
2869  generator = find_body_generator_accept(accept[i]);
2870  if (generator) {
2871  ast_debug(3, "Body generator %p found for accept type %s\n", generator, accept[i]);
2872  if (strcmp(generator->body_type, body_type)) {
2873  ast_log(LOG_WARNING, "Body generator '%s/%s'(%p) does not accept the type of data this event generates\n",
2874  generator->type, generator->subtype, generator);
2875  generator = NULL;
2876  continue;
2877  }
2878  break;
2879  } else {
2880  ast_debug(3, "No body generator found for accept type %s\n", accept[i]);
2881  }
2882  }
2883 
2884  return generator;
2885 }
Pubsub body generator.
const char * type
Content type In "plain/text", "plain" is the type.
#define LOG_WARNING
Definition: logger.h:274
static struct ast_sip_pubsub_body_generator * find_body_generator_accept(const char *accept)
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
static struct ast_generator generator
Definition: app_fax.c:359

◆ find_body_generator_accept()

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

Definition at line 2849 of file res_pjsip_pubsub.c.

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

2850 {
2851  char *accept_copy = ast_strdupa(accept);
2852  char *subtype = accept_copy;
2853  char *type = strsep(&subtype, "/");
2854 
2855  if (ast_strlen_zero(type) || ast_strlen_zero(subtype)) {
2856  return NULL;
2857  }
2858 
2859  return find_body_generator_type_subtype(type, subtype);
2860 }
static const char type[]
Definition: chan_ooh323.c:109
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype(const char *type, const char *subtype)
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
char * strsep(char **str, const char *delims)

◆ find_body_generator_type_subtype()

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

Definition at line 2839 of file res_pjsip_pubsub.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, find_body_generator_type_subtype_nolock(), and gen.

Referenced by ast_sip_pubsub_generate_body_content(), ast_sip_pubsub_is_body_generator_registered(), and find_body_generator_accept().

2840 {
2842 
2846  return gen;
2847 }
static const char type[]
Definition: chan_ooh323.c:109
static struct ast_sip_pubsub_body_generator * find_body_generator_type_subtype_nolock(const char *type, const char *subtype)
Pubsub body generator.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
static struct ast_generator gen
const char * subtype
Content subtype In "plain/text", "text" is the subtype.

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

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

Referenced by ast_sip_pubsub_register_body_generator(), and find_body_generator_type_subtype().

2826 {
2828 
2830  if (!strcmp(gen->type, type)
2831  && !strcmp(gen->subtype, subtype)) {
2832  break;
2833  }
2834  }
2835 
2836  return gen;
2837 }
static const char type[]
Definition: chan_ooh323.c:109
Pubsub body generator.
const char * type
Content type In "plain/text", "plain" is the type.
static struct ast_generator gen
const char * subtype
Content subtype In "plain/text", "text" is the subtype.
struct ast_sip_pubsub_body_generator::@306 list
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490

◆ find_pub_handler()

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

Definition at line 3084 of file res_pjsip_pubsub.c.

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

3085 {
3086  struct ast_sip_publish_handler *iter = NULL;
3087 
3090  if (strcmp(event, iter->event_name)) {
3091  ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
3092  continue;
3093  }
3094  ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
3095  break;
3096  }
3098 
3099  return iter;
3100 }
const char * event_name
The name of the event this handler deals with.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
Definition: astman.c:222
#define NULL
Definition: resample.c:96
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct ast_sip_publish_handler * next
Callbacks that publication handlers will define.

◆ find_sub_handler_for_event_name()

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

Definition at line 2763 of file res_pjsip_pubsub.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_sip_subscription_handler::event_name, and ast_sip_subscription_handler::next.

Referenced by ast_sip_register_subscription_handler(), subscription_get_handler_from_rdata(), and subscription_persistence_remove().

2764 {
2765  struct ast_sip_subscription_handler *iter;
2766 
2769  if (!strcmp(iter->event_name, event_name)) {
2770  break;
2771  }
2772  }
2774  return iter;
2775 }
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct ast_sip_subscription_handler * next

◆ for_each_subscription()

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

Definition at line 1800 of file res_pjsip_pubsub.c.

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

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

1801 {
1802  int num = 0;
1803  struct sip_subscription_tree *i;
1804 
1805  if (!on_subscription) {
1806  return num;
1807  }
1808 
1811  if (on_subscription(i, arg)) {
1812  break;
1813  }
1814  ++num;
1815  }
1817  return num;
1818 }
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
struct sip_subscription_tree * next
A tree of SIP subscriptions.

◆ format_ami_resource_lists()

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

Definition at line 4090 of file res_pjsip_pubsub.c.

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

4091 {
4092  struct resource_list *list = obj;
4093  struct ast_sip_ami *ami = arg;
4094  struct ast_str *buf;
4095 
4096  buf = ast_sip_create_ami_event("ResourceListDetail", ami);
4097  if (!buf) {
4098  return CMP_STOP;
4099  }
4100 
4101  if (ast_sip_sorcery_object_to_ami(list, &buf)) {
4102  ast_free(buf);
4103  return CMP_STOP;
4104  }
4105  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
4106  ast_free(buf);
4107 
4108  ++ami->count;
4109  return 0;
4110 }
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
void * arg
Definition: res_pjsip.h:2745
AMI variable container.
Definition: res_pjsip.h:2737
Resource list configuration item.
struct mansession * s
Definition: res_pjsip.h:2739
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ast_free(a)
Definition: astmm.h:182
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.
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.

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

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

Referenced by generate_list_body().

2216 {
2217  int i;
2218 
2219  for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
2220  struct body_part *part = AST_VECTOR_GET(parts, i);
2221  ast_free(part);
2222  }
2223 
2224  AST_VECTOR_FREE(parts);
2225 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
A multipart body part and meta-information.
#define ast_free(a)
Definition: astmm.h:182
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
pjsip_multipart_part * part
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

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

References ast_generate_random_string(), cid_name, and id.

Referenced by allocate_body_part(), and build_rlmi_body().

2109 {
2110  static const pj_str_t cid_name = { "Content-ID", 10 };
2111  pjsip_generic_string_hdr *cid;
2112  char id[6];
2113  size_t alloc_size;
2114  pj_str_t cid_value;
2115 
2116  /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
2117  alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
2118  cid_value.ptr = pj_pool_alloc(pool, alloc_size);
2119  cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
2120  ast_generate_random_string(id, sizeof(id)),
2121  (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
2122  cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
2123 
2124  return cid;
2125 }
static pj_pool_t * pool
Global memory pool for configuration and timers.
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
Definition: strings.c:227
pjsip_generic_string_hdr * cid
static char cid_name[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:165
enum queue_result id
Definition: app_queue.c:1507

◆ generate_initial_notify()

static int generate_initial_notify ( struct ast_sip_subscription sub)
static

Definition at line 2887 of file res_pjsip_pubsub.c.

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, ast_sip_subscription_handler::body_type, ast_sip_notifier::get_notify_data, ast_sip_subscription::handler, ast_sip_subscription_handler::notifier, pubsub_on_refresh_timeout(), and ast_sip_notifier::subscription_established.

Referenced by initial_notify_task().

2888 {
2889  void *notify_data;
2890  int res;
2891  struct ast_sip_body_data data = {
2892  .body_type = sub->handler->body_type,
2893  };
2894 
2895  if (AST_VECTOR_SIZE(&sub->children) > 0) {
2896  int i;
2897 
2898  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2899  if (generate_initial_notify(AST_VECTOR_GET(&sub->children, i))) {
2900  return -1;
2901  }
2902  }
2903 
2904  return 0;
2905  }
2906 
2907  /* We notify subscription establishment only on the tree leaves. */
2908  if (sub->handler->notifier->subscription_established(sub)) {
2909  return -1;
2910  }
2911 
2912  notify_data = sub->handler->notifier->get_notify_data(sub);
2913  if (!notify_data) {
2914  return -1;
2915  }
2916 
2917  data.body_data = notify_data;
2918 
2920  ast_sip_subscription_get_body_subtype(sub), &data, &sub->body_text);
2921 
2922  ao2_cleanup(notify_data);
2923 
2924  return res;
2925 }
void *(* get_notify_data)(struct ast_sip_subscription *sub)
Supply data needed to create a NOTIFY body.
static int generate_initial_notify(struct ast_sip_subscription *sub)
const char * body_type
Data used to create bodies for NOTIFY/PUBLISH requests.
struct ast_sip_notifier * notifier
const char * ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub)
Get the body subtype used for this subscription.
const struct ast_sip_subscription_handler * handler
int(* subscription_established)(struct ast_sip_subscription *sub)
Called when an inbound subscription has been accepted.
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.
const char * ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
Get the body type used for this subscription.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

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

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

Referenced by generate_notify_body().

2326 {
2327  int i;
2328  pjsip_multipart_part *rlmi_part;
2329  pjsip_msg_body *multipart;
2330  struct body_part_list body_parts;
2331  unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
2332 
2333  if (AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children))) {
2334  return NULL;
2335  }
2336 
2337  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
2338  build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
2339  }
2340 
2341  /* This can happen if issuing partial state and no children of the list have changed state */
2342  if (AST_VECTOR_SIZE(&body_parts) == 0) {
2343  free_body_parts(&body_parts);
2344  return NULL;
2345  }
2346 
2347  multipart = create_multipart_body(pool);
2348 
2349  rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
2350  if (!rlmi_part) {
2351  free_body_parts(&body_parts);
2352  return NULL;
2353  }
2354  pjsip_multipart_add_part(pool, multipart, rlmi_part);
2355 
2356  for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
2357  pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
2358  }
2359 
2360  free_body_parts(&body_parts);
2361  return multipart;
2362 }
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 pj_pool_t * pool
Global memory pool for configuration and timers.
#define NULL
Definition: resample.c:96
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 pjsip_msg_body * create_multipart_body(pj_pool_t *pool)
Create and initialize the PJSIP multipart body structure for a resource list subscription.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
static void free_body_parts(struct body_part_list *parts)
Destroy a list of body parts.

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

References ast_sip_subscription_get_body_subtype(), ast_sip_subscription_get_body_type(), ast_str_buffer(), AST_VECTOR_SIZE, generate_list_body(), NULL, text, and type.

Referenced by build_body_part(), build_rlmi_body(), and send_notify().

2373 {
2374  pjsip_msg_body *body;
2375 
2376  if (AST_VECTOR_SIZE(&root->children) == 0) {
2377  if (force_full_state || root->body_changed) {
2378  /* Not a list. We've already generated the body and saved it on the subscription.
2379  * Use that directly.
2380  */
2381  pj_str_t type;
2382  pj_str_t subtype;
2383  pj_str_t text;
2384 
2385  pj_cstr(&type, ast_sip_subscription_get_body_type(root));
2386  pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
2387  pj_cstr(&text, ast_str_buffer(root->body_text));
2388 
2389  body = pjsip_msg_body_create(pool, &type, &subtype, &text);
2390  root->body_changed = 0;
2391  } else {
2392  body = NULL;
2393  }
2394  } else {
2395  body = generate_list_body(pool, root, force_full_state);
2396  }
2397 
2398  return body;
2399 }
static const char type[]
Definition: chan_ooh323.c:109
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static pj_pool_t * pool
Global memory pool for configuration and timers.
char * text
Definition: app_queue.c:1508
#define NULL
Definition: resample.c:96
const char * ast_sip_subscription_get_body_subtype(struct ast_sip_subscription *sub)
Get the body subtype used for this subscription.
const char * ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
Get the body type used for this subscription.
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.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

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

References AST_VECTOR_GET, and AST_VECTOR_SIZE.

Referenced by build_node_children().

988 {
989  int i;
990 
991  for (i = 0; i < AST_VECTOR_SIZE(visited); ++i) {
992  if (!strcmp(resource, AST_VECTOR_GET(visited, i))) {
993  return 1;
994  }
995  }
996 
997  return 0;
998 }
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ ineligible_configuration()

static int ineligible_configuration ( void  )
static

Definition at line 5053 of file res_pjsip_pubsub.c.

References ast_config_destroy(), ast_config_load, ast_strlen_zero, ast_variable_retrieve(), config, and value.

Referenced by AST_TEST_DEFINE().

5054 {
5055  struct ast_config *config;
5056  struct ast_flags flags = {0,};
5057  const char *value;
5058 
5059  config = ast_config_load("sorcery.conf", flags);
5060  if (!config) {
5061  return 1;
5062  }
5063 
5064  value = ast_variable_retrieve(config, "res_pjsip_pubsub", "resource_list");
5065  if (ast_strlen_zero(value)) {
5066  ast_config_destroy(config);
5067  return 1;
5068  }
5069 
5070  if (strcasecmp(value, "memory") && strcasecmp(value, "astdb")) {
5071  ast_config_destroy(config);
5072  return 1;
5073  }
5074 
5075  return 0;
5076 }
char * config
Definition: conf2ael.c:66
unsigned int flags
Definition: utils.h:200
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_config_load(filename, flags)
Load a config file.
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
Structure used to handle boolean flags.
Definition: utils.h:199
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694

◆ initial_notify_task()

static int initial_notify_task ( void *  obj)
static

Definition at line 2929 of file res_pjsip_pubsub.c.

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

2930 {
2931  struct initial_notify_data *ind = obj;
2932 
2933  if (generate_initial_notify(ind->sub_tree->root)) {
2934  pjsip_evsub_terminate(ind->sub_tree->evsub, PJ_TRUE);
2935  } else {
2936  send_notify(ind->sub_tree, 1);
2937  ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
2938  "Resource: %s",
2939  ind->sub_tree->root->resource);
2940  }
2941 
2942  if (ind->expires != PJSIP_EXPIRES_NOT_SPECIFIED) {
2943  char *name = ast_alloca(strlen("->/ ") +
2944  strlen(ind->sub_tree->persistence->endpoint) +
2945  strlen(ind->sub_tree->root->resource) +
2946  strlen(ind->sub_tree->root->handler->event_name) +
2947  ind->sub_tree->dlg->call_id->id.slen + 1);
2948 
2949  sprintf(name, "%s->%s/%s %.*s", ind->sub_tree->persistence->endpoint,
2950  ind->sub_tree->root->resource, ind->sub_tree->root->handler->event_name,
2951  (int)ind->sub_tree->dlg->call_id->id.slen, ind->sub_tree->dlg->call_id->id.ptr);
2952 
2953  ast_debug(3, "Scheduling timer: %s\n", name);
2955  ind->expires * 1000, pubsub_on_refresh_timeout, name,
2957  if (!ind->sub_tree->expiration_task) {
2958  ast_log(LOG_ERROR, "Unable to create expiration timer of %d seconds for %s\n",
2959  ind->expires, name);
2960  }
2961  }
2962 
2963  ao2_ref(ind->sub_tree, -1);
2964  ast_free(ind);
2965 
2966  return 0;
2967 }
static int generate_initial_notify(struct ast_sip_subscription *sub)
struct ast_sip_subscription * root
struct subscription_persistence * persistence
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.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static int pubsub_on_refresh_timeout(void *userdata)
const struct ast_sip_subscription_handler * handler
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define LOG_ERROR
Definition: logger.h:285
static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
Send a NOTIFY request to a subscriber.
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
struct ast_sip_sched_task * expiration_task
struct ast_taskprocessor * serializer
struct sip_subscription_tree * sub_tree
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: res_pjsip.h:63

◆ item_in_vector()

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

Definition at line 4781 of file res_pjsip_pubsub.c.

References AST_VECTOR_GET, AST_VECTOR_SIZE, and resource_list::items.

Referenced by list_item_handler().

4782 {
4783  int i;
4784 
4785  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
4786  if (!strcmp(item, AST_VECTOR_GET(&list->items, i))) {
4787  return 1;
4788  }
4789  }
4790 
4791  return 0;
4792 }
static struct aco_type item
Definition: test_config.c:1463
struct resources items
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ list_item_handler()

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

Definition at line 4794 of file res_pjsip_pubsub.c.

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 ast_variable::value.

Referenced by apply_list_configuration().

4796 {
4797  struct resource_list *list = obj;
4798  char *items = ast_strdupa(var->value);
4799  char *item;
4800 
4801  while ((item = ast_strip(strsep(&items, ",")))) {
4802  if (ast_strlen_zero(item)) {
4803  continue;
4804  }
4805 
4806  if (item_in_vector(list, item)) {
4807  ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);
4808  continue;
4809  }
4810 
4811  item = ast_strdup(item);
4812  if (!item || AST_VECTOR_APPEND(&list->items, item)) {
4813  ast_free(item);
4814  return -1;
4815  }
4816  }
4817 
4818  return 0;
4819 }
#define LOG_WARNING
Definition: logger.h:274
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
static struct aco_type item
Definition: test_config.c:1463
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Resource list configuration item.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define ast_free(a)
Definition: astmm.h:182
struct resources items
static int item_in_vector(const struct resource_list *list, const char *item)
char * strsep(char **str, const char *delims)

◆ list_item_to_str()

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

Definition at line 4821 of file res_pjsip_pubsub.c.

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

Referenced by apply_list_configuration().

4822 {
4823  const struct resource_list *list = obj;
4824  int i;
4825  struct ast_str *str = ast_str_create(32);
4826 
4827  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
4828  ast_str_append(&str, 0, "%s,", AST_VECTOR_GET(&list->items, i));
4829  }
4830 
4831  /* Chop off trailing comma */
4832  ast_str_truncate(str, -1);
4833  *buf = ast_strdup(ast_str_buffer(str));
4834  ast_free(str);
4835  return 0;
4836 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
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:1091
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * str
Definition: app_jack.c:147
Resource list configuration item.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:738
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ast_free(a)
Definition: astmm.h:182
struct resources items
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ load_module()

static int load_module ( void  )
static

Definition at line 5560 of file res_pjsip_pubsub.c.

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

Referenced by unload_module().

5561 {
5562  static const pj_str_t str_PUBLISH = { "PUBLISH", 7 };
5563  struct ast_sorcery *sorcery;
5564 
5565  sorcery = ast_sip_get_sorcery();
5566 
5567  if (!(sched = ast_sched_context_create())) {
5568  ast_log(LOG_ERROR, "Could not create scheduler for publication expiration\n");
5569  return AST_MODULE_LOAD_DECLINE;
5570  }
5571 
5573  ast_log(LOG_ERROR, "Could not start scheduler thread for publication expiration\n");
5575  return AST_MODULE_LOAD_DECLINE;
5576  }
5577 
5578  ast_sorcery_apply_config(sorcery, "res_pjsip_pubsub");
5579  ast_sorcery_apply_default(sorcery, "subscription_persistence", "astdb", "subscription_persistence");
5580  if (ast_sorcery_object_register(sorcery, "subscription_persistence", subscription_persistence_alloc,
5581  NULL, NULL)) {
5582  ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
5584  return AST_MODULE_LOAD_DECLINE;
5585  }
5586  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "packet", "", OPT_CHAR_ARRAY_T, 0,
5587  CHARFLDSET(struct subscription_persistence, packet));
5588  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_name", "", OPT_CHAR_ARRAY_T, 0,
5589  CHARFLDSET(struct subscription_persistence, src_name));
5590  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_port", "0", OPT_UINT_T, 0,
5591  FLDSET(struct subscription_persistence, src_port));
5592  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "transport_key", "0", OPT_CHAR_ARRAY_T, 0,
5593  CHARFLDSET(struct subscription_persistence, transport_key));
5594  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_name", "", OPT_CHAR_ARRAY_T, 0,
5595  CHARFLDSET(struct subscription_persistence, local_name));
5596  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_port", "0", OPT_UINT_T, 0,
5597  FLDSET(struct subscription_persistence, local_port));
5598  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "cseq", "0", OPT_UINT_T, 0,
5599  FLDSET(struct subscription_persistence, cseq));
5600  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "endpoint", "",
5602  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "tag", "",
5604  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "expires", "",
5606  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "contact_uri", "", OPT_CHAR_ARRAY_T, 0,
5607  CHARFLDSET(struct subscription_persistence, contact_uri));
5608  ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "no", OPT_YESNO_T, 1,
5609  FLDSET(struct subscription_persistence, prune_on_boot));
5610  ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "generator_data", "",
5612 
5613  if (apply_list_configuration(sorcery)) {
5615  return AST_MODULE_LOAD_DECLINE;
5616  }
5617 
5618  ast_sorcery_apply_default(sorcery, "inbound-publication", "config", "pjsip.conf,criteria=type=inbound-publication");
5619  if (ast_sorcery_object_register(sorcery, "inbound-publication", publication_resource_alloc,
5620  NULL, NULL)) {
5621  ast_log(LOG_ERROR, "Could not register subscription persistence object support\n");
5623  return AST_MODULE_LOAD_DECLINE;
5624  }
5625  ast_sorcery_object_field_register(sorcery, "inbound-publication", "type", "", OPT_NOOP_T, 0, 0);
5626  ast_sorcery_object_field_register_custom(sorcery, "inbound-publication", "endpoint", "",
5628  ast_sorcery_object_fields_register(sorcery, "inbound-publication", "^event_", resource_event_handler, NULL);
5629  ast_sorcery_reload_object(sorcery, "inbound-publication");
5630 
5632  ast_log(LOG_ERROR, "Could not register pubsub service\n");
5634  return AST_MODULE_LOAD_DECLINE;
5635  }
5636 
5637  if (pjsip_evsub_init_module(ast_sip_get_pjsip_endpoint()) != PJ_SUCCESS) {
5638  ast_log(LOG_ERROR, "Could not initialize pjsip evsub module.\n");
5641  return AST_MODULE_LOAD_DECLINE;
5642  }
5643 
5644  /* Once pjsip_evsub_init_module succeeds we cannot unload.
5645  * Keep all module_load errors above this point. */
5647 
5648  pjsip_media_type_init2(&rlmi_media_type, "application", "rlmi+xml");
5649 
5650  pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &str_PUBLISH);
5651 
5654  } else {
5655  struct stasis_subscription *sub;
5656 
5660  }
5661 
5666  ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
5668 
5670 
5672  AST_TEST_REGISTER(complex_resource_tree);
5673  AST_TEST_REGISTER(bad_resource);
5674  AST_TEST_REGISTER(bad_branch);
5675  AST_TEST_REGISTER(duplicate_resource);
5676  AST_TEST_REGISTER(loop);
5677  AST_TEST_REGISTER(bad_event);
5678 
5679  return AST_MODULE_LOAD_SUCCESS;
5680 }
int ast_sched_start_thread(struct ast_sched_context *con)
Start a thread for processing scheduler entries.
Definition: sched.c:195
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND
static pjsip_media_type rlmi_media_type
static struct pjsip_module pubsub_module
#define ast_test_flag(p, flag)
Definition: utils.h:63
static int persistence_generator_data_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int ami_show_resource_lists(struct mansession *s, const struct message *m)
static int persistence_endpoint_struct2str(const void *obj, const intptr_t *args, char **buf)
static void * publication_resource_alloc(const char *name)
Allocator for publication resource.
static 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...
Definition: sched.c:76
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
Register a regex for multiple fields within an object.
Definition: sorcery.c:1160
#define CHARFLDSET(type, field)
A helper macro to pass the appropriate arguments to aco_option_register for OPT_CHAR_ARRAY_T.
Full structure for sorcery.
Definition: sorcery.c:230
Type for a default handler that should do nothing.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1079
static void * subscription_persistence_alloc(const char *name)
Allocator for subscription persistence.
Structure used for persisting an inbound subscription.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static int persistence_tag_struct2str(const void *obj, const intptr_t *args, char **buf)
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:456
static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
#define NULL
Definition: resample.c:96
static int apply_list_configuration(struct ast_sorcery *sorcery)
static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
static struct ast_cli_entry cli_commands[]
Type for default option handler for character array strings.
Type for default option handler for bools (ast_true/ast_false)
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
#define ast_log
Definition: astobj2.c:42
#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 FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
struct ast_module * self
Definition: module.h:342
A resource tree.
Type for default option handler for unsigned integers.
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:838
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3315
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:236
static int persistence_tag_str2struct(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)
#define LOG_ERROR
Definition: logger.h:285
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:477
#define stasis_subscribe_pool(topic, callback, data)
Definition: stasis.h:682
static int subscription_persistence_load(void *data)
Function which loads and recreates persisted subscriptions upon startup when the system is fully boot...
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:1720
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
struct ast_flags ast_options
Definition: options.c:61
static struct ast_sorcery * sorcery
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define AMI_SHOW_SUBSCRIPTIONS_INBOUND
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1025
struct stasis_forward * sub
Definition: res_corosync.c:240
static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
static int persistence_generator_data_struct2str(const void *obj, const intptr_t *args, char **buf)
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269
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
static int resource_endpoint_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)

◆ parse_simple_message_summary()

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

Definition at line 3585 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_mwi_notify_request().

3587 {
3588  char *line;
3589  char *buffer;
3590  int found_counts = 0;
3591 
3592  if (ast_strlen_zero(body) || !summary) {
3593  return -1;
3594  }
3595 
3596  buffer = ast_strdupa(body);
3597  memset(summary, 0, sizeof(*summary));
3598 
3599  while ((line = ast_read_line_from_buffer(&buffer))) {
3600  line = ast_str_to_lower(line);
3601 
3602  if (sscanf(line, "voice-message: %d/%d (%d/%d)",
3603  &summary->voice_messages_new, &summary->voice_messages_old,
3604  &summary->voice_messages_urgent_new, &summary->voice_messages_urgent_old)) {
3605  found_counts = 1;
3606  } else {
3607  sscanf(line, "message-account: %s", summary->message_account);
3608  }
3609  }
3610 
3611  return !found_counts;
3612 }
char message_account[PJSIP_MAX_URL_SIZE]
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition: strings.h:1268
char * ast_read_line_from_buffer(char **buffer)
Read lines from a string buffer.
Definition: strings.c:372

◆ persistence_endpoint_str2struct()

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

Definition at line 4673 of file res_pjsip_pubsub.c.

References ast_strdup, subscription_persistence::endpoint, and ast_variable::value.

Referenced by load_module().

4674 {
4675  struct subscription_persistence *persistence = obj;
4676 
4677  persistence->endpoint = ast_strdup(var->value);
4678  return 0;
4679 }
Structure used for persisting an inbound subscription.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243

◆ persistence_endpoint_struct2str()

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

Definition at line 4681 of file res_pjsip_pubsub.c.

References ast_strdup, and subscription_persistence::endpoint.

Referenced by load_module().

4682 {
4683  const struct subscription_persistence *persistence = obj;
4684 
4685  *buf = ast_strdup(persistence->endpoint);
4686  return 0;
4687 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Structure used for persisting an inbound subscription.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243

◆ persistence_expires_str2struct()

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

Definition at line 4738 of file res_pjsip_pubsub.c.

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

Referenced by load_module().

4739 {
4740  struct subscription_persistence *persistence = obj;
4741  return ast_get_timeval(var->value, &persistence->expires, ast_tv(0, 0), NULL);
4742 }
Structure used for persisting an inbound subscription.
#define NULL
Definition: resample.c:96
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
get values from config variables.
Definition: main/utils.c:2171
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:226

◆ persistence_expires_struct2str()

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

Definition at line 4744 of file res_pjsip_pubsub.c.

References ast_asprintf, and subscription_persistence::expires.

Referenced by load_module().

4745 {
4746  const struct subscription_persistence *persistence = obj;
4747  return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0;
4748 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Structure used for persisting an inbound subscription.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269

◆ persistence_generator_data_str2struct()

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

Definition at line 4705 of file res_pjsip_pubsub.c.

References ast_json_load_string(), subscription_persistence::generator_data, and ast_variable::value.

Referenced by load_module().

4706 {
4707  struct subscription_persistence *persistence = obj;
4708  struct ast_json_error error;
4709 
4710  /* We tolerate a failure of the JSON to load and instead start fresh, since this field
4711  * originates from the persistence code and not a user.
4712  */
4713  persistence->generator_data = ast_json_load_string(var->value, &error);
4714 
4715  return 0;
4716 }
Structure used for persisting an inbound subscription.
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
Definition: json.c:546
JSON parsing error information.
Definition: json.h:829
int error(const char *format,...)
Definition: utils/frame.c:999
struct ast_json * generator_data

◆ persistence_generator_data_struct2str()

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

Definition at line 4718 of file res_pjsip_pubsub.c.

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

Referenced by load_module().

4719 {
4720  const struct subscription_persistence *persistence = obj;
4721  char *value;
4722 
4723  if (!persistence->generator_data) {
4724  return 0;
4725  }
4726 
4727  value = ast_json_dump_string(persistence->generator_data);
4728  if (!value) {
4729  return -1;
4730  }
4731 
4732  *buf = ast_strdup(value);
4733  ast_json_free(value);
4734 
4735  return 0;
4736 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void ast_json_free(void *p)
Asterisk&#39;s custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:763
Structure used for persisting an inbound subscription.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
int value
Definition: syslog.c:37
struct ast_json * generator_data

◆ persistence_tag_str2struct()

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

Definition at line 4689 of file res_pjsip_pubsub.c.

References ast_strdup, subscription_persistence::tag, and ast_variable::value.

Referenced by load_module().

4690 {
4691  struct subscription_persistence *persistence = obj;
4692 
4693  persistence->tag = ast_strdup(var->value);
4694  return 0;
4695 }
Structure used for persisting an inbound subscription.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243

◆ persistence_tag_struct2str()

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

Definition at line 4697 of file res_pjsip_pubsub.c.

References ast_strdup, and subscription_persistence::tag.

Referenced by load_module().

4698 {
4699  const struct subscription_persistence *persistence = obj;
4700 
4701  *buf = ast_strdup(persistence->tag);
4702  return 0;
4703 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Structure used for persisting an inbound subscription.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243

◆ populate_list()

static int populate_list ( struct resource_list list,
const char *  event,
const char **  resources,
size_t  num_resources 
)
static

Set properties on an allocated resource list.

Parameters
listThe list to set details on.
eventThe list's event.
resourcesArray of resources to add to the list.
num_resourcesNumber of resources in the array.
Return values
0Success
non-zeroFailure

Definition at line 4942 of file res_pjsip_pubsub.c.

References ast_copy_string(), ast_free, ast_strdup, AST_VECTOR_APPEND, resource_list::event, and resource_list::items.

Referenced by create_resource_list().

4943 {
4944  int i;
4945 
4946  ast_copy_string(list->event, event, sizeof(list->event));
4947 
4948  for (i = 0; i < num_resources; ++i) {
4949  char *resource = ast_strdup(resources[i]);
4950 
4951  if (!resource || AST_VECTOR_APPEND(&list->items, resource)) {
4952  ast_free(resource);
4953  return -1;
4954  }
4955  }
4956  return 0;
4957 }
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
Definition: astman.c:222
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define ast_free(a)
Definition: astmm.h:182
struct resources items
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401

◆ publication_cmp_fn()

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

Definition at line 2701 of file res_pjsip_pubsub.c.

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

Referenced by ast_sip_register_publish_handler().

2702 {
2703  const struct ast_sip_publication *publication1 = obj;
2704  const struct ast_sip_publication *publication2 = arg;
2705  const int *entity_tag = arg;
2706 
2707  return (publication1->entity_tag == (flags & OBJ_KEY ? *entity_tag : publication2->entity_tag) ?
2708  CMP_MATCH | CMP_STOP : 0);
2709 }
#define OBJ_KEY
Definition: astobj2.h:1155
Structure representing a SIP publication.
int entity_tag
Entity tag for the publication.

◆ publication_destroy_fn()

static void publication_destroy_fn ( void *  obj)
static

Internal destructor for publications.

Definition at line 3133 of file res_pjsip_pubsub.c.

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

Referenced by sip_create_publication().

3134 {
3135  struct ast_sip_publication *publication = obj;
3136 
3137  ast_debug(3, "Destroying SIP publication\n");
3138 
3139  ao2_cleanup(publication->datastores);
3140  ao2_cleanup(publication->endpoint);
3141 
3143 }
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
struct ao2_container * datastores
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct ast_module * self
Definition: module.h:342
struct ast_sip_endpoint * endpoint
The endpoint with which the subscription is communicating.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Structure representing a SIP publication.

◆ publication_hash_fn()

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

Definition at line 2693 of file res_pjsip_pubsub.c.

References ast_sip_publication::entity_tag, and OBJ_KEY.

Referenced by ast_sip_register_publish_handler().

2694 {
2695  const struct ast_sip_publication *publication = obj;
2696  const int *entity_tag = obj;
2697 
2698  return flags & OBJ_KEY ? *entity_tag : publication->entity_tag;
2699 }
#define OBJ_KEY
Definition: astobj2.h:1155
Structure representing a SIP publication.
int entity_tag
Entity tag for the publication.

◆ publication_resource_alloc()

static void* publication_resource_alloc ( const char *  name)
static

Allocator for publication resource.

Definition at line 567 of file res_pjsip_pubsub.c.

References ast_sorcery_generic_alloc(), and publication_resource_destroy().

Referenced by load_module().

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

◆ publication_resource_destroy()

static void publication_resource_destroy ( void *  obj)
static

Destructor for publication resource.

Definition at line 558 of file res_pjsip_pubsub.c.

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

Referenced by publication_resource_alloc().

559 {
560  struct ast_sip_publication_resource *resource = obj;
561 
562  ast_free(resource->endpoint);
563  ast_variables_destroy(resource->events);
564 }
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
#define ast_free(a)
Definition: astmm.h:182
char * endpoint
Optional name of an endpoint that is only allowed to publish to this resource.
Structure representing a publication resource.
struct ast_variable * events
Mapping for event types to configuration.

◆ publish_add_handler()

static void publish_add_handler ( struct ast_sip_publish_handler handler)
static

Definition at line 2711 of file res_pjsip_pubsub.c.

References AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by ast_sip_register_publish_handler().

2712 {
2714  AST_RWLIST_INSERT_TAIL(&publish_handlers, handler, next);
2716 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:740

◆ publish_expire()

static int publish_expire ( const void *  data)
static

Definition at line 3312 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_publish_request().

3313 {
3314  struct ast_sip_publication *publication = (struct ast_sip_publication*)data;
3315 
3316  ao2_unlink(publication->handler->publications, publication);
3317  publication->sched_id = -1;
3318 
3319  if (ast_sip_push_task(NULL, publish_expire_callback, publication)) {
3320  ao2_cleanup(publication);
3321  }
3322 
3323  return 0;
3324 }
char data[0]
Data containing the above.
static int publish_expire_callback(void *data)
#define NULL
Definition: resample.c:96
struct ast_sip_publish_handler * handler
Handler for this publication.
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Structure representing a SIP publication.
struct ao2_container * publications
Publications.
int sched_id
Scheduled item for expiration of publication.

◆ publish_expire_callback()

static int publish_expire_callback ( void *  data)
static

Definition at line 3301 of file res_pjsip_pubsub.c.

References ao2_cleanup, and RAII_VAR.

Referenced by publish_expire().

3302 {
3303  RAII_VAR(struct ast_sip_publication *, publication, data, ao2_cleanup);
3304 
3305  if (publication->handler->publish_expire) {
3306  publication->handler->publish_expire(publication);
3307  }
3308 
3309  return 0;
3310 }
char data[0]
Data containing the above.
#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:911
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Structure representing a SIP publication.

◆ publish_request_initial()

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

Definition at line 3214 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_publish_request().

3216 {
3217  struct ast_sip_publication *publication;
3218  char *resource_name;
3219  size_t resource_size;
3221  struct ast_variable *event_configuration_name = NULL;
3222  pjsip_uri *request_uri;
3223  pjsip_sip_uri *request_uri_sip;
3224  int resp;
3225 
3226  request_uri = rdata->msg_info.msg->line.req.uri;
3227 
3228  if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
3229  char uri_str[PJSIP_MAX_URL_SIZE];
3230 
3231  pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
3232  ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3233  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3234  return NULL;
3235  }
3236 
3237  request_uri_sip = pjsip_uri_get_uri(request_uri);
3238  resource_size = pj_strlen(&request_uri_sip->user) + 1;
3239  resource_name = ast_alloca(resource_size);
3240  ast_copy_pj_str(resource_name, &request_uri_sip->user, resource_size);
3241 
3242  /*
3243  * We may want to match without any user options getting
3244  * in the way.
3245  */
3246  AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource_name);
3247 
3248  resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name);
3249  if (!resource) {
3250  ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name);
3251  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3252  return NULL;
3253  }
3254 
3255  if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) {
3256  ast_debug(1, "Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n",
3257  resource_name, resource->endpoint, ast_sorcery_object_get_id(endpoint));
3258  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
3259  return NULL;
3260  }
3261 
3262  for (event_configuration_name = resource->events; event_configuration_name; event_configuration_name = event_configuration_name->next) {
3263  if (!strcmp(event_configuration_name->name, handler->event_name)) {
3264  break;
3265  }
3266  }
3267 
3268  if (!event_configuration_name) {
3269  ast_debug(1, "Event '%s' is not configured for '%s'\n", handler->event_name, resource_name);
3270  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
3271  return NULL;
3272  }
3273 
3274  resp = handler->new_publication(endpoint, resource_name, event_configuration_name->value);
3275 
3276  if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3277  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3278  return NULL;
3279  }
3280 
3281  publication = sip_create_publication(endpoint, rdata, S_OR(resource_name, ""), event_configuration_name->value);
3282 
3283  if (!publication) {
3284  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 503, NULL, NULL, NULL);
3285  return NULL;
3286  }
3287 
3288  publication->handler = handler;
3289  if (publication->handler->publication_state_change(publication, rdata->msg_info.msg->body,
3291  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3292  ao2_cleanup(publication);
3293  return NULL;
3294  }
3295 
3296  sip_publication_respond(publication, resp, rdata);
3297 
3298  return publication;
3299 }
struct ast_variable * next
const char * event_name
The name of the event this handler deals with.
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3036
#define LOG_WARNING
Definition: logger.h:274
Structure for variables, used for configurations and for channel variables.
int(* new_publication)(struct ast_sip_endpoint *endpoint, const char *resource, const char *event_configuration)
Called when a PUBLISH to establish a new publication arrives.
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:5240
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#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:911
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
int(* publication_state_change)(struct ast_sip_publication *pub, pjsip_msg_body *body, enum ast_sip_publish_state state)
Published resource has changed states.
struct ast_sip_publish_handler * handler
Handler for this publication.
char * resource
The resource the publication is to.
static int sip_publication_respond(struct ast_sip_publication *pub, int status_code, pjsip_rx_data *rdata)
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
static struct ast_sip_publication * sip_create_publication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, const char *event_configuration_name)
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
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
Structure representing a SIP publication.
Structure representing a publication resource.

◆ pubsub_on_client_refresh()

static void pubsub_on_client_refresh ( pjsip_evsub *  sub)
static

Definition at line 3989 of file res_pjsip_pubsub.c.

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

3990 {
3991  struct sip_subscription_tree *sub_tree;
3992 
3993  if (!(sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
3994  return;
3995  }
3996 
3998  ao2_cleanup(sub_tree);
3999  }
4000 }
static struct pjsip_module pubsub_module
#define ao2_bump(obj)
Definition: astobj2.h:491
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
struct ast_taskprocessor * serializer
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A tree of SIP subscriptions.
static int serialized_pubsub_on_client_refresh(void *userdata)

◆ pubsub_on_evsub_state()

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

Callback sequence for subscription terminate:

  • Client initiated: pjproject receives SUBSCRIBE on the subscription's serializer thread calls pubsub_on_rx_refresh with dialog locked pubsub_on_rx_refresh sets TERMINATE_PENDING pushes serialized_pubsub_on_refresh_timeout returns to pjproject pjproject calls pubsub_on_evsub_state pubsub_evsub_set_state checks state == TERMINATE_IN_PROGRESS (no) ignore and return pjproject unlocks dialog serialized_pubsub_on_refresh_timeout starts (1) locks dialog checks state == TERMINATE_PENDING sets TERMINATE_IN_PROGRESS calls send_notify (2) send_notify ultimately calls pjsip_evsub_send_request pjsip_evsub_send_request calls evsub's set_state set_state calls pubsub_evsub_set_state pubsub_on_evsub_state checks state == TERMINATE_IN_PROGRESS removes the subscriptions cleans up references to evsub sets state = TERMINATED serialized_pubsub_on_refresh_timeout unlocks dialog
  • Subscription timer expires: pjproject timer expires locks dialog calls pubsub_on_server_timeout pubsub_on_server_timeout checks state == NORMAL sets TERMINATE_PENDING pushes serialized_pubsub_on_refresh_timeout returns to pjproject pjproject unlocks dialog serialized_pubsub_on_refresh_timeout starts See (1) Above
  • Transmission failure sending NOTIFY or error response from client pjproject transaction timer expires or non OK response pjproject locks dialog calls pubsub_on_evsub_state with event TSX_STATE pubsub_on_evsub_state checks event == TSX_STATE removes the subscriptions cleans up references to evsub sets state = TERMINATED pjproject unlocks dialog
  • ast_sip_subscription_notify is called checks state == NORMAL if not batched... sets TERMINATE_IN_PROGRESS (if terminate is requested) calls send_notify See (2) Above if batched... sets TERMINATE_PENDING schedules task scheduler runs sched_task sched_task pushes serialized_send_notify serialized_send_notify starts checks state <= TERMINATE_PENDING if state == TERMINATE_PENDING set state = TERMINATE_IN_PROGRESS call send_notify See (2) Above

PJSIP callback when underlying SIP subscription changes state

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

Definition at line 3807 of file res_pjsip_pubsub.c.

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

3808 {
3809  struct sip_subscription_tree *sub_tree =
3810  pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3811 
3812  ast_debug(3, "evsub %p state %s event %s sub_tree %p sub_tree state %s\n", evsub,
3813  pjsip_evsub_get_state_name(evsub), pjsip_event_str(event->type), sub_tree,
3814  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3815 
3816  if (!sub_tree || pjsip_evsub_get_state(evsub) != PJSIP_EVSUB_STATE_TERMINATED) {
3817  return;
3818  }
3819 
3820  /* It's easier to write this as what we WANT to process, then negate it. */
3821  if (!(sub_tree->state == SIP_SUB_TREE_TERMINATE_IN_PROGRESS
3822  || (event->type == PJSIP_EVENT_TSX_STATE && sub_tree->state == SIP_SUB_TREE_NORMAL)
3823  )) {
3824  ast_debug(3, "Do nothing.\n");
3825  return;
3826  }
3827 
3828  if (sub_tree->expiration_task) {
3829  char task_name[256];
3830 
3831  ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
3832  ast_debug(3, "Cancelling timer: %s\n", task_name);
3834  ao2_cleanup(sub_tree->expiration_task);
3835  sub_tree->expiration_task = NULL;
3836  }
3837 
3838  remove_subscription(sub_tree);
3839 
3840  pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
3841 
3842 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
3843  pjsip_evsub_dec_ref(sub_tree->evsub);
3844 #endif
3845 
3846  sub_tree->evsub = NULL;
3847 
3849  ast_sip_dialog_set_endpoint(sub_tree->dlg, NULL);
3850 
3852  shutdown_subscriptions(sub_tree->root);
3853 
3854  sub_tree->state = SIP_SUB_TREE_TERMINATED;
3855  /* Remove evsub's reference to the sub_tree */
3856  ao2_ref(sub_tree, -1);
3857 }
struct ast_sip_subscription * root
static void remove_subscription(struct sip_subscription_tree *obj)
static struct pjsip_module pubsub_module
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
Set a serializer on a SIP dialog so requests and responses are automatically serialized.
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
Definition: astman.c:222
#define NULL
Definition: resample.c:96
static char * sub_tree_state_description[]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_ref(o, delta)
Definition: astobj2.h:464
enum sip_subscription_tree_state state
static void subscription_persistence_remove(struct sip_subscription_tree *sub_tree)
Function which removes persistence of a subscription from sorcery.
struct ast_sip_sched_task * expiration_task
static void shutdown_subscriptions(struct ast_sip_subscription *sub)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
Gets the task name.
A tree of SIP subscriptions.

◆ pubsub_on_refresh_timeout()

static int pubsub_on_refresh_timeout ( void *  userdata)
static

Definition at line 3859 of file res_pjsip_pubsub.c.

References ast_debug, ast_test_suite_event_notify, sip_subscription_tree::dlg, sip_subscription_tree::root, send_notify(), set_state_terminated(), SIP_SUB_TREE_TERMINATE_IN_PROGRESS, SIP_SUB_TREE_TERMINATE_PENDING, sip_subscription_tree::state, and sub_tree_state_description.

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

3860 {
3861  struct sip_subscription_tree *sub_tree = userdata;
3862  pjsip_dialog *dlg = sub_tree->dlg;
3863 
3864  ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
3865  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3866 
3867  pjsip_dlg_inc_lock(dlg);
3868  if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS) {
3869  pjsip_dlg_dec_lock(dlg);
3870  return 0;
3871  }
3872 
3873  if (sub_tree->state == SIP_SUB_TREE_TERMINATE_PENDING) {
3875  set_state_terminated(sub_tree->root);
3876  }
3877 
3878  send_notify(sub_tree, 1);
3879 
3880  ast_test_suite_event_notify(sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED ?
3881  "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_REFRESHED",
3882  "Resource: %s", sub_tree->root->resource);
3883 
3884  pjsip_dlg_dec_lock(dlg);
3885 
3886  return 0;
3887 }
struct ast_sip_subscription * root
static char * sub_tree_state_description[]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
enum sip_subscription_tree_state state
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
Send a NOTIFY request to a subscriber.
static void set_state_terminated(struct ast_sip_subscription *sub)
A tree of SIP subscriptions.

◆ pubsub_on_rx_mwi_notify_request()

static pj_bool_t pubsub_on_rx_mwi_notify_request ( pjsip_rx_data *  rdata)
static

Definition at line 3614 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_notify_request().

3615 {
3617  struct simple_message_summary summary;
3618  const char *endpoint_name;
3619  char *atsign;
3620  char *context;
3621  char *body;
3622  char *mailbox;
3623  int rc;
3624 
3625  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3626  if (!endpoint) {
3627  ast_debug(1, "Incoming MWI: Endpoint not found in rdata (%p)\n", rdata);
3628  rc = 404;
3629  goto error;
3630  }
3631 
3632  endpoint_name = ast_sorcery_object_get_id(endpoint);
3633  ast_debug(1, "Incoming MWI: Found endpoint: %s\n", endpoint_name);
3634  if (ast_strlen_zero(endpoint->incoming_mwi_mailbox)) {
3635  ast_debug(1, "Incoming MWI: No incoming mailbox specified for endpoint '%s'\n", endpoint_name);
3636  ast_test_suite_event_notify("PUBSUB_NO_INCOMING_MWI_MAILBOX",
3637  "Endpoint: %s", endpoint_name);
3638  rc = 404;
3639  goto error;
3640  }
3641 
3642  mailbox = ast_strdupa(endpoint->incoming_mwi_mailbox);
3643  atsign = strchr(mailbox, '@');
3644  if (!atsign) {
3645  ast_debug(1, "Incoming MWI: No '@' found in endpoint %s's incoming mailbox '%s'. Can't parse context\n",
3646  endpoint_name, endpoint->incoming_mwi_mailbox);
3647  rc = 404;
3648  goto error;
3649  }
3650 
3651  *atsign = '\0';
3652  context = atsign + 1;
3653 
3654  body = ast_alloca(rdata->msg_info.msg->body->len + 1);
3655  rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, body,
3656  rdata->msg_info.msg->body->len + 1);
3657 
3658  if (parse_simple_message_summary(body, &summary) != 0) {
3659  ast_debug(1, "Incoming MWI: Endpoint: '%s' There was an issue getting message info from body '%s'\n",
3660  ast_sorcery_object_get_id(endpoint), body);
3661  rc = 404;
3662  goto error;
3663  }
3664 
3665  if (ast_publish_mwi_state(mailbox, context,
3666  summary.voice_messages_new, summary.voice_messages_old)) {
3667  ast_log(LOG_ERROR, "Incoming MWI: Endpoint: '%s' Could not publish MWI to stasis. "
3668  "Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3669  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3670  summary.voice_messages_new, summary.voice_messages_old,
3671  summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3672  rc = 404;
3673  } else {
3674  ast_debug(1, "Incoming MWI: Endpoint: '%s' Mailbox: %s Message-Account: %s Voice-Messages: %d/%d (%d/%d)\n",
3675  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3676  summary.voice_messages_new, summary.voice_messages_old,
3677  summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3678  ast_test_suite_event_notify("PUBSUB_INCOMING_MWI_PUBLISH",
3679  "Endpoint: %s\r\n"
3680  "Mailbox: %s\r\n"
3681  "MessageAccount: %s\r\n"
3682  "VoiceMessagesNew: %d\r\n"
3683  "VoiceMessagesOld: %d\r\n"
3684  "VoiceMessagesUrgentNew: %d\r\n"
3685  "VoiceMessagesUrgentOld: %d",
3686  endpoint_name, endpoint->incoming_mwi_mailbox, summary.message_account,
3687  summary.voice_messages_new, summary.voice_messages_old,
3688  summary.voice_messages_urgent_new, summary.voice_messages_urgent_old);
3689  rc = 200;
3690  }
3691 
3692 error:
3693  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, rc, NULL, NULL, NULL);
3694  return PJ_TRUE;
3695 }
struct ast_sip_endpoint * endpoint
static int parse_simple_message_summary(char *body, struct simple_message_summary *summary)
#define NULL
Definition: resample.c:96
#define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs)
Publish a MWI state update via stasis.
Definition: mwi.h:380
#define ast_strlen_zero(foo)
Definition: strings.h:52
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:204
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#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:911
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define LOG_ERROR
Definition: logger.h:285
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int error(const char *format,...)
Definition: utils/frame.c:999
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116

◆ pubsub_on_rx_notify()

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

Definition at line 3956 of file res_pjsip_pubsub.c.

References ast_sip_subscription::handler, pubsub_module, ast_sip_subscriber::state_change, sub, and ast_sip_subscription_handler::subscriber.

3958 {
3959  struct ast_sip_subscription *sub;
3960 
3961  if (!(sub = pjsip_evsub_get_mod_data(evsub, pubsub_module.id))) {
3962  return;
3963  }
3964 
3965  sub->handler->subscriber->state_change(sub, rdata->msg_info.msg->body,
3966  pjsip_evsub_get_state(evsub));
3967 }
struct ast_sip_subscriber * subscriber
static struct pjsip_module pubsub_module
const struct ast_sip_subscription_handler * handler
Structure representing a "virtual" SIP subscription.
void(* state_change)(struct ast_sip_subscription *sub, pjsip_msg_body *body, enum pjsip_evsub_state state)
A NOTIFY has been received.
struct stasis_forward * sub
Definition: res_corosync.c:240

◆ pubsub_on_rx_notify_request()

static pj_bool_t pubsub_on_rx_notify_request ( pjsip_rx_data *  rdata)
static

Definition at line 3697 of file res_pjsip_pubsub.c.

References ast_sip_is_content_type(), and pubsub_on_rx_mwi_notify_request().

Referenced by pubsub_on_rx_request().

3698 {
3699  if (rdata->msg_info.msg->body &&
3700  ast_sip_is_content_type(&rdata->msg_info.msg->body->content_type,
3701  "application", "simple-message-summary")) {
3702  return pubsub_on_rx_mwi_notify_request(rdata);
3703  }
3704  return PJ_FALSE;
3705 }
static pj_bool_t pubsub_on_rx_mwi_notify_request(pjsip_rx_data *rdata)
int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
Checks if the given content type matches type/subtype.
Definition: res_pjsip.c:5259

◆ pubsub_on_rx_publish_request()

static pj_bool_t pubsub_on_rx_publish_request ( pjsip_rx_data *  rdata)
static

Definition at line 3326 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_request().

3327 {
3328  pjsip_event_hdr *event_header;
3330  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3331  char event[32];
3332  static const pj_str_t str_sip_if_match = { "SIP-If-Match", 12 };
3333  pjsip_generic_string_hdr *etag_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_sip_if_match, NULL);
3334  enum sip_publish_type publish_type;
3335  RAII_VAR(struct ast_sip_publication *, publication, NULL, ao2_cleanup);
3336  unsigned int expires = 0;
3337  int entity_id, response = 0;
3338 
3339  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
3340  ast_assert(endpoint != NULL);
3341 
3342  event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
3343  if (!event_header) {
3344  ast_log(LOG_WARNING, "Incoming PUBLISH request from %s with no Event header\n",
3345  ast_sorcery_object_get_id(endpoint));
3346  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3347  return PJ_TRUE;
3348  }
3349  ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
3350 
3351  handler = find_pub_handler(event);
3352  if (!handler) {
3353  ast_log(LOG_WARNING, "No registered publish handler for event %s from %s\n", event,
3354  ast_sorcery_object_get_id(endpoint));
3355  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3356  return PJ_TRUE;
3357  }
3358 
3359  publish_type = determine_sip_publish_type(rdata, etag_hdr, &expires, &entity_id);
3360 
3361  /* If this is not an initial publish ensure that a publication is present */
3362  if ((publish_type != SIP_PUBLISH_INITIAL) && (publish_type != SIP_PUBLISH_UNKNOWN)) {
3363  if (!(publication = ao2_find(handler->publications, &entity_id, OBJ_KEY | OBJ_UNLINK))) {
3364  static const pj_str_t str_conditional_request_failed = { "Conditional Request Failed", 26 };
3365 
3366  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 412, &str_conditional_request_failed,
3367  NULL, NULL);
3368  return PJ_TRUE;
3369  }
3370 
3371  /* Per the RFC every response has to have a new entity tag */
3372  publication->entity_tag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
3373 
3374  /* Update the expires here so that the created responses will contain the correct value */
3375  publication->expires = expires;
3376  }
3377 
3378  switch (publish_type) {
3379  case SIP_PUBLISH_INITIAL:
3380  publication = publish_request_initial(endpoint, rdata, handler);
3381  break;
3382  case SIP_PUBLISH_REFRESH:
3383  case SIP_PUBLISH_MODIFY:
3384  if (handler->publication_state_change(publication, rdata->msg_info.msg->body,
3386  /* If an error occurs we want to terminate the publication */
3387  expires = 0;
3388  }
3389  response = 200;
3390  break;
3391  case SIP_PUBLISH_REMOVE:
3392  handler->publication_state_change(publication, rdata->msg_info.msg->body,
3394  response = 200;
3395  break;
3396  case SIP_PUBLISH_UNKNOWN:
3397  default:
3398  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3399  break;
3400  }
3401 
3402  if (publication) {
3403  if (expires) {
3404  ao2_link(handler->publications, publication);
3405 
3406  AST_SCHED_REPLACE_UNREF(publication->sched_id, sched, expires * 1000, publish_expire, publication,
3407  ao2_ref(_data, -1), ao2_ref(publication, -1), ao2_ref(publication, +1));
3408  } else {
3409  AST_SCHED_DEL_UNREF(sched, publication->sched_id, ao2_ref(publication, -1));
3410  }
3411  }
3412 
3413  if (response) {
3414  sip_publication_respond(publication, response, rdata);
3415  }
3416 
3417  return PJ_TRUE;
3418 }
static struct ast_sip_publish_handler * find_pub_handler(const char *event)
struct sched_id * sched_id
Definition: sched.c:79
#define OBJ_KEY
Definition: astobj2.h:1155
#define LOG_WARNING
Definition: logger.h:274
static int publish_expire(const void *data)
Definition: sched.c:76
#define AST_SCHED_DEL_UNREF(sched, id, refcall)
schedule task to get deleted and call unref function
Definition: sched.h:80
Definition: astman.c:222
#define ast_assert(a)
Definition: utils.h:695
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:5240
#define NULL
Definition: resample.c:96
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
#define ast_log
Definition: astobj2.c:42
#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:911
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
int(* publication_state_change)(struct ast_sip_publication *pub, pjsip_msg_body *body, enum ast_sip_publish_state state)
Published resource has changed states.
static struct ast_sip_publication * publish_request_initial(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, struct ast_sip_publish_handler *handler)
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)
Callbacks that publication handlers will define.
static int sip_publication_respond(struct ast_sip_publication *pub, int status_code, pjsip_rx_data *rdata)
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
#define AST_SCHED_REPLACE_UNREF(id, sched, when, callback, data, unrefcall, addfailcall, refcall)
Definition: sched.h:150
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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
sip_publish_type
The types of PUBLISH messages defined in RFC 3903.
Definition: sip.h:1562
Structure representing a SIP publication.
static const pj_str_t str_event_name
struct ao2_container * publications
Publications.
static int esc_etag_counter
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ pubsub_on_rx_refresh()

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

Called whenever an in-dialog SUBSCRIBE is received.

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

In either case we push serialized_pubsub_on_refresh_timeout to send an appropriate NOTIFY request.

Definition at line 3911 of file res_pjsip_pubsub.c.

References ao2_bump, ao2_cleanup, ao2_ref, ast_debug, ast_log, ast_sip_push_task(), ast_sip_sched_task_cancel(), ast_sip_sched_task_get_name(), create_require_eventlist(), sip_subscription_tree::evsub, sip_subscription_tree::expiration_task, sip_subscription_tree::is_list, LOG_ERROR, NULL, pubsub_module, serialized_pubsub_on_refresh_timeout(), sip_subscription_tree::serializer, SIP_SUB_TREE_NORMAL, SIP_SUB_TREE_TERMINATE_PENDING, sip_subscription_tree::state, sub_tree_state_description, SUBSCRIPTION_PERSISTENCE_REFRESHED, and subscription_persistence_update().

3913 {
3914  struct sip_subscription_tree *sub_tree;
3915 
3916  sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
3917  ast_debug(3, "evsub %p sub_tree %p sub_tree state %s\n", evsub, sub_tree,
3918  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3919 
3920  if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
3921  return;
3922  }
3923 
3924  if (sub_tree->expiration_task) {
3925  char task_name[256];
3926 
3927  ast_sip_sched_task_get_name(sub_tree->expiration_task, task_name, sizeof(task_name));
3928  ast_debug(3, "Cancelling timer: %s\n", task_name);
3930  ao2_cleanup(sub_tree->expiration_task);
3931  sub_tree->expiration_task = NULL;
3932  }
3933 
3934  /* PJSIP will set the evsub's state to terminated before calling into this function
3935  * if the Expires value of the incoming SUBSCRIBE is 0.
3936  */
3937 
3938  if (pjsip_evsub_get_state(sub_tree->evsub) == PJSIP_EVSUB_STATE_TERMINATED) {
3940  }
3941 
3943 
3945  /* If we can't push the NOTIFY refreshing task...we'll just go with it. */
3946  ast_log(LOG_ERROR, "Failed to push task to send NOTIFY.\n");
3947  sub_tree->state = SIP_SUB_TREE_NORMAL;
3948  ao2_ref(sub_tree, -1);
3949  }
3950 
3951  if (sub_tree->is_list) {
3952  pj_list_insert_before(res_hdr, create_require_eventlist(rdata->tp_info.pool));
3953  }
3954 }
static struct pjsip_module pubsub_module
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
#define NULL
Definition: resample.c:96
static pjsip_require_hdr * create_require_eventlist(pj_pool_t *pool)
Shortcut method to create a Require: eventlist header.
static char * sub_tree_state_description[]
#define ao2_bump(obj)
Definition: astobj2.h:491
static int serialized_pubsub_on_refresh_timeout(void *userdata)
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.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
enum sip_subscription_tree_state state
#define LOG_ERROR
Definition: logger.h:285
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
struct ast_sip_sched_task * expiration_task
struct ast_taskprocessor * serializer
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
Gets the task name.
A tree of SIP subscriptions.

◆ pubsub_on_rx_request()

static pj_bool_t pubsub_on_rx_request ( pjsip_rx_data *  rdata)
static

Opaque structure representing an RFC 3265 SIP subscription.

Definition at line 3707 of file res_pjsip_pubsub.c.

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

3708 {
3709  if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method())) {
3710  return pubsub_on_rx_subscribe_request(rdata);
3711  } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_publish_method)) {
3712  return pubsub_on_rx_publish_request(rdata);
3713  } else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_notify_method)) {
3714  return pubsub_on_rx_notify_request(rdata);
3715  }
3716 
3717  return PJ_FALSE;
3718 }
static pj_bool_t pubsub_on_rx_publish_request(pjsip_rx_data *rdata)
const pjsip_method pjsip_publish_method
Defined method for PUBLISH.
static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
static pj_bool_t pubsub_on_rx_notify_request(pjsip_rx_data *rdata)

◆ pubsub_on_rx_subscribe_request()

static pj_bool_t pubsub_on_rx_subscribe_request ( pjsip_rx_data *  rdata)
static

Definition at line 2969 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_request().

2970 {
2971  pjsip_expires_hdr *expires_header;
2973  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2974  struct sip_subscription_tree *sub_tree;
2976  char *resource;
2977  pjsip_uri *request_uri;
2978  pjsip_sip_uri *request_uri_sip;
2979  size_t resource_size;
2980  int resp;
2981  struct resource_tree tree;
2982  pj_status_t dlg_status;
2983 
2984  endpoint = ast_pjsip_rdata_get_endpoint(rdata);
2985  ast_assert(endpoint != NULL);
2986 
2987  if (!endpoint->subscription.allow) {
2988  ast_log(LOG_WARNING, "Subscriptions not permitted for endpoint %s.\n", ast_sorcery_object_get_id(endpoint));
2989  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 603, NULL, NULL, NULL);
2990  return PJ_TRUE;
2991  }
2992 
2993  request_uri = rdata->msg_info.msg->line.req.uri;
2994 
2995  if (!PJSIP_URI_SCHEME_IS_SIP(request_uri) && !PJSIP_URI_SCHEME_IS_SIPS(request_uri)) {
2996  char uri_str[PJSIP_MAX_URL_SIZE];
2997 
2998  pjsip_uri_print(PJSIP_URI_IN_REQ_URI, request_uri, uri_str, sizeof(uri_str));
2999  ast_log(LOG_WARNING, "Request URI '%s' is not a sip: or sips: URI.\n", uri_str);
3000  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
3001  return PJ_TRUE;
3002  }
3003 
3004  request_uri_sip = pjsip_uri_get_uri(request_uri);
3005  resource_size = pj_strlen(&request_uri_sip->user) + 1;
3006  resource = ast_alloca(resource_size);
3007  ast_copy_pj_str(resource, &request_uri_sip->user, resource_size);
3008 
3009  /*
3010  * We may want to match without any user options getting
3011  * in the way.
3012  */
3014 
3015  expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
3016  if (expires_header) {
3017  if (expires_header->ivalue == 0) {
3018  ast_debug(1, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
3019  ast_sorcery_object_get_id(endpoint));
3020  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
3021  return PJ_TRUE;
3022  }
3023  if (expires_header->ivalue < endpoint->subscription.minexpiry) {
3024  ast_log(LOG_WARNING, "Subscription expiration %d is too brief for endpoint %s. Minimum is %u\n",
3025  expires_header->ivalue, ast_sorcery_object_get_id(endpoint), endpoint->subscription.minexpiry);
3026  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 423, NULL, NULL, NULL);
3027  return PJ_TRUE;
3028  }
3029  }
3030 
3032  if (!handler) {
3033  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3034  return PJ_TRUE;
3035  }
3036 
3037  generator = subscription_get_generator_from_rdata(rdata, handler);
3038  if (!generator) {
3039  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 489, NULL, NULL, NULL);
3040  return PJ_TRUE;
3041  }
3042 
3043  memset(&tree, 0, sizeof(tree));
3044  resp = build_resource_tree(endpoint, handler, resource, &tree,
3046  if (!PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
3047  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, resp, NULL, NULL, NULL);
3048  resource_tree_destroy(&tree);
3049  return PJ_TRUE;
3050  }
3051 
3052  sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
3053  if (!sub_tree) {
3054  if (dlg_status != PJ_EEXISTS) {
3055  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3056  }
3057  } else {
3058  struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
3059 
3060  if (!ind) {
3061  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3062  resource_tree_destroy(&tree);
3063  return PJ_TRUE;
3064  }
3065 
3066  ind->sub_tree = ao2_bump(sub_tree);
3067  /* Since this is a normal subscribe, pjproject takes care of the timer */
3069 
3070  sub_tree->persistence = subscription_persistence_create(sub_tree);
3072  sip_subscription_accept(sub_tree, rdata, resp);
3073  if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {
3074  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3075  ao2_ref(sub_tree, -1);
3076  ast_free(ind);
3077  }
3078  }
3079 
3080  resource_tree_destroy(&tree);
3081  return PJ_TRUE;
3082 }
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3036
Pubsub body generator.
static struct subscription_persistence * subscription_persistence_create(struct sip_subscription_tree *sub_tree)
Function which creates initial persistence information of a subscription in sorcery.
#define LOG_WARNING
Definition: logger.h:274
static int initial_notify_task(void *obj)
#define ast_assert(a)
Definition: utils.h:695
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:5240
#define NULL
Definition: resample.c:96
struct subscription_persistence * persistence
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
#define ao2_bump(obj)
Definition: astobj2.h:491
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.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
A resource tree.
#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:911
static struct ast_sip_pubsub_body_generator * subscription_get_generator_from_rdata(pjsip_rx_data *rdata, const struct ast_sip_subscription_handler *handler)
Retrieve a body generator using the Accept header of an rdata message.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
static void resource_tree_destroy(struct resource_tree *tree)
Destroy a resource tree.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
static struct ast_generator generator
Definition: app_fax.c:359
static struct ast_sip_subscription_handler * subscription_get_handler_from_rdata(pjsip_rx_data *rdata, const char *endpoint)
Retrieve a handler using the Event header of an rdata message.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
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.
#define ast_free(a)
Definition: astmm.h:182
struct ast_taskprocessor * serializer
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
static struct sip_subscription_tree * create_subscription_tree(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree, pj_status_t *dlg_status, struct subscription_persistence *persistence)
Create a subscription tree based on a resource tree.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct sip_subscription_tree * sub_tree
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
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: res_pjsip.h:63
A tree of SIP subscriptions.
static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
Check if the rdata has a Supported header containing &#39;eventlist&#39;.

◆ pubsub_on_server_timeout()

static void pubsub_on_server_timeout ( pjsip_evsub *  sub)
static

Definition at line 4002 of file res_pjsip_pubsub.c.

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

4003 {
4004  struct sip_subscription_tree *sub_tree;
4005 
4006  /* PJSIP does not terminate the server timeout timer when a SUBSCRIBE
4007  * with Expires: 0 arrives to end a subscription, nor does it terminate
4008  * this timer when we send a NOTIFY request in response to receiving such
4009  * a SUBSCRIBE. PJSIP does not stop the server timeout timer until the
4010  * NOTIFY transaction has finished (either through receiving a response
4011  * or through a transaction timeout).
4012  *
4013  * Therefore, it is possible that we can be told that a server timeout
4014  * occurred after we already thought that the subscription had been
4015  * terminated. In such a case, we will have already removed the sub_tree
4016  * from the evsub's mod_data array.
4017  */
4018 
4019  sub_tree = pjsip_evsub_get_mod_data(evsub, pubsub_module.id);
4020  if (!sub_tree || sub_tree->state != SIP_SUB_TREE_NORMAL) {
4021  return;
4022  }
4023 
4026  sub_tree->state = SIP_SUB_TREE_NORMAL;
4027  ao2_cleanup(sub_tree);
4028  }
4029 }
static struct pjsip_module pubsub_module
#define ao2_bump(obj)
Definition: astobj2.h:491
static int serialized_pubsub_on_refresh_timeout(void *userdata)
enum sip_subscription_tree_state state
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
struct ast_taskprocessor * serializer
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A tree of SIP subscriptions.

◆ remove_subscription()

static void remove_subscription ( struct sip_subscription_tree obj)
static

Definition at line 1182 of file res_pjsip_pubsub.c.

References ast_debug, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_sip_subscription_get_resource_name(), ast_sorcery_object_get_id(), sip_subscription_tree::endpoint, sip_subscription_tree::next, and sip_subscription_tree::root.

Referenced by pubsub_on_evsub_state().

1183 {
1184  struct sip_subscription_tree *i;
1185 
1188  if (i == obj) {
1190  if (i->root) {
1191  ast_debug(2, "Removing subscription '%s->%s' from list of subscriptions\n",
1193  }
1194  break;
1195  }
1196  }
1199 }
struct ast_sip_subscription * root
struct ast_sip_endpoint * endpoint
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:569
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
const char * ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
Get the name of the subscribed resource.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:544
struct sip_subscription_tree * next
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:616
A tree of SIP subscriptions.

◆ resource_endpoint_handler()

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

Definition at line 5526 of file res_pjsip_pubsub.c.

References ast_free, ast_strdup, ast_sip_publication_resource::endpoint, and ast_variable::value.

Referenced by load_module().

5527 {
5528  struct ast_sip_publication_resource *resource = obj;
5529 
5530  ast_free(resource->endpoint);
5531  resource->endpoint = ast_strdup(var->value);
5532 
5533  return 0;
5534 }
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define ast_free(a)
Definition: astmm.h:182
char * endpoint
Optional name of an endpoint that is only allowed to publish to this resource.
Structure representing a publication resource.

◆ resource_event_handler()

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

Definition at line 5536 of file res_pjsip_pubsub.c.

References ast_strlen_zero, ast_variable_new, ast_sip_publication_resource::events, item, ast_variable::name, ast_variable::next, and ast_variable::value.

Referenced by load_module().

5537 {
5538  struct ast_sip_publication_resource *resource = obj;
5539  /* The event configuration name starts with 'event_' so skip past it to get the real name */
5540  const char *event = var->name + 6;
5541  struct ast_variable *item;
5542 
5543  if (ast_strlen_zero(event) || ast_strlen_zero(var->value)) {
5544  return -1;
5545  }
5546 
5547  item = ast_variable_new(event, var->value, "");
5548  if (!item) {
5549  return -1;
5550  }
5551 
5552  if (resource->events) {
5553  item->next = resource->events;
5554  }
5555  resource->events = item;
5556 
5557  return 0;
5558 }
struct ast_variable * next
Structure for variables, used for configurations and for channel variables.
Definition: astman.c:222
static struct aco_type item
Definition: test_config.c:1463
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_variable_new(name, value, filename)
Structure representing a publication resource.
struct ast_variable * events
Mapping for event types to configuration.

◆ resource_list_alloc()

static void* resource_list_alloc ( const char *  name)
static

Definition at line 4764 of file res_pjsip_pubsub.c.

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

Referenced by apply_list_configuration().

4765 {
4766  struct resource_list *list;
4767 
4768  list = ast_sorcery_generic_alloc(sizeof(*list), resource_list_destructor);
4769  if (!list) {
4770  return NULL;
4771  }
4772 
4774  ao2_cleanup(list);
4775  return NULL;
4776  }
4777 
4778  return list;
4779 }
#define RESOURCE_LIST_INIT_SIZE
#define NULL
Definition: resample.c:96
Resource list configuration item.
static void resource_list_destructor(void *obj)
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
struct resources items
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728

◆ resource_list_apply_handler()

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

Definition at line 4838 of file res_pjsip_pubsub.c.

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

Referenced by apply_list_configuration().

4839 {
4840  struct resource_list *list = obj;
4841 
4842  if (ast_strlen_zero(list->event)) {
4843  ast_log(LOG_WARNING, "Resource list '%s' has no event set\n",
4845  return -1;
4846  }
4847 
4848  if (AST_VECTOR_SIZE(&list->items) == 0) {
4849  ast_log(LOG_WARNING, "Resource list '%s' has no list items\n",
4851  return -1;
4852  }
4853 
4854  return 0;
4855 }
#define LOG_WARNING
Definition: logger.h:274
Resource list configuration item.
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct resources items
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ resource_list_destructor()

static void resource_list_destructor ( void *  obj)
static

Definition at line 4752 of file res_pjsip_pubsub.c.

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

Referenced by resource_list_alloc().

4753 {
4754  struct resource_list *list = obj;
4755  int i;
4756 
4757  for (i = 0; i < AST_VECTOR_SIZE(&list->items); ++i) {
4758  ast_free((char *) AST_VECTOR_GET(&list->items, i));
4759  }
4760 
4761  AST_VECTOR_FREE(&list->items);
4762 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
Resource list configuration item.
#define ast_free(a)
Definition: astmm.h:182
struct resources items
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ resource_tree_destroy()

static void resource_tree_destroy ( struct resource_tree tree)
static

Destroy a resource tree.

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

Parameters
treeThe tree to destroy.

Definition at line 1109 of file res_pjsip_pubsub.c.

References resource_tree::root, and tree_node_destroy().

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

1110 {
1111  if (tree) {
1112  tree_node_destroy(tree->root);
1113  }
1114 }
struct tree_node * root
static void tree_node_destroy(struct tree_node *node)
Destructor for a tree node.

◆ retrieve_resource_list()

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

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

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

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

Definition at line 902 of file res_pjsip_pubsub.c.

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

Referenced by build_node_children(), and build_resource_tree().

903 {
904  struct resource_list *list;
905 
906  list = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "resource_list", resource);
907  if (!list) {
908  return NULL;
909  }
910 
911  if (strcmp(list->event, event)) {
912  ast_log(LOG_WARNING, "Found resource list %s, but its event type (%s) does not match SUBSCRIBE's (%s)\n",
913  resource, list->event, event);
914  ao2_cleanup(list);
915  return NULL;
916  }
917 
918  return list;
919 }
#define LOG_WARNING
Definition: logger.h:274
Definition: astman.c:222
#define NULL
Definition: resample.c:96
Resource list configuration item.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_log
Definition: astobj2.c:42
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ rlmi_clone_data()

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

Definition at line 2140 of file res_pjsip_pubsub.c.

Referenced by build_rlmi_body().

2141 {
2142  const pj_xml_node *rlmi = data;
2143 
2144  return pj_xml_clone(pool, rlmi);
2145 }
static pj_pool_t * pool
Global memory pool for configuration and timers.

◆ rlmi_print_body()

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

Definition at line 2127 of file res_pjsip_pubsub.c.

References AST_PJSIP_XML_PROLOG_LEN.

Referenced by build_rlmi_body().

2128 {
2129  int num_printed;
2130  pj_xml_node *rlmi = msg_body->data;
2131 
2132  num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE);
2133  if (num_printed <= AST_PJSIP_XML_PROLOG_LEN) {
2134  return -1;
2135  }
2136 
2137  return num_printed;
2138 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_PJSIP_XML_PROLOG_LEN
Length of the XML prolog when printing presence or other XML in PJSIP.

◆ sched_cb()

static int sched_cb ( const void *  data)
static

Definition at line 2500 of file res_pjsip_pubsub.c.

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

Referenced by schedule_notification().

2501 {
2502  struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
2503 
2504  /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
2505  if (ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree)) {
2506  ao2_cleanup(sub_tree);
2507  }
2508 
2509  return 0;
2510 }
static int serialized_send_notify(void *userdata)
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
struct ast_taskprocessor * serializer
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A tree of SIP subscriptions.

◆ schedule_notification()

static int schedule_notification ( struct sip_subscription_tree sub_tree)
static

Definition at line 2512 of file res_pjsip_pubsub.c.

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

Referenced by ast_sip_subscription_notify().

2513 {
2514  /* There's already a notification scheduled */
2515  if (sub_tree->notify_sched_id > -1) {
2516  return 0;
2517  }
2518 
2519  sub_tree->send_scheduled_notify = 1;
2521  if (sub_tree->notify_sched_id < 0) {
2522  ao2_cleanup(sub_tree);
2523  return -1;
2524  }
2525 
2526  return 0;
2527 }
static int sched_cb(const void *data)
Definition: sched.c:76
#define ao2_bump(obj)
Definition: astobj2.h:491
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition: sched.c:565
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
unsigned int send_scheduled_notify
unsigned int notification_batch_interval

◆ send_notify()

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

Send a NOTIFY request to a subscriber.

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

Definition at line 2425 of file res_pjsip_pubsub.c.

References ast_shutdown_final(), create_require_eventlist(), sip_subscription_tree::evsub, generate_notify_body(), sip_subscription_tree::is_list, NULL, sip_subscription_tree::persistence, sip_subscription_tree::root, sip_subscription_tree::send_scheduled_notify, and sip_subscription_send_request().

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

2426 {
2427  pjsip_evsub *evsub = sub_tree->evsub;
2428  pjsip_tx_data *tdata;
2429 
2430  if (ast_shutdown_final()
2431  && sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED
2432  && sub_tree->persistence) {
2433  return 0;
2434  }
2435 
2436  if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
2437  NULL, NULL, &tdata) != PJ_SUCCESS) {
2438  return -1;
2439  }
2440 
2441  tdata->msg->body = generate_notify_body(tdata->pool, sub_tree->root, force_full_state);
2442  if (!tdata->msg->body) {
2443  pjsip_tx_data_dec_ref(tdata);
2444  return -1;
2445  }
2446 
2447  if (sub_tree->is_list) {
2448  pjsip_require_hdr *require = create_require_eventlist(tdata->pool);
2449  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) require);
2450  }
2451 
2452  if (sip_subscription_send_request(sub_tree, tdata)) {
2453  /* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */
2454  return -1;
2455  }
2456 
2457  sub_tree->send_scheduled_notify = 0;
2458 
2459  return 0;
2460 }
struct ast_sip_subscription * root
#define NULL
Definition: resample.c:96
struct subscription_persistence * persistence
static pjsip_require_hdr * create_require_eventlist(pj_pool_t *pool)
Shortcut method to create a Require: eventlist header.
static pjsip_msg_body * generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root, unsigned int force_full_state)
Create the body for a NOTIFY request.
static int sip_subscription_send_request(struct sip_subscription_tree *sub_tree, pjsip_tx_data *tdata)
int ast_shutdown_final(void)
Definition: asterisk.c:1829
unsigned int send_scheduled_notify

◆ serialized_pubsub_on_client_refresh()

static int serialized_pubsub_on_client_refresh ( void *  userdata)
static

Definition at line 3969 of file res_pjsip_pubsub.c.

References ao2_cleanup, sip_subscription_tree::evsub, and NULL.

Referenced by pubsub_on_client_refresh().

3970 {
3971  struct sip_subscription_tree *sub_tree = userdata;
3972  pjsip_tx_data *tdata;
3973 
3974  if (!sub_tree->evsub) {
3975  ao2_cleanup(sub_tree);
3976  return 0;
3977  }
3978 
3979  if (pjsip_evsub_initiate(sub_tree->evsub, NULL, -1, &tdata) == PJ_SUCCESS) {
3980  pjsip_evsub_send_request(sub_tree->evsub, tdata);
3981  } else {
3982  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
3983  }
3984 
3985  ao2_cleanup(sub_tree);
3986  return 0;
3987 }
#define NULL
Definition: resample.c:96
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A tree of SIP subscriptions.

◆ serialized_pubsub_on_refresh_timeout()

static int serialized_pubsub_on_refresh_timeout ( void *  userdata)
static

Definition at line 3889 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_refresh(), and pubsub_on_server_timeout().

3890 {
3891  struct sip_subscription_tree *sub_tree = userdata;
3892 
3893  ast_debug(3, "sub_tree %p sub_tree state %s\n", sub_tree,
3894  (sub_tree ? sub_tree_state_description[sub_tree->state] : "UNKNOWN"));
3895 
3896  pubsub_on_refresh_timeout(userdata);
3897  ao2_cleanup(sub_tree);
3898 
3899  return 0;
3900 }
static char * sub_tree_state_description[]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static int pubsub_on_refresh_timeout(void *userdata)
enum sip_subscription_tree_state state
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A tree of SIP subscriptions.

◆ serialized_send_notify()

static int serialized_send_notify ( void *  userdata)
static

Definition at line 2462 of file res_pjsip_pubsub.c.

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

Referenced by sched_cb().

2463 {
2464  struct sip_subscription_tree *sub_tree = userdata;
2465  pjsip_dialog *dlg = sub_tree->dlg;
2466 
2467  pjsip_dlg_inc_lock(dlg);
2468 
2469  /* It's possible that between when the notification was scheduled
2470  * and now a new SUBSCRIBE arrived requiring full state to be
2471  * sent out in an immediate NOTIFY. It's also possible that we're
2472  * already processing a terminate. If that has happened, we need to
2473  * bail out here instead of sending the batched NOTIFY.
2474  */
2475 
2476  if (sub_tree->state >= SIP_SUB_TREE_TERMINATE_IN_PROGRESS
2477  || !sub_tree->send_scheduled_notify) {
2478  pjsip_dlg_dec_lock(dlg);
2479  ao2_cleanup(sub_tree);
2480  return 0;
2481  }
2482 
2483  if (sub_tree->root->subscription_state == PJSIP_EVSUB_STATE_TERMINATED) {
2485  }
2486 
2487  send_notify(sub_tree, 0);
2488 
2490  sub_tree->state == SIP_SUB_TREE_TERMINATED
2491  ? "SUBSCRIPTION_TERMINATED" : "SUBSCRIPTION_STATE_CHANGED",
2492  "Resource: %s", sub_tree->root->resource);
2493 
2494  sub_tree->notify_sched_id = -1;
2495  pjsip_dlg_dec_lock(dlg);
2496  ao2_cleanup(sub_tree);
2497  return 0;
2498 }
struct ast_sip_subscription * root
enum sip_subscription_tree_state state
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
Send a NOTIFY request to a subscriber.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
unsigned int send_scheduled_notify
A tree of SIP subscriptions.

◆ set_state_terminated()

static void set_state_terminated ( struct ast_sip_subscription sub)
static

Definition at line 3720 of file res_pjsip_pubsub.c.

References AST_VECTOR_GET, and AST_VECTOR_SIZE.

Referenced by pubsub_on_refresh_timeout().

3721 {
3722  int i;
3723 
3724  sub->subscription_state = PJSIP_EVSUB_STATE_TERMINATED;
3725  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
3726  set_state_terminated(AST_VECTOR_GET(&sub->children, i));
3727  }
3728 }
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
static void set_state_terminated(struct ast_sip_subscription *sub)
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ shutdown_subscriptions()

static void shutdown_subscriptions ( struct ast_sip_subscription sub)
static

Definition at line 1328 of file res_pjsip_pubsub.c.

References AST_VECTOR_GET, AST_VECTOR_SIZE, ast_sip_subscription::handler, and ast_sip_subscription_handler::subscription_shutdown.

Referenced by pubsub_on_evsub_state().

1329 {
1330  int i;
1331 
1332  if (!sub) {
1333  return;
1334  }
1335 
1336  if (AST_VECTOR_SIZE(&sub->children) > 0) {
1337  for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
1338  shutdown_subscriptions(AST_VECTOR_GET(&sub->children, i));
1339  }
1340  return;
1341  }
1342 
1343  /* We notify subscription shutdown only on the tree leaves. */
1344  if (sub->handler->subscription_shutdown) {
1345  sub->handler->subscription_shutdown(sub);
1346  }
1347 }
const struct ast_sip_subscription_handler * handler
static void shutdown_subscriptions(struct ast_sip_subscription *sub)
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
void(* subscription_shutdown)(struct ast_sip_subscription *subscription)
Called when a subscription is to be destroyed.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ sip_create_publication()

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

Definition at line 3145 of file res_pjsip_pubsub.c.

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

Referenced by publish_request_initial().

3147 {
3148  struct ast_sip_publication *publication;
3149  pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
3150  size_t resource_len = strlen(resource) + 1, event_configuration_name_len = strlen(event_configuration_name) + 1;
3151  char *dst;
3152 
3153  ast_assert(endpoint != NULL);
3154 
3155  if (!(publication = ao2_alloc(sizeof(*publication) + resource_len + event_configuration_name_len, publication_destroy_fn))) {
3156  return NULL;
3157  }
3158 
3160 
3161  if (!(publication->datastores = ast_datastores_alloc())) {
3162  ao2_ref(publication, -1);
3163  return NULL;
3164  }
3165 
3167  ao2_ref(endpoint, +1);
3168  publication->endpoint = endpoint;
3169  publication->expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
3170  publication->sched_id = -1;
3171  dst = publication->data;
3172  publication->resource = strcpy(dst, resource);
3173  dst += resource_len;
3174  publication->event_configuration_name = strcpy(dst, event_configuration_name);
3175 
3176  return publication;
3177 }
char data[0]
Data containing the above.
static void publication_destroy_fn(void *obj)
Internal destructor for publications.
#define ast_assert(a)
Definition: utils.h:695
#define DEFAULT_PUBLISH_EXPIRES
Default expiration time for PUBLISH if one is not specified.
#define NULL
Definition: resample.c:96
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
struct ao2_container * ast_datastores_alloc(void)
Allocate a specialized data stores container.
Definition: datastore.c:95
struct ao2_container * datastores
struct ast_module * self
Definition: module.h:342
#define ao2_ref(o, delta)
Definition: astobj2.h:464
unsigned int expires
Expiration time of the publication.
char * event_configuration_name
The name of the event type configuration.
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
char * resource
The resource the publication is to.
struct ast_sip_endpoint * endpoint
The endpoint with which the subscription is communicating.
Structure representing a SIP publication.
int entity_tag
Entity tag for the publication.
int sched_id
Scheduled item for expiration of publication.
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443
static int esc_etag_counter

◆ sip_publication_respond()

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

Definition at line 3179 of file res_pjsip_pubsub.c.

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

Referenced by publish_request_initial(), and pubsub_on_rx_publish_request().

3181 {
3182  pjsip_tx_data *tdata;
3183  pjsip_transaction *tsx;
3184 
3185  if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, status_code, NULL, &tdata) != PJ_SUCCESS) {
3186  return -1;
3187  }
3188 
3189  if (PJSIP_IS_STATUS_IN_CLASS(status_code, 200)) {
3190  char buf[30];
3191 
3192  snprintf(buf, sizeof(buf), "%d", pub->entity_tag);
3193  ast_sip_add_header(tdata, "SIP-ETag", buf);
3194 
3195  snprintf(buf, sizeof(buf), "%d", pub->expires);
3196  ast_sip_add_header(tdata, "Expires", buf);
3197  }
3198 
3199  if (pjsip_tsx_create_uas(&pubsub_module, rdata, &tsx) != PJ_SUCCESS) {
3200  pjsip_tx_data_dec_ref(tdata);
3201  return -1;
3202  }
3203 
3204  pjsip_tsx_recv_msg(tsx, rdata);
3205 
3206  if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
3207  pjsip_tx_data_dec_ref(tdata);
3208  return -1;
3209  }
3210 
3211  return 0;
3212 }
static struct pjsip_module pubsub_module
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define NULL
Definition: resample.c:96
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition: res_pjsip.c:5063
unsigned int expires
Expiration time of the publication.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
int entity_tag
Entity tag for the publication.

◆ sip_subscription_accept()

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

Definition at line 2606 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_subscribe_request().

2607 {
2608  pjsip_hdr res_hdr;
2609 
2610  /* If this is a persistence recreation the subscription has already been accepted */
2611  if (ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_PERSISTENCE)) {
2612  return 0;
2613  }
2614 
2615  pj_list_init(&res_hdr);
2616  if (sub_tree->is_list) {
2617  /* If subscribing to a list, our response has to have a Require: eventlist header in it */
2618  pj_list_insert_before(&res_hdr, create_require_eventlist(rdata->tp_info.pool));
2619  }
2620 
2621  return pjsip_evsub_accept(sub_tree->evsub, rdata, response, &res_hdr) == PJ_SUCCESS ? 0 : -1;
2622 }
static struct pjsip_module pubsub_module
static pjsip_require_hdr * create_require_eventlist(pj_pool_t *pool)
Shortcut method to create a Require: eventlist header.
#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:2638
#define MOD_DATA_PERSISTENCE

◆ sip_subscription_send_request()

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

Definition at line 1989 of file res_pjsip_pubsub.c.

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

Referenced by send_notify().

1990 {
1991 #ifdef TEST_FRAMEWORK
1992  struct ast_sip_endpoint *endpoint = sub_tree->endpoint;
1993  pjsip_evsub *evsub = sub_tree->evsub;
1994 #endif
1995  int res;
1996 
1997  if (allocate_tdata_buffer(tdata)) {
1998  ast_log(LOG_ERROR, "SIP request %s is too large to send.\n", tdata->info);
1999  pjsip_tx_data_dec_ref(tdata);
2000  return -1;
2001  }
2002 
2003  res = pjsip_evsub_send_request(sub_tree->evsub, tdata);
2004 
2006 
2007  ast_test_suite_event_notify("SUBSCRIPTION_STATE_SET",
2008  "StateText: %s\r\n"
2009  "Endpoint: %s\r\n",
2010  pjsip_evsub_get_state_name(evsub),
2011  ast_sorcery_object_get_id(endpoint));
2012 
2013  return (res == PJ_SUCCESS ? 0 : -1);
2014 }
struct ast_sip_endpoint * endpoint
#define NULL
Definition: resample.c:96
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.
#define ast_log
Definition: astobj2.c:42
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
#define LOG_ERROR
Definition: logger.h:285
static int allocate_tdata_buffer(pjsip_tx_data *tdata)
Pre-allocate a buffer for the transmission.

◆ sip_subscription_to_ami()

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

Definition at line 1820 of file res_pjsip_pubsub.c.

References ast_callerid_merge(), ast_copy_pj_str(), ast_copy_string(), ast_sorcery_object_get_id(), ast_str_append(), sip_subscription_tree::dlg, sip_subscription_tree::endpoint, sip_subscription_tree::evsub, ast_sip_subscription::handler, ast_sip_endpoint::id, ast_party_id::name, NULL, ast_party_id::number, sip_subscription_tree::role, sip_subscription_tree::root, S_COR, ast_sip_endpoint_id_configuration::self, sip_subscription_roles_map, str, ast_party_name::str, ast_party_number::str, ast_sip_subscription_handler::to_ami, ast_party_name::valid, and ast_party_number::valid.

Referenced by ami_subscription_detail(), and cli_show_subscription_common().

1822 {
1823  char str[256];
1824  struct ast_sip_endpoint_id_configuration *id = &sub_tree->endpoint->id;
1825 
1826  ast_str_append(buf, 0, "Role: %s\r\n",
1827  sip_subscription_roles_map[sub_tree->role]);
1828  ast_str_append(buf, 0, "Endpoint: %s\r\n",
1829  ast_sorcery_object_get_id(sub_tree->endpoint));
1830 
1831  if (sub_tree->dlg) {
1832  ast_copy_pj_str(str, &sub_tree->dlg->call_id->id, sizeof(str));
1833  } else {
1834  ast_copy_string(str, "<unknown>", sizeof(str));
1835  }
1836  ast_str_append(buf, 0, "Callid: %s\r\n", str);
1837 
1838  ast_str_append(buf, 0, "State: %s\r\n", pjsip_evsub_get_state_name(sub_tree->evsub));
1839 
1840  ast_callerid_merge(str, sizeof(str),
1841  S_COR(id->self.name.valid, id->self.name.str, NULL),
1842  S_COR(id->self.number.valid, id->self.number.str, NULL),
1843  "Unknown");
1844 
1845  ast_str_append(buf, 0, "Callerid: %s\r\n", str);
1846 
1847  /* XXX This needs to be done recursively for lists */
1848  if (sub_tree->root->handler->to_ami) {
1849  sub_tree->root->handler->to_ami(sub_tree->root, buf);
1850  }
1851 }
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
struct ast_sip_subscription * root
struct ast_sip_endpoint * endpoint
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
Party identification options for endpoints.
Definition: res_pjsip.h:628
static const char * sip_subscription_roles_map[]
char * str
Subscriber name (Malloced)
Definition: channel.h:265
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:1091
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:5240
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
void(* to_ami)(struct ast_sip_subscription *sub, struct ast_str **buf)
Converts the subscriber to AMI.
enum ast_sip_subscription_role role
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
Definition: callerid.c:1073
const struct ast_sip_subscription_handler * handler
#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:85
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:847
struct ast_party_id self
Definition: res_pjsip.h:629
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343

◆ sub_add_handler()

static void sub_add_handler ( struct ast_sip_subscription_handler handler)
static

Definition at line 2756 of file res_pjsip_pubsub.c.

References AST_RWLIST_INSERT_TAIL, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, and ast_sip_publish_handler::next.

Referenced by ast_sip_register_subscription_handler().

2757 {
2761 }
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:740

◆ sub_persistence_recreate()

static int sub_persistence_recreate ( void *  obj)
static

Definition at line 1556 of file res_pjsip_pubsub.c.

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

Referenced by subscription_persistence_recreate().

1557 {
1558  struct persistence_recreate_data *recreate_data = obj;
1559  struct subscription_persistence *persistence = recreate_data->persistence;
1560  pjsip_rx_data *rdata = recreate_data->rdata;
1561  struct ast_sip_endpoint *endpoint;
1562  struct sip_subscription_tree *sub_tree;
1565  char *resource;
1566  pjsip_sip_uri *request_uri;
1567  size_t resource_size;
1568  int resp;
1569  struct resource_tree tree;
1570  pjsip_expires_hdr *expires_header;
1571  int64_t expires;
1572 
1573  request_uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri);
1574  resource_size = pj_strlen(&request_uri->user) + 1;
1575  resource = ast_alloca(resource_size);
1576  ast_copy_pj_str(resource, &request_uri->user, resource_size);
1577 
1578  /*
1579  * We may want to match without any user options getting
1580  * in the way.
1581  */
1583 
1584  handler = subscription_get_handler_from_rdata(rdata, persistence->endpoint);
1585  if (!handler || !handler->notifier) {
1586  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get subscription handler.\n",
1587  persistence->endpoint);
1588  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1589  return 0;
1590  }
1591 
1592  generator = subscription_get_generator_from_rdata(rdata, handler);
1593  if (!generator) {
1594  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Body generator not available.\n",
1595  persistence->endpoint);
1596  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1597  return 0;
1598  }
1599 
1600  ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data,
1601  pubsub_module.id, MOD_DATA_PERSISTENCE, persistence);
1602 
1603  /* Getting the endpoint may take some time that can affect the expiration. */
1604  endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1605  persistence->endpoint);
1606  if (!endpoint) {
1607  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The endpoint was not found\n",
1608  persistence->endpoint);
1609  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1610  return 0;
1611  }
1612 
1613  /* Update the expiration header with the new expiration */
1614  expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
1615  rdata->msg_info.msg->hdr.next);
1616  if (!expires_header) {
1617  expires_header = pjsip_expires_hdr_create(rdata->tp_info.pool, 0);
1618  if (!expires_header) {
1619  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not update expires header.\n",
1620  persistence->endpoint);
1621  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1622  ao2_ref(endpoint, -1);
1623  return 0;
1624  }
1625  pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr *) expires_header);
1626  }
1627 
1628  expires = (ast_tvdiff_ms(persistence->expires, ast_tvnow()) / 1000);
1629  if (expires <= 0) {
1630  /* The subscription expired since we started recreating the subscription. */
1631  ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1632  persistence->endpoint, persistence->tag);
1633  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1634  ao2_ref(endpoint, -1);
1635  return 0;
1636  }
1637  expires_header->ivalue = expires;
1638 
1639  memset(&tree, 0, sizeof(tree));
1640  resp = build_resource_tree(endpoint, handler, resource, &tree,
1642  if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
1643  pj_status_t dlg_status;
1644 
1645  sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,
1646  &tree, &dlg_status, persistence);
1647  if (!sub_tree) {
1648  if (dlg_status != PJ_EEXISTS) {
1649  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",
1650  persistence->endpoint);
1651  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1652  }
1653  } else {
1654  struct initial_notify_data *ind = ast_malloc(sizeof(*ind));
1655 
1656  if (!ind) {
1657  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1658  goto error;
1659  }
1660 
1661  ind->sub_tree = ao2_bump(sub_tree);
1662  ind->expires = expires_header->ivalue;
1663 
1665  if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {
1666  /* Could not send initial subscribe NOTIFY */
1667  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
1668  ao2_ref(sub_tree, -1);
1669  ast_free(ind);
1670  }
1671  }
1672  } else {
1673  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1674  }
1675 
1676 error:
1677  resource_tree_destroy(&tree);
1678  ao2_ref(endpoint, -1);
1679 
1680  return 0;
1681 }
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3036
static struct pjsip_module pubsub_module
Pubsub body generator.
#define LOG_WARNING
Definition: logger.h:274
static int initial_notify_task(void *obj)
struct ast_sip_notifier * notifier
Structure used for persisting an inbound subscription.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
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:5240
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ao2_bump(obj)
Definition: astobj2.h:491
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.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
A resource tree.
#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:2670
static struct ast_sip_pubsub_body_generator * subscription_get_generator_from_rdata(pjsip_rx_data *rdata, const struct ast_sip_subscription_handler *handler)
Retrieve a body generator using the Accept header of an rdata message.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
static void resource_tree_destroy(struct resource_tree *tree)
Destroy a resource tree.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2233
static struct ast_generator generator
Definition: app_fax.c:359
static struct ast_sip_subscription_handler * subscription_get_handler_from_rdata(pjsip_rx_data *rdata, const char *endpoint)
Retrieve a handler using the Event header of an rdata message.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
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.
struct subscription_persistence * persistence
#define ast_free(a)
Definition: astmm.h:182
struct ast_taskprocessor * serializer
static struct sip_subscription_tree * create_subscription_tree(const struct ast_sip_subscription_handler *handler, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource, struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree, pj_status_t *dlg_status, struct subscription_persistence *persistence)
Create a subscription tree based on a resource tree.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
struct sip_subscription_tree * sub_tree
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
int error(const char *format,...)
Definition: utils/frame.c:999
#define MOD_DATA_PERSISTENCE
A tree of SIP subscriptions.
static int ast_sip_pubsub_has_eventlist_support(pjsip_rx_data *rdata)
Check if the rdata has a Supported header containing &#39;eventlist&#39;.

◆ sub_tree_subscription_terminate_cb()

static int sub_tree_subscription_terminate_cb ( void *  data)
static

Definition at line 572 of file res_pjsip_pubsub.c.

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

Referenced by sub_tree_transport_cb().

573 {
574  struct sip_subscription_tree *sub_tree = data;
575 
576  if (!sub_tree->evsub) {
577  /* Something else already terminated the subscription. */
578  ao2_ref(sub_tree, -1);
579  return 0;
580  }
581 
582  ast_debug(3, "Transport destroyed. Removing subscription '%s->%s' prune on boot: %d\n",
583  sub_tree->persistence->endpoint, sub_tree->root->resource,
584  sub_tree->persistence->prune_on_boot);
585 
587  pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
588 
589  ao2_ref(sub_tree, -1);
590  return 0;
591 }
struct ast_sip_subscription * root
struct subscription_persistence * persistence
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_ref(o, delta)
Definition: astobj2.h:464
enum sip_subscription_tree_state state
A tree of SIP subscriptions.

◆ sub_tree_transport_cb()

static void sub_tree_transport_cb ( void *  data)
static

Definition at line 603 of file res_pjsip_pubsub.c.

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

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

604 {
605  struct sip_subscription_tree *sub_tree = data;
606 
607  /*
608  * Push off the subscription termination to the serializer to
609  * avoid deadlock. Another thread could be trying to send a
610  * message on the subscription that can deadlock with this
611  * thread.
612  */
613  ao2_ref(sub_tree, +1);
615  sub_tree)) {
616  ao2_ref(sub_tree, -1);
617  }
618 }
static int sub_tree_subscription_terminate_cb(void *data)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
struct ast_taskprocessor * serializer
A tree of SIP subscriptions.

◆ subscription_get_generator_from_rdata()

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

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

Definition at line 831 of file res_pjsip_pubsub.c.

References ast_copy_pj_str(), ast_copy_string(), AST_SIP_MAX_ACCEPT, ast_sip_subscription_handler::body_type, ast_sip_notifier::default_accept, exceptional_accept(), find_body_generator(), ast_sip_subscription_handler::notifier, and while().

Referenced by pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

833 {
834  pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
835  char accept[AST_SIP_MAX_ACCEPT][64];
836  size_t num_accept_headers = 0;
837 
838  while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next)) &&
839  (num_accept_headers < AST_SIP_MAX_ACCEPT)) {
840  int i;
841 
842  for (i = 0; i < accept_header->count && num_accept_headers < AST_SIP_MAX_ACCEPT; ++i) {
843  if (!exceptional_accept(&accept_header->values[i])) {
844  ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
845  ++num_accept_headers;
846  }
847  }
848  }
849 
850  if (num_accept_headers == 0) {
851  /* If a SUBSCRIBE contains no Accept headers, then we must assume that
852  * the default accept type for the event package is to be used.
853  */
854  ast_copy_string(accept[0], handler->notifier->default_accept, sizeof(accept[0]));
855  num_accept_headers = 1;
856  }
857 
858  return find_body_generator(accept, num_accept_headers, handler->body_type);
859 }
struct ast_sip_notifier * notifier
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:5240
static int exceptional_accept(const pj_str_t *accept)
Is the Accept header from the SUBSCRIBE in the list of exceptions?
while(1)
Definition: ast_expr2f.c:894
#define AST_SIP_MAX_ACCEPT
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
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)
const char * default_accept
Default body type defined for the event package this notifier handles.

◆ subscription_get_handler_from_rdata()

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

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

Definition at line 771 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_subscribe_request(), and sub_persistence_recreate().

772 {
773  pjsip_event_hdr *event_header;
774  char event[32];
776 
777  event_header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_event_name, rdata->msg_info.msg->hdr.next);
778  if (!event_header) {
779  ast_log(LOG_WARNING, "Incoming SUBSCRIBE request from %s with no Event header\n",
780  endpoint ? endpoint : "Unknown");
781  return NULL;
782  }
783  ast_copy_pj_str(event, &event_header->event_type, sizeof(event));
784 
786  if (!handler) {
787  ast_log(LOG_WARNING, "No registered subscribe handler for event %s from %s\n", event,
788  endpoint ? endpoint : "Unknown");
789  }
790 
791  return handler;
792 }
#define LOG_WARNING
Definition: logger.h:274
Definition: astman.c:222
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:5240
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
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
static struct ast_sip_subscription_handler * find_sub_handler_for_event_name(const char *event_name)
static const pj_str_t str_event_name

◆ subscription_persistence_alloc()

static void* subscription_persistence_alloc ( const char *  name)
static

Allocator for subscription persistence.

Definition at line 631 of file res_pjsip_pubsub.c.

References ast_sorcery_generic_alloc(), and subscription_persistence_destroy().

Referenced by load_module().

632 {
634 }
static void subscription_persistence_destroy(void *obj)
Destructor for subscription persistence.
Structure used for persisting an inbound subscription.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728

◆ subscription_persistence_create()

static struct subscription_persistence* subscription_persistence_create ( struct sip_subscription_tree sub_tree)
static

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

Definition at line 637 of file res_pjsip_pubsub.c.

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

Referenced by pubsub_on_rx_subscribe_request().

638 {
639  char tag[PJ_GUID_STRING_LENGTH + 1];
640 
641  /* The id of this persistence object doesn't matter as we keep it on the subscription and don't need to
642  * look it up by id at all.
643  */
645  "subscription_persistence", NULL);
646 
647  pjsip_dialog *dlg = sub_tree->dlg;
648 
649  if (!persistence) {
650  return NULL;
651  }
652 
653  persistence->endpoint = ast_strdup(ast_sorcery_object_get_id(sub_tree->endpoint));
654  ast_copy_pj_str(tag, &dlg->local.info->tag, sizeof(tag));
655  persistence->tag = ast_strdup(tag);
656 
657  ast_sorcery_create(ast_sip_get_sorcery(), persistence);
658  return persistence;
659 }
struct ast_sip_endpoint * endpoint
Structure used for persisting an inbound subscription.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
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:5240
#define NULL
Definition: resample.c:96
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2057
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.

◆ subscription_persistence_destroy()

static void subscription_persistence_destroy ( void *  obj)
static

Destructor for subscription persistence.

Definition at line 621 of file res_pjsip_pubsub.c.

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

Referenced by subscription_persistence_alloc().

622 {
623  struct subscription_persistence *persistence = obj;
624 
625  ast_free(persistence->endpoint);
626  ast_free(persistence->tag);
627  ast_json_unref(persistence->generator_data);
628 }
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
Structure used for persisting an inbound subscription.
#define ast_free(a)
Definition: astmm.h:182
struct ast_json * generator_data

◆ subscription_persistence_event_cb()

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

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

Definition at line 1772 of file res_pjsip_pubsub.c.

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

Referenced by load_module().

1773 {
1774  struct ast_json_payload *payload;
1775  const char *type;
1776 
1778  return;
1779  }
1780 
1781  payload = stasis_message_data(message);
1782  type = ast_json_string_get(ast_json_object_get(payload->json, "type"));
1783 
1784  /* This subscription only responds to the FullyBooted event so that all modules have been loaded when we
1785  * recreate SIP subscriptions.
1786  */
1787  if (strcmp(type, "FullyBooted")) {
1788  return;
1789  }
1790 
1791  /* This has to be here so the subscription is recreated when the body generator is available */
1793 
1794  /* Once the system is fully booted we don't care anymore */
1795  stasis_unsubscribe(sub);
1796 }
static const char type[]
Definition: chan_ooh323.c:109
struct ast_json * json
Definition: json.h:1025
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
#define NULL
Definition: resample.c:96
struct stasis_message_type * ast_manager_get_generic_type(void)
Get the stasis_message_type for generic messages.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:5138
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
static int subscription_persistence_load(void *data)
Function which loads and recreates persisted subscriptions upon startup when the system is fully boot...
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:973
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

◆ subscription_persistence_load()

static int subscription_persistence_load ( void *  data)
static

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

Definition at line 1750 of file res_pjsip_pubsub.c.

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

Referenced by load_module(), and subscription_persistence_event_cb().

1751 {
1752  struct ao2_container *persisted_subscriptions = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
1753  "subscription_persistence", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1754  pj_pool_t *pool;
1755 
1756  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "rtd%p", PJSIP_POOL_RDATA_LEN,
1757  PJSIP_POOL_RDATA_INC);
1758  if (!pool) {
1759  ast_log(LOG_WARNING, "Could not create a memory pool for recreating SIP subscriptions\n");
1760  return 0;
1761  }
1762 
1763  ao2_callback(persisted_subscriptions, OBJ_NODATA, subscription_persistence_recreate, pool);
1764 
1765  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1766 
1767  ao2_ref(persisted_subscriptions, -1);
1768  return 0;
1769 }
#define LOG_WARNING
Definition: logger.h:274
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
static pj_pool_t * pool
Global memory pool for configuration and timers.
Perform no matching, return all objects.
Definition: sorcery.h:123
Return all matching objects.
Definition: sorcery.h:120
#define NULL
Definition: resample.c:96
static int subscription_persistence_recreate(void *obj, void *arg, int flags)
Callback function to perform the actual recreation of a subscription.
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
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
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
Generic container type.

◆ subscription_persistence_recreate()

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

Callback function to perform the actual recreation of a subscription.

Definition at line 1684 of file res_pjsip_pubsub.c.

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

Referenced by subscription_persistence_load().

1685 {
1686  struct subscription_persistence *persistence = obj;
1687  pj_pool_t *pool = arg;
1688  struct ast_taskprocessor *serializer;
1689  pjsip_rx_data rdata;
1690  struct persistence_recreate_data recreate_data;
1691 
1692  /* If this subscription used a reliable transport it can't be reestablished so remove it */
1693  if (persistence->prune_on_boot) {
1694  ast_debug(3, "Deleting subscription marked as 'prune' from persistent store '%s' %s\n",
1695  persistence->endpoint, persistence->tag);
1696  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1697  return 0;
1698  }
1699 
1700  /* If this subscription has already expired remove it */
1701  if (ast_tvdiff_ms(persistence->expires, ast_tvnow()) <= 0) {
1702  ast_debug(3, "Expired subscription retrived from persistent store '%s' %s\n",
1703  persistence->endpoint, persistence->tag);
1704  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1705  return 0;
1706  }
1707 
1708  memset(&rdata, 0, sizeof(rdata));
1709  pj_pool_reset(pool);
1710  rdata.tp_info.pool = pool;
1711 
1712  if (ast_sip_create_rdata_with_contact(&rdata, persistence->packet, persistence->src_name,
1713  persistence->src_port, persistence->transport_key, persistence->local_name,
1714  persistence->local_port, persistence->contact_uri)) {
1715  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n",
1716  persistence->endpoint);
1717  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1718  return 0;
1719  }
1720 
1721  if (rdata.msg_info.msg->type != PJSIP_REQUEST_MSG) {
1722  ast_log(LOG_NOTICE, "Failed recreating '%s' subscription: Stored a SIP response instead of a request.\n",
1723  persistence->endpoint);
1724  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1725  return 0;
1726  }
1727 
1728  /* Continue the remainder in the distributor serializer */
1729  serializer = ast_sip_get_distributor_serializer(&rdata);
1730  if (!serializer) {
1731  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not get distributor serializer.\n",
1732  persistence->endpoint);
1733  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1734  return 0;
1735  }
1736  recreate_data.persistence = persistence;
1737  recreate_data.rdata = &rdata;
1739  &recreate_data)) {
1740  ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not continue under distributor serializer.\n",
1741  persistence->endpoint);
1742  ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
1743  }
1744  ast_taskprocessor_unreference(serializer);
1745 
1746  return 0;
1747 }
#define LOG_WARNING
Definition: logger.h:274
char local_name[PJ_INET6_ADDRSTRLEN]
static pj_pool_t * pool
Global memory pool for configuration and timers.
Structure used for persisting an inbound subscription.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
char packet[PJSIP_MAX_PKT_LEN]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:5218
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2233
struct subscription_persistence * persistence
static int sub_persistence_recreate(void *obj)
struct ast_taskprocessor * ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
Determine the distributor serializer for the SIP message.
#define LOG_NOTICE
Definition: logger.h:263
int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type, const char *local_name, int local_port, const char *contact_uri)
General purpose method for creating an rdata structure using specific information.
Definition: res_pjsip.c:4271
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
char contact_uri[PJSIP_MAX_URL_SIZE]
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
char src_name[PJ_INET6_ADDRSTRLEN]

◆ subscription_persistence_remove()

static void subscription_persistence_remove ( struct sip_subscription_tree sub_tree)
static

Function which removes persistence of a subscription from sorcery.

Definition at line 745 of file res_pjsip_pubsub.c.

References ao2_ref, ast_debug, ast_sip_get_sorcery(), AST_SIP_MAX_ACCEPT, ast_sip_transport_monitor_unregister(), ast_sorcery_delete(), ast_sorcery_object_get_id(), ast_sip_pubsub_body_generator::body_type, sip_subscription_tree::endpoint, ast_sip_subscription_handler::event_name, find_body_generator(), find_sub_handler_for_event_name(), NULL, sip_subscription_tree::persistence, subscription_persistence::prune_on_boot, sip_subscription_tree::root, sub_tree_transport_cb(), and sip_subscription_tree::transport.

Referenced by pubsub_on_evsub_state().

746 {
747  if (!sub_tree->persistence) {
748  return;
749  }
750 
751  if (sub_tree->persistence->prune_on_boot && sub_tree->transport) {
752  ast_debug(3, "Unregistering transport monitor on %s '%s->%s'\n",
753  sub_tree->transport->obj_name,
754  sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
755  sub_tree->root ? sub_tree->root->resource : "Unknown");
757  sub_tree_transport_cb, sub_tree, NULL);
758  }
759 
761  ao2_ref(sub_tree->persistence, -1);
762  sub_tree->persistence = NULL;
763 }
struct ast_sip_subscription * root
struct ast_sip_endpoint * endpoint
pjsip_transport * transport
#define NULL
Definition: resample.c:96
struct subscription_persistence * persistence
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static void sub_tree_transport_cb(void *data)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2233
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.

◆ subscription_persistence_update()

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

Function which updates persistence information of a subscription in sorcery.

Definition at line 662 of file res_pjsip_pubsub.c.

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

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

664 {
665  pjsip_dialog *dlg;
666 
667  if (!sub_tree->persistence) {
668  return;
669  }
670 
671  ast_debug(3, "Updating persistence for '%s->%s' prune on boot: %s\n",
672  sub_tree->persistence->endpoint, sub_tree->root->resource,
673  sub_tree->persistence->prune_on_boot ? "yes" : "no");
674 
675  dlg = sub_tree->dlg;
676  sub_tree->persistence->cseq = dlg->local.cseq;
677 
678  if (rdata) {
679  unsigned int expires;
680  pjsip_expires_hdr *expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
681  pjsip_contact_hdr *contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
682 
683  expires = expires_hdr ? expires_hdr->ivalue : DEFAULT_PUBLISH_EXPIRES;
684  sub_tree->persistence->expires = ast_tvadd(ast_tvnow(), ast_samp2tv(expires, 1));
685 
686  if (contact_hdr) {
687  if (contact_hdr) {
689  sub_tree->persistence->prune_on_boot =
691  (pjsip_sip_uri *)pjsip_uri_get_uri(contact_hdr->uri),
692  sub_tree->endpoint, rdata);
693 
694  if (sub_tree->persistence->prune_on_boot) {
695  ast_debug(3, "adding transport monitor on %s for '%s->%s' prune on boot: %d\n",
696  rdata->tp_info.transport->obj_name,
697  sub_tree->persistence->endpoint, sub_tree->root->resource,
698  sub_tree->persistence->prune_on_boot);
699  sub_tree->transport = rdata->tp_info.transport;
700  ast_sip_transport_monitor_register(rdata->tp_info.transport,
701  sub_tree_transport_cb, sub_tree);
702  /*
703  * FYI: ast_sip_transport_monitor_register holds a reference to the sub_tree
704  */
705  }
706  }
707  }
708 
709  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri,
710  sub_tree->persistence->contact_uri, sizeof(sub_tree->persistence->contact_uri));
711  } else {
712  ast_log(LOG_WARNING, "Contact not updated due to missing contact header\n");
713  }
714 
715  /* When receiving a packet on an streaming transport, it's possible to receive more than one SIP
716  * message at a time into the rdata->pkt_info.packet buffer. However, the rdata->msg_info.msg_buf
717  * will always point to the proper SIP message that is to be processed. When updating subscription
718  * persistence that is pulled from persistent storage, though, the rdata->pkt_info.packet will
719  * only ever have a single SIP message on it, and so we base persistence on that.
720  */
723  if (rdata->msg_info.msg_buf) {
724  ast_copy_string(sub_tree->persistence->packet, rdata->msg_info.msg_buf,
725  MIN(sizeof(sub_tree->persistence->packet), rdata->msg_info.len + 1));
726  } else {
727  ast_copy_string(sub_tree->persistence->packet, rdata->pkt_info.packet,
728  sizeof(sub_tree->persistence->packet));
729  }
730  }
731  ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name,
732  sizeof(sub_tree->persistence->src_name));
733  sub_tree->persistence->src_port = rdata->pkt_info.src_port;
734  ast_copy_string(sub_tree->persistence->transport_key, rdata->tp_info.transport->type_name,
735  sizeof(sub_tree->persistence->transport_key));
736  ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host,
737  sizeof(sub_tree->persistence->local_name));
738  sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port;
739  }
740 
742 }
static const char type[]
Definition: chan_ooh323.c:109
struct ast_sip_subscription * root
struct ast_sip_endpoint * endpoint
#define LOG_WARNING
Definition: logger.h:274
enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.
char local_name[PJ_INET6_ADDRSTRLEN]
pjsip_transport * transport
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define DEFAULT_PUBLISH_EXPIRES
Default expiration time for PUBLISH if one is not specified.
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:5240
#define NULL
Definition: resample.c:96
char packet[PJSIP_MAX_PKT_LEN]
struct subscription_persistence * persistence
#define MIN(a, b)
Definition: utils.h:226
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static void sub_tree_transport_cb(void *data)
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:238
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Definition: res_pjsip.c:3723
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
char contact_uri[PJSIP_MAX_URL_SIZE]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char src_name[PJ_INET6_ADDRSTRLEN]
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2145

◆ subscription_setup_dialog()

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

Definition at line 1396 of file res_pjsip_pubsub.c.

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

Referenced by ast_sip_create_subscription(), and create_subscription_tree().

1397 {
1398  sub_tree->dlg = dlg;
1399  ast_sip_dialog_set_serializer(dlg, sub_tree->serializer);
1400  ast_sip_dialog_set_endpoint(dlg, sub_tree->endpoint);
1401  pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
1402  pjsip_dlg_inc_session(dlg, &pubsub_module);
1403 }
static struct pjsip_module pubsub_module
struct ast_sip_endpoint * endpoint
void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
Set a serializer on a SIP dialog so requests and responses are automatically serialized.
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.
struct ast_taskprocessor * serializer

◆ subscription_tree_destructor()

static void subscription_tree_destructor ( void *  obj)
static

Definition at line 1367 of file res_pjsip_pubsub.c.

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

Referenced by allocate_subscription_tree().

1368 {
1369  struct sip_subscription_tree *sub_tree = obj;
1370 
1371  ast_debug(3, "Destroying subscription tree %p '%s->%s'\n",
1372  sub_tree,
1373  sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown",
1374  sub_tree->root ? sub_tree->root->resource : "Unknown");
1375 
1376  destroy_subscriptions(sub_tree->root);
1377 
1378  if (sub_tree->dlg) {
1381  }
1382 
1383  ao2_cleanup(sub_tree->endpoint);
1384 
1387 }
struct ast_sip_subscription * root
struct ast_sip_endpoint * endpoint
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:5204
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
struct ast_module * self
Definition: module.h:342
static int subscription_unreference_dialog(void *obj)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static void destroy_subscriptions(struct ast_sip_subscription *root)
struct ast_taskprocessor * serializer
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
A tree of SIP subscriptions.

◆ subscription_unreference_dialog()

static int subscription_unreference_dialog ( void *  obj)
static

Definition at line 1348 of file res_pjsip_pubsub.c.

References sip_subscription_tree::dlg, NULL, and pubsub_module.

Referenced by subscription_tree_destructor().

1349 {
1350  struct sip_subscription_tree *sub_tree = obj;
1351 
1352  /* This is why we keep the dialog on the subscription. When the subscription
1353  * is destroyed, there is no guarantee that the underlying dialog is ready
1354  * to be destroyed. Furthermore, there's no guarantee in the opposite direction
1355  * either. The dialog could be destroyed before our subscription is. We fix
1356  * this problem by keeping a reference to the dialog until it is time to
1357  * destroy the subscription. We need to have the dialog available when the
1358  * subscription is destroyed so that we can guarantee that our attempt to
1359  * remove the serializer will be successful.
1360  */
1361  pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
1362  sub_tree->dlg = NULL;
1363 
1364  return 0;
1365 }
static struct pjsip_module pubsub_module
#define NULL
Definition: resample.c:96
A tree of SIP subscriptions.

◆ test_new_subscribe()

static int test_new_subscribe ( struct ast_sip_endpoint endpoint,
const char *  resource 
)
static

new_subscribe callback for unit tests

Will give a 200 OK response to any resource except the "bad" ones.

Definition at line 4901 of file res_pjsip_pubsub.c.

References ARRAY_LEN, and bad_resources.

4902 {
4903  int i;
4904 
4905  for (i = 0; i < ARRAY_LEN(bad_resources); ++i) {
4906  if (!strcmp(resource, bad_resources[i])) {
4907  return 400;
4908  }
4909  }
4910 
4911  return 200;
4912 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
const char * bad_resources[]
"bad" resources

◆ test_resource_tree_destroy()

static void test_resource_tree_destroy ( struct resource_tree tree)
static

RAII_VAR callback to destroy an allocated resource tree.

Definition at line 5047 of file res_pjsip_pubsub.c.

References ast_free, and resource_tree_destroy().

Referenced by AST_TEST_DEFINE().

5048 {
5049  resource_tree_destroy(tree);
5050  ast_free(tree);
5051 }
static void resource_tree_destroy(struct resource_tree *tree)
Destroy a resource tree.
#define ast_free(a)
Definition: astmm.h:182

◆ tree_node_alloc()

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

Allocate a tree node.

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

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

Definition at line 934 of file res_pjsip_pubsub.c.

References ast_calloc, ast_free, AST_VECTOR_APPEND, AST_VECTOR_INIT, resource_list::full_state, and NULL.

Referenced by build_node_children(), and build_resource_tree().

935 {
936  struct tree_node *node;
937 
938  node = ast_calloc(1, sizeof(*node) + strlen(resource) + 1);
939  if (!node) {
940  return NULL;
941  }
942 
943  strcpy(node->resource, resource);
944  if (AST_VECTOR_INIT(&node->children, 4)) {
945  ast_free(node);
946  return NULL;
947  }
948  node->full_state = full_state;
949 
950  if (visited) {
951  AST_VECTOR_APPEND(visited, resource);
952  }
953  return node;
954 }
Definition: test_heap.c:38
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define NULL
Definition: resample.c:96
A node for a resource tree.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204

◆ tree_node_destroy()

static void tree_node_destroy ( struct tree_node node)
static

Destructor for a tree node.

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

Parameters
nodeThe node to destroy.

Definition at line 965 of file res_pjsip_pubsub.c.

References ast_free, AST_VECTOR_FREE, AST_VECTOR_GET, and AST_VECTOR_SIZE.

Referenced by build_node_children(), and resource_tree_destroy().

966 {
967  int i;
968  if (!node) {
969  return;
970  }
971 
972  for (i = 0; i < AST_VECTOR_SIZE(&node->children); ++i) {
973  tree_node_destroy(AST_VECTOR_GET(&node->children, i));
974  }
975  AST_VECTOR_FREE(&node->children);
976  ast_free(node);
977 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define ast_free(a)
Definition: astmm.h:182
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
static void tree_node_destroy(struct tree_node *node)
Destructor for a tree node.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 5682 of file res_pjsip_pubsub.c.

References AMI_SHOW_SUBSCRIPTIONS_INBOUND, AMI_SHOW_SUBSCRIPTIONS_OUTBOUND, ARRAY_LEN, ast_cli_unregister_multiple(), ast_manager_unregister(), AST_MODFLAG_GLOBAL_SYMBOLS, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_CHANNEL_DEPEND, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ast_sched_context_destroy(), ast_sip_transport_monitor_unregister_all(), ast_sip_unregister_service(), AST_TEST_UNREGISTER, ASTERISK_GPL_KEY, load_module(), NULL, pubsub_module, and sub_tree_transport_cb().

5683 {
5685  AST_TEST_UNREGISTER(complex_resource_tree);
5686  AST_TEST_UNREGISTER(bad_resource);
5687  AST_TEST_UNREGISTER(bad_branch);
5688  AST_TEST_UNREGISTER(duplicate_resource);
5689  AST_TEST_UNREGISTER(loop);
5690  AST_TEST_UNREGISTER(bad_event);
5691 
5693 
5695 
5698  ast_manager_unregister("PJSIPShowResourceLists");
5699 
5701  if (sched) {
5703  }
5704 
5705  return 0;
5706 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static struct pjsip_module pubsub_module
Definition: sched.c:76
#define NULL
Definition: resample.c:96
static struct ast_cli_entry cli_commands[]
A resource tree.
static void sub_tree_transport_cb(void *data)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
#define AMI_SHOW_SUBSCRIPTIONS_INBOUND
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:269

Variable Documentation

◆ __mod_info

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

Definition at line 5714 of file res_pjsip_pubsub.c.

◆ accept_exceptions

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

Accept headers that are exceptions to the rule.

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

Definition at line 806 of file res_pjsip_pubsub.c.

Referenced by exceptional_accept().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 5714 of file res_pjsip_pubsub.c.

◆ bad_resources

const char* bad_resources[]

"bad" resources

These are resources that the test handler will reject subscriptions to.

Definition at line 4889 of file res_pjsip_pubsub.c.

Referenced by test_new_subscribe().

◆ body_generators

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

◆ body_supplements

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

◆ cli_commands

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

Definition at line 4667 of file res_pjsip_pubsub.c.

◆ esc_etag_counter

int esc_etag_counter
static

Used to create new entity IDs by ESCs.

Definition at line 340 of file res_pjsip_pubsub.c.

Referenced by pubsub_on_rx_publish_request(), and sip_create_publication().

◆ pjsip_publish_method

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

Defined method for PUBLISH.

Definition at line 256 of file res_pjsip_pubsub.c.

Referenced by pubsub_on_rx_request().

◆ publish_handlers

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

◆ pubsub_cb

pjsip_evsub_user pubsub_cb
static

Definition at line 549 of file res_pjsip_pubsub.c.

Referenced by ast_sip_create_subscription(), and create_subscription_tree().

◆ pubsub_module

struct pjsip_module pubsub_module
static

◆ rlmi_media_type

pjsip_media_type rlmi_media_type
static

Definition at line 539 of file res_pjsip_pubsub.c.

Referenced by build_rlmi_body(), and load_module().

◆ sched

struct ast_sched_context* sched
static

Scheduler used for automatically expiring publications.

Definition at line 241 of file res_pjsip_pubsub.c.

◆ sip_subscription_roles_map

const char* sip_subscription_roles_map[]
static
Initial value:

Definition at line 518 of file res_pjsip_pubsub.c.

Referenced by sip_subscription_to_ami().

◆ str_event_name

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

◆ sub_tree_state_description

char* sub_tree_state_description[]
static

◆ subscription_handlers

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

◆ subscriptions

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

◆ test_handler

struct ast_sip_subscription_handler test_handler
Initial value:
= {
.event_name = "test",
.notifier = &test_notifier,
}
struct ast_sip_notifier test_notifier
Subscription notifier for unit tests.

Subscription handler for unit tests.

Definition at line 4927 of file res_pjsip_pubsub.c.

◆ test_notifier

struct ast_sip_notifier test_notifier
Initial value:
= {
.new_subscribe = test_new_subscribe,
}
static int test_new_subscribe(struct ast_sip_endpoint *endpoint, const char *resource)
new_subscribe callback for unit tests

Subscription notifier for unit tests.

Since unit tests are only concerned with building a resource tree, only the new_subscribe callback needs to be defined.

Definition at line 4920 of file res_pjsip_pubsub.c.