Asterisk - The Open Source Telephony Project GIT-master-545c459
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
pjsip_options.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include <pjlib.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/astobj2.h"
#include "asterisk/cli.h"
#include "asterisk/time.h"
#include "asterisk/test.h"
#include "asterisk/statsd.h"
#include "include/res_pjsip_private.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/taskpool.h"
Include dependency graph for pjsip_options.c:

Go to the source code of this file.

Data Structures

struct  sip_options_aor
 Structure which contains an AOR and contacts for qualifying purposes. More...
 
struct  sip_options_contact_callback_data
 Structure used to contain information for an OPTIONS callback. More...
 
struct  sip_options_contact_observer_task_data
 Task details for adding an AOR to an endpoint state compositor. More...
 
struct  sip_options_endpoint_aor_status
 Structure which contains status information for an AOR feeding an endpoint state compositor. More...
 
struct  sip_options_endpoint_compositor_task_data
 Task details for adding an AOR to an endpoint state compositor. More...
 
struct  sip_options_endpoint_state_compositor
 Structure which contains composites information for endpoint state. More...
 
struct  sip_options_qualify_resolve_task_data
 
struct  sip_options_synchronize_aor_task_data
 Task data for AOR creation or updating. More...
 
struct  sip_options_synchronize_task_data
 Structure which contains information required to synchronize. More...
 
struct  sip_options_target_result
 Result of qualifying an individual address belonging to a contact resolved from an A, AAAA or SRV record. More...
 

Macros

#define AOR_BUCKETS   1567
 These are the number of buckets to store AORs in.
 
#define AOR_STATUS_BUCKETS   3
 These are the number of buckets (per endpoint state compositor) to use to store AOR statuses.
 
#define CONTACT_BUCKETS   13
 These are the number of buckets (per AOR) to use to store contacts.
 
#define CONTACT_STATUS_BUCKETS   1567
 These are the number of contact status buckets.
 
#define DEFAULT_ENCODING   "identity"
 
#define DEFAULT_LANGUAGE   "en"
 
#define ENDPOINT_STATE_COMPOSITOR_BUCKETS   13
 These are the number of buckets to store endpoint state compositors.
 
#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE   1
 The initial vector size for the endpoint state compositors on an AOR.
 
#define MAX_UNLOAD_TIMEOUT_TIME   10 /* Seconds */
 Maximum wait time to join the below shutdown group.
 

Functions

static int ami_show_contacts (struct mansession *s, const struct message *m)
 
static int ami_sip_qualify (struct mansession *s, const struct message *m)
 
 AO2_STRING_FIELD_CMP_FN (ast_sip_contact_status, name)
 Comparator function for contact statuses.
 
 AO2_STRING_FIELD_CMP_FN (sip_options_aor, name)
 Comparator function for SIP OPTIONS AORs.
 
 AO2_STRING_FIELD_CMP_FN (sip_options_endpoint_aor_status, name)
 Comparator function for endpoint AOR status.
 
 AO2_STRING_FIELD_CMP_FN (sip_options_endpoint_state_compositor, name)
 Comparator function for endpoint state compositors.
 
 AO2_STRING_FIELD_HASH_FN (ast_sip_contact_status, name)
 Hashing function for contact statuses.
 
 AO2_STRING_FIELD_HASH_FN (sip_options_aor, name)
 Hashing function for OPTIONS AORs.
 
 AO2_STRING_FIELD_HASH_FN (sip_options_endpoint_aor_status, name)
 Hashing function for endpoint AOR status.
 
 AO2_STRING_FIELD_HASH_FN (sip_options_endpoint_state_compositor, name)
 Hashing function for endpoint state compositors.
 
 AO2_STRING_FIELD_SORT_FN (ast_sip_contact_status, name)
 Sort function for contact statuses.
 
static void aor_observer_deleted (const void *obj)
 Observer callback invoked on AOR deletion.
 
static void aor_observer_modified (const void *obj)
 Observer callback invoked on AOR creation or modification.
 
void ast_res_pjsip_cleanup_options_handling (void)
 
struct ast_sip_contact_statusast_res_pjsip_find_or_create_contact_status (const struct ast_sip_contact *contact)
 
int ast_res_pjsip_init_options_handling (int reload)
 
int ast_res_pjsip_preinit_options_handling (void)
 
int ast_sip_format_contact_ami (void *obj, void *arg, int flags)
 Formats the contact and sends over AMI.
 
const char * ast_sip_get_contact_short_status_label (const enum ast_sip_contact_status_type status)
 
struct ast_sip_contact_statusast_sip_get_contact_status (const struct ast_sip_contact *contact)
 Retrieve the current status for a contact.
 
const char * ast_sip_get_contact_status_label (const enum ast_sip_contact_status_type status)
 translate ast_sip_contact_status_type to character string.
 
static char * cli_qualify (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * cli_reload_qualify_aor (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * cli_reload_qualify_endpoint (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * cli_show_qualify_aor (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * cli_show_qualify_endpoint (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void contact_observer_created (const void *obj)
 Observer callback invoked on contact creation.
 
static void contact_observer_deleted (const void *obj)
 Observer callback invoked on contact deletion.
 
static void contact_observer_updated (const void *obj)
 Observer callback invoked on contact update.
 
static int contact_status_publish_update_task (void *obj)
 Task to notify endpoints of a contact status change.
 
static void endpoint_observer_deleted (const void *obj)
 Observer callback invoked on endpoint deletion.
 
static void endpoint_observer_modified (const void *obj)
 Observer callback invoked on endpoint creation or modification.
 
static int format_ami_contact_status (const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
 
static int format_ami_contactlist_handler (void *obj, void *arg, int flags)
 
static int format_contact_status_for_aor (void *obj, void *arg, int flags)
 
static struct ao2_containerget_all_contacts (void)
 
static int has_qualify_changed (const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
 Check if the contact qualify options are different than local aor qualify options.
 
static pj_bool_t options_on_rx_request (pjsip_rx_data *rdata)
 
static void qualify_contact_cb (void *token, pjsip_event *e)
 Callback for an OPTIONS response, timeout, or transport error.
 
static pj_status_t send_options_response (pjsip_rx_data *rdata, int code)
 
static struct ast_sip_contact_statussip_contact_status_alloc (const char *name)
 
static struct ast_sip_contact_statussip_contact_status_copy (const struct ast_sip_contact_status *src)
 
static void sip_contact_status_dtor (void *obj)
 Destructor for contact statuses.
 
static int sip_contact_to_ami (const struct ast_sip_contact *contact, struct ast_str **buf)
 
static struct sip_options_aorsip_options_aor_alloc (struct ast_sip_aor *aor)
 Allocator for AOR OPTIONS.
 
static void sip_options_aor_dtor (void *obj)
 Destructor function for SIP OPTIONS AORs.
 
static int sip_options_aor_observer_deleted_task (void *obj)
 Task to delete an AOR from the known universe.
 
static int sip_options_aor_observer_modified_task (void *obj)
 Task to synchronize the AOR.
 
static int sip_options_aor_remove_task (void *obj)
 Task which removes an AOR from all of the ESCs it is reporting to.
 
static void sip_options_apply_aor_configuration (struct sip_options_aor *aor_options, struct ast_sip_aor *aor, int is_new)
 Function which applies configuration to an AOR options structure.
 
static pj_status_t sip_options_apply_transport_to_destination (const pjsip_tx_data *tdata, pjsip_host_info *destination)
 Apply a request's transport selector to its DNS destination.
 
static void sip_options_cancel_target_transactions (struct sip_options_contact_callback_data *batch)
 Terminate all in-flight target transactions for a batch.
 
static int sip_options_cleanup_aor_task (void *obj)
 Management task to clean up an AOR.
 
static int sip_options_cleanup_task (void *obj)
 Management task to clean up the environment.
 
static int sip_options_contact_add_management_task (void *obj)
 Task to add a dynamic contact to an AOR in its serializer.
 
static int sip_options_contact_add_task (void *obj)
 Task which adds a dynamic contact to an AOR.
 
static struct sip_options_contact_callback_datasip_options_contact_callback_data_alloc (struct ast_sip_contact *contact, struct sip_options_aor *aor_options, struct ast_sip_endpoint *endpoint, pjsip_tx_data *resolve_tdata)
 Contact callback data allocator.
 
static void sip_options_contact_callback_data_dtor (void *obj)
 Destructor for contact callback data.
 
static int sip_options_contact_delete_management_task (void *obj)
 Task to delete a contact from an AOR in its serializer.
 
static int sip_options_contact_delete_task (void *obj)
 Task which deletes a dynamic contact from an AOR.
 
static int sip_options_contact_status_available_count (void *obj, void *arg, int flags)
 Count AVAILABLE qualified contacts.
 
static int sip_options_contact_status_notify_task (void *obj)
 Task to notify an AOR of a contact status change.
 
static void sip_options_contact_status_update (struct ast_sip_contact_status *contact_status)
 
static struct ao2_containersip_options_contact_statuses_alloc (void)
 Helper function to allocate a contact statuses container.
 
static int sip_options_contact_update_task (void *obj)
 Task which updates a dynamic contact to an AOR.
 
static int sip_options_determine_initial_qualify_time (int qualify_frequency)
 Determine an initial time for scheduling AOR qualifying.
 
static int sip_options_endpoint_compositor_add_task (void *obj)
 Task which adds an AOR to an endpoint state compositor.
 
static int sip_options_endpoint_compositor_remove_task (void *obj)
 Task which adds removes an AOR from an endpoint state compositor.
 
static int sip_options_endpoint_observer_deleted_task (void *obj)
 Task to delete an endpoint from the known universe.
 
static int sip_options_endpoint_observer_modified_task (void *obj)
 Task to synchronize the endpoint.
 
static void sip_options_endpoint_state_compositor_dtor (void *obj)
 Destructor for endpoint state compositors.
 
static struct sip_options_endpoint_state_compositorsip_options_endpoint_state_compositor_find_or_alloc (const struct ast_sip_endpoint *endpoint)
 Find (or create) an endpoint state compositor.
 
static void sip_options_endpoint_unlink_aor_feeders (struct ast_sip_endpoint *endpoint, struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
 Unlink AORs feeding the endpoint status compositor.
 
static enum ast_endpoint_state sip_options_get_endpoint_state_compositor_state (const struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
 Return the current state of an endpoint state compositor.
 
static int sip_options_init_task (void *mgmt_serializer)
 Management task to finish setting up the environment.
 
static void sip_options_notify_endpoint_state_compositors (struct sip_options_aor *aor_options, enum ast_sip_contact_status_type status)
 Function which notifies endpoint state compositors of a state change of an AOR.
 
static void sip_options_publish_contact_state (const struct sip_options_aor *aor_options, const struct ast_sip_contact_status *contact_status)
 Function which publishes a contact status update to all interested endpoints.
 
static int sip_options_qualify_aor (void *obj)
 Task to qualify contacts of an AOR.
 
static int sip_options_qualify_contact (void *obj, void *arg, int flags)
 Send a SIP OPTIONS request for a contact.
 
static void sip_options_qualify_resolve_cb (pj_status_t status, void *token, const pjsip_server_addresses *addresses)
 DNS callback used to fan out a qualify to every resolved target.
 
static int sip_options_qualify_resolve_task (void *obj)
 Process a DNS resolution result on the AOR serializer.
 
static void sip_options_qualify_resolve_task_dtor (void *obj)
 
static void sip_options_queue_target_result (struct sip_options_contact_callback_data *batch, enum ast_sip_contact_status_type status)
 Queue a resolved target's qualification result to be combined with the other targets.
 
static int sip_options_remove_contact (void *obj, void *arg, int flags)
 Forward declaration of this helpful function.
 
static void sip_options_remove_contact_status (struct sip_options_aor *aor_options, struct ast_sip_contact *contact)
 Remove contact status for a hint.
 
static void sip_options_set_contact_status (struct ast_sip_contact_status *contact_status, enum ast_sip_contact_status_type status)
 Set the contact status for a contact.
 
static int sip_options_set_contact_status_qualified (void *obj, void *arg, int flags)
 Transition the contact status to qualified mode.
 
static int sip_options_set_contact_status_unqualified (void *obj, void *arg, int flags)
 Transition the contact status to unqualified mode.
 
static void sip_options_synchronize (int reload)
 Synchronize our local container of AORs and endpoint state compositors with the current configuration.
 
static int sip_options_synchronize_aor (void *obj, void *arg, int flags)
 Synchronize an AOR with our local state.
 
static int sip_options_synchronize_aor_task (void *obj)
 Task to synchronize an AOR with our local state.
 
static int sip_options_synchronize_endpoint (void *obj, void *arg, int flags)
 Synchronize an endpoint with our local state.
 
static int sip_options_synchronize_task (void *obj)
 Task to synchronize our local container of AORs and endpoint state compositors with the current configuration.
 
static void sip_options_target_result_dtor (void *obj)
 Destructor for a resolved target's qualification result.
 
static int sip_options_target_result_task (void *obj)
 Combine the result of one resolved target with the other targets.
 
static void sip_options_transaction_free (pjsip_transaction *tsx)
 
static int sip_options_unused_aor (void *obj, void *arg, int flags)
 Callback which removes any unused AORs that remained after reloading.
 
static int sip_options_unused_endpoint_state_compositor (void *obj, void *arg, int flags)
 Callback function used to unlink and remove event state compositors that have no AORs feeding them.
 
static int sip_options_update_aor_task (void *obj)
 Task to synchronize an AOR with our local state.
 
static void sip_options_update_endpoint_state_compositor_aor (struct sip_options_endpoint_state_compositor *endpoint_state_compositor, const char *name, enum ast_sip_contact_status_type status)
 Update the AOR status on an endpoint state compositor.
 

Variables

static const struct ast_sorcery_observer aor_observer_callbacks
 Observer callbacks for AORs.
 
static struct ast_cli_entry cli_options []
 
static const struct ast_sorcery_observer contact_observer_callbacks
 Observer callbacks for contacts.
 
static struct ast_sip_endpoint_formatter contact_status_formatter
 
static const struct ast_sorcery_observer endpoint_observer_callbacks
 Observer callbacks for endpoints.
 
static struct ast_taskprocessormanagement_serializer
 
static pjsip_module options_module
 
static const char * short_status_map []
 
static struct ao2_containersip_options_aors
 
static struct ao2_containersip_options_contact_statuses
 
static struct ao2_containersip_options_endpoint_state_compositors
 
static const char * status_map []
 

Macro Definition Documentation

◆ AOR_BUCKETS

#define AOR_BUCKETS   1567

These are the number of buckets to store AORs in.

Definition at line 103 of file pjsip_options.c.

◆ AOR_STATUS_BUCKETS

#define AOR_STATUS_BUCKETS   3

These are the number of buckets (per endpoint state compositor) to use to store AOR statuses.

Definition at line 123 of file pjsip_options.c.

◆ CONTACT_BUCKETS

#define CONTACT_BUCKETS   13

These are the number of buckets (per AOR) to use to store contacts.

Definition at line 114 of file pjsip_options.c.

◆ CONTACT_STATUS_BUCKETS

#define CONTACT_STATUS_BUCKETS   1567

These are the number of contact status buckets.

Definition at line 110 of file pjsip_options.c.

◆ DEFAULT_ENCODING

#define DEFAULT_ENCODING   "identity"

Definition at line 97 of file pjsip_options.c.

◆ DEFAULT_LANGUAGE

#define DEFAULT_LANGUAGE   "en"

Definition at line 96 of file pjsip_options.c.

◆ ENDPOINT_STATE_COMPOSITOR_BUCKETS

#define ENDPOINT_STATE_COMPOSITOR_BUCKETS   13

These are the number of buckets to store endpoint state compositors.

Definition at line 117 of file pjsip_options.c.

◆ ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE

#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE   1

The initial vector size for the endpoint state compositors on an AOR.

Definition at line 120 of file pjsip_options.c.

◆ MAX_UNLOAD_TIMEOUT_TIME

#define MAX_UNLOAD_TIMEOUT_TIME   10 /* Seconds */

Maximum wait time to join the below shutdown group.

Definition at line 126 of file pjsip_options.c.

Function Documentation

◆ ami_show_contacts()

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

Definition at line 2859 of file pjsip_options.c.

2860{
2861 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2862 struct ao2_container *contacts;
2863
2864 contacts = get_all_contacts();
2865 if (!contacts) {
2866 astman_send_error(s, m, "Could not get Contacts\n");
2867 return 0;
2868 }
2869
2870 if (!ao2_container_count(contacts)) {
2871 astman_send_error(s, m, "No Contacts found\n");
2872 ao2_ref(contacts, -1);
2873 return 0;
2874 }
2875
2876 astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",
2877 "start");
2878
2880
2881 astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);
2883
2884 ao2_ref(contacts, -1);
2885
2886 return 0;
2887}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
@ OBJ_NODATA
Definition astobj2.h:1044
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:1963
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1921
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:1999
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1582
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2007
static struct ao2_container * get_all_contacts(void)
static int format_ami_contactlist_handler(void *obj, void *arg, int flags)
Generic container type.
AMI variable container.
Definition res_pjsip.h:3274
struct mansession * s
Definition res_pjsip.h:3276
const struct message * m
Definition res_pjsip.h:3278

References ao2_callback, ao2_container_count(), ao2_ref, 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_contactlist_handler(), get_all_contacts(), ast_sip_ami::m, OBJ_NODATA, and ast_sip_ami::s.

Referenced by ast_res_pjsip_init_options_handling().

◆ ami_sip_qualify()

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

Definition at line 3074 of file pjsip_options.c.

3075{
3076 const char *endpoint_name = astman_get_header(m, "Endpoint");
3077 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3078 char *aors;
3079 char *aor_name;
3080
3081 if (ast_strlen_zero(endpoint_name)) {
3082 astman_send_error(s, m, "Endpoint parameter missing.");
3083 return 0;
3084 }
3085
3086 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
3087 endpoint_name);
3088 if (!endpoint) {
3089 astman_send_error(s, m, "Unable to retrieve endpoint\n");
3090 return 0;
3091 }
3092
3093 /* send a qualify for all contacts registered with the endpoint */
3094 if (ast_strlen_zero(endpoint->aors)) {
3095 astman_send_error(s, m, "No AoRs configured for endpoint\n");
3096 return 0;
3097 }
3098
3099 aors = ast_strdupa(endpoint->aors);
3100 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
3101 struct sip_options_aor *aor_options;
3102
3103 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
3104 if (!aor_options) {
3105 continue;
3106 }
3107
3109 aor_options);
3110 ao2_ref(aor_options, -1);
3111 }
3112
3113 astman_send_ack(s, m, "Endpoint found, will qualify");
3114 return 0;
3115}
char * strsep(char **str, const char *delims)
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:1953
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2221
static struct ao2_container * sip_options_aors
static int sip_options_qualify_aor(void *obj)
Task to qualify contacts of an AOR.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define NULL
Definition resample.c:96
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition sorcery.c:1917
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
Structure which contains an AOR and contacts for qualifying purposes.
struct ast_taskprocessor * serializer
The serializer for this AOR.
#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:981

References ao2_cleanup, ao2_find, ao2_ref, ast_sip_get_sorcery(), ast_sip_push_task_wait_serializer, ast_sorcery_retrieve_by_id(), ast_strdupa, ast_strip(), ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), NULL, OBJ_SEARCH_KEY, RAII_VAR, sip_options_aor::serializer, sip_options_aors, sip_options_qualify_aor(), and strsep().

Referenced by ast_res_pjsip_init_options_handling().

◆ AO2_STRING_FIELD_CMP_FN() [1/4]

AO2_STRING_FIELD_CMP_FN ( ast_sip_contact_status  ,
name   
)

Comparator function for contact statuses.

◆ AO2_STRING_FIELD_CMP_FN() [2/4]

AO2_STRING_FIELD_CMP_FN ( sip_options_aor  ,
name   
)

Comparator function for SIP OPTIONS AORs.

◆ AO2_STRING_FIELD_CMP_FN() [3/4]

AO2_STRING_FIELD_CMP_FN ( sip_options_endpoint_aor_status  ,
name   
)

Comparator function for endpoint AOR status.

◆ AO2_STRING_FIELD_CMP_FN() [4/4]

AO2_STRING_FIELD_CMP_FN ( sip_options_endpoint_state_compositor  ,
name   
)

Comparator function for endpoint state compositors.

◆ AO2_STRING_FIELD_HASH_FN() [1/4]

AO2_STRING_FIELD_HASH_FN ( ast_sip_contact_status  ,
name   
)

Hashing function for contact statuses.

◆ AO2_STRING_FIELD_HASH_FN() [2/4]

AO2_STRING_FIELD_HASH_FN ( sip_options_aor  ,
name   
)

Hashing function for OPTIONS AORs.

◆ AO2_STRING_FIELD_HASH_FN() [3/4]

AO2_STRING_FIELD_HASH_FN ( sip_options_endpoint_aor_status  ,
name   
)

Hashing function for endpoint AOR status.

◆ AO2_STRING_FIELD_HASH_FN() [4/4]

AO2_STRING_FIELD_HASH_FN ( sip_options_endpoint_state_compositor  ,
name   
)

Hashing function for endpoint state compositors.

◆ AO2_STRING_FIELD_SORT_FN()

AO2_STRING_FIELD_SORT_FN ( ast_sip_contact_status  ,
name   
)

Sort function for contact statuses.

◆ aor_observer_deleted()

static void aor_observer_deleted ( const void *  obj)
static

Observer callback invoked on AOR deletion.

Definition at line 2451 of file pjsip_options.c.

2452{
2455}
static int sip_options_aor_observer_deleted_task(void *obj)
Task to delete an AOR from the known universe.
static struct ast_taskprocessor * management_serializer

References ast_sip_push_task_wait_serializer, management_serializer, and sip_options_aor_observer_deleted_task().

◆ aor_observer_modified()

static void aor_observer_modified ( const void *  obj)
static

Observer callback invoked on AOR creation or modification.

Definition at line 2420 of file pjsip_options.c.

2421{
2424}
static int sip_options_aor_observer_modified_task(void *obj)
Task to synchronize the AOR.

References ast_sip_push_task_wait_serializer, management_serializer, and sip_options_aor_observer_modified_task().

◆ ast_res_pjsip_cleanup_options_handling()

void ast_res_pjsip_cleanup_options_handling ( void  )

Definition at line 3246 of file pjsip_options.c.

3247{
3248 struct ast_taskprocessor *mgmt_serializer;
3249
3251 ast_manager_unregister("PJSIPQualify");
3252 ast_manager_unregister("PJSIPShowContacts");
3254
3261
3262 mgmt_serializer = management_serializer;
3264 if (mgmt_serializer) {
3266 ast_taskprocessor_unreference(mgmt_serializer);
3267 }
3268
3275
3276 pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
3277}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7782
static pjsip_module options_module
static const struct ast_sorcery_observer endpoint_observer_callbacks
Observer callbacks for endpoints.
static struct ao2_container * sip_options_contact_statuses
static struct ao2_container * sip_options_endpoint_state_compositors
static struct ast_cli_entry cli_options[]
static int sip_options_cleanup_task(void *obj)
Management task to clean up the environment.
static const struct ast_sorcery_observer aor_observer_callbacks
Observer callbacks for AORs.
static const struct ast_sorcery_observer contact_observer_callbacks
Observer callbacks for contacts.
static struct ast_sip_endpoint_formatter contact_status_formatter
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition res_pjsip.c:485
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition sorcery.c:2487
A ast_taskprocessor structure is a singleton by name.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
#define ARRAY_LEN(a)
Definition utils.h:706

References ao2_cleanup, aor_observer_callbacks, ARRAY_LEN, ast_cli_unregister_multiple(), ast_manager_unregister(), ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sip_push_task_wait_serializer, ast_sip_unregister_endpoint_formatter(), ast_sorcery_observer_remove(), ast_taskprocessor_unreference(), cli_options, contact_observer_callbacks, contact_status_formatter, endpoint_observer_callbacks, management_serializer, NULL, options_module, sip_options_aors, sip_options_cleanup_task(), sip_options_contact_statuses, and sip_options_endpoint_state_compositors.

Referenced by ast_res_pjsip_init_options_handling(), and unload_pjsip().

◆ ast_res_pjsip_find_or_create_contact_status()

struct ast_sip_contact_status * ast_res_pjsip_find_or_create_contact_status ( const struct ast_sip_contact contact)

Definition at line 463 of file pjsip_options.c.

464{
465 struct ast_sip_contact_status *contact_status;
466 int res;
467
468 /*
469 * At startup a contact status can be retrieved when static contacts
470 * are themselves being setup. This happens before we are fully setup.
471 * Since we don't actually trigger qualify or anything as a result it
472 * is safe to do so. They'll just get back a contact status that will
473 * be updated later. At this time they only care that the contact
474 * status gets created for the static contact anyway.
475 */
477 /*
478 * We haven't been pre-initialized or we are shutting down.
479 * Neither situation should happen.
480 */
481 ast_assert(0);
482 return NULL;
483 }
484
486
487 /* If contact status for this contact already exists just return it */
488 contact_status = ao2_find(sip_options_contact_statuses,
490 if (contact_status) {
492 return contact_status;
493 }
494
495 /* Otherwise we have to create and store a new contact status */
496 contact_status = sip_contact_status_alloc(ast_sorcery_object_get_id(contact));
497 if (!contact_status) {
499 return NULL;
500 }
501
502 contact_status->rtt = 0;
503 contact_status->status = CREATED;
504 contact_status->last_status = CREATED;
505 res = ast_string_field_set(contact_status, uri, contact->uri);
506 res |= ast_string_field_set(contact_status, aor, contact->aor);
507 if (res) {
509 ao2_ref(contact_status, -1);
510 return NULL;
511 }
512
515
516 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
517 "+1", 1.0, ast_sip_get_contact_status_label(contact_status->status));
518
519 sip_options_contact_status_update(contact_status);
520
521 return contact_status;
522}
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition astobj2.h:1554
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063
static void sip_options_contact_status_update(struct ast_sip_contact_status *contact_status)
const char * ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status)
translate ast_sip_contact_status_type to character string.
static struct ast_sip_contact_status * sip_contact_status_alloc(const char *name)
@ CREATED
Definition res_pjsip.h:444
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
void AST_OPTIONAL_API_NAME() ast_statsd_log_string_va(const char *metric_name, const char *metric_type, const char *value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition res_statsd.c:205
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition statsd.h:32
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
A contact's status.
Definition res_pjsip.h:453
const ast_string_field uri
Definition res_pjsip.h:459
enum ast_sip_contact_status_type status
Definition res_pjsip.h:470
enum ast_sip_contact_status_type last_status
Definition res_pjsip.h:472
const ast_string_field aor
Definition res_pjsip.h:459
const ast_string_field uri
Definition res_pjsip.h:414
const ast_string_field aor
Definition res_pjsip.h:414
#define ast_assert(a)
Definition utils.h:779

References ao2_find, ao2_link_flags, ao2_lock, ao2_ref, ao2_unlock, ast_sip_contact::aor, ast_sip_contact_status::aor, ast_assert, ast_sip_get_contact_status_label(), ast_sorcery_object_get_id(), AST_STATSD_GAUGE, ast_statsd_log_string_va(), ast_string_field_set, CREATED, ast_sip_contact_status::last_status, NULL, OBJ_NOLOCK, OBJ_SEARCH_KEY, ast_sip_contact_status::rtt, sip_contact_status_alloc(), sip_options_contact_status_update(), sip_options_contact_statuses, ast_sip_contact_status::status, ast_sip_contact::uri, and ast_sip_contact_status::uri.

Referenced by contact_apply_handler(), permanent_uri_handler(), sip_options_contact_add_task(), sip_options_contact_status_available_count(), sip_options_qualify_contact(), sip_options_set_contact_status_qualified(), and sip_options_set_contact_status_unqualified().

◆ ast_res_pjsip_init_options_handling()

int ast_res_pjsip_init_options_handling ( int  reload)

Definition at line 3311 of file pjsip_options.c.

3312{
3313 struct ast_taskprocessor *mgmt_serializer;
3314
3315 static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
3316
3317 if (reload) {
3319 return 0;
3320 }
3321
3322 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
3323 != PJ_SUCCESS) {
3324 return -1;
3325 }
3326
3327 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
3328 NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
3330 return -1;
3331 }
3332
3334 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
3335 if (!sip_options_aors) {
3337 return -1;
3338 }
3342 sip_options_endpoint_state_compositor_hash_fn, NULL,
3343 sip_options_endpoint_state_compositor_cmp_fn);
3346 return -1;
3347 }
3348
3349 mgmt_serializer = ast_sip_create_serializer("pjsip/options/manage");
3350 if (!mgmt_serializer) {
3352 return -1;
3353 }
3354
3355 /*
3356 * Set the water mark levels high because we can get a flood of
3357 * contact status updates from sip_options_synchronize() that
3358 * quickly clears on initial load or reload.
3359 */
3360 ast_taskprocessor_alert_set_levels(mgmt_serializer, -1,
3362
3363 /*
3364 * We make sure that the environment is completely setup before we allow
3365 * any other threads to post contact_status updates to the
3366 * management_serializer.
3367 */
3369 mgmt_serializer)) {
3370 /* Set management_serializer in case pushing the task actually failed. */
3371 management_serializer = mgmt_serializer;
3373 return -1;
3374 }
3375
3381
3382 return 0;
3383}
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition astobj2.h:365
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition res_pjsip.c:2137
#define EVENT_FLAG_REPORTING
Definition manager.h:84
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
static void sip_options_synchronize(int reload)
Synchronize our local container of AORs and endpoint state compositors with the current configuration...
static int ami_sip_qualify(struct mansession *s, const struct message *m)
void ast_res_pjsip_cleanup_options_handling(void)
#define ENDPOINT_STATE_COMPOSITOR_BUCKETS
These are the number of buckets to store endpoint state compositors.
#define AOR_BUCKETS
These are the number of buckets to store AORs in.
static int ami_show_contacts(struct mansession *s, const struct message *m)
static int sip_options_init_task(void *mgmt_serializer)
Management task to finish setting up the environment.
static int reload(void)
void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Register an endpoint formatter.
Definition res_pjsip.c:479
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water)
Set the high and low alert water marks of the given taskprocessor queue.

