Asterisk - The Open Source Telephony Project GIT-master-266378a
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_status * ast_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_status * ast_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_container * get_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_status * sip_contact_status_alloc (const char *name)
 
static struct ast_sip_contact_status * sip_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_aor * sip_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_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_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_container * sip_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_compositor * sip_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_taskprocessor * management_serializer
 
static pjsip_module options_module
 
static const char * short_status_map []
 
static struct ao2_container * sip_options_aors
 
static struct ao2_container * sip_options_contact_statuses
 
static struct ao2_container * sip_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 2874 of file pjsip_options.c.

2875{
2876 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2877 struct ao2_container *contacts;
2878
2879 contacts = get_all_contacts();
2880 if (!contacts) {
2881 astman_send_error(s, m, "Could not get Contacts\n");
2882 return 0;
2883 }
2884
2885 if (!ao2_container_count(contacts)) {
2886 astman_send_error(s, m, "No Contacts found\n");
2887 ao2_ref(contacts, -1);
2888 return 0;
2889 }
2890
2891 astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",
2892 "start");
2893
2895
2896 astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);
2898
2899 ao2_ref(contacts, -1);
2900
2901 return 0;
2902}
#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 3089 of file pjsip_options.c.

3090{
3091 const char *endpoint_name = astman_get_header(m, "Endpoint");
3092 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
3093 char *aors;
3094 char *aor_name;
3095
3096 if (ast_strlen_zero(endpoint_name)) {
3097 astman_send_error(s, m, "Endpoint parameter missing.");
3098 return 0;
3099 }
3100
3101 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
3102 endpoint_name);
3103 if (!endpoint) {
3104 astman_send_error(s, m, "Unable to retrieve endpoint\n");
3105 return 0;
3106 }
3107
3108 /* send a qualify for all contacts registered with the endpoint */
3109 if (ast_strlen_zero(endpoint->aors)) {
3110 astman_send_error(s, m, "No AoRs configured for endpoint\n");
3111 return 0;
3112 }
3113
3114 aors = ast_strdupa(endpoint->aors);
3115 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
3116 struct sip_options_aor *aor_options;
3117
3118 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
3119 if (!aor_options) {
3120 continue;
3121 }
3122
3124 aor_options);
3125 ao2_ref(aor_options, -1);
3126 }
3127
3128 astman_send_ack(s, m, "Endpoint found, will qualify");
3129 return 0;
3130}
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 2466 of file pjsip_options.c.

2467{
2470}
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 2435 of file pjsip_options.c.

2436{
2439}
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 3261 of file pjsip_options.c.

3262{
3263 struct ast_taskprocessor *mgmt_serializer;
3264
3266 ast_manager_unregister("PJSIPQualify");
3267 ast_manager_unregister("PJSIPShowContacts");
3269
3276
3277 mgmt_serializer = management_serializer;
3279 if (mgmt_serializer) {
3281 ast_taskprocessor_unreference(mgmt_serializer);
3282 }
3283
3290
3291 pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
3292}
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:7792
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 3326 of file pjsip_options.c.

3327{
3328 struct ast_taskprocessor *mgmt_serializer;
3329
3330 static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
3331
3332 if (reload) {
3334 return 0;
3335 }
3336
3337 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
3338 != PJ_SUCCESS) {
3339 return -1;
3340 }
3341
3342 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
3343 NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
3345 return -1;
3346 }
3347
3349 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
3350 if (!sip_options_aors) {
3352 return -1;
3353 }
3357 sip_options_endpoint_state_compositor_hash_fn, NULL,
3358 sip_options_endpoint_state_compositor_cmp_fn);
3361 return -1;
3362 }
3363
3364 mgmt_serializer = ast_sip_create_serializer("pjsip/options/manage");
3365 if (!mgmt_serializer) {
3367 return -1;
3368 }
3369
3370 /*
3371 * Set the water mark levels high because we can get a flood of
3372 * contact status updates from sip_options_synchronize() that
3373 * quickly clears on initial load or reload.
3374 */
3375 ast_taskprocessor_alert_set_levels(mgmt_serializer, -1,
3377
3378 /*
3379 * We make sure that the environment is completely setup before we allow
3380 * any other threads to post contact_status updates to the
3381 * management_serializer.
3382 */
3384 mgmt_serializer)) {
3385 /* Set management_serializer in case pushing the task actually failed. */
3386 management_serializer = mgmt_serializer;
3388 return -1;
3389 }
3390
3396
3397 return 0;
3398}
@ 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 3320 of file pjsip_options.c.

3321{
3323 return sip_options_contact_statuses ? 0 : -1;
3324}
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 3140 of file pjsip_options.c.

3141{
3142 struct ast_sip_contact_wrapper *wrapper = obj;
3143 struct ast_sip_contact *contact = wrapper->contact;
3144 struct ast_sip_ami *ami = arg;
3146 struct ast_str *buf;
3147 const struct ast_sip_endpoint *endpoint = ami->arg;
3148 char secs[AST_TIME_T_LEN];
3149
3150 buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
3151 if (!buf) {
3152 return -1;
3153 }
3154
3156
3157 ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
3158 ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
3159 ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
3160 ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
3161 ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
3162 if (!ast_strlen_zero(contact->via_addr)) {
3163 ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
3164 if (contact->via_port) {
3165 ast_str_append(&buf, 0, ":%d", contact->via_port);
3166 }
3167 ast_str_append(&buf, 0, "\r\n");
3168 }
3169 if (!ast_strlen_zero(contact->call_id)) {
3170 ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
3171 }
3172 ast_str_append(&buf, 0, "Status: %s\r\n",
3174 if (!status || status->status != AVAILABLE) {
3175 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
3176 } else {
3177 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
3178 }
3179 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
3180 endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
3181
3182 ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
3183 ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
3184 ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
3185 ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
3186 ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
3187 ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
3188 ast_str_append(&buf, 0, "Qualify2xxOnly: %d\r\n", contact->qualify_2xx_only);
3189
3190 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
3191 ami->count++;
3192
3193 ast_free(buf);
3195 return 0;
3196}
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 2767 of file pjsip_options.c.

2768{
2769 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2770 const char *endpoint_name;
2771 char *aors;
2772 char *aor_name;
2773
2774 switch (cmd) {
2775 case CLI_INIT:
2776 e->command = "pjsip qualify";
2777 e->usage =
2778 "Usage: pjsip qualify <endpoint>\n"
2779 " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
2780 return NULL;
2781 case CLI_GENERATE:
2782 return NULL;
2783 }
2784
2785 if (a->argc != 3) {
2786 return CLI_SHOWUSAGE;
2787 }
2788
2789 endpoint_name = a->argv[2];
2790
2791 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2792 endpoint_name);
2793 if (!endpoint) {
2794 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2795 return CLI_FAILURE;
2796 }
2797
2798 if (ast_strlen_zero(endpoint->aors)) {
2799 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2800 return CLI_FAILURE;
2801 }
2802
2803 aors = ast_strdupa(endpoint->aors);
2804 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2805 struct sip_options_aor *aor_options;
2806
2807 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2808 if (!aor_options) {
2809 continue;
2810 }
2811
2812 ast_cli(a->fd, "Qualifying AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2814 aor_options);
2815 ao2_ref(aor_options, -1);
2816 }
2817
2818 return CLI_SUCCESS;
2819}
#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 3053 of file pjsip_options.c.

3054{
3055 struct ast_sip_aor *aor;
3056 const char *aor_name;
3057
3058 switch (cmd) {
3059 case CLI_INIT:
3060 e->command = "pjsip reload qualify aor";
3061 e->usage =
3062 "Usage: pjsip reload qualify aor <id>\n"
3063 " Synchronize the PJSIP Aor qualify options.\n";
3064 return NULL;
3065 case CLI_GENERATE:
3066 return NULL;
3067 }
3068
3069 if (a->argc != 5) {
3070 return CLI_SHOWUSAGE;
3071 }
3072
3073 aor_name = a->argv[4];
3074
3075 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
3076 if (!aor) {
3077 ast_cli(a->fd, "Unable to retrieve aor '%s'\n", aor_name);
3078 return CLI_FAILURE;
3079 }
3080
3081 ast_cli(a->fd, "Synchronizing AOR '%s'\n", aor_name);
3084 ao2_ref(aor, -1);
3085
3086 return CLI_SUCCESS;
3087}
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 2999 of file pjsip_options.c.

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

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 2961 of file pjsip_options.c.

