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