References ami_show_contacts(), ami_sip_qualify(), AO2_ALLOC_OPT_LOCK_RWLOCK, ao2_container_alloc_hash, AOR_BUCKETS, ARRAY_LEN, ast_cli_register_multiple, ast_manager_register_xml, ast_res_pjsip_cleanup_options_handling(), ast_sip_create_serializer(), ast_sip_get_pjsip_endpoint(), ast_sip_push_task_wait_serializer, ast_sip_register_endpoint_formatter(), ast_taskprocessor_alert_set_levels(), AST_TASKPROCESSOR_HIGH_WATER_LEVEL, cli_options, contact_status_formatter, ENDPOINT_STATE_COMPOSITOR_BUCKETS, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, management_serializer, NULL, options_module, reload(), sip_options_aors, sip_options_endpoint_state_compositors, sip_options_init_task(), and sip_options_synchronize().

Referenced by load_module(), and reload_configuration_task().

◆ ast_res_pjsip_preinit_options_handling()

int ast_res_pjsip_preinit_options_handling ( void  )

Definition at line 3305 of file pjsip_options.c.

3306{
3308 return sip_options_contact_statuses ? 0 : -1;
3309}
static struct ao2_container * sip_options_contact_statuses_alloc(void)
Helper function to allocate a contact statuses container.

References sip_options_contact_statuses, and sip_options_contact_statuses_alloc().

Referenced by load_module().

◆ ast_sip_format_contact_ami()

int ast_sip_format_contact_ami ( void *  obj,
void *  arg,
int  flags 
)

Formats the contact and sends over AMI.

Parameters
obja pointer an ast_sip_contact_wrapper structure
arga pointer to an ast_sip_ami structure
flagsignored
Return values
0Success, otherwise non-zero on error

Definition at line 3125 of file pjsip_options.c.

3126{
3127 struct ast_sip_contact_wrapper *wrapper = obj;
3128 struct ast_sip_contact *contact = wrapper->contact;
3129 struct ast_sip_ami *ami = arg;
3131 struct ast_str *buf;
3132 const struct ast_sip_endpoint *endpoint = ami->arg;
3133 char secs[AST_TIME_T_LEN];
3134
3135 buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
3136 if (!buf) {
3137 return -1;
3138 }
3139
3141
3142 ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
3143 ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
3144 ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
3145 ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
3146 ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
3147 if (!ast_strlen_zero(contact->via_addr)) {
3148 ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
3149 if (contact->via_port) {
3150 ast_str_append(&buf, 0, ":%d", contact->via_port);
3151 }
3152 ast_str_append(&buf, 0, "\r\n");
3153 }
3154 if (!ast_strlen_zero(contact->call_id)) {
3155 ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
3156 }
3157 ast_str_append(&buf, 0, "Status: %s\r\n",
3159 if (!status || status->status != AVAILABLE) {
3160 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
3161 } else {
3162 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
3163 }
3164 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
3165 endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
3166
3167 ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
3168 ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
3169 ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
3170 ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
3171 ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
3172 ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
3173 ast_str_append(&buf, 0, "Qualify2xxOnly: %d\r\n", contact->qualify_2xx_only);
3174
3175 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
3176 ami->count++;
3177
3178 ast_free(buf);
3180 return 0;
3181}
jack_status_t status
Definition app_jack.c:149
#define ast_free(a)
Definition astmm.h:180
char buf[BUFSIZE]
Definition eagi_proxy.c:66
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1842
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
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.
@ AVAILABLE
Definition res_pjsip.h:440
@ UNKNOWN
Definition res_pjsip.h:442
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
A wrapper for contact that adds the aor_id and a consistent contact id. Used by ast_sip_for_each_cont...
Definition res_pjsip.h:521
struct ast_sip_contact * contact
Definition res_pjsip.h:527
Contact associated with an address of record.
Definition res_pjsip.h:392
double qualify_timeout
Definition res_pjsip.h:422
const ast_string_field via_addr
Definition res_pjsip.h:414
const ast_string_field call_id
Definition res_pjsip.h:414
const ast_string_field outbound_proxy
Definition res_pjsip.h:414
struct timeval expiration_time
Definition res_pjsip.h:416
const ast_string_field path
Definition res_pjsip.h:414
int authenticate_qualify
Definition res_pjsip.h:420
const ast_string_field user_agent
Definition res_pjsip.h:414
unsigned int qualify_frequency
Definition res_pjsip.h:418
Support for dynamic strings.
Definition strings.h:623
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
Definition time.c:152
#define AST_TIME_T_LEN
Definition time.h:45

References ao2_cleanup, ast_sip_contact_wrapper::aor_id, ast_sip_ami::arg, ast_free, ast_sip_create_ami_event(), ast_sip_get_contact_status(), ast_sip_get_contact_status_label(), ast_sorcery_object_get_id(), ast_str_append(), ast_str_buffer(), ast_strlen_zero(), AST_TIME_T_LEN, ast_time_t_to_string(), astman_append(), ast_sip_contact::authenticate_qualify, AVAILABLE, buf, ast_sip_contact::call_id, ast_sip_contact_wrapper::contact, ast_sip_ami::count, ast_sip_contact::endpoint_name, ast_sip_contact::expiration_time, ast_sip_contact::outbound_proxy, ast_sip_contact::path, ast_sip_contact::qualify_2xx_only, ast_sip_contact::qualify_frequency, ast_sip_contact::qualify_timeout, ast_sip_ami::s, S_OR, status, UNKNOWN, ast_sip_contact::uri, ast_sip_contact::user_agent, ast_sip_contact::via_addr, and ast_sip_contact::via_port.

Referenced by ami_show_registration_contact_statuses(), and format_contact_status_for_aor().

◆ ast_sip_get_contact_short_status_label()

const char * ast_sip_get_contact_short_status_label ( const enum ast_sip_contact_status_type  status)

Definition at line 338 of file pjsip_options.c.

339{
341 return short_status_map[status];
342}
static const char * short_status_map[]

References ARRAY_LEN, ast_assert, short_status_map, and status.

Referenced by cli_contact_print_body().

◆ ast_sip_get_contact_status()

struct ast_sip_contact_status * ast_sip_get_contact_status ( const struct ast_sip_contact contact)

◆ ast_sip_get_contact_status_label()

const char * ast_sip_get_contact_status_label ( const enum ast_sip_contact_status_type  status)

◆ cli_qualify()

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

Definition at line 2752 of file pjsip_options.c.

2753{
2754 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2755 const char *endpoint_name;
2756 char *aors;
2757 char *aor_name;
2758
2759 switch (cmd) {
2760 case CLI_INIT:
2761 e->command = "pjsip qualify";
2762 e->usage =
2763 "Usage: pjsip qualify <endpoint>\n"
2764 " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
2765 return NULL;
2766 case CLI_GENERATE:
2767 return NULL;
2768 }
2769
2770 if (a->argc != 3) {
2771 return CLI_SHOWUSAGE;
2772 }
2773
2774 endpoint_name = a->argv[2];
2775
2776 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2777 endpoint_name);
2778 if (!endpoint) {
2779 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2780 return CLI_FAILURE;
2781 }
2782
2783 if (ast_strlen_zero(endpoint->aors)) {
2784 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2785 return CLI_FAILURE;
2786 }
2787
2788 aors = ast_strdupa(endpoint->aors);
2789 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2790 struct sip_options_aor *aor_options;
2791
2792 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2793 if (!aor_options) {
2794 continue;
2795 }
2796
2797 ast_cli(a->fd, "Qualifying AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2799 aor_options);
2800 ao2_ref(aor_options, -1);
2801 }
2802
2803 return CLI_SUCCESS;
2804}
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
static struct test_val a