2962{
2963 struct sip_options_aor *aor_options;
2964 const char *aor_name;
2965
2966 switch (cmd) {
2967 case CLI_INIT:
2968 e->command = "pjsip show qualify aor";
2969 e->usage =
2970 "Usage: pjsip show qualify aor <id>\n"
2971 " Show the PJSIP Aor current qualify options.\n";
2972 return NULL;
2973 case CLI_GENERATE:
2974 return NULL;
2975 }
2976
2977 if (a->argc != 5) {
2978 return CLI_SHOWUSAGE;
2979 }
2980
2981 aor_name = a->argv[4];
2982
2983 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2984 if (!aor_options) {
2985 ast_cli(a->fd, "Unable to retrieve aor '%s' qualify options\n", aor_name);
2986 return CLI_FAILURE;
2987 }
2988
2989 ast_cli(a->fd, " * AOR '%s'\n", aor_name);
2990 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2991 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2992 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2993 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2994 ao2_ref(aor_options, -1);
2995
2996 return CLI_SUCCESS;
2997}
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 2904 of file pjsip_options.c.

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

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 2608 of file pjsip_options.c.

2609{
2612}
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 2754 of file pjsip_options.c.

2755{
2758}
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 2646 of file pjsip_options.c.

2647{
2648 const struct ast_sip_contact *contact = obj;
2649 struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY);
2650
2651 if (has_qualify_changed(contact, aor_options)) {
2652 struct ast_sip_aor *aor;
2653
2655 contact->aor);
2656 if (aor) {
2657 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2658 contact->aor);
2661 ao2_ref(aor, -1);
2662 }
2663 }
2664
2667
2668 task_data = ast_malloc(sizeof(*task_data));
2669 if (!task_data) {
2670 ao2_ref(aor_options, -1);
2671 return;
2672 }
2673
2674 task_data->contact = (struct ast_sip_contact *) contact;
2675 /* task_data takes ownership of aor_options and will take care of releasing the ref */
2676 task_data->aor_options = aor_options;
2677
2678 ao2_ref(task_data->contact, +1);
2679 if (ast_sip_push_task(task_data->aor_options->serializer,
2681 ao2_ref(task_data->contact, -1);
2682 ao2_ref(task_data->aor_options, -1);
2684 }
2685 } else {
2686 ao2_cleanup(aor_options);
2687 }
2688}
#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 2303 of file pjsip_options.c.

2304{
2307}
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 2335 of file pjsip_options.c.

2336{
2339}
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 3205 of file pjsip_options.c.

3207{
3208 ami->arg = (void *)endpoint;
3210}
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 2837 of file pjsip_options.c.

2838{
2839 struct ast_sip_contact *contact = obj;
2840 struct ast_sip_ami *ami = arg;
2841 struct ast_str *buf;
2843
2844 buf = ast_sip_create_ami_event("ContactList", ami);
2845 if (!buf) {
2846 return CMP_STOP;
2847 }
2848
2849 if (sip_contact_to_ami(contact, &buf)) {
2850 ast_free(buf);
2851 return CMP_STOP;
2852 }
2853
2854 /* Add extra info */
2856 ast_str_append(&buf, 0, "Status: %s\r\n",
2858 if (!status || status->status != AVAILABLE) {
2859 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2860 } else {
2861 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2862 }
2864
2865 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2866
2867 ami->count++;
2868
2869 ast_free(buf);
2870
2871 return 0;
2872}
@ 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 3198 of file pjsip_options.c.

3199{
3200 struct ast_sip_aor *aor = obj;
3201
3203}
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 2821 of file pjsip_options.c.

2822{
2823 struct ao2_container *contacts;
2824
2827
2828 return contacts;
2829}
@ 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 2491 of file pjsip_options.c.

2492{
2493 if (!contact) {
2494 return 0;
2495 }
2496
2497 if (!aor_options) {
2498 if (contact->qualify_frequency) {
2499 return 1;
2500 }
2501 } else if (contact->qualify_frequency != aor_options->qualify_frequency
2502 || contact->authenticate_qualify != aor_options->authenticate_qualify
2503 || contact->qualify_2xx_only != aor_options->qualify_2xx_only
2504 || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
2505 return 1;
2506 }
2507
2508 return 0;
2509}

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:1888
#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 1033 of file pjsip_options.c.

1034{
1035 struct sip_options_contact_callback_data *contact_callback_data = token;
1037
1038 switch(e->body.tsx_state.type) {
1039 default:
1040 ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type);
1041 /* Fall through */
1042 case PJSIP_EVENT_TRANSPORT_ERROR:
1043 case PJSIP_EVENT_TIMER:
1045 break;
1046 case PJSIP_EVENT_RX_MSG:
1047 if (contact_callback_data->aor_options->qualify_2xx_only &&
1048 (e->body.tsx_state.tsx->status_code < 200 || e->body.tsx_state.tsx->status_code >= 300)) {
1050 } else {
1051 status = AVAILABLE;
1052 }
1053 break;
1054 case PJSIP_EVENT_USER:
1055 /*
1056 * When one resolved target responds, we know the endpoint is available and we cancel the other
1057 * outstanding transactions. The cancelled transactions will trigger this user event, which we
1058 * can ignore as we already have a result for the contact.
1059 */
1060 ast_debug(3, "Received user event for contact '%s', ignoring\n",
1061 ast_sorcery_object_get_id(contact_callback_data->contact));
1062 /* Decrement reference count for the contact callback data and return as we have no result */
1063 ao2_ref(contact_callback_data, -1);
1064 return;
1065 }
1066
1067 sip_options_queue_target_result(contact_callback_data, status);
1068 ao2_ref(contact_callback_data, -1);
1069}
#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 2831 of file pjsip_options.c.

2833{
2834 return ast_sip_sorcery_object_to_ami(contact, buf);
2835}
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 1386 of file pjsip_options.c.

1387{
1388 struct sip_options_aor *aor_options;
1389
1390 aor_options = ao2_alloc_options(sizeof(*aor_options) + strlen(ast_sorcery_object_get_id(aor)) + 1,
1392 if (!aor_options) {
1393 return NULL;
1394 }
1395
1396 strcpy(aor_options->name, ast_sorcery_object_get_id(aor)); /* SAFE */
1397
1399 if (!aor_options->serializer) {
1400 ao2_ref(aor_options, -1);
1401 return NULL;
1402 }
1403
1405 ao2_ref(aor_options, -1);
1406 return NULL;
1407 }
1408
1412 if (!aor_options->contacts) {
1413 ao2_ref(aor_options, -1);
1414 return NULL;
1415 }
1416
1420 if (!aor_options->dynamic_contacts) {
1421 ao2_ref(aor_options, -1);
1422 return NULL;
1423 }
1424
1425 return aor_options;
1426}
@ 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 1364 of file pjsip_options.c.

1365{
1366 struct sip_options_aor *aor_options = obj;
1367
1368 /*
1369 * Any contacts are unreachable since the AOR is being destroyed
1370 * so remove their contact status
1371 */
1372 if (aor_options->contacts) {
1374 sip_options_remove_contact, aor_options);
1375 ao2_ref(aor_options->contacts, -1);
1376 }
1377 ao2_cleanup(aor_options->dynamic_contacts);
1378
1380
1381 ast_assert(AST_VECTOR_SIZE(&aor_options->compositors) == 0);
1382 AST_VECTOR_FREE(&aor_options->compositors);
1383}
@ 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 2445 of file pjsip_options.c.

2446{
2447 struct ast_sip_aor *aor = obj;
2448 struct sip_options_aor *aor_options;
2449
2452 if (!aor_options) {
2453 return 0;
2454 }
2455
2456 ast_debug(3, "AOR '%s' has been deleted, removing it\n", aor_options->name);
2457
2459 aor_options);
2460 ao2_ref(aor_options, -1);
2461
2462 return 0;
2463}
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 2380 of file pjsip_options.c.