References a, ao2_cleanup, ao2_find, ao2_ref, ast_cli(), ast_sip_get_sorcery(), ast_sip_push_task_wait_serializer, ast_sorcery_retrieve_by_id(), ast_strdupa, ast_strip(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, OBJ_SEARCH_KEY, RAII_VAR, sip_options_aor::serializer, sip_options_aors, sip_options_qualify_aor(), strsep(), and ast_cli_entry::usage.

◆ cli_reload_qualify_aor()

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

Definition at line 3038 of file pjsip_options.c.

3039{
3040 struct ast_sip_aor *aor;
3041 const char *aor_name;
3042
3043 switch (cmd) {
3044 case CLI_INIT:
3045 e->command = "pjsip reload qualify aor";
3046 e->usage =
3047 "Usage: pjsip reload qualify aor <id>\n"
3048 " Synchronize the PJSIP Aor qualify options.\n";
3049 return NULL;
3050 case CLI_GENERATE:
3051 return NULL;
3052 }
3053
3054 if (a->argc != 5) {
3055 return CLI_SHOWUSAGE;
3056 }
3057
3058 aor_name = a->argv[4];
3059
3060 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
3061 if (!aor) {
3062 ast_cli(a->fd, "Unable to retrieve aor '%s'\n", aor_name);
3063 return CLI_FAILURE;
3064 }
3065
3066 ast_cli(a->fd, "Synchronizing AOR '%s'\n", aor_name);
3069 ao2_ref(aor, -1);
3070
3071 return CLI_SUCCESS;
3072}
A SIP address of record.
Definition res_pjsip.h:480

References a, ao2_ref, ast_cli(), ast_sip_get_sorcery(), ast_sip_push_task_wait_serializer, ast_sorcery_retrieve_by_id(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, management_serializer, NULL, sip_options_aor_observer_modified_task(), and ast_cli_entry::usage.

◆ cli_reload_qualify_endpoint()

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

Definition at line 2984 of file pjsip_options.c.

2985{
2986 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2987 const char *endpoint_name;
2988 char *aors;
2989 char *aor_name;
2990
2991 switch (cmd) {
2992 case CLI_INIT:
2993 e->command = "pjsip reload qualify endpoint";
2994 e->usage =
2995 "Usage: pjsip reload qualify endpoint <id>\n"
2996 " Synchronize the qualify options for all Aors on the PJSIP endpoint.\n";
2997 return NULL;
2998 case CLI_GENERATE:
2999 return NULL;
3000 }
3001
3002 if (a->argc != 5) {
3003 return CLI_SHOWUSAGE;
3004 }
3005
3006 endpoint_name = a->argv[4];
3007
3008 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
3009 endpoint_name);
3010 if (!endpoint) {
3011 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
3012 return CLI_FAILURE;
3013 }
3014
3015 if (ast_strlen_zero(endpoint->aors)) {
3016 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
3017 return CLI_FAILURE;
3018 }
3019
3020 aors = ast_strdupa(endpoint->aors);
3021 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
3022 struct ast_sip_aor *aor;
3023
3024 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
3025 if (!aor) {
3026 continue;
3027 }
3028
3029 ast_cli(a->fd, "Synchronizing AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
3032 ao2_ref(aor, -1);
3033 }
3034
3035 return CLI_SUCCESS;
3036}

References a, ao2_cleanup, ao2_ref, ast_cli(), ast_sip_get_sorcery(), ast_sip_push_task_wait_serializer, ast_sorcery_retrieve_by_id(), ast_strdupa, ast_strip(), ast_strlen_zero(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, management_serializer, NULL, RAII_VAR, sip_options_aor_observer_modified_task(), strsep(), and ast_cli_entry::usage.

◆ cli_show_qualify_aor()

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

Definition at line 2946 of file pjsip_options.c.

2947{
2948 struct sip_options_aor *aor_options;
2949 const char *aor_name;
2950
2951 switch (cmd) {
2952 case CLI_INIT:
2953 e->command = "pjsip show qualify aor";
2954 e->usage =
2955 "Usage: pjsip show qualify aor <id>\n"
2956 " Show the PJSIP Aor current qualify options.\n";
2957 return NULL;
2958 case CLI_GENERATE:
2959 return NULL;
2960 }
2961
2962 if (a->argc != 5) {
2963 return CLI_SHOWUSAGE;
2964 }
2965
2966 aor_name = a->argv[4];
2967
2968 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2969 if (!aor_options) {
2970 ast_cli(a->fd, "Unable to retrieve aor '%s' qualify options\n", aor_name);
2971 return CLI_FAILURE;
2972 }
2973
2974 ast_cli(a->fd, " * AOR '%s'\n", aor_name);
2975 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2976 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2977 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2978 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2979 ao2_ref(aor_options, -1);
2980
2981 return CLI_SUCCESS;
2982}
double qualify_timeout
Qualify timeout. 0 is diabled.
int qualify_2xx_only
If true only authenticate if OPTIONS response is 2XX.
unsigned int qualify_frequency
Frequency to send OPTIONS requests to AOR contacts. 0 is disabled.

References a, ao2_find, ao2_ref, ast_cli(), sip_options_aor::authenticate_qualify, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, OBJ_SEARCH_KEY, sip_options_aor::qualify_2xx_only, sip_options_aor::qualify_frequency, sip_options_aor::qualify_timeout, sip_options_aors, and ast_cli_entry::usage.

◆ cli_show_qualify_endpoint()

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

Definition at line 2889 of file pjsip_options.c.

2890{
2891 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2892 const char *endpoint_name;
2893 char *aors;
2894 char *aor_name;
2895
2896 switch (cmd) {
2897 case CLI_INIT:
2898 e->command = "pjsip show qualify endpoint";
2899 e->usage =
2900 "Usage: pjsip show qualify endpoint <id>\n"
2901 " Show the current qualify options for all Aors on the PJSIP endpoint.\n";
2902 return NULL;
2903 case CLI_GENERATE:
2904 return NULL;
2905 }
2906
2907 if (a->argc != 5) {
2908 return CLI_SHOWUSAGE;
2909 }
2910
2911 endpoint_name = a->argv[4];
2912
2913 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2914 endpoint_name);
2915 if (!endpoint) {
2916 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2917 return CLI_FAILURE;
2918 }
2919
2920 if (ast_strlen_zero(endpoint->aors)) {
2921 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2922 return CLI_FAILURE;
2923 }
2924
2925 aors = ast_strdupa(endpoint->aors);
2926 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2927 struct sip_options_aor *aor_options;
2928
2929 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2930 if (!aor_options) {
2931 continue;
2932 }
2933
2934 ast_cli(a->fd, " * AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2935 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2936 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2937 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2938 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2939 ast_cli(a->fd, "\n");
2940 ao2_ref(aor_options, -1);
2941 }
2942
2943 return CLI_SUCCESS;
2944}

References a, ao2_cleanup, ao2_find, ao2_ref, ast_cli(), ast_sip_get_sorcery(), ast_sorcery_retrieve_by_id(), ast_strdupa, ast_strip(), ast_strlen_zero(), sip_options_aor::authenticate_qualify, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, OBJ_SEARCH_KEY, sip_options_aor::qualify_2xx_only, sip_options_aor::qualify_frequency, sip_options_aor::qualify_timeout, RAII_VAR, sip_options_aors, strsep(), and ast_cli_entry::usage.

◆ contact_observer_created()

static void contact_observer_created ( const void *  obj)
static

Observer callback invoked on contact creation.

Definition at line 2593 of file pjsip_options.c.

2594{
2597}
static int sip_options_contact_add_management_task(void *obj)
Task to add a dynamic contact to an AOR in its serializer.

References ast_sip_push_task_wait_serializer, management_serializer, and sip_options_contact_add_management_task().

◆ contact_observer_deleted()

static void contact_observer_deleted ( const void *  obj)
static

Observer callback invoked on contact deletion.

Definition at line 2739 of file pjsip_options.c.

2740{
2743}
static int sip_options_contact_delete_management_task(void *obj)
Task to delete a contact from an AOR in its serializer.

References ast_sip_push_task_wait_serializer, management_serializer, and sip_options_contact_delete_management_task().

◆ contact_observer_updated()

static void contact_observer_updated ( const void *  obj)
static

Observer callback invoked on contact update.

Definition at line 2631 of file pjsip_options.c.

2632{
2633 const struct ast_sip_contact *contact = obj;
2634 struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY);
2635
2636 if (has_qualify_changed(contact, aor_options)) {
2637 struct ast_sip_aor *aor;
2638
2640 contact->aor);
2641 if (aor) {
2642 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2643 contact->aor);
2646 ao2_ref(aor, -1);
2647 }
2648 }
2649
2652
2653 task_data = ast_malloc(sizeof(*task_data));
2654 if (!task_data) {
2655 ao2_ref(aor_options, -1);
2656 return;
2657 }
2658
2659 task_data->contact = (struct ast_sip_contact *) contact;
2660 /* task_data takes ownership of aor_options and will take care of releasing the ref */
2661 task_data->aor_options = aor_options;
2662
2663 ao2_ref(task_data->contact, +1);
2664 if (ast_sip_push_task(task_data->aor_options->serializer,
2666 ao2_ref(task_data->contact, -1);
2667 ao2_ref(task_data->aor_options, -1);
2669 }
2670 } else {
2671 ao2_cleanup(aor_options);
2672 }
2673}
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2126
#define ast_debug(level,...)
Log a DEBUG message.
static int sip_options_contact_update_task(void *obj)
Task which updates a dynamic contact to an AOR.
static int has_qualify_changed(const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
Check if the contact qualify options are different than local aor qualify options.
unsigned int ast_sip_get_send_contact_status_on_update_registration(void)
Retrieve the global setting 'send_contact_status_on_update_registration'.
Task details for adding an AOR to an endpoint state compositor.
struct sip_options_aor * aor_options
The AOR options that the contact is referring to.
userdata associated with baseline taskprocessor test

References ao2_cleanup, ao2_find, ao2_ref, ast_sip_contact::aor, sip_options_contact_observer_task_data::aor_options, ast_debug, ast_free, ast_malloc, ast_sip_get_send_contact_status_on_update_registration(), ast_sip_get_sorcery(), ast_sip_push_task, ast_sip_push_task_wait_serializer, ast_sorcery_retrieve_by_id(), has_qualify_changed(), management_serializer, OBJ_SEARCH_KEY, sip_options_aor_observer_modified_task(), sip_options_aors, and sip_options_contact_update_task().

◆ contact_status_publish_update_task()

static int contact_status_publish_update_task ( void *  obj)
static

Task to notify endpoints of a contact status change.

Note
Run by management_serializer

Definition at line 435 of file pjsip_options.c.

436{
437 struct ast_sip_contact_status *contact_status = obj;
438 struct sip_options_aor *aor_options;
439
440 aor_options = ao2_find(sip_options_aors, contact_status->aor, OBJ_SEARCH_KEY);
441 if (aor_options) {
442 sip_options_publish_contact_state(aor_options, contact_status);
443 ao2_ref(aor_options, -1);
444 }
445 ao2_ref(contact_status, -1);
446
447 return 0;
448}
static void sip_options_publish_contact_state(const struct sip_options_aor *aor_options, const struct ast_sip_contact_status *contact_status)
Function which publishes a contact status update to all interested endpoints.

References ao2_find, ao2_ref, ast_sip_contact_status::aor, OBJ_SEARCH_KEY, sip_options_aors, and sip_options_publish_contact_state().

Referenced by sip_options_contact_status_update().

◆ endpoint_observer_deleted()

static void endpoint_observer_deleted ( const void *  obj)
static

Observer callback invoked on endpoint deletion.

Definition at line 2288 of file pjsip_options.c.

2289{
2292}
static int sip_options_endpoint_observer_deleted_task(void *obj)
Task to delete an endpoint from the known universe.

References ast_sip_push_task_wait_serializer, management_serializer, and sip_options_endpoint_observer_deleted_task().

◆ endpoint_observer_modified()

static void endpoint_observer_modified ( const void *  obj)
static

Observer callback invoked on endpoint creation or modification.

Definition at line 2320 of file pjsip_options.c.

2321{
2324}
static int sip_options_endpoint_observer_modified_task(void *obj)
Task to synchronize the endpoint.

References ast_sip_push_task_wait_serializer, management_serializer, and sip_options_endpoint_observer_modified_task().

◆ format_ami_contact_status()

static int format_ami_contact_status ( const struct ast_sip_endpoint endpoint,
struct ast_sip_ami ami 
)
static

Definition at line 3190 of file pjsip_options.c.

3192{
3193 ami->arg = (void *)endpoint;
3195}
static int format_contact_status_for_aor(void *obj, void *arg, int flags)
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
For every aor in the comma separated aors string call the given 'on_aor' handler.
Definition location.c:688
const ast_string_field aors
Definition res_pjsip.h:1096

References ast_sip_endpoint::aors, ast_sip_ami::arg, ast_sip_for_each_aor(), and format_contact_status_for_aor().

◆ format_ami_contactlist_handler()

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

Definition at line 2822 of file pjsip_options.c.

2823{
2824 struct ast_sip_contact *contact = obj;
2825 struct ast_sip_ami *ami = arg;
2826 struct ast_str *buf;
2828
2829 buf = ast_sip_create_ami_event("ContactList", ami);
2830 if (!buf) {
2831 return CMP_STOP;
2832 }
2833
2834 if (sip_contact_to_ami(contact, &buf)) {
2835 ast_free(buf);
2836 return CMP_STOP;
2837 }
2838
2839 /* Add extra info */
2841 ast_str_append(&buf, 0, "Status: %s\r\n",
2843 if (!status || status->status != AVAILABLE) {
2844 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2845 } else {
2846 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2847 }
2849
2850 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2851
2852 ami->count++;
2853
2854 ast_free(buf);
2855
2856 return 0;
2857}
@ CMP_STOP
Definition astobj2.h:1028
static int sip_contact_to_ami(const struct ast_sip_contact *contact, struct ast_str **buf)

References ao2_cleanup, ast_sip_ami::arg, ast_free, ast_sip_create_ami_event(), ast_sip_get_contact_status(), ast_sip_get_contact_status_label(), ast_str_append(), ast_str_buffer(), astman_append(), AVAILABLE, buf, CMP_STOP, ast_sip_ami::count, ast_sip_ami::s, sip_contact_to_ami(), status, and UNKNOWN.

Referenced by ami_show_contacts().

◆ format_contact_status_for_aor()

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

Definition at line 3183 of file pjsip_options.c.

3184{
3185 struct ast_sip_aor *aor = obj;
3186
3188}
int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
Formats the contact and sends over AMI.
int ast_sip_for_each_contact(const struct ast_sip_aor *aor, ao2_callback_fn on_contact, void *arg)
For every contact on an AOR call the given 'on_contact' handler.
Definition location.c:723

References ast_sip_for_each_contact(), and ast_sip_format_contact_ami().

Referenced by format_ami_contact_status().

◆ get_all_contacts()

static struct ao2_container * get_all_contacts ( void  )
static

Definition at line 2806 of file pjsip_options.c.

2807{
2808 struct ao2_container *contacts;
2809
2812
2813 return contacts;
2814}
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition sorcery.h:123
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition sorcery.c:1961

References AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_sorcery(), ast_sorcery_retrieve_by_fields(), and NULL.

Referenced by ami_show_contacts().

◆ has_qualify_changed()

static int has_qualify_changed ( const struct ast_sip_contact contact,
const struct sip_options_aor aor_options 
)
static

Check if the contact qualify options are different than local aor qualify options.

Definition at line 2476 of file pjsip_options.c.

2477{
2478 if (!contact) {
2479 return 0;
2480 }
2481
2482 if (!aor_options) {
2483 if (contact->qualify_frequency) {
2484 return 1;
2485 }
2486 } else if (contact->qualify_frequency != aor_options->qualify_frequency
2487 || contact->authenticate_qualify != aor_options->authenticate_qualify
2488 || contact->qualify_2xx_only != aor_options->qualify_2xx_only
2489 || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
2490 return 1;
2491 }
2492
2493 return 0;
2494}

References ast_sip_contact::authenticate_qualify, sip_options_aor::authenticate_qualify, ast_sip_contact::qualify_2xx_only, sip_options_aor::qualify_2xx_only, ast_sip_contact::qualify_frequency, sip_options_aor::qualify_frequency, ast_sip_contact::qualify_timeout, and sip_options_aor::qualify_timeout.

Referenced by contact_observer_updated(), and sip_options_contact_add_management_task().

◆ options_on_rx_request()

static pj_bool_t options_on_rx_request ( pjsip_rx_data *  rdata)
static

Definition at line 266 of file pjsip_options.c.

267{
268 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
269 pjsip_uri *ruri;
270 char exten[AST_MAX_EXTENSION];
271
272 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
273 return PJ_FALSE;
274 }
275
276 if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
277 return PJ_FALSE;
278 }
279
280 ruri = rdata->msg_info.msg->line.req.uri;
281 if (!ast_sip_is_allowed_uri(ruri)) {
282 send_options_response(rdata, 416);
283 return PJ_TRUE;
284 }
285
286 ast_copy_pj_str(exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(exten));
287
288 /*
289 * We may want to match in the dialplan without any user
290 * options getting in the way.
291 */
293
294 if (ast_shutting_down()) {
295 /*
296 * Not taking any new calls at this time.
297 * Likely a server availability OPTIONS poll.
298 */
299 send_options_response(rdata, 503);
300 } else if (!ast_strlen_zero(exten)
301 && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
302 send_options_response(rdata, 404);
303 } else {
304 send_options_response(rdata, 200);
305 }
306 return PJ_TRUE;
307}
int ast_shutting_down(void)
Definition asterisk.c:1889
#define AST_MAX_EXTENSION
Definition channel.h:134
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition pbx.c:2735
static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
const pj_str_t * ast_sip_pjsip_uri_get_username(pjsip_uri *uri)
Get the user portion of the pjsip_uri.
Definition res_pjsip.c:3497
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition res_pjsip.c:3492
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition res_pjsip.h:3578
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
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:2221

References ao2_cleanup, ast_copy_pj_str(), ast_exists_extension(), AST_MAX_EXTENSION, ast_pjsip_rdata_get_endpoint(), ast_shutting_down(), ast_sip_is_allowed_uri(), ast_sip_pjsip_uri_get_username(), AST_SIP_USER_OPTIONS_TRUNCATE_CHECK, ast_strlen_zero(), NULL, RAII_VAR, and send_options_response().

◆ qualify_contact_cb()

static void qualify_contact_cb ( void *  token,
pjsip_event *  e 
)
static

Callback for an OPTIONS response, timeout, or transport error.

Definition at line 1018 of file pjsip_options.c.

1019{
1020 struct sip_options_contact_callback_data *contact_callback_data = token;
1022
1023 switch(e->body.tsx_state.type) {
1024 default:
1025 ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type);
1026 /* Fall through */
1027 case PJSIP_EVENT_TRANSPORT_ERROR:
1028 case PJSIP_EVENT_TIMER:
1030 break;
1031 case PJSIP_EVENT_RX_MSG:
1032 if (contact_callback_data->aor_options->qualify_2xx_only &&
1033 (e->body.tsx_state.tsx->status_code < 200 || e->body.tsx_state.tsx->status_code >= 300)) {
1035 } else {
1036 status = AVAILABLE;
1037 }
1038 break;
1039 case PJSIP_EVENT_USER:
1040 /*
1041 * When one resolved target responds, we know the endpoint is available and we cancel the other
1042 * outstanding transactions. The cancelled transactions will trigger this user event, which we
1043 * can ignore as we already have a result for the contact.
1044 */
1045 ast_debug(3, "Received user event for contact '%s', ignoring\n",
1046 ast_sorcery_object_get_id(contact_callback_data->contact));
1047 /* Decrement reference count for the contact callback data and return as we have no result */
1048 ao2_ref(contact_callback_data, -1);
1049 return;
1050 }
1051
1052 sip_options_queue_target_result(contact_callback_data, status);
1053 ao2_ref(contact_callback_data, -1);
1054}
#define ast_log
Definition astobj2.c:42
#define LOG_ERROR
static void sip_options_queue_target_result(struct sip_options_contact_callback_data *batch, enum ast_sip_contact_status_type status)
Queue a resolved target's qualification result to be combined with the other targets.
ast_sip_contact_status_type
Status type for a contact.
Definition res_pjsip.h:436
@ UNAVAILABLE
Definition res_pjsip.h:438
Structure used to contain information for an OPTIONS callback.
struct ast_sip_contact * contact
The contact we qualified.
struct sip_options_aor * aor_options
The AOR options.

References ao2_ref, sip_options_contact_callback_data::aor_options, ast_debug, ast_log, ast_sorcery_object_get_id(), AVAILABLE, sip_options_contact_callback_data::contact, LOG_ERROR, sip_options_aor::qualify_2xx_only, sip_options_queue_target_result(), status, and UNAVAILABLE.

Referenced by sip_options_qualify_resolve_task().

◆ send_options_response()

static pj_status_t send_options_response ( pjsip_rx_data *  rdata,
int  code 
)
static

Definition at line 214 of file pjsip_options.c.

215{
216 pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
217 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
218 pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
219 pjsip_tx_data *tdata;
220 const pjsip_hdr *hdr;
221 pj_status_t status;
222
223 /* Make the response object */
224 status = ast_sip_create_response(rdata, code, NULL, &tdata);
225 if (status != PJ_SUCCESS) {
226 ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
227 return status;
228 }
229
230 /* Add appropriate headers */
231 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
232 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
233 }
234 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
235 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
236 }
237 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
238 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
239 }
240
241 /*
242 * XXX TODO: pjsip doesn't care a lot about either of these headers -
243 * while it provides specific methods to create them, they are defined
244 * to be the standard string header creation. Hard coded here.
245 */
246 ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
247 ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
248
249 if (dlg && trans) {
250 status = pjsip_dlg_send_response(dlg, trans, tdata);
251 } else {
252 struct ast_sip_endpoint *endpoint;
253
254 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
255 status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
256 ao2_cleanup(endpoint);
257 }
258
259 if (status != PJ_SUCCESS) {
260 ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
261 }
262
263 return status;
264}
#define DEFAULT_ENCODING
#define DEFAULT_LANGUAGE
int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code, struct ast_sip_contact *contact, pjsip_tx_data **p_tdata)
General purpose method for creating a SIP response.
Definition res_pjsip.c:2488
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition res_pjsip.c:2051
int ast_sip_send_stateful_response(pjsip_rx_data *rdata, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
Send a stateful response to an out of dialog request.
Definition res_pjsip.c:2444

References ao2_cleanup, ast_log, ast_pjsip_rdata_get_endpoint(), ast_sip_add_header(), ast_sip_create_response(), ast_sip_get_pjsip_endpoint(), ast_sip_send_stateful_response(), DEFAULT_ENCODING, DEFAULT_LANGUAGE, LOG_ERROR, NULL, and status.

Referenced by options_on_rx_request().

◆ sip_contact_status_alloc()

static struct ast_sip_contact_status * sip_contact_status_alloc ( const char *  name)
static

Definition at line 354 of file pjsip_options.c.

355{
356 struct ast_sip_contact_status *contact_status;
357 size_t size = sizeof(*contact_status) + strlen(name) + 1;
358
359 contact_status = ao2_alloc_options(size, sip_contact_status_dtor,
361 if (!contact_status) {
362 return NULL;
363 }
364 if (ast_string_field_init(contact_status, 256)) {
365 ao2_ref(contact_status, -1);
366 return NULL;
367 }
368 AST_VECTOR_INIT(&contact_status->security_mechanisms, 0);
369 strcpy(contact_status->name, name); /* SAFE */
370 return contact_status;
371}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
static const char name[]
Definition format_mp3.c:68
static void sip_contact_status_dtor(void *obj)
Destructor for contact statuses.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
struct ast_sip_security_mechanism_vector security_mechanisms
Definition res_pjsip.h:468
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_ref, ast_string_field_init, AST_VECTOR_INIT, ast_sip_contact_status::name, name, NULL, ast_sip_contact_status::security_mechanisms, and sip_contact_status_dtor().

Referenced by ast_res_pjsip_find_or_create_contact_status(), and sip_contact_status_copy().

◆ sip_contact_status_copy()

static struct ast_sip_contact_status * sip_contact_status_copy ( const struct ast_sip_contact_status src)
static

Definition at line 373 of file pjsip_options.c.

374{
375 struct ast_sip_contact_status *dst;
376
377 dst = sip_contact_status_alloc(src->name);
378 if (!dst) {
379 return NULL;
380 }
381
382 if (ast_string_fields_copy(dst, src)) {
383 ao2_ref(dst, -1);
384 return NULL;
385 }
386 dst->rtt = src->rtt;
387 dst->status = src->status;
388 dst->last_status = src->last_status;
389
391 return dst;
392}
void ast_sip_security_mechanisms_vector_copy(struct ast_sip_security_mechanism_vector *dst, const struct ast_sip_security_mechanism_vector *src)
Duplicate a security mechanism.
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.

References ao2_ref, ast_sip_security_mechanisms_vector_copy(), ast_string_fields_copy, ast_sip_contact_status::last_status, ast_sip_contact_status::name, NULL, ast_sip_contact_status::rtt, ast_sip_contact_status::security_mechanisms, sip_contact_status_alloc(), and ast_sip_contact_status::status.

Referenced by sip_options_contact_status_notify_task(), sip_options_remove_contact_status(), and sip_options_set_contact_status().

◆ sip_contact_status_dtor()

static void sip_contact_status_dtor ( void *  obj)
static

Destructor for contact statuses.

Definition at line 345 of file pjsip_options.c.

346{
347 struct ast_sip_contact_status *contact_status = obj;
348
350
351 ast_string_field_free_memory(contact_status);
352}
void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms)
Free contents of a security mechanism vector.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object

References ast_sip_security_mechanisms_vector_destroy(), ast_string_field_free_memory, and ast_sip_contact_status::security_mechanisms.

Referenced by sip_contact_status_alloc().

◆ sip_contact_to_ami()

static int sip_contact_to_ami ( const struct ast_sip_contact contact,
struct ast_str **  buf 
)
static

Definition at line 2816 of file pjsip_options.c.

2818{
2819 return ast_sip_sorcery_object_to_ami(contact, buf);
2820}
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.

References ast_sip_sorcery_object_to_ami(), and buf.

Referenced by format_ami_contactlist_handler().

◆ sip_options_aor_alloc()

static struct sip_options_aor * sip_options_aor_alloc ( struct ast_sip_aor aor)
static

Allocator for AOR OPTIONS.

Definition at line 1371 of file pjsip_options.c.

1372{
1373 struct sip_options_aor *aor_options;
1374
1375 aor_options = ao2_alloc_options(sizeof(*aor_options) + strlen(ast_sorcery_object_get_id(aor)) + 1,
1377 if (!aor_options) {
1378 return NULL;
1379 }
1380
1381 strcpy(aor_options->name, ast_sorcery_object_get_id(aor)); /* SAFE */
1382
1384 if (!aor_options->serializer) {
1385 ao2_ref(aor_options, -1);
1386 return NULL;
1387 }
1388
1390 ao2_ref(aor_options, -1);
1391 return NULL;
1392 }
1393
1397 if (!aor_options->contacts) {
1398 ao2_ref(aor_options, -1);
1399 return NULL;
1400 }
1401
1405 if (!aor_options->dynamic_contacts) {
1406 ao2_ref(aor_options, -1);
1407 return NULL;
1408 }
1409
1410 return aor_options;
1411}
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition astobj2.h:1188
struct ast_taskprocessor * ast_sip_get_distributor_serializer_hash(int hash)
Determine the distributor serializer for a given hash.
#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE
The initial vector size for the endpoint state compositors on an AOR.
static void sip_options_aor_dtor(void *obj)
Destructor function for SIP OPTIONS AORs.
#define CONTACT_BUCKETS
These are the number of buckets (per AOR) to use to store contacts.
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition sorcery.c:2528
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition sorcery.c:2504
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
Definition sorcery.c:2539
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition strings.h:1259
struct ao2_container * contacts
All contacts associated with this AOR.
struct sip_options_aor::@491 compositors
The endpoint state compositors we are feeding, a reference is held to each.
struct ao2_container * dynamic_contacts
Only dynamic contacts associated with this AOR.
char name[0]
The name of the AOR.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_container_alloc_hash, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, ao2_ref, ast_sip_get_distributor_serializer_hash(), ast_sorcery_object_get_id(), ast_sorcery_object_id_compare(), ast_sorcery_object_id_hash(), ast_sorcery_object_id_sort(), ast_str_hash(), AST_VECTOR_INIT, sip_options_aor::compositors, CONTACT_BUCKETS, sip_options_aor::contacts, sip_options_aor::dynamic_contacts, ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE, sip_options_aor::name, NULL, sip_options_aor::serializer, and sip_options_aor_dtor().

Referenced by sip_options_aor_observer_modified_task(), and sip_options_synchronize_aor().

◆ sip_options_aor_dtor()

static void sip_options_aor_dtor ( void *  obj)
static

Destructor function for SIP OPTIONS AORs.

Definition at line 1349 of file pjsip_options.c.

1350{
1351 struct sip_options_aor *aor_options = obj;
1352
1353 /*
1354 * Any contacts are unreachable since the AOR is being destroyed
1355 * so remove their contact status
1356 */
1357 if (aor_options->contacts) {
1359 sip_options_remove_contact, aor_options);
1360 ao2_ref(aor_options->contacts, -1);
1361 }
1362 ao2_cleanup(aor_options->dynamic_contacts);
1363
1365
1366 ast_assert(AST_VECTOR_SIZE(&aor_options->compositors) == 0);
1367 AST_VECTOR_FREE(&aor_options->compositors);
1368}
@ OBJ_UNLINK
Definition astobj2.h:1039
static int sip_options_remove_contact(void *obj, void *arg, int flags)
Forward declaration of this helpful function.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185

References ao2_callback, ao2_cleanup, ao2_ref, ast_assert, ast_taskprocessor_unreference(), AST_VECTOR_FREE, AST_VECTOR_SIZE, sip_options_aor::compositors, sip_options_aor::contacts, sip_options_aor::dynamic_contacts, OBJ_NODATA, OBJ_UNLINK, sip_options_aor::serializer, and sip_options_remove_contact().

Referenced by sip_options_aor_alloc().

◆ sip_options_aor_observer_deleted_task()

static int sip_options_aor_observer_deleted_task ( void *  obj)
static

Task to delete an AOR from the known universe.

Note
Run by management_serializer

Definition at line 2430 of file pjsip_options.c.

2431{
2432 struct ast_sip_aor *aor = obj;
2433 struct sip_options_aor *aor_options;
2434
2437 if (!aor_options) {
2438 return 0;
2439 }
2440
2441 ast_debug(3, "AOR '%s' has been deleted, removing it\n", aor_options->name);
2442
2444 aor_options);
2445 ao2_ref(aor_options, -1);
2446
2447 return 0;
2448}
static int sip_options_aor_remove_task(void *obj)
Task which removes an AOR from all of the ESCs it is reporting to.

References ao2_find, ao2_ref, ast_debug, ast_sip_push_task_wait_serializer, ast_sorcery_object_get_id(), sip_options_aor::name, OBJ_SEARCH_KEY, OBJ_UNLINK, sip_options_aor::serializer, sip_options_aor_remove_task(), and sip_options_aors.

Referenced by aor_observer_deleted().

◆ sip_options_aor_observer_modified_task()

static int sip_options_aor_observer_modified_task ( void *  obj)
static

Task to synchronize the AOR.

Note
Run by management_serializer

Definition at line 2365 of file pjsip_options.c.

2366{
2367 struct ast_sip_aor *aor = obj;
2368 struct sip_options_aor *aor_options;
2369
2372 if (!aor_options) {
2373 struct ao2_container *endpoints;
2374
2375 aor_options = sip_options_aor_alloc(aor);
2376 if (!aor_options) {
2377 return 0;
2378 }
2379
2380 /*
2381 * This is a newly added AOR and we need to establish any
2382 * endpoint state compositors that may reference only the
2383 * AOR. If these need to be updated later then they'll
2384 * be done by modifying the endpoint or issuing a reload.
2385 */
2386 sip_options_apply_aor_configuration(aor_options, aor, 1);
2387 ao2_link(sip_options_aors, aor_options);
2388
2389 /*
2390 * Using LIKE doesn't seem to work very well with non-realtime so we
2391 * fetch everything right now and do a filter on our side.
2392 */
2395 if (endpoints) {
2397 ao2_ref(endpoints, -1);
2398 }
2399 } else {
2401 .aor_options = aor_options,
2402 .aor = aor,
2403 };
2404
2405 /*
2406 * If this AOR was modified we have to do our work in its serializer
2407 * instead of this thread to ensure that things aren't modified by
2408 * multiple threads.
2409 */
2412 }
2413
2414 ao2_ref(aor_options, -1);
2415
2416 return 0;
2417}
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
static struct ao2_container * endpoints
static void sip_options_apply_aor_configuration(struct sip_options_aor *aor_options, struct ast_sip_aor *aor, int is_new)
Function which applies configuration to an AOR options structure.
static int sip_options_synchronize_endpoint(void *obj, void *arg, int flags)
Synchronize an endpoint with our local state.
static struct sip_options_aor * sip_options_aor_alloc(struct ast_sip_aor *aor)
Allocator for AOR OPTIONS.
static int sip_options_update_aor_task(void *obj)
Task to synchronize an AOR with our local state.
Task data for AOR creation or updating.
struct sip_options_aor * aor_options
The AOR options for this AOR.
struct ast_sip_aor * aor
The AOR which contains the new configuraton.

References ao2_callback, ao2_find, ao2_link, ao2_ref, sip_options_synchronize_aor_task_data::aor, sip_options_synchronize_aor_task_data::aor_options, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_sorcery(), ast_sip_push_task_wait_serializer, ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_fields(), endpoints, NULL, OBJ_NODATA, OBJ_SEARCH_KEY, sip_options_aor::serializer, sip_options_aor_alloc(), sip_options_aors, sip_options_apply_aor_configuration(), sip_options_synchronize_endpoint(), and sip_options_update_aor_task().

Referenced by aor_observer_modified(), cli_reload_qualify_aor(), cli_reload_qualify_endpoint(), contact_observer_updated(), and sip_options_contact_add_management_task().

◆ sip_options_aor_remove_task()

static int sip_options_aor_remove_task ( void *  obj)
static

Task which removes an AOR from all of the ESCs it is reporting to.

Note
Run by aor_options->serializer

Definition at line 2093 of file pjsip_options.c.

2094{
2095 struct sip_options_aor *aor_options = obj;
2096
2098
2099 if (aor_options->sched_task) {
2101 ao2_ref(aor_options->sched_task, -1);
2102 aor_options->sched_task = NULL;
2103 }
2104
2105 return 0;
2106}
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
static void sip_options_notify_endpoint_state_compositors(struct sip_options_aor *aor_options, enum ast_sip_contact_status_type status)
Function which notifies endpoint state compositors of a state change of an AOR.
@ REMOVED
Definition res_pjsip.h:445
struct ast_sip_sched_task * sched_task
The scheduler task for this AOR.

References ao2_ref, ast_sip_sched_task_cancel(), NULL, REMOVED, sip_options_aor::sched_task, and sip_options_notify_endpoint_state_compositors().

Referenced by sip_options_aor_observer_deleted_task(), and sip_options_unused_aor().

◆ sip_options_apply_aor_configuration()

static void sip_options_apply_aor_configuration ( struct sip_options_aor aor_options,
struct ast_sip_aor aor,
int  is_new 
)
static

Function which applies configuration to an AOR options structure.

Note
Run by aor_options->serializer (or management_serializer on aor_options creation)

Definition at line 1644 of file pjsip_options.c.

1646{
1647 struct ao2_container *existing_contacts;
1648 struct ast_sip_contact *contact;
1649 struct ao2_iterator iter;
1650
1651 ast_debug(3, "Configuring AOR '%s' with current state of configuration and world\n",
1652 aor_options->name);
1653
1654 /*
1655 * Permanent contacts, since we receive no notification that they
1656 * are gone, follow the same approach as AORs. We create a copy
1657 * of the existing container and any reused contacts are removed
1658 * from it. Any contacts remaining in the container after
1659 * processing no longer exist so we need to remove their state.
1660 */
1661 existing_contacts = ao2_container_clone(aor_options->contacts, 0);
1662 if (!existing_contacts) {
1663 ast_log(LOG_WARNING, "Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1664 aor_options->name);
1665 return;
1666 }
1667
1669 NULL, NULL);
1670
1671 /* Process permanent contacts */
1672 if (aor->permanent_contacts) {
1673 iter = ao2_iterator_init(aor->permanent_contacts, 0);
1674 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1675 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1677 ao2_link(aor_options->contacts, contact);
1678 }
1679 ao2_iterator_destroy(&iter);
1680 }
1681
1682 /*
1683 * If this is newly added we need to see if there are any
1684 * existing dynamic contacts to add. Ones that are added
1685 * after creation will occur as a result of the contact
1686 * observer creation callback.
1687 */
1688 if (is_new) {
1689 size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
1690 char prefix[prefix_len + 1];
1691 struct ao2_container *contacts;
1692
1693 sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
1695 prefix, prefix_len);
1696 if (contacts) {
1697 ao2_container_dup(aor_options->dynamic_contacts, contacts, 0);
1698 ao2_ref(contacts, -1);
1699 }
1700 }
1701
1702 /* Process dynamic contacts */
1703 iter = ao2_iterator_init(aor_options->dynamic_contacts, 0);
1704 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1705 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1707 ao2_link(aor_options->contacts, contact);
1708 }
1709 ao2_iterator_destroy(&iter);
1710
1711 /* Any contacts left no longer exist, so raise events and make them disappear */
1712 ao2_callback(existing_contacts, OBJ_NODATA | OBJ_UNLINK,
1713 sip_options_remove_contact, aor_options);
1714 ao2_ref(existing_contacts, -1);
1715
1716 /*
1717 * Update the available count if we transition between qualified
1718 * and unqualified. In the qualified case we need to start with
1719 * 0 available as the qualify process will take care of it. In
1720 * the unqualified case it is based on the number of contacts
1721 * present.
1722 */
1723 if (!aor->qualify_frequency) {
1724 ao2_callback(aor_options->contacts, OBJ_NODATA,
1726 aor_options->available = ao2_container_count(aor_options->contacts);
1727 ast_debug(3, "AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1728 aor_options->name, aor_options->available);
1729 } else if (!aor_options->qualify_frequency) {
1730 ao2_callback(aor_options->contacts, OBJ_NODATA,
1732 aor_options->available = 0;
1733 ast_debug(3, "AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1734 aor_options->name);
1735 } else {
1736 /*
1737 * Count the number of AVAILABLE qualified contacts to ensure
1738 * the count is in sync with reality.
1739 */
1740 aor_options->available = 0;
1741 ao2_callback(aor_options->contacts, OBJ_NODATA,
1743 }
1744
1745 aor_options->authenticate_qualify = aor->authenticate_qualify;
1746 aor_options->qualify_2xx_only = aor->qualify_2xx_only;
1747 aor_options->qualify_timeout = aor->qualify_timeout;
1748
1749 /*
1750 * If we need to stop or start the scheduled callback then do so.
1751 * This occurs due to the following:
1752 * 1. The qualify frequency has changed
1753 * 2. Contacts were added when previously there were none
1754 * 3. There are no contacts but previously there were some
1755 */
1756 if (aor_options->qualify_frequency != aor->qualify_frequency
1757 || (!aor_options->sched_task && ao2_container_count(aor_options->contacts))
1758 || (aor_options->sched_task && !ao2_container_count(aor_options->contacts))) {
1759 if (aor_options->sched_task) {
1761 ao2_ref(aor_options->sched_task, -1);
1762 aor_options->sched_task = NULL;
1763 }
1764
1765 /* If there is still a qualify frequency then schedule this */
1766 aor_options->qualify_frequency = aor->qualify_frequency;
1767 if (aor_options->qualify_frequency
1768 && ao2_container_count(aor_options->contacts)) {
1769 aor_options->sched_task = ast_sip_schedule_task(aor_options->serializer,
1773 if (!aor_options->sched_task) {
1774 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
1775 aor_options->name);
1776 }
1777 }
1778 }
1779
1780 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1781 aor_options->available);
1782}
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_MULTIPLE
Definition astobj2.h:1049
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
Definition astobj2.h:1419
struct ast_sip_sched_task * ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, const char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)
Schedule a task to run in the res_pjsip taskpool.
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition res_pjsip.h:2274
@ AST_SIP_SCHED_TASK_VARIABLE
Definition res_pjsip.h:2257
static char prefix[MAX_PREFIX]
Definition http.c:145
#define LOG_WARNING
static int sip_options_contact_status_available_count(void *obj, void *arg, int flags)
Count AVAILABLE qualified contacts.
static int sip_options_set_contact_status_unqualified(void *obj, void *arg, int flags)
Transition the contact status to unqualified mode.
static int sip_options_set_contact_status_qualified(void *obj, void *arg, int flags)
Transition the contact status to qualified mode.
static int sip_options_determine_initial_qualify_time(int qualify_frequency)
Determine an initial time for scheduling AOR qualifying.
struct ao2_container * ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
Retrieve multiple objects whose id begins with the specified prefix.
Definition sorcery.c:2053
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
double qualify_timeout
Definition res_pjsip.h:508
int qualify_2xx_only
Definition res_pjsip.h:514
struct ao2_container * permanent_contacts
Definition res_pjsip.h:504
int authenticate_qualify
Definition res_pjsip.h:498
unsigned int qualify_frequency
Definition res_pjsip.h:496
unsigned int available
The number of available contacts on this AOR.
const char * ast_taskprocessor_name(struct ast_taskprocessor *tps)
Return the name of the taskprocessor singleton.

References ao2_callback, ao2_container_clone, ao2_container_count(), ao2_container_dup(), ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_debug, ast_log, ast_sip_get_sorcery(), ast_sip_sched_task_cancel(), AST_SIP_SCHED_TASK_DATA_AO2, AST_SIP_SCHED_TASK_VARIABLE, ast_sip_schedule_task(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_prefix(), ast_taskprocessor_name(), ast_sip_aor::authenticate_qualify, sip_options_aor::authenticate_qualify, sip_options_aor::available, sip_options_aor::contacts, sip_options_aor::dynamic_contacts, LOG_ERROR, LOG_WARNING, sip_options_aor::name, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_SEARCH_KEY, OBJ_UNLINK, ast_sip_aor::permanent_contacts, prefix, ast_sip_aor::qualify_2xx_only, sip_options_aor::qualify_2xx_only, ast_sip_aor::qualify_frequency, sip_options_aor::qualify_frequency, ast_sip_aor::qualify_timeout, sip_options_aor::qualify_timeout, sip_options_aor::sched_task, sip_options_aor::serializer, sip_options_contact_status_available_count(), sip_options_determine_initial_qualify_time(), sip_options_qualify_aor(), sip_options_remove_contact(), sip_options_set_contact_status_qualified(), and sip_options_set_contact_status_unqualified().

Referenced by sip_options_aor_observer_modified_task(), sip_options_synchronize_aor_task(), and sip_options_update_aor_task().

◆ sip_options_apply_transport_to_destination()

static pj_status_t sip_options_apply_transport_to_destination ( const pjsip_tx_data *  tdata,
pjsip_host_info *  destination 
)
static

Apply a request's transport selector to its DNS destination.

pjsip_get_request_dest builds the destination from the Request-URI and may miss an outbound transport/listener. Before manual DNS resolution, apply the selected transport to the destination and check for mismatches so we use the correct transport for the request.

Definition at line 1113 of file pjsip_options.c.

1115{
1116 pjsip_transport_type_e transport_type = PJSIP_TRANSPORT_UNSPECIFIED;
1117
1118 if ((tdata->tp_sel.type != PJSIP_TPSELECTOR_TRANSPORT
1119 && tdata->tp_sel.type != PJSIP_TPSELECTOR_LISTENER)
1120 || !tdata->tp_sel.u.ptr) {
1121 return PJ_SUCCESS;
1122 }
1123
1124 if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
1125 transport_type = tdata->tp_sel.u.transport->key.type;
1126 } else {
1127 transport_type = tdata->tp_sel.u.listener->type;
1128 }
1129
1130 if (destination->type != PJSIP_TRANSPORT_UNSPECIFIED
1131 && ((destination->type | PJSIP_TRANSPORT_IPV6)
1132 != (transport_type | PJSIP_TRANSPORT_IPV6))) {
1133 return PJSIP_ETPNOTSUITABLE;
1134 }
1135
1136 destination->type = transport_type;
1137 return PJ_SUCCESS;
1138}

Referenced by sip_options_qualify_contact().

◆ sip_options_cancel_target_transactions()

static void sip_options_cancel_target_transactions ( struct sip_options_contact_callback_data batch)
static

Terminate all in-flight target transactions for a batch.

Definition at line 689 of file pjsip_options.c.

691{
692 unsigned int idx;
693
694 for (idx = 0; idx < AST_VECTOR_SIZE(&batch->target_transactions); ++idx) {
695 pjsip_transaction *tsx = AST_VECTOR_GET(&batch->target_transactions, idx);
696
697 if (tsx) {
698 pjsip_tsx_terminate_async(tsx, PJSIP_SC_REQUEST_TERMINATED);
699 }
700 }
701}
static struct cdr_batch * batch
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708

References AST_VECTOR_GET, AST_VECTOR_SIZE, and batch.

Referenced by sip_options_target_result_task().

◆ sip_options_cleanup_aor_task()

static int sip_options_cleanup_aor_task ( void *  obj)
static

Management task to clean up an AOR.

Note
Run by aor_options->serializer

Definition at line 3205 of file pjsip_options.c.

3206{
3207 struct sip_options_aor *aor_options = obj;
3208
3209 ast_debug(2, "Cleaning up AOR '%s' for shutdown\n", aor_options->name);
3210
3211 aor_options->qualify_frequency = 0;
3212 if (aor_options->sched_task) {
3214 ao2_ref(aor_options->sched_task, -1);
3215 aor_options->sched_task = NULL;
3216 }
3218
3219 return 0;
3220}
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition vector.h:653

References ao2_cleanup, ao2_ref, ast_debug, ast_sip_sched_task_cancel(), AST_VECTOR_RESET, sip_options_aor::compositors, sip_options_aor::name, NULL, sip_options_aor::qualify_frequency, and sip_options_aor::sched_task.

Referenced by sip_options_cleanup_task().

◆ sip_options_cleanup_task()

static int sip_options_cleanup_task ( void *  obj)
static

Management task to clean up the environment.

Note
Run by management_serializer

Definition at line 3226 of file pjsip_options.c.

3227{
3228 struct ao2_iterator it_aor;
3229 struct sip_options_aor *aor_options;
3230
3231 if (!sip_options_aors) {
3232 /* Nothing to do */
3233 return 0;
3234 }
3235
3237 for (; (aor_options = ao2_iterator_next(&it_aor)); ao2_ref(aor_options, -1)) {
3239 sip_options_cleanup_aor_task, aor_options);
3240 }
3241 ao2_iterator_destroy(&it_aor);
3242
3243 return 0;
3244}
@ AO2_ITERATOR_UNLINK
Definition astobj2.h:1863
static int sip_options_cleanup_aor_task(void *obj)
Management task to clean up an AOR.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, AO2_ITERATOR_UNLINK, ao2_ref, ast_sip_push_task_wait_serializer, sip_options_aor::serializer, sip_options_aors, and sip_options_cleanup_aor_task().

Referenced by ast_res_pjsip_cleanup_options_handling().

◆ sip_options_contact_add_management_task()

static int sip_options_contact_add_management_task ( void *  obj)
static

Task to add a dynamic contact to an AOR in its serializer.

Note
Run by management_serializer

Definition at line 2560 of file pjsip_options.c.

2561{
2563
2564 task_data.contact = obj;
2565 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2567
2568 if (has_qualify_changed(task_data.contact, task_data.aor_options)) {
2569 struct ast_sip_aor *aor;
2570
2572 task_data.contact->aor);
2573 if (aor) {
2574 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2575 task_data.contact->aor);
2577 ao2_ref(aor, -1);
2578 }
2579 }
2580
2581 if (!task_data.aor_options) {
2582 return 0;
2583 }
2584
2585 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2587 ao2_ref(task_data.aor_options, -1);
2588
2589 return 0;
2590}
static int sip_options_contact_add_task(void *obj)
Task which adds a dynamic contact to an AOR.