2381{
2382 struct ast_sip_aor *aor = obj;
2383 struct sip_options_aor *aor_options;
2384
2387 if (!aor_options) {
2388 struct ao2_container *endpoints;
2389
2390 aor_options = sip_options_aor_alloc(aor);
2391 if (!aor_options) {
2392 return 0;
2393 }
2394
2395 /*
2396 * This is a newly added AOR and we need to establish any
2397 * endpoint state compositors that may reference only the
2398 * AOR. If these need to be updated later then they'll
2399 * be done by modifying the endpoint or issuing a reload.
2400 */
2401 sip_options_apply_aor_configuration(aor_options, aor, 1);
2402 ao2_link(sip_options_aors, aor_options);
2403
2404 /*
2405 * Using LIKE doesn't seem to work very well with non-realtime so we
2406 * fetch everything right now and do a filter on our side.
2407 */
2410 if (endpoints) {
2412 ao2_ref(endpoints, -1);
2413 }
2414 } else {
2416 .aor_options = aor_options,
2417 .aor = aor,
2418 };
2419
2420 /*
2421 * If this AOR was modified we have to do our work in its serializer
2422 * instead of this thread to ensure that things aren't modified by
2423 * multiple threads.
2424 */
2427 }
2428
2429 ao2_ref(aor_options, -1);
2430
2431 return 0;
2432}
#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 2108 of file pjsip_options.c.

2109{
2110 struct sip_options_aor *aor_options = obj;
2111
2113
2114 if (aor_options->sched_task) {
2116 ao2_ref(aor_options->sched_task, -1);
2117 aor_options->sched_task = NULL;
2118 }
2119
2120 return 0;
2121}
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 1659 of file pjsip_options.c.

1661{
1662 struct ao2_container *existing_contacts;
1663 struct ast_sip_contact *contact;
1664 struct ao2_iterator iter;
1665
1666 ast_debug(3, "Configuring AOR '%s' with current state of configuration and world\n",
1667 aor_options->name);
1668
1669 /*
1670 * Permanent contacts, since we receive no notification that they
1671 * are gone, follow the same approach as AORs. We create a copy
1672 * of the existing container and any reused contacts are removed
1673 * from it. Any contacts remaining in the container after
1674 * processing no longer exist so we need to remove their state.
1675 */
1676 existing_contacts = ao2_container_clone(aor_options->contacts, 0);
1677 if (!existing_contacts) {
1678 ast_log(LOG_WARNING, "Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1679 aor_options->name);
1680 return;
1681 }
1682
1684 NULL, NULL);
1685
1686 /* Process permanent contacts */
1687 if (aor->permanent_contacts) {
1688 iter = ao2_iterator_init(aor->permanent_contacts, 0);
1689 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1690 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1692 ao2_link(aor_options->contacts, contact);
1693 }
1694 ao2_iterator_destroy(&iter);
1695 }
1696
1697 /*
1698 * If this is newly added we need to see if there are any
1699 * existing dynamic contacts to add. Ones that are added
1700 * after creation will occur as a result of the contact
1701 * observer creation callback.
1702 */
1703 if (is_new) {
1704 size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
1705 char prefix[prefix_len + 1];
1706 struct ao2_container *contacts;
1707
1708 sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
1710 prefix, prefix_len);
1711 if (contacts) {
1712 ao2_container_dup(aor_options->dynamic_contacts, contacts, 0);
1713 ao2_ref(contacts, -1);
1714 }
1715 }
1716
1717 /* Process dynamic contacts */
1718 iter = ao2_iterator_init(aor_options->dynamic_contacts, 0);
1719 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1720 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1722 ao2_link(aor_options->contacts, contact);
1723 }
1724 ao2_iterator_destroy(&iter);
1725
1726 /* Any contacts left no longer exist, so raise events and make them disappear */
1727 ao2_callback(existing_contacts, OBJ_NODATA | OBJ_UNLINK,
1728 sip_options_remove_contact, aor_options);
1729 ao2_ref(existing_contacts, -1);
1730
1731 /*
1732 * Update the available count if we transition between qualified
1733 * and unqualified. In the qualified case we need to start with
1734 * 0 available as the qualify process will take care of it. In
1735 * the unqualified case it is based on the number of contacts
1736 * present.
1737 */
1738 if (!aor->qualify_frequency) {
1739 ao2_callback(aor_options->contacts, OBJ_NODATA,
1741 aor_options->available = ao2_container_count(aor_options->contacts);
1742 ast_debug(3, "AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1743 aor_options->name, aor_options->available);
1744 } else if (!aor_options->qualify_frequency) {
1745 ao2_callback(aor_options->contacts, OBJ_NODATA,
1747 aor_options->available = 0;
1748 ast_debug(3, "AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1749 aor_options->name);
1750 } else {
1751 /*
1752 * Count the number of AVAILABLE qualified contacts to ensure
1753 * the count is in sync with reality.
1754 */
1755 aor_options->available = 0;
1756 ao2_callback(aor_options->contacts, OBJ_NODATA,
1758 }
1759
1760 aor_options->authenticate_qualify = aor->authenticate_qualify;
1761 aor_options->qualify_2xx_only = aor->qualify_2xx_only;
1762 aor_options->qualify_timeout = aor->qualify_timeout;
1763
1764 /*
1765 * If we need to stop or start the scheduled callback then do so.
1766 * This occurs due to the following:
1767 * 1. The qualify frequency has changed
1768 * 2. Contacts were added when previously there were none
1769 * 3. There are no contacts but previously there were some
1770 */
1771 if (aor_options->qualify_frequency != aor->qualify_frequency
1772 || (!aor_options->sched_task && ao2_container_count(aor_options->contacts))
1773 || (aor_options->sched_task && !ao2_container_count(aor_options->contacts))) {
1774 if (aor_options->sched_task) {
1776 ao2_ref(aor_options->sched_task, -1);
1777 aor_options->sched_task = NULL;
1778 }
1779
1780 /* If there is still a qualify frequency then schedule this */
1781 aor_options->qualify_frequency = aor->qualify_frequency;
1782 if (aor_options->qualify_frequency
1783 && ao2_container_count(aor_options->contacts)) {
1784 aor_options->sched_task = ast_sip_schedule_task(aor_options->serializer,
1788 if (!aor_options->sched_task) {
1789 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
1790 aor_options->name);
1791 }
1792 }
1793 }
1794
1795 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1796 aor_options->available);
1797}
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 1128 of file pjsip_options.c.

1130{
1131 pjsip_transport_type_e transport_type = PJSIP_TRANSPORT_UNSPECIFIED;
1132
1133 if ((tdata->tp_sel.type != PJSIP_TPSELECTOR_TRANSPORT
1134 && tdata->tp_sel.type != PJSIP_TPSELECTOR_LISTENER)
1135 || !tdata->tp_sel.u.ptr) {
1136 return PJ_SUCCESS;
1137 }
1138
1139 if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT) {
1140 transport_type = tdata->tp_sel.u.transport->key.type;
1141 } else {
1142 transport_type = tdata->tp_sel.u.listener->type;
1143 }
1144
1145 if (destination->type != PJSIP_TRANSPORT_UNSPECIFIED
1146 && ((destination->type | PJSIP_TRANSPORT_IPV6)
1147 != (transport_type | PJSIP_TRANSPORT_IPV6))) {
1148 return PJSIP_ETPNOTSUITABLE;
1149 }
1150
1151 destination->type = transport_type;
1152 return PJ_SUCCESS;
1153}

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 704 of file pjsip_options.c.

706{
707 unsigned int idx;
708
709 for (idx = 0; idx < AST_VECTOR_SIZE(&batch->target_transactions); ++idx) {
710 pjsip_transaction *tsx = AST_VECTOR_GET(&batch->target_transactions, idx);
711
712 if (tsx) {
713 pjsip_tsx_terminate_async(tsx, PJSIP_SC_REQUEST_TERMINATED);
714 }
715 }
716}
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 3220 of file pjsip_options.c.

3221{
3222 struct sip_options_aor *aor_options = obj;
3223
3224 ast_debug(2, "Cleaning up AOR '%s' for shutdown\n", aor_options->name);
3225
3226 aor_options->qualify_frequency = 0;
3227 if (aor_options->sched_task) {
3229 ao2_ref(aor_options->sched_task, -1);
3230 aor_options->sched_task = NULL;
3231 }
3233
3234 return 0;
3235}
#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 3241 of file pjsip_options.c.

3242{
3243 struct ao2_iterator it_aor;
3244 struct sip_options_aor *aor_options;
3245
3246 if (!sip_options_aors) {
3247 /* Nothing to do */
3248 return 0;
3249 }
3250
3252 for (; (aor_options = ao2_iterator_next(&it_aor)); ao2_ref(aor_options, -1)) {
3254 sip_options_cleanup_aor_task, aor_options);
3255 }
3256 ao2_iterator_destroy(&it_aor);
3257
3258 return 0;
3259}
@ 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 2575 of file pjsip_options.c.

2576{
2578
2579 task_data.contact = obj;
2580 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2582
2583 if (has_qualify_changed(task_data.contact, task_data.aor_options)) {
2584 struct ast_sip_aor *aor;
2585
2587 task_data.contact->aor);
2588 if (aor) {
2589 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2590 task_data.contact->aor);
2592 ao2_ref(aor, -1);
2593 }
2594 }
2595
2596 if (!task_data.aor_options) {
2597 return 0;
2598 }
2599
2600 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2602 ao2_ref(task_data.aor_options, -1);
2603
2604 return 0;
2605}
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 2515 of file pjsip_options.c.