References ao2_find, ao2_ref, ast_debug, ast_sip_get_sorcery(), ast_sip_push_task_wait_serializer, ast_sorcery_retrieve_by_id(), has_qualify_changed(), OBJ_SEARCH_KEY, sip_options_aor_observer_modified_task(), sip_options_aors, and sip_options_contact_add_task().

Referenced by contact_observer_created().

◆ sip_options_contact_add_task()

static int sip_options_contact_add_task ( void *  obj)
static

Task which adds a dynamic contact to an AOR.

Note
Run by aor_options->serializer

Definition at line 2500 of file pjsip_options.c.

2501{
2503 struct ast_sip_contact_status *contact_status;
2504
2505 ao2_link(task_data->aor_options->dynamic_contacts, task_data->contact);
2506 ao2_link(task_data->aor_options->contacts, task_data->contact);
2507
2508 contact_status = ast_res_pjsip_find_or_create_contact_status(task_data->contact);
2509 ao2_cleanup(contact_status);
2510
2511 if (task_data->aor_options->qualify_frequency) {
2512 /* There will always be a contact here, and we need to immediately schedule
2513 * a qualify so that contacts are not waiting for the qualify_frequency
2514 * timer duration before qualifying.
2515 */
2516 ast_debug(3, "Starting scheduled callback on AOR '%s' for qualifying as there is now a contact on it\n",
2517 task_data->aor_options->name);
2518 /*
2519 * We immediately schedule the initial qualify so that we get
2520 * reachable/unreachable as soon as possible. Realistically
2521 * since they pretty much just registered they should be
2522 * reachable.
2523 */
2524 if (task_data->aor_options->sched_task) {
2525 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2526 ao2_ref(task_data->aor_options->sched_task, -1);
2527 task_data->aor_options->sched_task = NULL;
2528 }
2529 task_data->aor_options->sched_task = ast_sip_schedule_task(
2530 task_data->aor_options->serializer, 1, sip_options_qualify_aor,
2531 ast_taskprocessor_name(task_data->aor_options->serializer),
2532 task_data->aor_options,
2534 if (!task_data->aor_options->sched_task) {
2535 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
2536 task_data->aor_options->name);
2537 }
2538 } else {
2539 /*
2540 * If this was the first contact added to a non-qualified AOR then
2541 * it should become available.
2542 */
2543 task_data->aor_options->available =
2544 ao2_container_count(task_data->aor_options->contacts);
2545 if (task_data->aor_options->available == 1) {
2546 ast_debug(3, "An unqualified contact has been added to AOR '%s' so it is now available\n",
2547 task_data->aor_options->name);
2549 AVAILABLE);
2550 }
2551 }
2552
2553 return 0;
2554}
struct ast_sip_contact_status * ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact)

References ao2_cleanup, ao2_container_count(), ao2_link, ao2_ref, ast_debug, ast_log, ast_res_pjsip_find_or_create_contact_status(), ast_sip_sched_task_cancel(), AST_SIP_SCHED_TASK_DATA_AO2, AST_SIP_SCHED_TASK_VARIABLE, ast_sip_schedule_task(), ast_taskprocessor_name(), AVAILABLE, LOG_ERROR, NULL, sip_options_notify_endpoint_state_compositors(), and sip_options_qualify_aor().

Referenced by sip_options_contact_add_management_task().

◆ sip_options_contact_callback_data_alloc()

static struct sip_options_contact_callback_data * sip_options_contact_callback_data_alloc ( struct ast_sip_contact contact,
struct sip_options_aor aor_options,
struct ast_sip_endpoint endpoint,
pjsip_tx_data *  resolve_tdata 
)
static

Contact callback data allocator.

Definition at line 1078 of file pjsip_options.c.

1081{
1082 struct sip_options_contact_callback_data *contact_callback_data;
1083
1084 contact_callback_data = ao2_alloc_options(sizeof(*contact_callback_data),
1086 if (!contact_callback_data) {
1087 return NULL;
1088 }
1089
1090 if (AST_VECTOR_INIT(&contact_callback_data->target_transactions, PJSIP_MAX_RESOLVED_ADDRESSES)) {
1091 ao2_ref(contact_callback_data, -1);
1092 return NULL;
1093 }
1094
1095 contact_callback_data->contact = ao2_bump(contact);
1096 contact_callback_data->aor_options = ao2_bump(aor_options);
1097 contact_callback_data->endpoint = ao2_bump(endpoint);
1098 contact_callback_data->resolve_tdata = resolve_tdata;
1099 contact_callback_data->rtt_start = ast_tvnow();
1100
1101 return contact_callback_data;
1102}
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
static void sip_options_contact_callback_data_dtor(void *obj)
Destructor for contact callback data.
pjsip_tx_data * resolve_tdata
Transaction data for the resolve request.
struct timeval rtt_start
The time at which this OPTIONS attempt was started.
struct ast_sip_endpoint * endpoint
Endpoint used to create and send each target request.
struct sip_options_contact_callback_data::@492 target_transactions
Transactions for all target OPTIONS requests in this batch.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ao2_ref, sip_options_contact_callback_data::aor_options, ast_tvnow(), AST_VECTOR_INIT, sip_options_contact_callback_data::contact, sip_options_contact_callback_data::endpoint, NULL, sip_options_contact_callback_data::resolve_tdata, sip_options_contact_callback_data::rtt_start, sip_options_contact_callback_data_dtor(), and sip_options_contact_callback_data::target_transactions.

Referenced by sip_options_qualify_contact().

◆ sip_options_contact_callback_data_dtor()

static void sip_options_contact_callback_data_dtor ( void *  obj)
static

Destructor for contact callback data.

Definition at line 1057 of file pjsip_options.c.

1058{
1059 struct sip_options_contact_callback_data *contact_callback_data = obj;
1060
1061 ao2_cleanup(contact_callback_data->contact);
1062 ao2_cleanup(contact_callback_data->aor_options);
1063 ao2_cleanup(contact_callback_data->endpoint);
1064 /*
1065 * sip_options_qualify_resolve_cb should handle cleaning the resolve_tdata, but
1066 * keep this fallback just in case.
1067 */
1068 if (contact_callback_data->resolve_tdata) {
1069 pjsip_tx_data_dec_ref(contact_callback_data->resolve_tdata);
1070 contact_callback_data->resolve_tdata = NULL;
1071 }
1072 AST_VECTOR_RESET(&contact_callback_data->target_transactions,
1074 AST_VECTOR_FREE(&contact_callback_data->target_transactions);
1075}
static void sip_options_transaction_free(pjsip_transaction *tsx)

References ao2_cleanup, sip_options_contact_callback_data::aor_options, AST_VECTOR_FREE, AST_VECTOR_RESET, sip_options_contact_callback_data::contact, sip_options_contact_callback_data::endpoint, NULL, sip_options_contact_callback_data::resolve_tdata, sip_options_transaction_free(), and sip_options_contact_callback_data::target_transactions.

Referenced by sip_options_contact_callback_data_alloc().

◆ sip_options_contact_delete_management_task()

static int sip_options_contact_delete_management_task ( void *  obj)
static

Task to delete a contact from an AOR in its serializer.

Note
Run by management_serializer

Definition at line 2719 of file pjsip_options.c.

2720{
2722
2723 task_data.contact = obj;
2724 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2726 if (!task_data.aor_options) {
2727 /* For contacts that are deleted we don't really care if there is no AOR locally */
2728 return 0;
2729 }
2730
2731 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2733 ao2_ref(task_data.aor_options, -1);
2734
2735 return 0;
2736}
static int sip_options_contact_delete_task(void *obj)
Task which deletes a dynamic contact from an AOR.

References ao2_find, ao2_ref, ast_sip_push_task_wait_serializer, OBJ_SEARCH_KEY, sip_options_aors, and sip_options_contact_delete_task().

Referenced by contact_observer_deleted().

◆ sip_options_contact_delete_task()

static int sip_options_contact_delete_task ( void *  obj)
static

Task which deletes a dynamic contact from an AOR.

Note
Run by aor_options->serializer

Definition at line 2679 of file pjsip_options.c.

2680{
2682
2683 ao2_find(task_data->aor_options->dynamic_contacts, task_data->contact,
2685 ao2_find(task_data->aor_options->contacts, task_data->contact,
2687
2689
2690 if (task_data->aor_options->qualify_frequency) {
2691 /* If this is the last contact then we need to stop the scheduled callback */
2692 if (!ao2_container_count(task_data->aor_options->contacts)) {
2693 ast_debug(3, "Terminating scheduled callback on AOR '%s' as there are no contacts to qualify\n",
2694 task_data->aor_options->name);
2695 if (task_data->aor_options->sched_task) {
2696 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2697 ao2_ref(task_data->aor_options->sched_task, -1);
2698 task_data->aor_options->sched_task = NULL;
2699 }
2700 }
2701 } else {
2702 task_data->aor_options->available =
2703 ao2_container_count(task_data->aor_options->contacts);
2704 if (!task_data->aor_options->available) {
2705 ast_debug(3, "An unqualified contact has been removed from AOR '%s' leaving no remaining contacts\n",
2706 task_data->aor_options->name);
2708 UNAVAILABLE);
2709 }
2710 }
2711
2712 return 0;
2713}
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition astobj2.h:1087
static void sip_options_remove_contact_status(struct sip_options_aor *aor_options, struct ast_sip_contact *contact)
Remove contact status for a hint.

References ao2_container_count(), ao2_find, ao2_ref, ast_debug, ast_sip_sched_task_cancel(), NULL, OBJ_NODATA, OBJ_SEARCH_OBJECT, OBJ_UNLINK, sip_options_notify_endpoint_state_compositors(), sip_options_remove_contact_status(), and UNAVAILABLE.

Referenced by sip_options_contact_delete_management_task().

◆ sip_options_contact_status_available_count()

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

Count AVAILABLE qualified contacts.

Definition at line 1612 of file pjsip_options.c.

1613{
1614 struct ast_sip_contact *contact = obj;
1615 unsigned int *available = arg;
1616 struct ast_sip_contact_status *contact_status;
1617
1618 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1619 if (!contact_status) {
1620 return 0;
1621 }
1622
1623 /* Count qualified available contacts. */
1624 switch (contact_status->status) {
1625 case AVAILABLE:
1626 ++*available;
1627 break;
1628 case UNAVAILABLE:
1629 case UNKNOWN:
1630 case CREATED:
1631 case REMOVED:
1632 break;
1633 }
1634
1635 ao2_ref(contact_status, -1);
1636
1637 return 0;
1638}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)

References ao2_ref, ast_res_pjsip_find_or_create_contact_status(), available(), AVAILABLE, CREATED, REMOVED, ast_sip_contact_status::status, UNAVAILABLE, and UNKNOWN.

Referenced by sip_options_apply_aor_configuration().

◆ sip_options_contact_status_notify_task()

static int sip_options_contact_status_notify_task ( void *  obj)
static

Task to notify an AOR of a contact status change.

Note
Run by aor_options->serializer

Definition at line 811 of file pjsip_options.c.

812{
813 struct sip_options_contact_callback_data *contact_callback_data = obj;
814 struct ast_sip_contact *contact;
815 struct ast_sip_contact_status *cs_old;
816 struct ast_sip_contact_status *cs_new;
817
818 /*
819 * Determine if this is a late arriving notification, as it is
820 * possible that we get a callback from PJSIP giving us contact
821 * status but in the mean time said contact has been removed
822 * from the controlling AOR.
823 */
824
825 if (!contact_callback_data->aor_options->qualify_frequency) {
826 /* Contact qualify response is late */
827 ao2_ref(contact_callback_data, -1);
828 return 0;
829 }
830
831 contact = ao2_find(contact_callback_data->aor_options->contacts,
832 contact_callback_data->contact, OBJ_SEARCH_OBJECT);
833 if (!contact) {
834 /* Contact qualify response is late */
835 ao2_ref(contact_callback_data, -1);
836 return 0;
837 }
838 ao2_ref(contact, -1);
839
841 ast_sorcery_object_get_id(contact_callback_data->contact), OBJ_SEARCH_KEY);
842 if (!cs_old) {
843 /* Contact qualify response is late */
844 ao2_ref(contact_callback_data, -1);
845 return 0;
846 }
847
848 /* Update the contact specific status information */
849 cs_new = sip_contact_status_copy(cs_old);
850 ao2_ref(cs_old, -1);
851 if (!cs_new) {
852 ao2_ref(contact_callback_data, -1);
853 return 0;
854 }
855 cs_new->last_status = cs_new->status;
856 cs_new->status = contact_callback_data->status;
857 cs_new->rtt =
858 cs_new->status == AVAILABLE
859 ? ast_tvdiff_us(ast_tvnow(), contact_callback_data->rtt_start)
860 : 0;
862
863 /*
864 * If the status has changed then notify the endpoint state compositors
865 * and publish our events.
866 */
867 if (cs_new->last_status != cs_new->status) {
868 if (cs_new->status == AVAILABLE) {
869 /* If this is the first available contact then the AOR has become available */
870 ++contact_callback_data->aor_options->available;
871 if (contact_callback_data->aor_options->available == 1) {
873 contact_callback_data->aor_options, AVAILABLE);
874 }
875 } else if (cs_new->last_status == AVAILABLE) {
876 ast_assert(cs_new->status == UNAVAILABLE);
877
878 /* If there are no more available contacts then this AOR is unavailable */
879 --contact_callback_data->aor_options->available;
880 if (!contact_callback_data->aor_options->available) {
882 contact_callback_data->aor_options, UNAVAILABLE);
883 }
884 }
885
886 ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n",
887 cs_new->aor,
888 cs_new->uri,
890 cs_new->rtt / 1000.0);
891
892 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
894 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
895 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
896
898
899 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
900 "Contact: %s\r\n"
901 "Status: %s",
902 cs_new->name,
904 } else {
905 ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
906 cs_new->aor,
907 cs_new->uri,
909 cs_new->rtt / 1000.0);
910 }
911
912 ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
913 cs_new->status != AVAILABLE ? -1 : cs_new->rtt / 1000,
914 1.0,
915 cs_new->name);
916
917 ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
918 "Contact: %s\r\n"
919 "Status: %s\r\n"
920 "RTT: %" PRId64,
921 cs_new->name,
923 cs_new->rtt);
924
925 ast_debug(3, "AOR '%s' now has %d available contacts\n",
926 contact_callback_data->aor_options->name,
927 contact_callback_data->aor_options->available);
928
929 ao2_ref(cs_new, -1);
930 ao2_ref(contact_callback_data, -1);
931
932 return 0;
933}
#define ast_verb(level,...)
static struct ast_sip_contact_status * sip_contact_status_copy(const struct ast_sip_contact_status *src)
#define AST_STATSD_TIMER
Definition statsd.h:41
void AST_OPTIONAL_API_NAME() ast_statsd_log_full_va(const char *metric_name, const char *metric_type, intmax_t value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition res_statsd.c:228
enum ast_sip_contact_status_type status
The new status of the contact.
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition time.h:87

References ao2_find, ao2_link, ao2_ref, ast_sip_contact_status::aor, sip_options_contact_callback_data::aor_options, ast_assert, ast_debug, ast_sip_get_contact_status_label(), ast_sorcery_object_get_id(), AST_STATSD_GAUGE, ast_statsd_log_full_va(), ast_statsd_log_string_va(), AST_STATSD_TIMER, ast_test_suite_event_notify, ast_tvdiff_us(), ast_tvnow(), ast_verb, AVAILABLE, sip_options_aor::available, sip_options_contact_callback_data::contact, sip_options_aor::contacts, ast_sip_contact_status::last_status, ast_sip_contact_status::name, sip_options_aor::name, OBJ_SEARCH_KEY, OBJ_SEARCH_OBJECT, sip_options_aor::qualify_frequency, ast_sip_contact_status::rtt, sip_options_contact_callback_data::rtt_start, sip_contact_status_copy(), sip_options_contact_status_update(), sip_options_contact_statuses, sip_options_notify_endpoint_state_compositors(), ast_sip_contact_status::status, sip_options_contact_callback_data::status, UNAVAILABLE, and ast_sip_contact_status::uri.

Referenced by sip_options_target_result_task().

◆ sip_options_contact_status_update()

static void sip_options_contact_status_update ( struct ast_sip_contact_status contact_status)
static

Definition at line 450 of file pjsip_options.c.

451{
452 struct ast_taskprocessor *mgmt_serializer = management_serializer;
453
454 if (mgmt_serializer) {
455 ao2_ref(contact_status, +1);
457 contact_status)) {
458 ao2_ref(contact_status, -1);
459 }
460 }
461}
static int contact_status_publish_update_task(void *obj)
Task to notify endpoints of a contact status change.

References ao2_ref, ast_sip_push_task, contact_status_publish_update_task(), and management_serializer.

Referenced by ast_res_pjsip_find_or_create_contact_status(), sip_options_contact_status_notify_task(), sip_options_contact_update_task(), sip_options_remove_contact_status(), and sip_options_set_contact_status().

◆ sip_options_contact_statuses_alloc()

static struct ao2_container * sip_options_contact_statuses_alloc ( void  )
static

Helper function to allocate a contact statuses container.

Definition at line 404 of file pjsip_options.c.

405{
406 /*
407 * Replace duplicate objects so we can update the immutable
408 * contact status objects by simply linking in a new object.
409 */
412 ast_sip_contact_status_hash_fn, ast_sip_contact_status_sort_fn,
413 ast_sip_contact_status_cmp_fn);
414}
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
Definition astobj2.h:1211
#define CONTACT_STATUS_BUCKETS
These are the number of contact status buckets.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, and CONTACT_STATUS_BUCKETS.

Referenced by ast_res_pjsip_preinit_options_handling().

◆ sip_options_contact_update_task()

static int sip_options_contact_update_task ( void *  obj)
static

Task which updates a dynamic contact to an AOR.

Note
Run by aor_options->serializer

Definition at line 2603 of file pjsip_options.c.