2516{
2518 struct ast_sip_contact_status *contact_status;
2519
2520 ao2_link(task_data->aor_options->dynamic_contacts, task_data->contact);
2521 ao2_link(task_data->aor_options->contacts, task_data->contact);
2522
2523 contact_status = ast_res_pjsip_find_or_create_contact_status(task_data->contact);
2524 ao2_cleanup(contact_status);
2525
2526 if (task_data->aor_options->qualify_frequency) {
2527 /* There will always be a contact here, and we need to immediately schedule
2528 * a qualify so that contacts are not waiting for the qualify_frequency
2529 * timer duration before qualifying.
2530 */
2531 ast_debug(3, "Starting scheduled callback on AOR '%s' for qualifying as there is now a contact on it\n",
2532 task_data->aor_options->name);
2533 /*
2534 * We immediately schedule the initial qualify so that we get
2535 * reachable/unreachable as soon as possible. Realistically
2536 * since they pretty much just registered they should be
2537 * reachable.
2538 */
2539 if (task_data->aor_options->sched_task) {
2540 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2541 ao2_ref(task_data->aor_options->sched_task, -1);
2542 task_data->aor_options->sched_task = NULL;
2543 }
2544 task_data->aor_options->sched_task = ast_sip_schedule_task(
2545 task_data->aor_options->serializer, 1, sip_options_qualify_aor,
2546 ast_taskprocessor_name(task_data->aor_options->serializer),
2547 task_data->aor_options,
2549 if (!task_data->aor_options->sched_task) {
2550 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
2551 task_data->aor_options->name);
2552 }
2553 } else {
2554 /*
2555 * If this was the first contact added to a non-qualified AOR then
2556 * it should become available.
2557 */
2558 task_data->aor_options->available =
2559 ao2_container_count(task_data->aor_options->contacts);
2560 if (task_data->aor_options->available == 1) {
2561 ast_debug(3, "An unqualified contact has been added to AOR '%s' so it is now available\n",
2562 task_data->aor_options->name);
2564 AVAILABLE);
2565 }
2566 }
2567
2568 return 0;
2569}
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 1093 of file pjsip_options.c.

1096{
1097 struct sip_options_contact_callback_data *contact_callback_data;
1098
1099 contact_callback_data = ao2_alloc_options(sizeof(*contact_callback_data),
1101 if (!contact_callback_data) {
1102 return NULL;
1103 }
1104
1105 if (AST_VECTOR_INIT(&contact_callback_data->target_transactions, PJSIP_MAX_RESOLVED_ADDRESSES)) {
1106 ao2_ref(contact_callback_data, -1);
1107 return NULL;
1108 }
1109
1110 contact_callback_data->contact = ao2_bump(contact);
1111 contact_callback_data->aor_options = ao2_bump(aor_options);
1112 contact_callback_data->endpoint = ao2_bump(endpoint);
1113 contact_callback_data->resolve_tdata = resolve_tdata;
1114 contact_callback_data->rtt_start = ast_tvnow();
1115
1116 return contact_callback_data;
1117}
#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 1072 of file pjsip_options.c.

1073{
1074 struct sip_options_contact_callback_data *contact_callback_data = obj;
1075
1076 ao2_cleanup(contact_callback_data->contact);
1077 ao2_cleanup(contact_callback_data->aor_options);
1078 ao2_cleanup(contact_callback_data->endpoint);
1079 /*
1080 * sip_options_qualify_resolve_cb should handle cleaning the resolve_tdata, but
1081 * keep this fallback just in case.
1082 */
1083 if (contact_callback_data->resolve_tdata) {
1084 pjsip_tx_data_dec_ref(contact_callback_data->resolve_tdata);
1085 contact_callback_data->resolve_tdata = NULL;
1086 }
1087 AST_VECTOR_RESET(&contact_callback_data->target_transactions,
1089 AST_VECTOR_FREE(&contact_callback_data->target_transactions);
1090}
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 2734 of file pjsip_options.c.

2735{
2737
2738 task_data.contact = obj;
2739 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2741 if (!task_data.aor_options) {
2742 /* For contacts that are deleted we don't really care if there is no AOR locally */
2743 return 0;
2744 }
2745
2746 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2748 ao2_ref(task_data.aor_options, -1);
2749
2750 return 0;
2751}
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 2694 of file pjsip_options.c.

2695{
2697
2698 ao2_find(task_data->aor_options->dynamic_contacts, task_data->contact,
2700 ao2_find(task_data->aor_options->contacts, task_data->contact,
2702
2704
2705 if (task_data->aor_options->qualify_frequency) {
2706 /* If this is the last contact then we need to stop the scheduled callback */
2707 if (!ao2_container_count(task_data->aor_options->contacts)) {
2708 ast_debug(3, "Terminating scheduled callback on AOR '%s' as there are no contacts to qualify\n",
2709 task_data->aor_options->name);
2710 if (task_data->aor_options->sched_task) {
2711 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2712 ao2_ref(task_data->aor_options->sched_task, -1);
2713 task_data->aor_options->sched_task = NULL;
2714 }
2715 }
2716 } else {
2717 task_data->aor_options->available =
2718 ao2_container_count(task_data->aor_options->contacts);
2719 if (!task_data->aor_options->available) {
2720 ast_debug(3, "An unqualified contact has been removed from AOR '%s' leaving no remaining contacts\n",
2721 task_data->aor_options->name);
2723 UNAVAILABLE);
2724 }
2725 }
2726
2727 return 0;
2728}
@ 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 1627 of file pjsip_options.c.

1628{
1629 struct ast_sip_contact *contact = obj;
1630 unsigned int *available = arg;
1631 struct ast_sip_contact_status *contact_status;
1632
1633 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1634 if (!contact_status) {
1635 return 0;
1636 }
1637
1638 /* Count qualified available contacts. */
1639 switch (contact_status->status) {
1640 case AVAILABLE:
1641 ++*available;
1642 break;
1643 case UNAVAILABLE:
1644 case UNKNOWN:
1645 case CREATED:
1646 case REMOVED:
1647 break;
1648 }
1649
1650 ao2_ref(contact_status, -1);
1651
1652 return 0;
1653}
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 826 of file pjsip_options.c.

827{
828 struct sip_options_contact_callback_data *contact_callback_data = obj;
829 struct ast_sip_contact *contact;
830 struct ast_sip_contact_status *cs_old;
831 struct ast_sip_contact_status *cs_new;
832
833 /*
834 * Determine if this is a late arriving notification, as it is
835 * possible that we get a callback from PJSIP giving us contact
836 * status but in the mean time said contact has been removed
837 * from the controlling AOR.
838 */
839
840 if (!contact_callback_data->aor_options->qualify_frequency) {
841 /* Contact qualify response is late */
842 ao2_ref(contact_callback_data, -1);
843 return 0;
844 }
845
846 contact = ao2_find(contact_callback_data->aor_options->contacts,
847 contact_callback_data->contact, OBJ_SEARCH_OBJECT);
848 if (!contact) {
849 /* Contact qualify response is late */
850 ao2_ref(contact_callback_data, -1);
851 return 0;
852 }
853 ao2_ref(contact, -1);
854
856 ast_sorcery_object_get_id(contact_callback_data->contact), OBJ_SEARCH_KEY);
857 if (!cs_old) {
858 /* Contact qualify response is late */
859 ao2_ref(contact_callback_data, -1);
860 return 0;
861 }
862
863 /* Update the contact specific status information */
864 cs_new = sip_contact_status_copy(cs_old);
865 ao2_ref(cs_old, -1);
866 if (!cs_new) {
867 ao2_ref(contact_callback_data, -1);
868 return 0;
869 }
870 cs_new->last_status = cs_new->status;
871 cs_new->status = contact_callback_data->status;
872 cs_new->rtt =
873 cs_new->status == AVAILABLE
874 ? ast_tvdiff_us(ast_tvnow(), contact_callback_data->rtt_start)
875 : 0;
877
878 /*
879 * If the status has changed then notify the endpoint state compositors
880 * and publish our events.
881 */
882 if (cs_new->last_status != cs_new->status) {
883 if (cs_new->status == AVAILABLE) {
884 /* If this is the first available contact then the AOR has become available */
885 ++contact_callback_data->aor_options->available;
886 if (contact_callback_data->aor_options->available == 1) {
888 contact_callback_data->aor_options, AVAILABLE);
889 }
890 } else if (cs_new->last_status == AVAILABLE) {
891 ast_assert(cs_new->status == UNAVAILABLE);
892
893 /* If there are no more available contacts then this AOR is unavailable */
894 --contact_callback_data->aor_options->available;
895 if (!contact_callback_data->aor_options->available) {
897 contact_callback_data->aor_options, UNAVAILABLE);
898 }
899 }
900
901 ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n",
902 cs_new->aor,
903 cs_new->uri,
905 cs_new->rtt / 1000.0);
906
907 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
909 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
910 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
911
913
914 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
915 "Contact: %s\r\n"
916 "Status: %s",
917 cs_new->name,
919 } else {
920 ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
921 cs_new->aor,
922 cs_new->uri,
924 cs_new->rtt / 1000.0);
925 }
926
927 ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
928 cs_new->status != AVAILABLE ? -1 : cs_new->rtt / 1000,
929 1.0,
930 cs_new->name);
931
932 ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
933 "Contact: %s\r\n"
934 "Status: %s\r\n"
935 "RTT: %" PRId64,
936 cs_new->name,
938 cs_new->rtt);
939
940 ast_debug(3, "AOR '%s' now has %d available contacts\n",
941 contact_callback_data->aor_options->name,
942 contact_callback_data->aor_options->available);
943
944 ao2_ref(cs_new, -1);
945 ao2_ref(contact_callback_data, -1);
946
947 return 0;
948}
#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 2618 of file pjsip_options.c.