2604{
2606 struct ast_sip_contact_status *contact_status;
2607
2608 contact_status = ast_sip_get_contact_status(task_data->contact);
2609 if (contact_status) {
2610 switch (contact_status->status) {
2611 case CREATED:
2612 case UNAVAILABLE:
2613 case AVAILABLE:
2614 case UNKNOWN:
2615 /* Refresh the ContactStatus AMI events. */
2616 sip_options_contact_status_update(contact_status);
2617 break;
2618 case REMOVED:
2619 break;
2620 }
2621 ao2_ref(contact_status, -1);
2622 }
2623
2624 ao2_ref(task_data->contact, -1);
2625 ao2_ref(task_data->aor_options, -1);
2627 return 0;
2628}

References ao2_ref, ast_free, ast_sip_get_contact_status(), AVAILABLE, CREATED, REMOVED, sip_options_contact_status_update(), ast_sip_contact_status::status, UNAVAILABLE, and UNKNOWN.

Referenced by contact_observer_updated().

◆ sip_options_determine_initial_qualify_time()

static int sip_options_determine_initial_qualify_time ( int  qualify_frequency)
static

Determine an initial time for scheduling AOR qualifying.

Definition at line 1498 of file pjsip_options.c.

1499{
1500 int initial_interval;
1501 int max_time = ast_sip_get_max_initial_qualify_time();
1502
1503 if (max_time && max_time < qualify_frequency) {
1504 initial_interval = max_time;
1505 } else {
1506 initial_interval = qualify_frequency;
1507 }
1508
1509 initial_interval = (int)((initial_interval * 1000) * ast_random_double());
1510 return 0 < initial_interval ? initial_interval : 1;
1511}
unsigned int ast_sip_get_max_initial_qualify_time(void)
Retrieve the system max initial qualify time.
#define ast_random_double()
Returns a random number between 0.0 and 1.0, inclusive.
Definition utils.h:664

References ast_random_double, ast_sip_get_max_initial_qualify_time(), and sip_options_aor::qualify_frequency.

Referenced by sip_options_apply_aor_configuration().

◆ sip_options_endpoint_compositor_add_task()

static int sip_options_endpoint_compositor_add_task ( void *  obj)
static

Task which adds an AOR to an endpoint state compositor.

Note
Run by aor_options->serializer

Definition at line 1932 of file pjsip_options.c.

1933{
1935
1936 ast_debug(3, "Adding endpoint compositor '%s' to AOR '%s'\n",
1937 task_data->endpoint_state_compositor->name, task_data->aor_options->name);
1938
1939 ao2_ref(task_data->endpoint_state_compositor, +1);
1940 if (AST_VECTOR_APPEND(&task_data->aor_options->compositors,
1941 task_data->endpoint_state_compositor)) {
1942 /* Failed to add so no need to update the endpoint status. Nothing changed. */
1943 ao2_ref(task_data->endpoint_state_compositor, -1);
1944 return 0;
1945 }
1946
1947 ao2_lock(task_data->endpoint_state_compositor);
1949 task_data->aor_options->name,
1950 task_data->aor_options->available ? AVAILABLE : UNAVAILABLE);
1951 ao2_unlock(task_data->endpoint_state_compositor);
1952
1953 return 0;
1954}
static void sip_options_update_endpoint_state_compositor_aor(struct sip_options_endpoint_state_compositor *endpoint_state_compositor, const char *name, enum ast_sip_contact_status_type status)
Update the AOR status on an endpoint state compositor.
Task details for adding an AOR to an endpoint state compositor.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267

References ao2_lock, ao2_ref, ao2_unlock, ast_debug, AST_VECTOR_APPEND, AVAILABLE, sip_options_update_endpoint_state_compositor_aor(), and UNAVAILABLE.

Referenced by sip_options_synchronize_endpoint().

◆ sip_options_endpoint_compositor_remove_task()

static int sip_options_endpoint_compositor_remove_task ( void *  obj)
static

Task which adds removes an AOR from an endpoint state compositor.

Note
Run by aor_options->serializer

Definition at line 1960 of file pjsip_options.c.

1961{
1963 int i;
1964
1965 ast_debug(3, "Removing endpoint compositor '%s' from AOR '%s'\n",
1966 task_data->endpoint_state_compositor->name,
1967 task_data->aor_options->name);
1968
1969 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1970 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1971
1972 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1973 if (endpoint_state_compositor != task_data->endpoint_state_compositor) {
1974 continue;
1975 }
1976
1977 AST_VECTOR_REMOVE(&task_data->aor_options->compositors, i, 0);
1978 ao2_ref(endpoint_state_compositor, -1);
1979 break;
1980 }
1981
1982 return 0;
1983}
Structure which contains composites information for endpoint state.
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition vector.h:440

References ao2_ref, ast_debug, AST_VECTOR_GET, AST_VECTOR_REMOVE, and AST_VECTOR_SIZE.

Referenced by sip_options_endpoint_unlink_aor_feeders().

◆ sip_options_endpoint_observer_deleted_task()

static int sip_options_endpoint_observer_deleted_task ( void *  obj)
static

Task to delete an endpoint from the known universe.

Note
Run by management_serializer

Definition at line 2268 of file pjsip_options.c.

2269{
2270 struct ast_sip_endpoint *endpoint = obj;
2271 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
2272
2273 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
2275 if (!endpoint_state_compositor) {
2276 return 0;
2277 }
2278
2279 ast_debug(3, "Endpoint '%s' has been deleted, removing endpoint state compositor from AORs\n",
2280 ast_sorcery_object_get_id(endpoint));
2281 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
2282 ao2_ref(endpoint_state_compositor, -1);
2283
2284 return 0;
2285}
static void sip_options_endpoint_unlink_aor_feeders(struct ast_sip_endpoint *endpoint, struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
Unlink AORs feeding the endpoint status compositor.

References ao2_find, ao2_ref, ast_debug, ast_sorcery_object_get_id(), OBJ_SEARCH_KEY, OBJ_UNLINK, sip_options_endpoint_state_compositors, and sip_options_endpoint_unlink_aor_feeders().

Referenced by endpoint_observer_deleted().

◆ sip_options_endpoint_observer_modified_task()

static int sip_options_endpoint_observer_modified_task ( void *  obj)
static

Task to synchronize the endpoint.

Note
Run by management_serializer

Definition at line 2298 of file pjsip_options.c.

2299{
2300 struct ast_sip_endpoint *endpoint = obj;
2301 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
2302
2303 ast_debug(3, "Endpoint '%s' has been created or modified, updating state\n",
2304 ast_sorcery_object_get_id(endpoint));
2305
2306 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
2308 if (endpoint_state_compositor) {
2309 /* Unlink the AORs currently feeding the endpoint. */
2310 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
2311 ao2_ref(endpoint_state_compositor, -1);
2312 }
2313
2314 /* Connect the AORs that now feed the endpoint. */
2316 return 0;
2317}

References ao2_find, ao2_ref, ast_debug, ast_sorcery_object_get_id(), NULL, OBJ_SEARCH_KEY, OBJ_UNLINK, sip_options_endpoint_state_compositors, sip_options_endpoint_unlink_aor_feeders(), and sip_options_synchronize_endpoint().

Referenced by endpoint_observer_modified().

◆ sip_options_endpoint_state_compositor_dtor()

static void sip_options_endpoint_state_compositor_dtor ( void *  obj)
static

Destructor for endpoint state compositors.

Definition at line 1863 of file pjsip_options.c.

1864{
1865 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1866
1867 ao2_cleanup(endpoint_state_compositor->aor_statuses);
1868}
struct ao2_container * aor_statuses
The last contributed available status of the AORs feeding this compositor.

References ao2_cleanup, and sip_options_endpoint_state_compositor::aor_statuses.

Referenced by sip_options_endpoint_state_compositor_find_or_alloc().

◆ sip_options_endpoint_state_compositor_find_or_alloc()

static struct sip_options_endpoint_state_compositor * sip_options_endpoint_state_compositor_find_or_alloc ( const struct ast_sip_endpoint endpoint)
static

Find (or create) an endpoint state compositor.

Definition at line 1877 of file pjsip_options.c.

1878{
1879 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1880
1882 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1884 if (endpoint_state_compositor) {
1886 return endpoint_state_compositor;
1887 }
1888
1889 endpoint_state_compositor = ao2_alloc(sizeof(*endpoint_state_compositor)
1890 + strlen(ast_sorcery_object_get_id(endpoint)) + 1,
1892 if (!endpoint_state_compositor) {
1894 return NULL;
1895 }
1896
1897 /*
1898 * NOTE: The endpoint_state_compositor->aor_statuses container is
1899 * externally protected by the endpoint_state_compositor lock.
1900 */
1901 endpoint_state_compositor->aor_statuses = ao2_container_alloc_hash(
1903 sip_options_endpoint_aor_status_hash_fn, NULL,
1904 sip_options_endpoint_aor_status_cmp_fn);
1905 if (!endpoint_state_compositor->aor_statuses) {
1907 ao2_ref(endpoint_state_compositor, -1);
1908 return NULL;
1909 }
1910
1911 strcpy(endpoint_state_compositor->name, ast_sorcery_object_get_id(endpoint)); /* SAFE */
1912
1913 ao2_link_flags(sip_options_endpoint_state_compositors, endpoint_state_compositor,
1914 OBJ_NOLOCK);
1916
1917 return endpoint_state_compositor;
1918}
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
static void sip_options_endpoint_state_compositor_dtor(void *obj)
Destructor for endpoint state compositors.
#define AOR_STATUS_BUCKETS
These are the number of buckets (per endpoint state compositor) to use to store AOR statuses.
char name[0]
The name of the endpoint.

References ao2_alloc, AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_hash, ao2_find, ao2_link_flags, ao2_lock, ao2_ref, ao2_unlock, AOR_STATUS_BUCKETS, sip_options_endpoint_state_compositor::aor_statuses, ast_sorcery_object_get_id(), sip_options_endpoint_state_compositor::name, NULL, OBJ_NOLOCK, OBJ_SEARCH_KEY, sip_options_endpoint_state_compositor_dtor(), and sip_options_endpoint_state_compositors.

Referenced by sip_options_synchronize_endpoint().

◆ sip_options_endpoint_unlink_aor_feeders()

static void sip_options_endpoint_unlink_aor_feeders ( struct ast_sip_endpoint endpoint,
struct sip_options_endpoint_state_compositor endpoint_state_compositor 
)
static

Unlink AORs feeding the endpoint status compositor.

Note
Run by management_serializer

Definition at line 2224 of file pjsip_options.c.

2226{
2227 struct ao2_iterator it_aor_statuses;
2228 struct sip_options_endpoint_aor_status *aor_status;
2230 .endpoint_state_compositor = endpoint_state_compositor,
2231 };
2232
2235
2236 /* Unlink AOR feeders pointing to endpoint */
2238 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
2239 task_data.aor_options = ao2_find(sip_options_aors, aor_status->name,
2241 if (!task_data.aor_options) {
2242 continue;
2243 }
2244
2245 ast_debug(3, "Removing endpoint state compositor '%s' from AOR '%s'\n",
2246 ast_sorcery_object_get_id(endpoint), aor_status->name);
2248 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2251 ao2_ref(task_data.aor_options, -1);
2252 }
2253 ao2_iterator_destroy(&it_aor_statuses);
2254
2255 /*
2256 * We do not need to remove the AOR feeder status memory from the
2257 * aor_statuses container. The endpoint_state_compositor is about
2258 * to die and do it for us.
2259 */
2260
2262}
static int sip_options_endpoint_compositor_remove_task(void *obj)
Task which adds removes an AOR from an endpoint state compositor.
Structure which contains status information for an AOR feeding an endpoint state compositor.
char name[0]
The name of the AOR.
struct sip_options_endpoint_state_compositor * endpoint_state_compositor
The endpoint state compositor.
char active
Non-zero if the compositor is in normal operation. i.e. Not being setup/reconfigured.

References sip_options_endpoint_state_compositor::active, ao2_find, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_lock, ao2_ref, ao2_unlock, sip_options_endpoint_state_compositor::aor_statuses, ast_debug, ast_sip_push_task_wait_serializer, ast_sorcery_object_get_id(), sip_options_endpoint_compositor_task_data::endpoint_state_compositor, sip_options_endpoint_aor_status::name, OBJ_SEARCH_KEY, sip_options_aors, and sip_options_endpoint_compositor_remove_task().

Referenced by sip_options_endpoint_observer_deleted_task(), and sip_options_endpoint_observer_modified_task().

◆ sip_options_get_endpoint_state_compositor_state()

static enum ast_endpoint_state sip_options_get_endpoint_state_compositor_state ( const struct sip_options_endpoint_state_compositor endpoint_state_compositor)
static

Return the current state of an endpoint state compositor.

Precondition
The endpoint_state_compositor lock must be held.

Definition at line 707 of file pjsip_options.c.

709{
710 struct ao2_iterator it_aor_statuses;
711 struct sip_options_endpoint_aor_status *aor_status;
713
714 it_aor_statuses = ao2_iterator_init(endpoint_state_compositor->aor_statuses, 0);
715 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
716 if (aor_status->available) {
718 ao2_ref(aor_status, -1);
719 break;
720 }
721 }
722 ao2_iterator_destroy(&it_aor_statuses);
723
724 return state;
725}
ast_endpoint_state
Valid states for an endpoint.
Definition endpoints.h:51
@ AST_ENDPOINT_OFFLINE
Definition endpoints.h:55
@ AST_ENDPOINT_ONLINE
Definition endpoints.h:57
char available
The last contributed available status of the named AOR (1 if available, 0 if not available)

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, sip_options_endpoint_state_compositor::aor_statuses, AST_ENDPOINT_OFFLINE, AST_ENDPOINT_ONLINE, and sip_options_endpoint_aor_status::available.

Referenced by sip_options_synchronize_endpoint(), and sip_options_update_endpoint_state_compositor_aor().

◆ sip_options_init_task()

static int sip_options_init_task ( void *  mgmt_serializer)
static

Management task to finish setting up the environment.

Note
Run by management_serializer

Definition at line 3283 of file pjsip_options.c.

3284{
3285 management_serializer = mgmt_serializer;
3286
3289 return -1;
3290 }
3293 return -1;
3294 }
3297 return -1;
3298 }
3299
3301
3302 return 0;
3303}
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition sorcery.c:2455

References aor_observer_callbacks, ast_sip_get_sorcery(), ast_sorcery_observer_add(), contact_observer_callbacks, endpoint_observer_callbacks, management_serializer, and sip_options_synchronize().

Referenced by ast_res_pjsip_init_options_handling().

◆ sip_options_notify_endpoint_state_compositors()

static void sip_options_notify_endpoint_state_compositors ( struct sip_options_aor aor_options,
enum ast_sip_contact_status_type  status 
)
static

Function which notifies endpoint state compositors of a state change of an AOR.

Definition at line 785 of file pjsip_options.c.

787{
788 int i;
789
790 /* Iterate through the associated endpoint state compositors updating them */
791 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
792 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
793
794 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
795
796 ao2_lock(endpoint_state_compositor);
797 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
798 aor_options->name, status);
799 ao2_unlock(endpoint_state_compositor);
800 }
801
802 if (status == REMOVED) {
804 }
805}

References ao2_cleanup, ao2_lock, ao2_unlock, AST_VECTOR_GET, AST_VECTOR_RESET, AST_VECTOR_SIZE, sip_options_aor::compositors, sip_options_aor::name, REMOVED, sip_options_update_endpoint_state_compositor_aor(), and status.

Referenced by sip_options_aor_remove_task(), sip_options_contact_add_task(), sip_options_contact_delete_task(), sip_options_contact_status_notify_task(), sip_options_remove_contact_status(), and sip_options_update_aor_task().

◆ sip_options_publish_contact_state()

static void sip_options_publish_contact_state ( const struct sip_options_aor aor_options,
const struct ast_sip_contact_status contact_status 
)
static

Function which publishes a contact status update to all interested endpoints.

Definition at line 417 of file pjsip_options.c.

419{
420 int i;
421
422 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
423 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
424
425 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
427 contact_status);
428 }
429}
void ast_sip_persistent_endpoint_publish_contact_state(const char *endpoint_name, const struct ast_sip_contact_status *contact_status)
Publish the change of state for a contact.

References ast_sip_persistent_endpoint_publish_contact_state(), AST_VECTOR_GET, AST_VECTOR_SIZE, sip_options_aor::compositors, and sip_options_endpoint_state_compositor::name.

Referenced by contact_status_publish_update_task().

◆ sip_options_qualify_aor()

static int sip_options_qualify_aor ( void *  obj)
static

Task to qualify contacts of an AOR.

Note
Run by aor_options->serializer

Definition at line 1331 of file pjsip_options.c.

1332{
1333 struct sip_options_aor *aor_options = obj;
1334
1335 ast_debug(3, "Qualifying all contacts on AOR '%s'\n", aor_options->name);
1336
1337 /* Attempt to send an OPTIONS request to every contact on this AOR */
1339 (struct sip_options_aor *) aor_options);
1340
1341 /* Always reschedule to the frequency we should go */
1342 return aor_options->qualify_frequency * 1000;
1343}
static int sip_options_qualify_contact(void *obj, void *arg, int flags)
Send a SIP OPTIONS request for a contact.

References ao2_callback, ast_debug, sip_options_aor::contacts, sip_options_aor::name, OBJ_NODATA, sip_options_aor::qualify_frequency, and sip_options_qualify_contact().

Referenced by ami_sip_qualify(), cli_qualify(), sip_options_apply_aor_configuration(), and sip_options_contact_add_task().

◆ sip_options_qualify_contact()

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

Send a SIP OPTIONS request for a contact.

Definition at line 1236 of file pjsip_options.c.

1237{
1238 struct ast_sip_contact *contact = obj;
1239 struct sip_options_aor *aor_options = arg;
1240 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1241 pjsip_tx_data *tdata;
1242 pjsip_host_info destination;
1243 struct ast_sip_contact_status *contact_status;
1244 struct sip_options_contact_callback_data *contact_callback_data;
1245
1246 ast_debug(3, "Qualifying contact '%s' on AOR '%s'\n",
1248
1252 }
1254 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1255
1256 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, 0);
1257 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1258 endpoint_state_compositor->name);
1259 }
1260 if (!endpoint) {
1261 ast_debug(3, "Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
1262 ast_sorcery_object_get_id(contact), aor_options->name);
1263 return 0;
1264 }
1265
1266 /*
1267 * Create a request solely for DNS resolution. Its pool keeps the resolver strings alive,
1268 * and passing a URI with no contact avoids leaving a contact reference behind in case
1269 * resolution fails before it can send.
1270 */
1271 if (ast_sip_create_request("OPTIONS", NULL, endpoint, contact->uri, NULL,
1272 &tdata)) {
1273 ast_log(LOG_ERROR, "Unable to create request to qualify contact %s on AOR %s\n",
1274 contact->uri, aor_options->name);
1275 return 0;
1276 }
1277
1278 /* If an outbound proxy is specified set it on this request */
1279 if (!ast_strlen_zero(contact->outbound_proxy) &&
1280 ast_sip_set_outbound_proxy(tdata, contact->outbound_proxy)) {
1281 ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
1282 contact->uri);
1283 pjsip_tx_data_dec_ref(tdata);
1284 return 0;
1285 }
1286
1287 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1288 if (!contact_status) {
1289 ast_log(LOG_ERROR, "Unable to retrieve contact status information for contact %s on AOR %s\n",
1290 contact->uri, aor_options->name);
1291 pjsip_tx_data_dec_ref(tdata);
1292 return 0;
1293 }
1294 ao2_ref(contact_status, -1);
1295
1296 contact_callback_data = sip_options_contact_callback_data_alloc(contact,
1297 aor_options, endpoint, tdata);
1298 if (!contact_callback_data) {
1299 ast_log(LOG_ERROR, "Unable to create object to contain callback data for contact %s on AOR %s\n",
1300 contact->uri, aor_options->name);
1301 pjsip_tx_data_dec_ref(tdata);
1302 return 0;
1303 }
1304
1305
1306 /*
1307 * Resolve the contact destination explicitly via DNS, then create and send
1308 * an independent OPTIONS for each returned transport/address/port tuple.
1309 * Keep the resolver-only tdata alive because its pool owns strings used
1310 * by the asynchronous resolver.
1311 */
1312 if (pjsip_get_request_dest(tdata, &destination) != PJ_SUCCESS
1313 || sip_options_apply_transport_to_destination(tdata, &destination)
1314 != PJ_SUCCESS) {
1315 ast_log(LOG_ERROR, "Unable to resolve destination to qualify contact %s on AOR %s\n",
1316 contact->uri, aor_options->name);
1317 ao2_ref(contact_callback_data, -1);
1318 return 0;
1319 }
1320
1321 pjsip_endpt_resolve(ast_sip_get_pjsip_endpoint(), tdata->pool, &destination,
1322 contact_callback_data, sip_options_qualify_resolve_cb);
1323
1324 return 0;
1325}
static struct sip_options_contact_callback_data * sip_options_contact_callback_data_alloc(struct ast_sip_contact *contact, struct sip_options_aor *aor_options, struct ast_sip_endpoint *endpoint, pjsip_tx_data *resolve_tdata)
Contact callback data allocator.
static void sip_options_qualify_resolve_cb(pj_status_t status, void *token, const pjsip_server_addresses *addresses)
DNS callback used to fan out a qualify to every resolved target.
static pj_status_t sip_options_apply_transport_to_destination(const pjsip_tx_data *tdata, pjsip_host_info *destination)
Apply a request's transport selector to its DNS destination.
int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy)
Set the outbound proxy for an outbound SIP message.
Definition res_pjsip.c:2035
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
Definition res_pjsip.c:1433
const ast_string_field endpoint_name
Definition res_pjsip.h:414