2619{
2621 struct ast_sip_contact_status *contact_status;
2622
2623 contact_status = ast_sip_get_contact_status(task_data->contact);
2624 if (contact_status) {
2625 switch (contact_status->status) {
2626 case CREATED:
2627 case UNAVAILABLE:
2628 case AVAILABLE:
2629 case UNKNOWN:
2630 /* Refresh the ContactStatus AMI events. */
2631 sip_options_contact_status_update(contact_status);
2632 break;
2633 case REMOVED:
2634 break;
2635 }
2636 ao2_ref(contact_status, -1);
2637 }
2638
2639 ao2_ref(task_data->contact, -1);
2640 ao2_ref(task_data->aor_options, -1);
2642 return 0;
2643}

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 1513 of file pjsip_options.c.

1514{
1515 int initial_interval;
1516 int max_time = ast_sip_get_max_initial_qualify_time();
1517
1518 if (max_time && max_time < qualify_frequency) {
1519 initial_interval = max_time;
1520 } else {
1521 initial_interval = qualify_frequency;
1522 }
1523
1524 initial_interval = (int)((initial_interval * 1000) * ast_random_double());
1525 return 0 < initial_interval ? initial_interval : 1;
1526}
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 1947 of file pjsip_options.c.

1948{
1950
1951 ast_debug(3, "Adding endpoint compositor '%s' to AOR '%s'\n",
1952 task_data->endpoint_state_compositor->name, task_data->aor_options->name);
1953
1954 ao2_ref(task_data->endpoint_state_compositor, +1);
1955 if (AST_VECTOR_APPEND(&task_data->aor_options->compositors,
1956 task_data->endpoint_state_compositor)) {
1957 /* Failed to add so no need to update the endpoint status. Nothing changed. */
1958 ao2_ref(task_data->endpoint_state_compositor, -1);
1959 return 0;
1960 }
1961
1962 ao2_lock(task_data->endpoint_state_compositor);
1964 task_data->aor_options->name,
1965 task_data->aor_options->available ? AVAILABLE : UNAVAILABLE);
1966 ao2_unlock(task_data->endpoint_state_compositor);
1967
1968 return 0;
1969}
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 1975 of file pjsip_options.c.

1976{
1978 int i;
1979
1980 ast_debug(3, "Removing endpoint compositor '%s' from AOR '%s'\n",
1981 task_data->endpoint_state_compositor->name,
1982 task_data->aor_options->name);
1983
1984 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1985 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1986
1987 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1988 if (endpoint_state_compositor != task_data->endpoint_state_compositor) {
1989 continue;
1990 }
1991
1992 AST_VECTOR_REMOVE(&task_data->aor_options->compositors, i, 0);
1993 ao2_ref(endpoint_state_compositor, -1);
1994 break;
1995 }
1996
1997 return 0;
1998}
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 2283 of file pjsip_options.c.

2284{
2285 struct ast_sip_endpoint *endpoint = obj;
2286 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
2287
2288 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
2290 if (!endpoint_state_compositor) {
2291 return 0;
2292 }
2293
2294 ast_debug(3, "Endpoint '%s' has been deleted, removing endpoint state compositor from AORs\n",
2295 ast_sorcery_object_get_id(endpoint));
2296 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
2297 ao2_ref(endpoint_state_compositor, -1);
2298
2299 return 0;
2300}
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 2313 of file pjsip_options.c.

2314{
2315 struct ast_sip_endpoint *endpoint = obj;
2316 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
2317
2318 ast_debug(3, "Endpoint '%s' has been created or modified, updating state\n",
2319 ast_sorcery_object_get_id(endpoint));
2320
2321 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
2323 if (endpoint_state_compositor) {
2324 /* Unlink the AORs currently feeding the endpoint. */
2325 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
2326 ao2_ref(endpoint_state_compositor, -1);
2327 }
2328
2329 /* Connect the AORs that now feed the endpoint. */
2331 return 0;
2332}

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 1878 of file pjsip_options.c.

1879{
1880 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1881
1882 ao2_cleanup(endpoint_state_compositor->aor_statuses);
1883}
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 1892 of file pjsip_options.c.

1893{
1894 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1895
1897 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1899 if (endpoint_state_compositor) {
1901 return endpoint_state_compositor;
1902 }
1903
1904 endpoint_state_compositor = ao2_alloc(sizeof(*endpoint_state_compositor)
1905 + strlen(ast_sorcery_object_get_id(endpoint)) + 1,
1907 if (!endpoint_state_compositor) {
1909 return NULL;
1910 }
1911
1912 /*
1913 * NOTE: The endpoint_state_compositor->aor_statuses container is
1914 * externally protected by the endpoint_state_compositor lock.
1915 */
1916 endpoint_state_compositor->aor_statuses = ao2_container_alloc_hash(
1918 sip_options_endpoint_aor_status_hash_fn, NULL,
1919 sip_options_endpoint_aor_status_cmp_fn);
1920 if (!endpoint_state_compositor->aor_statuses) {
1922 ao2_ref(endpoint_state_compositor, -1);
1923 return NULL;
1924 }
1925
1926 strcpy(endpoint_state_compositor->name, ast_sorcery_object_get_id(endpoint)); /* SAFE */
1927
1928 ao2_link_flags(sip_options_endpoint_state_compositors, endpoint_state_compositor,
1929 OBJ_NOLOCK);
1931
1932 return endpoint_state_compositor;
1933}
#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 2239 of file pjsip_options.c.

2241{
2242 struct ao2_iterator it_aor_statuses;
2243 struct sip_options_endpoint_aor_status *aor_status;
2245 .endpoint_state_compositor = endpoint_state_compositor,
2246 };
2247
2250
2251 /* Unlink AOR feeders pointing to endpoint */
2253 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
2254 task_data.aor_options = ao2_find(sip_options_aors, aor_status->name,
2256 if (!task_data.aor_options) {
2257 continue;
2258 }
2259
2260 ast_debug(3, "Removing endpoint state compositor '%s' from AOR '%s'\n",
2261 ast_sorcery_object_get_id(endpoint), aor_status->name);
2263 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2266 ao2_ref(task_data.aor_options, -1);
2267 }
2268 ao2_iterator_destroy(&it_aor_statuses);
2269
2270 /*
2271 * We do not need to remove the AOR feeder status memory from the
2272 * aor_statuses container. The endpoint_state_compositor is about
2273 * to die and do it for us.
2274 */
2275
2277}
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 722 of file pjsip_options.c.

724{
725 struct ao2_iterator it_aor_statuses;
726 struct sip_options_endpoint_aor_status *aor_status;
728
729 it_aor_statuses = ao2_iterator_init(endpoint_state_compositor->aor_statuses, 0);
730 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
731 if (aor_status->available) {
733 ao2_ref(aor_status, -1);
734 break;
735 }
736 }
737 ao2_iterator_destroy(&it_aor_statuses);
738
739 return state;
740}
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 3298 of file pjsip_options.c.

3299{
3300 management_serializer = mgmt_serializer;
3301
3304 return -1;
3305 }
3308 return -1;
3309 }
3312 return -1;
3313 }
3314
3316
3317 return 0;
3318}
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 800 of file pjsip_options.c.

802{
803 int i;
804
805 /* Iterate through the associated endpoint state compositors updating them */
806 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
807 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
808
809 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
810
811 ao2_lock(endpoint_state_compositor);
812 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
813 aor_options->name, status);
814 ao2_unlock(endpoint_state_compositor);
815 }
816
817 if (status == REMOVED) {
819 }
820}

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 1346 of file pjsip_options.c.

1347{
1348 struct sip_options_aor *aor_options = obj;
1349
1350 ast_debug(3, "Qualifying all contacts on AOR '%s'\n", aor_options->name);
1351
1352 /* Attempt to send an OPTIONS request to every contact on this AOR */
1354 (struct sip_options_aor *) aor_options);
1355
1356 /* Always reschedule to the frequency we should go */
1357 return aor_options->qualify_frequency * 1000;
1358}
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 1251 of file pjsip_options.c.

1252{
1253 struct ast_sip_contact *contact = obj;
1254 struct sip_options_aor *aor_options = arg;
1255 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1256 pjsip_tx_data *tdata;
1257 pjsip_host_info destination;
1258 struct ast_sip_contact_status *contact_status;
1259 struct sip_options_contact_callback_data *contact_callback_data;
1260
1261 ast_debug(3, "Qualifying contact '%s' on AOR '%s'\n",
1263
1267 }
1269 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1270
1271 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, 0);
1272 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
1273 endpoint_state_compositor->name);
1274 }
1275 if (!endpoint) {
1276 ast_debug(3, "Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
1277 ast_sorcery_object_get_id(contact), aor_options->name);
1278 return 0;
1279 }
1280
1281 /*
1282 * Create a request solely for DNS resolution. Its pool keeps the resolver strings alive,
1283 * and passing a URI with no contact avoids leaving a contact reference behind in case
1284 * resolution fails before it can send.
1285 */
1286 if (ast_sip_create_request("OPTIONS", NULL, endpoint, contact->uri, NULL,
1287 &tdata)) {
1288 ast_log(LOG_ERROR, "Unable to create request to qualify contact %s on AOR %s\n",
1289 contact->uri, aor_options->name);
1290 return 0;
1291 }
1292
1293 /* If an outbound proxy is specified set it on this request */
1294 if (!ast_strlen_zero(contact->outbound_proxy) &&
1295 ast_sip_set_outbound_proxy(tdata, contact->outbound_proxy)) {
1296 ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
1297 contact->uri);
1298 pjsip_tx_data_dec_ref(tdata);
1299 return 0;
1300 }
1301
1302 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1303 if (!contact_status) {
1304 ast_log(LOG_ERROR, "Unable to retrieve contact status information for contact %s on AOR %s\n",
1305 contact->uri, aor_options->name);
1306 pjsip_tx_data_dec_ref(tdata);
1307 return 0;
1308 }
1309 ao2_ref(contact_status, -1);
1310
1311 contact_callback_data = sip_options_contact_callback_data_alloc(contact,
1312 aor_options, endpoint, tdata);
1313 if (!contact_callback_data) {
1314 ast_log(LOG_ERROR, "Unable to create object to contain callback data for contact %s on AOR %s\n",
1315 contact->uri, aor_options->name);
1316 pjsip_tx_data_dec_ref(tdata);
1317 return 0;
1318 }
1319
1320
1321 /*
1322 * Resolve the contact destination explicitly via DNS, then create and send
1323 * an independent OPTIONS for each returned transport/address/port tuple.
1324 * Keep the resolver-only tdata alive because its pool owns strings used
1325 * by the asynchronous resolver.
1326 */
1327 if (pjsip_get_request_dest(tdata, &destination) != PJ_SUCCESS
1328 || sip_options_apply_transport_to_destination(tdata, &destination)
1329 != PJ_SUCCESS) {
1330 ast_log(LOG_ERROR, "Unable to resolve destination to qualify contact %s on AOR %s\n",
1331 contact->uri, aor_options->name);
1332 ao2_ref(contact_callback_data, -1);
1333 return 0;
1334 }
1335
1336 pjsip_endpt_resolve(ast_sip_get_pjsip_endpoint(), tdata->pool, &destination,
1337 contact_callback_data, sip_options_qualify_resolve_cb);
1338
1339 return 0;
1340}
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 1156 of file pjsip_options.c.

1158{
1161 unsigned int idx;
1162
1165 if (!task_data) {
1166 /*
1167 * Resolver callbacks are not guaranteed to run on the AOR serializer,
1168 * so on allocation failure we must log and drop to avoid potential state
1169 * issues.
1170 */
1172 "Unable to allocate qualify resolve task for '%s'\n",
1174 ao2_ref(batch, -1);
1175 return;
1176 }
1177
1178 memset(task_data, 0, sizeof(*task_data));
1179 task_data->batch = ao2_bump(batch);
1180 task_data->status = status;
1181
1182 if (status != PJ_SUCCESS || !addresses || !addresses->count) {
1183 if (batch->resolve_tdata) {
1184 pjsip_tx_data_dec_ref(batch->resolve_tdata);
1185 batch->resolve_tdata = NULL;
1186 }
1187
1188 if (ast_sip_push_task(batch->aor_options->serializer,
1191 "Unable to queue qualify resolve task for '%s'\n",
1193 ao2_ref(task_data, -1);
1194 }
1195 ao2_ref(batch, -1);
1196 return;
1197 }
1198
1199 /* Each resolved address must contribute exactly one batch result. */
1200 task_data->count = addresses->count;
1201 if (task_data->count > PJSIP_MAX_RESOLVED_ADDRESSES) {
1202 task_data->count = PJSIP_MAX_RESOLVED_ADDRESSES;
1203 }
1204
1205 for (idx = 0; idx < task_data->count; ++idx) {
1206 char *name_copy;
1207
1208 name_copy = ast_malloc(addresses->entry[idx].name.slen + 1);
1209 if (!name_copy) {
1210 task_data->status = PJ_ENOMEM;
1211 task_data->count = idx;
1212 break;
1213 }
1214
1215 ast_copy_pj_str(name_copy, &addresses->entry[idx].name,
1216 addresses->entry[idx].name.slen + 1);
1217 task_data->names[idx] = name_copy;
1218 task_data->addresses.entry[idx] = addresses->entry[idx];
1219 task_data->addresses.entry[idx].name.ptr = name_copy;
1220 task_data->addresses.entry[idx].name.slen = addresses->entry[idx].name.slen;
1221 }
1222
1223 if (task_data->status == PJ_SUCCESS) {
1224 task_data->addresses.count = task_data->count;
1225 }
1226
1227 if (batch->resolve_tdata) {
1228 pjsip_tx_data_dec_ref(batch->resolve_tdata);
1229 batch->resolve_tdata = NULL;
1230 }
1231
1232 /*
1233 * Push the qualify resolve task to the AOR serializer to avoid potential race
1234 * conditions between the resolve callback and the qualify contact task.
1235 */
1236 if (ast_sip_push_task(batch->aor_options->serializer,
1239 "Unable to queue qualify resolve task for '%s'\n",
1241 ao2_ref(task_data, -1);
1242 } else {
1243 ao2_ref(batch, -1);
1244 return;
1245 }
1246
1247 ao2_ref(batch, -1);
1248}
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_host_info target_dest;
610 pjsip_via_hdr *via;
611 pjsip_transaction *tsx = NULL;
612
613 if (ast_sip_create_request("OPTIONS", NULL, batch->endpoint, NULL,
614 batch->contact, &tdata)) {
616 continue;
617 }
618
619 if (!ast_strlen_zero(batch->contact->outbound_proxy) &&
620 ast_sip_set_outbound_proxy(tdata, batch->contact->outbound_proxy)) {
621 pjsip_tx_data_dec_ref(tdata);
623 continue;
624 }
625
626 if (pjsip_get_request_dest(tdata, &target_dest) != PJ_SUCCESS) {
627 pjsip_tx_data_dec_ref(tdata);
629 continue;
630 }
631
632 /*
633 * Build a new request per resolved target so each send gets its own
634 * transaction and Via branch. Setting exactly one pre-resolved
635 * destination here avoids PJSIP re-resolving and choosing only the
636 * first DNS result.
637 */
638 tdata->dest_info.addr.count = 1;
639 tdata->dest_info.cur_addr = 0;
640 tdata->dest_info.addr.entry[0].type = task_data->addresses.entry[idx].type;
641 tdata->dest_info.addr.entry[0].priority = task_data->addresses.entry[idx].priority;
642 tdata->dest_info.addr.entry[0].weight = task_data->addresses.entry[idx].weight;
643 tdata->dest_info.addr.entry[0].addr_len = task_data->addresses.entry[idx].addr_len;
644 pj_sockaddr_cp(&tdata->dest_info.addr.entry[0].addr,
645 &task_data->addresses.entry[idx].addr);
646 pj_strdup(tdata->pool, &tdata->dest_info.addr.entry[0].name,
647 &task_data->addresses.entry[idx].name);
648
649 /*
650 * PJPROJECT only sets dest_info.name when it does the resolution itself.
651 * Set it here since TLS/WSS uses it for connection reuse and SNI/certificate
652 * verification.
653 */
654 pj_strdup(tdata->pool, &tdata->dest_info.name, &target_dest.addr.host);
655
656 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
657 if (via) {
658 via->branch_param.slen = 0;
659 }
660
661 /* ast_sip_send_out_of_dialog_request_with_tsx consumes the tdata reference. */
663 (int)(batch->aor_options->qualify_timeout * 1000),
665 ao2_ref(batch, -1);
667 } else if (tsx) {
668 /*
669 * It is possible that we will not get back a transaction under two circumstances:
670 * 1. The send failed.
671 * 2. The build of PJPROJECT used does not contain pjsip_endpt_send_request2() so
672 * there is no way to get an in-flight transaction reference for the OPTIONS.
673 *
674 * With no transaction references, we can not cancel in-flight OPTIONS requests when
675 * an endpoint responds with a 2xx response to one of the requests. This is not ideal
676 * and will result in unnecessary OPTIONS retransmissions being sent.
677 *
678 * The Append should never fail as we init the vector to PJSIP_MAX_RESOLVED_ADDRESSES
679 * and also limit the count of resolved addresses in sip_options_qualify_resolve_cb.
680 */
681 AST_VECTOR_APPEND(&batch->target_transactions, tsx);
682 }
683 }
684
685 ao2_ref(task_data, -1);
686 return 0;
687}
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 992 of file pjsip_options.c.