References ao2_cleanup, ao2_ref, sip_options_contact_callback_data::aor_options, ast_debug, ast_log, ast_res_pjsip_find_or_create_contact_status(), ast_sip_create_request(), ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sip_set_outbound_proxy(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_id(), ast_strlen_zero(), AST_VECTOR_GET, AST_VECTOR_SIZE, sip_options_aor::compositors, sip_options_contact_callback_data::contact, sip_options_contact_callback_data::endpoint, ast_sip_contact::endpoint_name, LOG_ERROR, sip_options_endpoint_state_compositor::name, sip_options_aor::name, NULL, ast_sip_contact::outbound_proxy, RAII_VAR, sip_options_apply_transport_to_destination(), sip_options_contact_callback_data_alloc(), sip_options_qualify_resolve_cb(), and ast_sip_contact::uri.

Referenced by sip_options_qualify_aor().

◆ sip_options_qualify_resolve_cb()

static void sip_options_qualify_resolve_cb ( pj_status_t  status,
void *  token,
const pjsip_server_addresses *  addresses 
)
static

DNS callback used to fan out a qualify to every resolved target.

Definition at line 1141 of file pjsip_options.c.

1143{
1146 unsigned int idx;
1147
1150 if (!task_data) {
1151 /*
1152 * Resolver callbacks are not guaranteed to run on the AOR serializer,
1153 * so on allocation failure we must log and drop to avoid potential state
1154 * issues.
1155 */
1157 "Unable to allocate qualify resolve task for '%s'\n",
1159 ao2_ref(batch, -1);
1160 return;
1161 }
1162
1163 memset(task_data, 0, sizeof(*task_data));
1164 task_data->batch = ao2_bump(batch);
1165 task_data->status = status;
1166
1167 if (status != PJ_SUCCESS || !addresses || !addresses->count) {
1168 if (batch->resolve_tdata) {
1169 pjsip_tx_data_dec_ref(batch->resolve_tdata);
1170 batch->resolve_tdata = NULL;
1171 }
1172
1173 if (ast_sip_push_task(batch->aor_options->serializer,
1176 "Unable to queue qualify resolve task for '%s'\n",
1178 ao2_ref(task_data, -1);
1179 }
1180 ao2_ref(batch, -1);
1181 return;
1182 }
1183
1184 /* Each resolved address must contribute exactly one batch result. */
1185 task_data->count = addresses->count;
1186 if (task_data->count > PJSIP_MAX_RESOLVED_ADDRESSES) {
1187 task_data->count = PJSIP_MAX_RESOLVED_ADDRESSES;
1188 }
1189
1190 for (idx = 0; idx < task_data->count; ++idx) {
1191 char *name_copy;
1192
1193 name_copy = ast_malloc(addresses->entry[idx].name.slen + 1);
1194 if (!name_copy) {
1195 task_data->status = PJ_ENOMEM;
1196 task_data->count = idx;
1197 break;
1198 }
1199
1200 ast_copy_pj_str(name_copy, &addresses->entry[idx].name,
1201 addresses->entry[idx].name.slen + 1);
1202 task_data->names[idx] = name_copy;
1203 task_data->addresses.entry[idx] = addresses->entry[idx];
1204 task_data->addresses.entry[idx].name.ptr = name_copy;
1205 task_data->addresses.entry[idx].name.slen = addresses->entry[idx].name.slen;
1206 }
1207
1208 if (task_data->status == PJ_SUCCESS) {
1209 task_data->addresses.count = task_data->count;
1210 }
1211
1212 if (batch->resolve_tdata) {
1213 pjsip_tx_data_dec_ref(batch->resolve_tdata);
1214 batch->resolve_tdata = NULL;
1215 }
1216
1217 /*
1218 * Push the qualify resolve task to the AOR serializer to avoid potential race
1219 * conditions between the resolve callback and the qualify contact task.
1220 */
1221 if (ast_sip_push_task(batch->aor_options->serializer,
1224 "Unable to queue qualify resolve task for '%s'\n",
1226 ao2_ref(task_data, -1);
1227 } else {
1228 ao2_ref(batch, -1);
1229 return;
1230 }
1231
1232 ao2_ref(batch, -1);
1233}
static void sip_options_qualify_resolve_task_dtor(void *obj)
static int sip_options_qualify_resolve_task(void *obj)
Process a DNS resolution result on the AOR serializer.

References sip_options_qualify_resolve_task_data::addresses, AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ao2_ref, ast_copy_pj_str(), ast_log, ast_malloc, ast_sip_push_task, ast_sorcery_object_get_id(), batch, LOG_WARNING, NULL, sip_options_qualify_resolve_task(), sip_options_qualify_resolve_task_dtor(), and status.

Referenced by sip_options_qualify_contact().

◆ sip_options_qualify_resolve_task()

static int sip_options_qualify_resolve_task ( void *  obj)
static

Process a DNS resolution result on the AOR serializer.

Definition at line 590 of file pjsip_options.c.

591{
594 unsigned int idx;
595
596 if (task_data->status != PJ_SUCCESS || !task_data->count) {
597 /* This failure is a de facto single pending result. */
598 batch->pending = 1;
600 ao2_ref(task_data, -1);
601 return 0;
602 }
603
604 /* Each resolved address must contribute exactly one batch result. */
605 batch->pending = task_data->count;
606
607 for (idx = 0; idx < task_data->count; ++idx) {
608 pjsip_tx_data *tdata;
609 pjsip_via_hdr *via;
610 pjsip_transaction *tsx = NULL;
611
612 if (ast_sip_create_request("OPTIONS", NULL, batch->endpoint, NULL,
613 batch->contact, &tdata)) {
615 continue;
616 }
617
618 if (!ast_strlen_zero(batch->contact->outbound_proxy) &&
619 ast_sip_set_outbound_proxy(tdata, batch->contact->outbound_proxy)) {
620 pjsip_tx_data_dec_ref(tdata);
622 continue;
623 }
624
625 /*
626 * Build a new request per resolved target so each send gets its own
627 * transaction and Via branch. Setting exactly one pre-resolved
628 * destination here avoids PJSIP re-resolving and choosing only the
629 * first DNS result.
630 */
631 tdata->dest_info.addr.count = 1;
632 tdata->dest_info.cur_addr = 0;
633 tdata->dest_info.addr.entry[0].type = task_data->addresses.entry[idx].type;
634 tdata->dest_info.addr.entry[0].priority = task_data->addresses.entry[idx].priority;
635 tdata->dest_info.addr.entry[0].weight = task_data->addresses.entry[idx].weight;
636 tdata->dest_info.addr.entry[0].addr_len = task_data->addresses.entry[idx].addr_len;
637 pj_sockaddr_cp(&tdata->dest_info.addr.entry[0].addr,
638 &task_data->addresses.entry[idx].addr);
639 pj_strdup(tdata->pool, &tdata->dest_info.addr.entry[0].name,
640 &task_data->addresses.entry[idx].name);
641 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
642 if (via) {
643 via->branch_param.slen = 0;
644 }
645
646 /* ast_sip_send_out_of_dialog_request_with_tsx consumes the tdata reference. */
648 (int)(batch->aor_options->qualify_timeout * 1000),
650 ao2_ref(batch, -1);
652 } else if (tsx) {
653 /*
654 * It is possible that we will not get back a transaction under two circumstances:
655 * 1. The send failed.
656 * 2. The build of PJPROJECT used does not contain pjsip_endpt_send_request2() so
657 * there is no way to get an in-flight transaction reference for the OPTIONS.
658 *
659 * With no transaction references, we can not cancel in-flight OPTIONS requests when
660 * an endpoint responds with a 2xx response to one of the requests. This is not ideal
661 * and will result in unnecessary OPTIONS retransmissions being sent.
662 *
663 * The Append should never fail as we init the vector to PJSIP_MAX_RESOLVED_ADDRESSES
664 * and also limit the count of resolved addresses in sip_options_qualify_resolve_cb.
665 */
666 AST_VECTOR_APPEND(&batch->target_transactions, tsx);
667 }
668 }
669
670 ao2_ref(task_data, -1);
671 return 0;
672}
static void qualify_contact_cb(void *token, pjsip_event *e)
Callback for an OPTIONS response, timeout, or transport error.
int ast_sip_send_out_of_dialog_request_with_tsx(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint, int timeout, void *token, void(*callback)(void *token, pjsip_event *e), pjsip_transaction **tsx)
Send an Out-Of-Dialog SIP request and return its transaction.
Definition res_pjsip.c:1969

References ao2_bump, ao2_ref, ast_sip_create_request(), ast_sip_send_out_of_dialog_request_with_tsx(), ast_sip_set_outbound_proxy(), ast_strlen_zero(), AST_VECTOR_APPEND, batch, NULL, qualify_contact_cb(), sip_options_queue_target_result(), and UNAVAILABLE.

Referenced by sip_options_qualify_resolve_cb().

◆ sip_options_qualify_resolve_task_dtor()

static void sip_options_qualify_resolve_task_dtor ( void *  obj)
static

Definition at line 577 of file pjsip_options.c.

578{
580 unsigned int idx;
581
582 for (idx = 0; idx < task_data->count; ++idx) {
583 ast_free(task_data->names[idx]);
584 }
585
586 ao2_ref(task_data->batch, -1);
587}

References ao2_ref, and ast_free.

Referenced by sip_options_qualify_resolve_cb().

◆ sip_options_queue_target_result()

static void sip_options_queue_target_result ( struct sip_options_contact_callback_data batch,
enum ast_sip_contact_status_type  status 
)
static

Queue a resolved target's qualification result to be combined with the other targets.

Definition at line 977 of file pjsip_options.c.

980{
982
985 if (!result) {
986 ast_log(LOG_WARNING, "Unable to allocate qualify target result for '%s'\n",
988 return;
989 }
990
991 result->batch = ao2_bump(batch);
992 result->status = status;
993 /*
994 * Callbacks may arrive on non-serializer threads, so they queue one result per
995 * target onto the AOR serializer, the single owner of the batch's processing.
996 *
997 * Sends and callbacks can execute synchronously while we are already
998 * running on that serializer thread. Re-queueing to the same serializer in
999 * that case would defer updates and can break processing.
1000 *
1001 * Process inline when already on the same taskpool serializer to preserve
1002 * immediate, in-order state transitions.
1003 */
1004 if (batch->aor_options->serializer == ast_taskpool_serializer_get_current()) {
1006 return;
1007 }
1008
1009 if (ast_sip_push_task(batch->aor_options->serializer,
1011 ast_log(LOG_WARNING, "Unable to queue qualify target result for '%s'\n",
1013 ao2_ref(result, -1);
1014 }
1015}
static PGresult * result
Definition cel_pgsql.c:84
static int sip_options_target_result_task(void *obj)
Combine the result of one resolved target with the other targets.
static void sip_options_target_result_dtor(void *obj)
Destructor for a resolved target's qualification result.
Result of qualifying an individual address belonging to a contact resolved from an A,...
struct ast_taskprocessor * ast_taskpool_serializer_get_current(void)
Get the taskpool serializer currently associated with this thread.
Definition taskpool.c:842

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ao2_ref, ast_log, ast_sip_push_task, ast_sorcery_object_get_id(), ast_taskpool_serializer_get_current(), batch, LOG_WARNING, result, sip_options_target_result_dtor(), sip_options_target_result_task(), and status.

Referenced by qualify_contact_cb(), and sip_options_qualify_resolve_task().

◆ sip_options_remove_contact()

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

Forward declaration of this helpful function.

Callback function to remove a contact and its contact status from an AOR.

Definition at line 1487 of file pjsip_options.c.

1488{
1489 struct ast_sip_contact *contact = obj;
1490 struct sip_options_aor *aor_options = arg;
1491
1492 sip_options_remove_contact_status(aor_options, contact);
1493
1494 return CMP_MATCH;
1495}
@ CMP_MATCH
Definition astobj2.h:1027

References CMP_MATCH, and sip_options_remove_contact_status().

Referenced by sip_options_aor_dtor(), and sip_options_apply_aor_configuration().

◆ sip_options_remove_contact_status()

static void sip_options_remove_contact_status ( struct sip_options_aor aor_options,
struct ast_sip_contact contact 
)
static

Remove contact status for a hint.

Definition at line 1414 of file pjsip_options.c.

1416{
1417 struct ast_sip_contact_status *cs_new;
1418 struct ast_sip_contact_status *cs_old;
1419
1422 if (!cs_old) {
1423 ast_debug(3, "Attempted to remove contact status for '%s' but it does not exist\n",
1424 ast_sorcery_object_get_id(contact));
1425 return;
1426 }
1427
1428 ast_verb(2, "Contact %s/%s has been deleted\n", contact->aor, contact->uri);
1429
1430 /* Update the contact status to reflect its new state */
1431 cs_new = sip_contact_status_copy(cs_old);
1432 if (!cs_new) {
1433 /*
1434 * We'll have to violate the immutable property because we
1435 * couldn't create a new one to modify and we are deleting
1436 * the contact status anyway.
1437 */
1438 cs_new = cs_old;
1439 } else {
1440 ao2_ref(cs_old, -1);
1441 }
1442 cs_new->last_status = cs_new->status;
1443 cs_new->status = REMOVED;
1444 cs_new->rtt = 0;
1445
1446 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1447 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1448 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1449 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1450
1452
1453 /*
1454 * The only time we need to update the AOR is if this contact was
1455 * available and qualify is in use, otherwise we can just stop
1456 * early.
1457 */
1458 if (!aor_options->qualify_frequency || cs_new->last_status != AVAILABLE) {
1459 ao2_ref(cs_new, -1);
1460 return;
1461 }
1462
1463 --aor_options->available;
1464 if (!aor_options->available) {
1466 }
1467
1468 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1469 aor_options->available);
1470
1471 ao2_ref(cs_new, -1);
1472}

References ao2_find, ao2_ref, ast_sip_contact::aor, ast_debug, ast_sip_get_contact_status_label(), ast_sorcery_object_get_id(), AST_STATSD_GAUGE, ast_statsd_log_string_va(), ast_verb, AVAILABLE, sip_options_aor::available, ast_sip_contact_status::last_status, sip_options_aor::name, OBJ_SEARCH_KEY, OBJ_UNLINK, sip_options_aor::qualify_frequency, REMOVED, ast_sip_contact_status::rtt, sip_contact_status_copy(), sip_options_contact_status_update(), sip_options_contact_statuses, sip_options_notify_endpoint_state_compositors(), ast_sip_contact_status::status, UNAVAILABLE, and ast_sip_contact::uri.

Referenced by sip_options_contact_delete_task(), and sip_options_remove_contact().

◆ sip_options_set_contact_status()

static void sip_options_set_contact_status ( struct ast_sip_contact_status contact_status,
enum ast_sip_contact_status_type  status 
)
static

Set the contact status for a contact.

Definition at line 1514 of file pjsip_options.c.

1516{
1517 struct ast_sip_contact_status *cs_new;
1518
1519 /* Update the contact specific status information */
1520 cs_new = sip_contact_status_copy(contact_status);
1521 if (!cs_new) {
1522 return;
1523 }
1524 cs_new->last_status = cs_new->status;
1525 cs_new->status = status;
1526
1527 /*
1528 * We need to always set the RTT to zero because we haven't completed
1529 * an OPTIONS ping so RTT is unknown. If the OPTIONS ping were still
1530 * running it will be refreshed on the next go round anyway.
1531 */
1532 cs_new->rtt = 0;
1533
1535
1536 if (cs_new->status != cs_new->last_status) {
1537 ast_verb(3, "Contact %s/%s is now %s.\n",
1538 cs_new->aor, cs_new->uri,
1540
1541 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1542 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1543 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1544 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1545
1547
1548 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
1549 "Contact: %s\r\n"
1550 "Status: %s",
1551 cs_new->name,
1553 }
1554 ao2_ref(cs_new, -1);
1555}

References ao2_link, ao2_ref, ast_sip_contact_status::aor, ast_sip_get_contact_status_label(), AST_STATSD_GAUGE, ast_statsd_log_string_va(), ast_test_suite_event_notify, ast_verb, ast_sip_contact_status::last_status, ast_sip_contact_status::name, ast_sip_contact_status::rtt, sip_contact_status_copy(), sip_options_contact_status_update(), sip_options_contact_statuses, status, ast_sip_contact_status::status, and ast_sip_contact_status::uri.

Referenced by sip_options_set_contact_status_qualified(), and sip_options_set_contact_status_unqualified().

◆ sip_options_set_contact_status_qualified()

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

Transition the contact status to qualified mode.

Definition at line 1585 of file pjsip_options.c.

1586{
1587 struct ast_sip_contact *contact = obj;
1588 struct ast_sip_contact_status *contact_status;
1589
1590 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1591 if (!contact_status) {
1592 return 0;
1593 }
1594
1595 switch (contact_status->status) {
1596 case AVAILABLE:
1598 break;
1599 case UNAVAILABLE:
1600 case UNKNOWN:
1601 case CREATED:
1602 case REMOVED:
1603 break;
1604 }
1605
1606 ao2_ref(contact_status, -1);
1607
1608 return 0;
1609}
static void sip_options_set_contact_status(struct ast_sip_contact_status *contact_status, enum ast_sip_contact_status_type status)
Set the contact status for a contact.

References ao2_ref, ast_res_pjsip_find_or_create_contact_status(), AVAILABLE, CREATED, REMOVED, sip_options_set_contact_status(), ast_sip_contact_status::status, UNAVAILABLE, and UNKNOWN.

Referenced by sip_options_apply_aor_configuration().

◆ sip_options_set_contact_status_unqualified()

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

Transition the contact status to unqualified mode.

Definition at line 1558 of file pjsip_options.c.

1559{
1560 struct ast_sip_contact *contact = obj;
1561 struct ast_sip_contact_status *contact_status;
1562
1563 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1564 if (!contact_status) {
1565 return 0;
1566 }
1567
1568 switch (contact_status->status) {
1569 case AVAILABLE:
1570 case UNAVAILABLE:
1571 case UNKNOWN:
1572 sip_options_set_contact_status(contact_status, CREATED);
1573 break;
1574 case CREATED:
1575 case REMOVED:
1576 break;
1577 }
1578
1579 ao2_ref(contact_status, -1);
1580
1581 return 0;
1582}

References ao2_ref, ast_res_pjsip_find_or_create_contact_status(), AVAILABLE, CREATED, REMOVED, sip_options_set_contact_status(), ast_sip_contact_status::status, UNAVAILABLE, and UNKNOWN.

Referenced by sip_options_apply_aor_configuration().

◆ sip_options_synchronize()

static void sip_options_synchronize ( int  reload)
static

Synchronize our local container of AORs and endpoint state compositors with the current configuration.

Definition at line 2210 of file pjsip_options.c.

2211{
2213 .reload = reload,
2214 };
2215
2217 &task_data);
2218}
static int sip_options_synchronize_task(void *obj)
Task to synchronize our local container of AORs and endpoint state compositors with the current confi...
Structure which contains information required to synchronize.

References ast_sip_push_task_wait_serializer, management_serializer, reload(), and sip_options_synchronize_task().

Referenced by ast_res_pjsip_init_options_handling(), and sip_options_init_task().

◆ sip_options_synchronize_aor()

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

Synchronize an AOR with our local state.

Note
Run by management_serializer

Definition at line 1826 of file pjsip_options.c.

1827{
1829 .aor = obj,
1830 .existing = arg,
1831 };
1832
1833 task_data.aor_options = ao2_find(sip_options_aors,
1835 if (!task_data.aor_options) {
1836 task_data.aor_options = sip_options_aor_alloc(task_data.aor);
1837 if (!task_data.aor_options) {
1838 return 0;
1839 }
1840
1841 task_data.added = 1;
1842
1843 /* Nothing is aware of this AOR yet so we can just update it in this thread */
1845 ao2_link(sip_options_aors, task_data.aor_options);
1846 } else {
1847 /* This AOR already exists so we have to do manipulation in its serializer */
1848 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1850 }
1851
1852 ao2_ref(task_data.aor_options, -1);
1853
1854 if (task_data.existing) {
1857 }
1858
1859 return 0;
1860}
static int sip_options_synchronize_aor_task(void *obj)
Task to synchronize an AOR with our local state.

References ao2_find, ao2_link, ao2_ref, ast_sip_push_task_wait_serializer, ast_sorcery_object_get_id(), OBJ_NODATA, OBJ_SEARCH_KEY, OBJ_UNLINK, sip_options_aor_alloc(), sip_options_aors, and sip_options_synchronize_aor_task().

Referenced by sip_options_synchronize_task().

◆ sip_options_synchronize_aor_task()

static int sip_options_synchronize_aor_task ( void *  obj)
static

Task to synchronize an AOR with our local state.

Note
Run by aor_options->serializer (or management_serializer on aor_options creation)

Definition at line 1788 of file pjsip_options.c.

1789{
1791 int i;
1792
1793 ast_debug(3, "Synchronizing AOR '%s' with current state of configuration and world\n",
1794 task_data->aor_options->name);
1795
1797 task_data->added);
1798
1799 /*
1800 * Endpoint state compositors are removed in this operation but not
1801 * added. To reduce the amount of work done they are done later. In
1802 * the mean time things can still qualify and once an endpoint state
1803 * compositor is added to the AOR it will be updated with the current
1804 * state.
1805 */
1806 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1807 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1808
1809 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1810
1811 ao2_lock(endpoint_state_compositor);
1812 endpoint_state_compositor->active = 0;
1813 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
1814 task_data->aor_options->name, REMOVED);
1815 ao2_unlock(endpoint_state_compositor);
1816 }
1817 AST_VECTOR_RESET(&task_data->aor_options->compositors, ao2_cleanup);
1818
1819 return 0;
1820}

References sip_options_endpoint_state_compositor::active, ao2_cleanup, ao2_lock, ao2_unlock, ast_debug, AST_VECTOR_GET, AST_VECTOR_RESET, AST_VECTOR_SIZE, REMOVED, sip_options_apply_aor_configuration(), and sip_options_update_endpoint_state_compositor_aor().

Referenced by sip_options_synchronize_aor().

◆ sip_options_synchronize_endpoint()

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

Synchronize an endpoint with our local state.

Note
Run by management_serializer

Definition at line 1989 of file pjsip_options.c.

1990{
1991 struct ast_sip_endpoint *endpoint = obj;
1992 struct ast_sip_aor *aor = arg;
1993 char *aors;
1994 char *aor_name;
1996
1997 if (ast_strlen_zero(endpoint->aors)) {
1998 /* There are no AORs, so really... who the heck knows */
1999 ast_debug(3, "Endpoint '%s' is not interested in any AORs so not creating endpoint state compositor\n",
2000 ast_sorcery_object_get_id(endpoint));
2001 return 0;
2002 }
2003
2004 ast_debug(3, "Synchronizing endpoint '%s' with AORs '%s'\n",
2005 ast_sorcery_object_get_id(endpoint), endpoint->aors);
2006
2007 aors = ast_strdupa(endpoint->aors);
2008 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2009 if (ast_strlen_zero(aor_name)) {
2010 continue;
2011 }
2012 if (aor && strcasecmp(ast_sorcery_object_get_id(aor), aor_name)) {
2013 ast_debug(3, "Filtered AOR '%s' on endpoint '%s' as we are looking for '%s'\n",
2014 aor_name, ast_sorcery_object_get_id(endpoint),
2016 continue;
2017 }
2018
2019 task_data.aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2020 if (!task_data.aor_options) {
2021 /*
2022 * They have referenced an invalid AOR. If that's all they've
2023 * done we will set them to offline at the end.
2024 */
2025 ast_debug(3, "Endpoint '%s' referenced invalid AOR '%s'\n",
2026 ast_sorcery_object_get_id(endpoint), aor_name);
2027 continue;
2028 }
2029
2030 if (!task_data.endpoint_state_compositor) {
2031 /*
2032 * We create an endpoint state compositor only after we know
2033 * for sure we need it.
2034 */
2035 task_data.endpoint_state_compositor =
2037 if (!task_data.endpoint_state_compositor) {
2039 "Could not create endpoint state compositor for '%s', endpoint state will be incorrect\n",
2040 ast_sorcery_object_get_id(endpoint));
2041 ao2_ref(task_data.aor_options, -1);
2044 return 0;
2045 }
2046 }
2047
2048 /* We use a synchronous task so that we don't flood the system */
2049 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2051
2052 ao2_ref(task_data.aor_options, -1);
2053
2054 /*
2055 * If we filtered on a specific AOR name then the endpoint can
2056 * only reference it once so break early.
2057 */
2058 if (aor) {
2059 break;
2060 }
2061 }
2062
2063 if (task_data.endpoint_state_compositor) {
2064 /*
2065 * If an endpoint state compositor is present determine the current state
2066 * of the endpoint and update it.
2067 */
2068 ao2_lock(task_data.endpoint_state_compositor);
2069 task_data.endpoint_state_compositor->active = 1;
2072 ao2_unlock(task_data.endpoint_state_compositor);
2073
2074 ao2_ref(task_data.endpoint_state_compositor, -1);
2075 } else if (!aor) {
2076 /* If no explicit AOR is specified we are updating the endpoint itself, so then set
2077 * it to offline if no endpoint compositor exists as they referenced an invalid AOR
2078 * or none at all
2079 */
2080 ast_debug(3, "Endpoint '%s' has no AORs feeding it, setting it to offline state as default\n",
2081 ast_sorcery_object_get_id(endpoint));
2084 }
2085
2086 return 0;
2087}
static struct sip_options_endpoint_state_compositor * sip_options_endpoint_state_compositor_find_or_alloc(const struct ast_sip_endpoint *endpoint)
Find (or create) an endpoint state compositor.
static int sip_options_endpoint_compositor_add_task(void *obj)
Task which adds an AOR to an endpoint state compositor.
static enum ast_endpoint_state sip_options_get_endpoint_state_compositor_state(const struct sip_options_endpoint_state_compositor *endpoint_state_compositor)
Return the current state of an endpoint state compositor.
int ast_sip_persistent_endpoint_update_state(const char *endpoint_name, enum ast_endpoint_state state)
Change state of a persistent endpoint.

References ao2_find, ao2_lock, ao2_ref, ao2_unlock, ast_sip_endpoint::aors, ast_debug, AST_ENDPOINT_OFFLINE, ast_log, ast_sip_persistent_endpoint_update_state(), ast_sip_push_task_wait_serializer, ast_sorcery_object_get_id(), ast_strdupa, ast_strip(), ast_strlen_zero(), LOG_WARNING, NULL, OBJ_SEARCH_KEY, sip_options_aors, sip_options_endpoint_compositor_add_task(), sip_options_endpoint_state_compositor_find_or_alloc(), sip_options_get_endpoint_state_compositor_state(), and strsep().

Referenced by sip_options_aor_observer_modified_task(), sip_options_endpoint_observer_modified_task(), and sip_options_synchronize_task().

◆ sip_options_synchronize_task()

static int sip_options_synchronize_task ( void *  obj)
static

Task to synchronize our local container of AORs and endpoint state compositors with the current configuration.

Note
Run by management_serializer

Definition at line 2154 of file pjsip_options.c.

2155{
2157 struct ao2_container *existing = NULL;
2158 struct ao2_container *objects;
2159
2160 /*
2161 * When reloading we keep track of the existing AORs so we can
2162 * terminate old ones that are no longer referenced or used.
2163 */
2164 if (task_data->reload) {
2166 if (!existing) {
2167 return 0;
2168 }
2169 }
2170
2173 if (objects) {
2174 /* Go through the returned AORs and synchronize with our local state */
2176 ao2_ref(objects, -1);
2177 }
2178
2179 /*
2180 * Any AORs remaining in existing are no longer referenced by
2181 * the current container of AORs we retrieved, so remove them.
2182 */
2183 if (existing) {
2186 ao2_ref(existing, -1);
2187 }
2188
2191 if (objects) {
2192 /* Go through the provided endpoints and update AORs */
2194 ao2_ref(objects, -1);
2195 }
2196
2197 /*
2198 * All endpoint state compositors that don't have any AORs
2199 * feeding them information can be removed. If they end
2200 * up getting needed later they'll just be recreated.
2201 */
2205
2206 return 0;
2207}
static int sip_options_unused_aor(void *obj, void *arg, int flags)
Callback which removes any unused AORs that remained after reloading.
static int sip_options_unused_endpoint_state_compositor(void *obj, void *arg, int flags)
Callback function used to unlink and remove event state compositors that have no AORs feeding them.
static int sip_options_synchronize_aor(void *obj, void *arg, int flags)
Synchronize an AOR with our local state.

References ao2_callback, ao2_container_clone, ao2_ref, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_sorcery(), ast_sorcery_retrieve_by_fields(), NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, sip_options_aors, sip_options_endpoint_state_compositors, sip_options_synchronize_aor(), sip_options_synchronize_endpoint(), sip_options_unused_aor(), and sip_options_unused_endpoint_state_compositor().

Referenced by sip_options_synchronize().

◆ sip_options_target_result_dtor()

static void sip_options_target_result_dtor ( void *  obj)
static

Destructor for a resolved target's qualification result.

Definition at line 936 of file pjsip_options.c.

937{
938 struct sip_options_target_result *result = obj;
939 ao2_cleanup(result->batch);
940}

References ao2_cleanup, and result.

Referenced by sip_options_queue_target_result().

◆ sip_options_target_result_task()

static int sip_options_target_result_task ( void *  obj)
static

Combine the result of one resolved target with the other targets.

Note
Run by aor_options->serializer

Definition at line 946 of file pjsip_options.c.

947{
948 struct sip_options_target_result *result = obj;
950
951 if (!batch->completed) {
952 /* If the result is available then we can mark the batch as completed
953 and notify the AOR */
954 ast_assert(batch->pending);
955 --batch->pending;
956
957 if (result->status == AVAILABLE) {
958 /* At least one resolved target was available. */
959 batch->completed = 1;
960 batch->status = AVAILABLE;
962 /* The notify task inherits this reference. */
964 } else if (!batch->pending) {
965 /* Every resolved target failed. */
966 batch->completed = 1;
967 batch->status = UNAVAILABLE;
969 }
970 }
971
972 ao2_ref(result, -1);
973 return 0;
974}
static int sip_options_contact_status_notify_task(void *obj)
Task to notify an AOR of a contact status change.
static void sip_options_cancel_target_transactions(struct sip_options_contact_callback_data *batch)
Terminate all in-flight target transactions for a batch.

References ao2_bump, ao2_ref, ast_assert, AVAILABLE, batch, result, sip_options_cancel_target_transactions(), sip_options_contact_status_notify_task(), and UNAVAILABLE.

Referenced by sip_options_queue_target_result().

◆ sip_options_transaction_free()

static void sip_options_transaction_free ( pjsip_transaction *  tsx)
static

Definition at line 674 of file pjsip_options.c.

675{
676 if (tsx) {
677 pj_grp_lock_dec_ref(tsx->grp_lock);
678 }
679}

Referenced by sip_options_contact_callback_data_dtor().

◆ sip_options_unused_aor()

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

Callback which removes any unused AORs that remained after reloading.

Note
Run by management_serializer

Definition at line 2112 of file pjsip_options.c.

2113{
2114 struct sip_options_aor *aor_options = obj;
2115
2116 ast_debug(3, "AOR '%s' is no longer configured, removing it\n", aor_options->name);
2117
2119 aor_options);
2120 ao2_unlink(sip_options_aors, aor_options);
2121
2122 return CMP_MATCH;
2123}
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578

References ao2_unlink, ast_debug, ast_sip_push_task_wait_serializer, CMP_MATCH, sip_options_aor::name, sip_options_aor::serializer, sip_options_aor_remove_task(), and sip_options_aors.

Referenced by sip_options_synchronize_task().

◆ sip_options_unused_endpoint_state_compositor()

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

Callback function used to unlink and remove event state compositors that have no AORs feeding them.

Note
Run by management_serializer

Definition at line 2129 of file pjsip_options.c.

2130{
2131 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
2132
2133 if (ao2_container_count(endpoint_state_compositor->aor_statuses)) {
2134 return 0;
2135 }
2136
2137 /* No AORs are feeding this endpoint state compositor */
2138 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
2140
2141 return CMP_MATCH;
2142}

References ao2_container_count(), sip_options_endpoint_state_compositor::aor_statuses, AST_ENDPOINT_OFFLINE, ast_sip_persistent_endpoint_update_state(), CMP_MATCH, and sip_options_endpoint_state_compositor::name.

Referenced by sip_options_synchronize_task().

◆ sip_options_update_aor_task()

static int sip_options_update_aor_task ( void *  obj)
static

Task to synchronize an AOR with our local state.

Note
Run by aor_options->serializer

Definition at line 2337 of file pjsip_options.c.

2338{
2340 int available = task_data->aor_options->available;
2341
2342 ast_debug(3, "Individually updating AOR '%s' with current state of configuration and world\n",
2343 task_data->aor_options->name);
2344
2346 task_data->added);
2347
2348 if (!available && task_data->aor_options->available) {
2349 ast_debug(3, "After modifying AOR '%s' it has now become available\n",
2350 task_data->aor_options->name);
2352 } else if (available && !task_data->aor_options->available) {
2353 ast_debug(3, "After modifying AOR '%s' it has become unavailable\n",
2354 task_data->aor_options->name);
2356 }
2357
2358 return 0;
2359}

References ast_debug, available(), AVAILABLE, sip_options_apply_aor_configuration(), sip_options_notify_endpoint_state_compositors(), and UNAVAILABLE.

Referenced by sip_options_aor_observer_modified_task().

◆ sip_options_update_endpoint_state_compositor_aor()

static void sip_options_update_endpoint_state_compositor_aor ( struct sip_options_endpoint_state_compositor endpoint_state_compositor,
const char *  name,
enum ast_sip_contact_status_type  status 
)
static

Update the AOR status on an endpoint state compositor.

Precondition
The endpoint_state_compositor lock must be held.

Definition at line 731 of file pjsip_options.c.

733{
734 struct sip_options_endpoint_aor_status *aor_status;
735 enum ast_endpoint_state endpoint_state;
736
737 aor_status = ao2_find(endpoint_state_compositor->aor_statuses, name,
739 if (!aor_status) {
740 /* The AOR status doesn't exist already so we don't need to go any further */
741 if (status == REMOVED) {
742 return;
743 }
744
745 aor_status = ao2_alloc_options(sizeof(*aor_status) + strlen(name) + 1, NULL,
747 if (!aor_status) {
748 return;
749 }
750
751 strcpy(aor_status->name, name); /* SAFE */
752 ao2_link(endpoint_state_compositor->aor_statuses, aor_status);
753 }
754
755 if (status == REMOVED) {
756 /*
757 * If the AOR is being removed then remove its AOR status
758 * from the endpoint compositor.
759 */
760 ao2_unlink(endpoint_state_compositor->aor_statuses, aor_status);
761 } else {
762 aor_status->available = (status == AVAILABLE ? 1 : 0);
763 }
764 ao2_ref(aor_status, -1);
765
766 if (!endpoint_state_compositor->active) {
767 return;
768 }
769
770 /* If this AOR is available then the endpoint itself has to be online */
771 if (status == AVAILABLE) {
772 ast_debug(3, "Endpoint state compositor '%s' is online as AOR '%s' is available\n",
773 endpoint_state_compositor->name, name);
774 endpoint_state = AST_ENDPOINT_ONLINE;
775 } else {
776 endpoint_state =
777 sip_options_get_endpoint_state_compositor_state(endpoint_state_compositor);
778 }
779
780 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
781 endpoint_state);
782}

References sip_options_endpoint_state_compositor::active, AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_find, ao2_link, ao2_ref, ao2_unlink, sip_options_endpoint_state_compositor::aor_statuses, ast_debug, AST_ENDPOINT_ONLINE, ast_sip_persistent_endpoint_update_state(), AVAILABLE, sip_options_endpoint_aor_status::available, sip_options_endpoint_aor_status::name, sip_options_endpoint_state_compositor::name, name, NULL, OBJ_NOLOCK, OBJ_SEARCH_KEY, REMOVED, sip_options_get_endpoint_state_compositor_state(), and status.

Referenced by sip_options_endpoint_compositor_add_task(), sip_options_notify_endpoint_state_compositors(), and sip_options_synchronize_aor_task().

Variable Documentation

◆ aor_observer_callbacks

const struct ast_sorcery_observer aor_observer_callbacks
static
Initial value:
= {
}
static void aor_observer_deleted(const void *obj)
Observer callback invoked on AOR deletion.
static void aor_observer_modified(const void *obj)
Observer callback invoked on AOR creation or modification.

Observer callbacks for AORs.

Definition at line 2458 of file pjsip_options.c.

2458 {
2459 .created = aor_observer_modified,
2460 .updated = aor_observer_modified,
2461 .deleted = aor_observer_deleted,
2462};

Referenced by ast_res_pjsip_cleanup_options_handling(), and sip_options_init_task().

◆ cli_options

struct ast_cli_entry cli_options[]
static

Definition at line 3117 of file pjsip_options.c.

3117 {
3118 AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint"),
3119 AST_CLI_DEFINE(cli_show_qualify_endpoint, "Show the current qualify options for all Aors on the PJSIP endpoint"),
3120 AST_CLI_DEFINE(cli_show_qualify_aor, "Show the PJSIP Aor current qualify options"),
3121 AST_CLI_DEFINE(cli_reload_qualify_endpoint, "Synchronize the qualify options for all Aors on the PJSIP endpoint"),
3122 AST_CLI_DEFINE(cli_reload_qualify_aor, "Synchronize the PJSIP Aor qualify options"),
3123};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
static char * cli_reload_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_reload_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_show_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_show_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Referenced by ast_res_pjsip_cleanup_options_handling(), and ast_res_pjsip_init_options_handling().

◆ contact_observer_callbacks

const struct ast_sorcery_observer contact_observer_callbacks
static
Initial value:
= {
}
static void contact_observer_created(const void *obj)
Observer callback invoked on contact creation.
static void contact_observer_deleted(const void *obj)
Observer callback invoked on contact deletion.
static void contact_observer_updated(const void *obj)
Observer callback invoked on contact update.

Observer callbacks for contacts.

Definition at line 2746 of file pjsip_options.c.

2746 {
2747 .created = contact_observer_created,
2748 .updated = contact_observer_updated,
2749 .deleted = contact_observer_deleted,
2750};

Referenced by ast_res_pjsip_cleanup_options_handling(), and sip_options_init_task().

◆ contact_status_formatter

struct ast_sip_endpoint_formatter contact_status_formatter
static
Initial value:
= {
}
static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)

Definition at line 3197 of file pjsip_options.c.

3197 {
3198 .format_ami = format_ami_contact_status
3199};

Referenced by ast_res_pjsip_cleanup_options_handling(), and ast_res_pjsip_init_options_handling().

◆ endpoint_observer_callbacks

const struct ast_sorcery_observer endpoint_observer_callbacks
static
Initial value:
= {
}
static void endpoint_observer_modified(const void *obj)
Observer callback invoked on endpoint creation or modification.
static void endpoint_observer_deleted(const void *obj)
Observer callback invoked on endpoint deletion.

Observer callbacks for endpoints.

Definition at line 2327 of file pjsip_options.c.

2327 {
2328 .created = endpoint_observer_modified,
2329 .updated = endpoint_observer_modified,
2330 .deleted = endpoint_observer_deleted,
2331};

Referenced by ast_res_pjsip_cleanup_options_handling(), and sip_options_init_task().

◆ management_serializer

struct ast_taskprocessor* management_serializer
static

◆ options_module

pjsip_module options_module
static

Definition at line 309 of file pjsip_options.c.

309 {
310 .name = {"Options Module", 14},
311 .id = -1,
312 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
313 .on_rx_request = options_on_rx_request,
314};
static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)

Referenced by ast_res_pjsip_cleanup_options_handling(), and ast_res_pjsip_init_options_handling().

◆ short_status_map

const char* short_status_map[]
static

Definition at line 324 of file pjsip_options.c.

324 {
325 [UNAVAILABLE] = "Unavail",
326 [AVAILABLE] = "Avail",
327 [UNKNOWN] = "Unknown",
328 [CREATED] = "NonQual",
329 [REMOVED] = "Removed",
330};

Referenced by ast_sip_get_contact_short_status_label().

◆ sip_options_aors

struct ao2_container* sip_options_aors
static

◆ sip_options_contact_statuses

struct ao2_container* sip_options_contact_statuses
static

◆ sip_options_endpoint_state_compositors

struct ao2_container* sip_options_endpoint_state_compositors
static

◆ status_map

const char* status_map[]
static

Definition at line 316 of file pjsip_options.c.

316 {
317 [UNAVAILABLE] = "Unreachable",
318 [AVAILABLE] = "Reachable",
319 [UNKNOWN] = "Unknown",
320 [CREATED] = "NonQualified",
321 [REMOVED] = "Removed",
322};