995{
997
1000 if (!result) {
1001 ast_log(LOG_WARNING, "Unable to allocate qualify target result for '%s'\n",
1003 return;
1004 }
1005
1006 result->batch = ao2_bump(batch);
1007 result->status = status;
1008 /*
1009 * Callbacks may arrive on non-serializer threads, so they queue one result per
1010 * target onto the AOR serializer, the single owner of the batch's processing.
1011 *
1012 * Sends and callbacks can execute synchronously while we are already
1013 * running on that serializer thread. Re-queueing to the same serializer in
1014 * that case would defer updates and can break processing.
1015 *
1016 * Process inline when already on the same taskpool serializer to preserve
1017 * immediate, in-order state transitions.
1018 */
1019 if (batch->aor_options->serializer == ast_taskpool_serializer_get_current()) {
1021 return;
1022 }
1023
1024 if (ast_sip_push_task(batch->aor_options->serializer,
1026 ast_log(LOG_WARNING, "Unable to queue qualify target result for '%s'\n",
1028 ao2_ref(result, -1);
1029 }
1030}
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 1502 of file pjsip_options.c.

1503{
1504 struct ast_sip_contact *contact = obj;
1505 struct sip_options_aor *aor_options = arg;
1506
1507 sip_options_remove_contact_status(aor_options, contact);
1508
1509 return CMP_MATCH;
1510}
@ 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 1429 of file pjsip_options.c.

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

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 1529 of file pjsip_options.c.

1531{
1532 struct ast_sip_contact_status *cs_new;
1533
1534 /* Update the contact specific status information */
1535 cs_new = sip_contact_status_copy(contact_status);
1536 if (!cs_new) {
1537 return;
1538 }
1539 cs_new->last_status = cs_new->status;
1540 cs_new->status = status;
1541
1542 /*
1543 * We need to always set the RTT to zero because we haven't completed
1544 * an OPTIONS ping so RTT is unknown. If the OPTIONS ping were still
1545 * running it will be refreshed on the next go round anyway.
1546 */
1547 cs_new->rtt = 0;
1548
1550
1551 if (cs_new->status != cs_new->last_status) {
1552 ast_verb(3, "Contact %s/%s is now %s.\n",
1553 cs_new->aor, cs_new->uri,
1555
1556 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1557 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1558 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1559 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1560
1562
1563 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
1564 "Contact: %s\r\n"
1565 "Status: %s",
1566 cs_new->name,
1568 }
1569 ao2_ref(cs_new, -1);
1570}

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 1600 of file pjsip_options.c.

1601{
1602 struct ast_sip_contact *contact = obj;
1603 struct ast_sip_contact_status *contact_status;
1604
1605 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1606 if (!contact_status) {
1607 return 0;
1608 }
1609
1610 switch (contact_status->status) {
1611 case AVAILABLE:
1613 break;
1614 case UNAVAILABLE:
1615 case UNKNOWN:
1616 case CREATED:
1617 case REMOVED:
1618 break;
1619 }
1620
1621 ao2_ref(contact_status, -1);
1622
1623 return 0;
1624}
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 1573 of file pjsip_options.c.

1574{
1575 struct ast_sip_contact *contact = obj;
1576 struct ast_sip_contact_status *contact_status;
1577
1578 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1579 if (!contact_status) {
1580 return 0;
1581 }
1582
1583 switch (contact_status->status) {
1584 case AVAILABLE:
1585 case UNAVAILABLE:
1586 case UNKNOWN:
1587 sip_options_set_contact_status(contact_status, CREATED);
1588 break;
1589 case CREATED:
1590 case REMOVED:
1591 break;
1592 }
1593
1594 ao2_ref(contact_status, -1);
1595
1596 return 0;
1597}

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 2225 of file pjsip_options.c.

2226{
2228 .reload = reload,
2229 };
2230
2232 &task_data);
2233}
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 1841 of file pjsip_options.c.

1842{
1844 .aor = obj,
1845 .existing = arg,
1846 };
1847
1848 task_data.aor_options = ao2_find(sip_options_aors,
1850 if (!task_data.aor_options) {
1851 task_data.aor_options = sip_options_aor_alloc(task_data.aor);
1852 if (!task_data.aor_options) {
1853 return 0;
1854 }
1855
1856 task_data.added = 1;
1857
1858 /* Nothing is aware of this AOR yet so we can just update it in this thread */
1860 ao2_link(sip_options_aors, task_data.aor_options);
1861 } else {
1862 /* This AOR already exists so we have to do manipulation in its serializer */
1863 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1865 }
1866
1867 ao2_ref(task_data.aor_options, -1);
1868
1869 if (task_data.existing) {
1872 }
1873
1874 return 0;
1875}
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 1803 of file pjsip_options.c.

1804{
1806 int i;
1807
1808 ast_debug(3, "Synchronizing AOR '%s' with current state of configuration and world\n",
1809 task_data->aor_options->name);
1810
1812 task_data->added);
1813
1814 /*
1815 * Endpoint state compositors are removed in this operation but not
1816 * added. To reduce the amount of work done they are done later. In
1817 * the mean time things can still qualify and once an endpoint state
1818 * compositor is added to the AOR it will be updated with the current
1819 * state.
1820 */
1821 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1822 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1823
1824 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1825
1826 ao2_lock(endpoint_state_compositor);
1827 endpoint_state_compositor->active = 0;
1828 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
1829 task_data->aor_options->name, REMOVED);
1830 ao2_unlock(endpoint_state_compositor);
1831 }
1832 AST_VECTOR_RESET(&task_data->aor_options->compositors, ao2_cleanup);
1833
1834 return 0;
1835}

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 2004 of file pjsip_options.c.

2005{
2006 struct ast_sip_endpoint *endpoint = obj;
2007 struct ast_sip_aor *aor = arg;
2008 char *aors;
2009 char *aor_name;
2011
2012 if (ast_strlen_zero(endpoint->aors)) {
2013 /* There are no AORs, so really... who the heck knows */
2014 ast_debug(3, "Endpoint '%s' is not interested in any AORs so not creating endpoint state compositor\n",
2015 ast_sorcery_object_get_id(endpoint));
2016 return 0;
2017 }
2018
2019 ast_debug(3, "Synchronizing endpoint '%s' with AORs '%s'\n",
2020 ast_sorcery_object_get_id(endpoint), endpoint->aors);
2021
2022 aors = ast_strdupa(endpoint->aors);
2023 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2024 if (ast_strlen_zero(aor_name)) {
2025 continue;
2026 }
2027 if (aor && strcasecmp(ast_sorcery_object_get_id(aor), aor_name)) {
2028 ast_debug(3, "Filtered AOR '%s' on endpoint '%s' as we are looking for '%s'\n",
2029 aor_name, ast_sorcery_object_get_id(endpoint),
2031 continue;
2032 }
2033
2034 task_data.aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2035 if (!task_data.aor_options) {
2036 /*
2037 * They have referenced an invalid AOR. If that's all they've
2038 * done we will set them to offline at the end.
2039 */
2040 ast_debug(3, "Endpoint '%s' referenced invalid AOR '%s'\n",
2041 ast_sorcery_object_get_id(endpoint), aor_name);
2042 continue;
2043 }
2044
2045 if (!task_data.endpoint_state_compositor) {
2046 /*
2047 * We create an endpoint state compositor only after we know
2048 * for sure we need it.
2049 */
2050 task_data.endpoint_state_compositor =
2052 if (!task_data.endpoint_state_compositor) {
2054 "Could not create endpoint state compositor for '%s', endpoint state will be incorrect\n",
2055 ast_sorcery_object_get_id(endpoint));
2056 ao2_ref(task_data.aor_options, -1);
2059 return 0;
2060 }
2061 }
2062
2063 /* We use a synchronous task so that we don't flood the system */
2064 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2066
2067 ao2_ref(task_data.aor_options, -1);
2068
2069 /*
2070 * If we filtered on a specific AOR name then the endpoint can
2071 * only reference it once so break early.
2072 */
2073 if (aor) {
2074 break;
2075 }
2076 }
2077
2078 if (task_data.endpoint_state_compositor) {
2079 /*
2080 * If an endpoint state compositor is present determine the current state
2081 * of the endpoint and update it.
2082 */
2083 ao2_lock(task_data.endpoint_state_compositor);
2084 task_data.endpoint_state_compositor->active = 1;
2087 ao2_unlock(task_data.endpoint_state_compositor);
2088
2089 ao2_ref(task_data.endpoint_state_compositor, -1);
2090 } else if (!aor) {
2091 /* If no explicit AOR is specified we are updating the endpoint itself, so then set
2092 * it to offline if no endpoint compositor exists as they referenced an invalid AOR
2093 * or none at all
2094 */
2095 ast_debug(3, "Endpoint '%s' has no AORs feeding it, setting it to offline state as default\n",
2096 ast_sorcery_object_get_id(endpoint));
2099 }
2100
2101 return 0;
2102}
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 2169 of file pjsip_options.c.

2170{
2172 struct ao2_container *existing = NULL;
2173 struct ao2_container *objects;
2174
2175 /*
2176 * When reloading we keep track of the existing AORs so we can
2177 * terminate old ones that are no longer referenced or used.
2178 */
2179 if (task_data->reload) {
2181 if (!existing) {
2182 return 0;
2183 }
2184 }
2185
2188 if (objects) {
2189 /* Go through the returned AORs and synchronize with our local state */
2191 ao2_ref(objects, -1);
2192 }
2193
2194 /*
2195 * Any AORs remaining in existing are no longer referenced by
2196 * the current container of AORs we retrieved, so remove them.
2197 */
2198 if (existing) {
2201 ao2_ref(existing, -1);
2202 }
2203
2206 if (objects) {
2207 /* Go through the provided endpoints and update AORs */
2209 ao2_ref(objects, -1);
2210 }
2211
2212 /*
2213 * All endpoint state compositors that don't have any AORs
2214 * feeding them information can be removed. If they end
2215 * up getting needed later they'll just be recreated.
2216 */
2220
2221 return 0;
2222}
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 951 of file pjsip_options.c.

952{
953 struct sip_options_target_result *result = obj;
954 ao2_cleanup(result->batch);
955}

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 961 of file pjsip_options.c.

962{
963 struct sip_options_target_result *result = obj;
965
966 if (!batch->completed) {
967 /* If the result is available then we can mark the batch as completed
968 and notify the AOR */
969 ast_assert(batch->pending);
970 --batch->pending;
971
972 if (result->status == AVAILABLE) {
973 /* At least one resolved target was available. */
974 batch->completed = 1;
975 batch->status = AVAILABLE;
977 /* The notify task inherits this reference. */
979 } else if (!batch->pending) {
980 /* Every resolved target failed. */
981 batch->completed = 1;
982 batch->status = UNAVAILABLE;
984 }
985 }
986
987 ao2_ref(result, -1);
988 return 0;
989}
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 689 of file pjsip_options.c.

690{
691 if (tsx) {
692 pj_grp_lock_dec_ref(tsx->grp_lock);
693 }
694}

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 2127 of file pjsip_options.c.

2128{
2129 struct sip_options_aor *aor_options = obj;
2130
2131 ast_debug(3, "AOR '%s' is no longer configured, removing it\n", aor_options->name);
2132
2134 aor_options);
2135 ao2_unlink(sip_options_aors, aor_options);
2136
2137 return CMP_MATCH;
2138}
#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 2144 of file pjsip_options.c.

2145{
2146 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
2147
2148 if (ao2_container_count(endpoint_state_compositor->aor_statuses)) {
2149 return 0;
2150 }
2151
2152 /* No AORs are feeding this endpoint state compositor */
2153 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
2155
2156 return CMP_MATCH;
2157}

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 2352 of file pjsip_options.c.

2353{
2355 int available = task_data->aor_options->available;
2356
2357 ast_debug(3, "Individually updating AOR '%s' with current state of configuration and world\n",
2358 task_data->aor_options->name);
2359
2361 task_data->added);
2362
2363 if (!available && task_data->aor_options->available) {
2364 ast_debug(3, "After modifying AOR '%s' it has now become available\n",
2365 task_data->aor_options->name);
2367 } else if (available && !task_data->aor_options->available) {
2368 ast_debug(3, "After modifying AOR '%s' it has become unavailable\n",
2369 task_data->aor_options->name);
2371 }
2372
2373 return 0;
2374}

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 746 of file pjsip_options.c.

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

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 2473 of file pjsip_options.c.

2473 {
2474 .created = aor_observer_modified,
2475 .updated = aor_observer_modified,
2476 .deleted = aor_observer_deleted,
2477};

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 3132 of file pjsip_options.c.

3132 {
3133 AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint"),
3134 AST_CLI_DEFINE(cli_show_qualify_endpoint, "Show the current qualify options for all Aors on the PJSIP endpoint"),
3135 AST_CLI_DEFINE(cli_show_qualify_aor, "Show the PJSIP Aor current qualify options"),
3136 AST_CLI_DEFINE(cli_reload_qualify_endpoint, "Synchronize the qualify options for all Aors on the PJSIP endpoint"),
3137 AST_CLI_DEFINE(cli_reload_qualify_aor, "Synchronize the PJSIP Aor qualify options"),
3138};
#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 2761 of file pjsip_options.c.

2761 {
2762 .created = contact_observer_created,
2763 .updated = contact_observer_updated,
2764 .deleted = contact_observer_deleted,
2765};

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 3212 of file pjsip_options.c.

3212 {
3213 .format_ami = format_ami_contact_status
3214};

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 2342 of file pjsip_options.c.

2342 {
2343 .created = endpoint_observer_modified,
2344 .updated = endpoint_observer_modified,
2345 .deleted = endpoint_observer_deleted,
2346};

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};