Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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/threadpool.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_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...
 

Macros

#define AOR_BUCKETS   1567
 These are the number of buckets to store AORs in. More...
 
#define AOR_STATUS_BUCKETS   3
 These are the number of buckets (per endpoint state compositor) to use to store AOR statuses. More...
 
#define CONTACT_BUCKETS   13
 These are the number of buckets (per AOR) to use to store contacts. More...
 
#define CONTACT_STATUS_BUCKETS   1567
 These are the number of contact status buckets. More...
 
#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. More...
 
#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE   1
 The initial vector size for the endpoint state compositors on an AOR. More...
 
#define MAX_UNLOAD_TIMEOUT_TIME   10 /* Seconds */
 Maximum wait time to join the below shutdown group. More...
 

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. More...
 
 AO2_STRING_FIELD_CMP_FN (sip_options_aor, name)
 Comparator function for SIP OPTIONS AORs. More...
 
 AO2_STRING_FIELD_CMP_FN (sip_options_endpoint_aor_status, name)
 Comparator function for endpoint AOR status. More...
 
 AO2_STRING_FIELD_CMP_FN (sip_options_endpoint_state_compositor, name)
 Comparator function for endpoint state compositors. More...
 
 AO2_STRING_FIELD_HASH_FN (ast_sip_contact_status, name)
 Hashing function for contact statuses. More...
 
 AO2_STRING_FIELD_HASH_FN (sip_options_aor, name)
 Hashing function for OPTIONS AORs. More...
 
 AO2_STRING_FIELD_HASH_FN (sip_options_endpoint_aor_status, name)
 Hashing function for endpoint AOR status. More...
 
 AO2_STRING_FIELD_HASH_FN (sip_options_endpoint_state_compositor, name)
 Hashing function for endpoint state compositors. More...
 
 AO2_STRING_FIELD_SORT_FN (ast_sip_contact_status, name)
 Sort function for contact statuses. More...
 
static void aor_observer_deleted (const void *obj)
 Observer callback invoked on AOR deletion. More...
 
static void aor_observer_modified (const void *obj)
 Observer callback invoked on AOR creation or modification. More...
 
void ast_res_pjsip_cleanup_options_handling (void)
 
struct ast_sip_contact_statusast_res_pjsip_find_or_create_contact_status (const struct ast_sip_contact *contact)
 
int ast_res_pjsip_init_options_handling (int reload)
 
int ast_res_pjsip_preinit_options_handling (void)
 
int ast_sip_format_contact_ami (void *obj, void *arg, int flags)
 Formats the contact and sends over AMI. More...
 
const char * ast_sip_get_contact_short_status_label (const enum ast_sip_contact_status_type status)
 
struct ast_sip_contact_statusast_sip_get_contact_status (const struct ast_sip_contact *contact)
 Retrieve the current status for a contact. More...
 
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. More...
 
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. More...
 
static void contact_observer_deleted (const void *obj)
 Observer callback invoked on contact deletion. More...
 
static void contact_observer_updated (const void *obj)
 Observer callback invoked on contact update. More...
 
static int contact_status_publish_update_task (void *obj)
 Task to notify endpoints of a contact status change. More...
 
static void endpoint_observer_deleted (const void *obj)
 Observer callback invoked on endpoint deletion. More...
 
static void endpoint_observer_modified (const void *obj)
 Observer callback invoked on endpoint creation or modification. More...
 
static int format_ami_contact_status (const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
 
static int format_ami_contactlist_handler (void *obj, void *arg, int flags)
 
static int format_contact_status_for_aor (void *obj, void *arg, int flags)
 
static struct ao2_containerget_all_contacts (void)
 
static int has_qualify_changed (const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
 Check if the contact qualify options are different than local aor qualify options. More...
 
static pj_bool_t options_on_rx_request (pjsip_rx_data *rdata)
 
static void qualify_contact_cb (void *token, pjsip_event *e)
 Callback for when we get a result from a SIP OPTIONS request (a response or a timeout) More...
 
static pj_status_t send_options_response (pjsip_rx_data *rdata, int code)
 
static struct ast_sip_contact_statussip_contact_status_alloc (const char *name)
 
static struct ast_sip_contact_statussip_contact_status_copy (const struct ast_sip_contact_status *src)
 
static void sip_contact_status_dtor (void *obj)
 Destructor for contact statuses. More...
 
static int sip_contact_to_ami (const struct ast_sip_contact *contact, struct ast_str **buf)
 
static struct sip_options_aorsip_options_aor_alloc (struct ast_sip_aor *aor)
 Allocator for AOR OPTIONS. More...
 
static void sip_options_aor_dtor (void *obj)
 Destructor function for SIP OPTIONS AORs. More...
 
static int sip_options_aor_observer_deleted_task (void *obj)
 Task to delete an AOR from the known universe. More...
 
static int sip_options_aor_observer_modified_task (void *obj)
 Task to synchronize the AOR. More...
 
static int sip_options_aor_remove_task (void *obj)
 Task which removes an AOR from all of the ESCs it is reporting to. More...
 
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. More...
 
static int sip_options_cleanup_aor_task (void *obj)
 Management task to clean up an AOR. More...
 
static int sip_options_cleanup_task (void *obj)
 Management task to clean up the environment. More...
 
static int sip_options_contact_add_management_task (void *obj)
 Task to add a dynamic contact to an AOR in its serializer. More...
 
static int sip_options_contact_add_task (void *obj)
 Task which adds a dynamic contact to an AOR. More...
 
static struct sip_options_contact_callback_datasip_options_contact_callback_data_alloc (struct ast_sip_contact *contact, struct sip_options_aor *aor_options)
 Contact callback data allocator. More...
 
static void sip_options_contact_callback_data_dtor (void *obj)
 Destructor for contact callback data. More...
 
static int sip_options_contact_delete_management_task (void *obj)
 Task to delete a contact from an AOR in its serializer. More...
 
static int sip_options_contact_delete_task (void *obj)
 Task which deletes a dynamic contact from an AOR. More...
 
static int sip_options_contact_status_available_count (void *obj, void *arg, int flags)
 Count AVAILABLE qualified contacts. More...
 
static int sip_options_contact_status_notify_task (void *obj)
 Task to notify an AOR of a contact status change. More...
 
static void sip_options_contact_status_update (struct ast_sip_contact_status *contact_status)
 
static struct ao2_containersip_options_contact_statuses_alloc (void)
 Helper function to allocate a contact statuses container. More...
 
static int sip_options_contact_update_task (void *obj)
 Task which updates a dynamic contact to an AOR. More...
 
static int sip_options_determine_initial_qualify_time (int qualify_frequency)
 Determine an initial time for scheduling AOR qualifying. More...
 
static int sip_options_endpoint_compositor_add_task (void *obj)
 Task which adds an AOR to an endpoint state compositor. More...
 
static int sip_options_endpoint_compositor_remove_task (void *obj)
 Task which adds removes an AOR from an endpoint state compositor. More...
 
static int sip_options_endpoint_observer_deleted_task (void *obj)
 Task to delete an endpoint from the known universe. More...
 
static int sip_options_endpoint_observer_modified_task (void *obj)
 Task to synchronize the endpoint. More...
 
static void sip_options_endpoint_state_compositor_dtor (void *obj)
 Destructor for endpoint state compositors. More...
 
static struct sip_options_endpoint_state_compositorsip_options_endpoint_state_compositor_find_or_alloc (const struct ast_sip_endpoint *endpoint)
 Find (or create) an endpoint state compositor. More...
 
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. More...
 
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. More...
 
static int sip_options_init_task (void *mgmt_serializer)
 Management task to finish setting up the environment. More...
 
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. More...
 
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. More...
 
static int sip_options_qualify_aor (void *obj)
 Task to qualify contacts of an AOR. More...
 
static int sip_options_qualify_contact (void *obj, void *arg, int flags)
 Send a SIP OPTIONS request for a contact. More...
 
static int sip_options_remove_contact (void *obj, void *arg, int flags)
 Forward declaration of this helpful function. More...
 
static void sip_options_remove_contact_status (struct sip_options_aor *aor_options, struct ast_sip_contact *contact)
 Remove contact status for a hint. More...
 
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. More...
 
static int sip_options_set_contact_status_qualified (void *obj, void *arg, int flags)
 Transition the contact status to qualified mode. More...
 
static int sip_options_set_contact_status_unqualified (void *obj, void *arg, int flags)
 Transition the contact status to unqualified mode. More...
 
static void sip_options_synchronize (int reload)
 Synchronize our local container of AORs and endpoint state compositors with the current configuration. More...
 
static int sip_options_synchronize_aor (void *obj, void *arg, int flags)
 Synchronize an AOR with our local state. More...
 
static int sip_options_synchronize_aor_task (void *obj)
 Task to synchronize an AOR with our local state. More...
 
static int sip_options_synchronize_endpoint (void *obj, void *arg, int flags)
 Synchronize an endpoint with our local state. More...
 
static int sip_options_synchronize_task (void *obj)
 Task to synchronize our local container of AORs and endpoint state compositors with the current configuration. More...
 
static int sip_options_unused_aor (void *obj, void *arg, int flags)
 Callback which removes any unused AORs that remained after reloading. More...
 
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. More...
 
static int sip_options_update_aor_task (void *obj)
 Task to synchronize an AOR with our local state. More...
 
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. More...
 

Variables

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

Macro Definition Documentation

◆ AOR_BUCKETS

#define AOR_BUCKETS   1567

These are the number of buckets to store AORs in.

Definition at line 103 of file pjsip_options.c.

◆ AOR_STATUS_BUCKETS

#define AOR_STATUS_BUCKETS   3

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

Definition at line 123 of file pjsip_options.c.

◆ CONTACT_BUCKETS

#define CONTACT_BUCKETS   13

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

Definition at line 114 of file pjsip_options.c.

◆ CONTACT_STATUS_BUCKETS

#define CONTACT_STATUS_BUCKETS   1567

These are the number of contact status buckets.

Definition at line 110 of file pjsip_options.c.

◆ DEFAULT_ENCODING

#define DEFAULT_ENCODING   "identity"

Definition at line 97 of file pjsip_options.c.

◆ DEFAULT_LANGUAGE

#define DEFAULT_LANGUAGE   "en"

Definition at line 96 of file pjsip_options.c.

◆ ENDPOINT_STATE_COMPOSITOR_BUCKETS

#define ENDPOINT_STATE_COMPOSITOR_BUCKETS   13

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

Definition at line 117 of file pjsip_options.c.

◆ ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE

#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE   1

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

Definition at line 120 of file pjsip_options.c.

◆ MAX_UNLOAD_TIMEOUT_TIME

#define MAX_UNLOAD_TIMEOUT_TIME   10 /* Seconds */

Maximum wait time to join the below shutdown group.

Definition at line 126 of file pjsip_options.c.

Function Documentation

◆ ami_show_contacts()

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

Definition at line 2464 of file pjsip_options.c.

2465{
2466 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2467 struct ao2_container *contacts;
2468
2469 contacts = get_all_contacts();
2470 if (!contacts) {
2471 astman_send_error(s, m, "Could not get Contacts\n");
2472 return 0;
2473 }
2474
2475 if (!ao2_container_count(contacts)) {
2476 astman_send_error(s, m, "No Contacts found\n");
2477 ao2_ref(contacts, -1);
2478 return 0;
2479 }
2480
2481 astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",
2482 "start");
2483
2485
2486 astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);
2488
2489 ao2_ref(contacts, -1);
2490
2491 return 0;
2492}
#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:2028
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1986
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:2064
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
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:3200
struct mansession * s
Definition: res_pjsip.h:3202
const struct message * m
Definition: res_pjsip.h:3204

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

2680{
2681 const char *endpoint_name = astman_get_header(m, "Endpoint");
2682 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2683 char *aors;
2684 char *aor_name;
2685
2686 if (ast_strlen_zero(endpoint_name)) {
2687 astman_send_error(s, m, "Endpoint parameter missing.");
2688 return 0;
2689 }
2690
2691 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2692 endpoint_name);
2693 if (!endpoint) {
2694 astman_send_error(s, m, "Unable to retrieve endpoint\n");
2695 return 0;
2696 }
2697
2698 /* send a qualify for all contacts registered with the endpoint */
2699 if (ast_strlen_zero(endpoint->aors)) {
2700 astman_send_error(s, m, "No AoRs configured for endpoint\n");
2701 return 0;
2702 }
2703
2704 aors = ast_strdupa(endpoint->aors);
2705 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2706 struct sip_options_aor *aor_options;
2707
2708 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2709 if (!aor_options) {
2710 continue;
2711 }
2712
2714 aor_options);
2715 ao2_ref(aor_options, -1);
2716 }
2717
2718 astman_send_ack(s, m, "Endpoint found, will qualify");
2719 return 0;
2720}
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:2018
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2179
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:1853
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:1051
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:941

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

2057{
2060}
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 2025 of file pjsip_options.c.

2026{
2029}
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 2851 of file pjsip_options.c.

2852{
2853 int remaining;
2854 struct ast_taskprocessor *mgmt_serializer;
2855
2857 ast_manager_unregister("PJSIPQualify");
2858 ast_manager_unregister("PJSIPShowContacts");
2860
2867
2868 mgmt_serializer = management_serializer;
2870 if (mgmt_serializer) {
2872 }
2873
2876 if (remaining) {
2877 ast_log(LOG_WARNING, "Cleanup incomplete. Could not stop %d AORs.\n",
2878 remaining);
2879 }
2882
2883 if (mgmt_serializer) {
2884 ast_taskprocessor_unreference(mgmt_serializer);
2885 }
2886
2893
2894 pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
2895}
#define ast_log
Definition: astobj2.c:42
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
#define LOG_WARNING
static pjsip_module options_module
static struct ast_serializer_shutdown_group * shutdown_group
Shutdown group for options serializers.
#define MAX_UNLOAD_TIMEOUT_TIME
Maximum wait time to join the below shutdown group.
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:520
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition: res_pjsip.c:487
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:2423
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
int ast_serializer_shutdown_group_join(struct ast_serializer_shutdown_group *shutdown_group, int timeout)
Wait for the serializers in the group to shutdown with timeout.
Definition: threadpool.c:1241
#define ARRAY_LEN(a)
Definition: utils.h:666

References ao2_cleanup, aor_observer_callbacks, ARRAY_LEN, ast_cli_unregister_multiple(), ast_log, ast_manager_unregister(), ast_serializer_shutdown_group_join(), 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, LOG_WARNING, management_serializer, MAX_UNLOAD_TIMEOUT_TIME, NULL, options_module, shutdown_group, 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 466 of file pjsip_options.c.

467{
468 struct ast_sip_contact_status *contact_status;
469 int res;
470
471 /*
472 * At startup a contact status can be retrieved when static contacts
473 * are themselves being setup. This happens before we are fully setup.
474 * Since we don't actually trigger qualify or anything as a result it
475 * is safe to do so. They'll just get back a contact status that will
476 * be updated later. At this time they only care that the contact
477 * status gets created for the static contact anyway.
478 */
480 /*
481 * We haven't been pre-initialized or we are shutting down.
482 * Neither situation should happen.
483 */
484 ast_assert(0);
485 return NULL;
486 }
487
489
490 /* If contact status for this contact already exists just return it */
491 contact_status = ao2_find(sip_options_contact_statuses,
493 if (contact_status) {
495 return contact_status;
496 }
497
498 /* Otherwise we have to create and store a new contact status */
499 contact_status = sip_contact_status_alloc(ast_sorcery_object_get_id(contact));
500 if (!contact_status) {
502 return NULL;
503 }
504
505 contact_status->rtt = 0;
506 contact_status->status = CREATED;
507 contact_status->last_status = CREATED;
508 res = ast_string_field_set(contact_status, uri, contact->uri);
509 res |= ast_string_field_set(contact_status, aor, contact->aor);
510 if (res) {
512 ao2_ref(contact_status, -1);
513 return NULL;
514 }
515
518
519 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
520 "+1", 1.0, ast_sip_get_contact_status_label(contact_status->status));
521
522 sip_options_contact_status_update(contact_status);
523
524 return contact_status;
525}
#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:442
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
void 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.
Definition: stringfields.h:521
A contact's status.
Definition: res_pjsip.h:451
const ast_string_field uri
Definition: res_pjsip.h:457
enum ast_sip_contact_status_type status
Definition: res_pjsip.h:468
enum ast_sip_contact_status_type last_status
Definition: res_pjsip.h:470
const ast_string_field aor
Definition: res_pjsip.h:457
const ast_string_field uri
Definition: res_pjsip.h:412
const ast_string_field aor
Definition: res_pjsip.h:412
#define ast_assert(a)
Definition: utils.h:739

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

2935{
2936 struct ast_taskprocessor *mgmt_serializer;
2937
2938 static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
2939
2940 if (reload) {
2942 return 0;
2943 }
2944
2945 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
2946 != PJ_SUCCESS) {
2947 return -1;
2948 }
2949
2950 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
2951 NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
2953 return -1;
2954 }
2955
2957 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
2958 if (!sip_options_aors) {
2960 return -1;
2961 }
2965 sip_options_endpoint_state_compositor_hash_fn, NULL,
2966 sip_options_endpoint_state_compositor_cmp_fn);
2969 return -1;
2970 }
2971
2972 mgmt_serializer = ast_sip_create_serializer("pjsip/options/manage");
2973 if (!mgmt_serializer) {
2975 return -1;
2976 }
2977
2978 /*
2979 * Set the water mark levels high because we can get a flood of
2980 * contact status updates from sip_options_synchronize() that
2981 * quickly clears on initial load or reload.
2982 */
2983 ast_taskprocessor_alert_set_levels(mgmt_serializer, -1,
2985
2986 /*
2987 * We make sure that the environment is completely setup before we allow
2988 * any other threads to post contact_status updates to the
2989 * management_serializer.
2990 */
2992 mgmt_serializer)) {
2993 /* Set management_serializer in case pushing the task actually failed. */
2994 management_serializer = mgmt_serializer;
2996 return -1;
2997 }
2998
3004
3005 return 0;
3006}
@ 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:2094
#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:192
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:481
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:64
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 2928 of file pjsip_options.c.

2929{
2931 return sip_options_contact_statuses ? 0 : -1;
2932}
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 2730 of file pjsip_options.c.

2731{
2732 struct ast_sip_contact_wrapper *wrapper = obj;
2733 struct ast_sip_contact *contact = wrapper->contact;
2734 struct ast_sip_ami *ami = arg;
2736 struct ast_str *buf;
2737 const struct ast_sip_endpoint *endpoint = ami->arg;
2738 char secs[AST_TIME_T_LEN];
2739
2740 buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
2741 if (!buf) {
2742 return -1;
2743 }
2744
2746
2747 ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
2748 ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
2749 ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
2750 ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
2751 ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
2752 if (!ast_strlen_zero(contact->via_addr)) {
2753 ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
2754 if (contact->via_port) {
2755 ast_str_append(&buf, 0, ":%d", contact->via_port);
2756 }
2757 ast_str_append(&buf, 0, "\r\n");
2758 }
2759 if (!ast_strlen_zero(contact->call_id)) {
2760 ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
2761 }
2762 ast_str_append(&buf, 0, "Status: %s\r\n",
2764 if (!status || status->status != AVAILABLE) {
2765 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2766 } else {
2767 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2768 }
2769 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
2770 endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
2771
2772 ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
2773 ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
2774 ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
2775 ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
2776 ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
2777 ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
2778 ast_str_append(&buf, 0, "Qualify2xxOnly: %d\r\n", contact->qualify_2xx_only);
2779
2780 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2781 ami->count++;
2782
2783 ast_free(buf);
2785 return 0;
2786}
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:1907
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:438
@ UNKNOWN
Definition: res_pjsip.h:440
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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
void * arg
Definition: res_pjsip.h:3208
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:519
struct ast_sip_contact * contact
Definition: res_pjsip.h:525
Contact associated with an address of record.
Definition: res_pjsip.h:390
double qualify_timeout
Definition: res_pjsip.h:420
const ast_string_field via_addr
Definition: res_pjsip.h:412
int qualify_2xx_only
Definition: res_pjsip.h:428
const ast_string_field call_id
Definition: res_pjsip.h:412
const ast_string_field outbound_proxy
Definition: res_pjsip.h:412
struct timeval expiration_time
Definition: res_pjsip.h:414
const ast_string_field path
Definition: res_pjsip.h:412
const ast_string_field endpoint_name
Definition: res_pjsip.h:412
int authenticate_qualify
Definition: res_pjsip.h:418
const ast_string_field user_agent
Definition: res_pjsip.h:412
unsigned int qualify_frequency
Definition: res_pjsip.h:416
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 341 of file pjsip_options.c.

342{
344 return short_status_map[status];
345}
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 2357 of file pjsip_options.c.

2358{
2359 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2360 const char *endpoint_name;
2361 char *aors;
2362 char *aor_name;
2363
2364 switch (cmd) {
2365 case CLI_INIT:
2366 e->command = "pjsip qualify";
2367 e->usage =
2368 "Usage: pjsip qualify <endpoint>\n"
2369 " Send a SIP OPTIONS request to all contacts on the endpoint.\n";
2370 return NULL;
2371 case CLI_GENERATE:
2372 return NULL;
2373 }
2374
2375 if (a->argc != 3) {
2376 return CLI_SHOWUSAGE;
2377 }
2378
2379 endpoint_name = a->argv[2];
2380
2381 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2382 endpoint_name);
2383 if (!endpoint) {
2384 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2385 return CLI_FAILURE;
2386 }
2387
2388 if (ast_strlen_zero(endpoint->aors)) {
2389 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2390 return CLI_FAILURE;
2391 }
2392
2393 aors = ast_strdupa(endpoint->aors);
2394 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2395 struct sip_options_aor *aor_options;
2396
2397 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2398 if (!aor_options) {
2399 continue;
2400 }
2401
2402 ast_cli(a->fd, "Qualifying AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2404 aor_options);
2405 ao2_ref(aor_options, -1);
2406 }
2407
2408 return CLI_SUCCESS;
2409}
#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 2643 of file pjsip_options.c.

2644{
2645 struct ast_sip_aor *aor;
2646 const char *aor_name;
2647
2648 switch (cmd) {
2649 case CLI_INIT:
2650 e->command = "pjsip reload qualify aor";
2651 e->usage =
2652 "Usage: pjsip reload qualify aor <id>\n"
2653 " Synchronize the PJSIP Aor qualify options.\n";
2654 return NULL;
2655 case CLI_GENERATE:
2656 return NULL;
2657 }
2658
2659 if (a->argc != 5) {
2660 return CLI_SHOWUSAGE;
2661 }
2662
2663 aor_name = a->argv[4];
2664
2665 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
2666 if (!aor) {
2667 ast_cli(a->fd, "Unable to retrieve aor '%s'\n", aor_name);
2668 return CLI_FAILURE;
2669 }
2670
2671 ast_cli(a->fd, "Synchronizing AOR '%s'\n", aor_name);
2674 ao2_ref(aor, -1);
2675
2676 return CLI_SUCCESS;
2677}
A SIP address of record.
Definition: res_pjsip.h:478

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

2590{
2591 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2592 const char *endpoint_name;
2593 char *aors;
2594 char *aor_name;
2595
2596 switch (cmd) {
2597 case CLI_INIT:
2598 e->command = "pjsip reload qualify endpoint";
2599 e->usage =
2600 "Usage: pjsip reload qualify endpoint <id>\n"
2601 " Synchronize the qualify options for all Aors on the PJSIP endpoint.\n";
2602 return NULL;
2603 case CLI_GENERATE:
2604 return NULL;
2605 }
2606
2607 if (a->argc != 5) {
2608 return CLI_SHOWUSAGE;
2609 }
2610
2611 endpoint_name = a->argv[4];
2612
2613 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2614 endpoint_name);
2615 if (!endpoint) {
2616 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2617 return CLI_FAILURE;
2618 }
2619
2620 if (ast_strlen_zero(endpoint->aors)) {
2621 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2622 return CLI_FAILURE;
2623 }
2624
2625 aors = ast_strdupa(endpoint->aors);
2626 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2627 struct ast_sip_aor *aor;
2628
2629 aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
2630 if (!aor) {
2631 continue;
2632 }
2633
2634 ast_cli(a->fd, "Synchronizing AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2637 ao2_ref(aor, -1);
2638 }
2639
2640 return CLI_SUCCESS;
2641}

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

2552{
2553 struct sip_options_aor *aor_options;
2554 const char *aor_name;
2555
2556 switch (cmd) {
2557 case CLI_INIT:
2558 e->command = "pjsip show qualify aor";
2559 e->usage =
2560 "Usage: pjsip show qualify aor <id>\n"
2561 " Show the PJSIP Aor current qualify options.\n";
2562 return NULL;
2563 case CLI_GENERATE:
2564 return NULL;
2565 }
2566
2567 if (a->argc != 5) {
2568 return CLI_SHOWUSAGE;
2569 }
2570
2571 aor_name = a->argv[4];
2572
2573 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2574 if (!aor_options) {
2575 ast_cli(a->fd, "Unable to retrieve aor '%s' qualify options\n", aor_name);
2576 return CLI_FAILURE;
2577 }
2578
2579 ast_cli(a->fd, " * AOR '%s'\n", aor_name);
2580 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2581 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2582 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2583 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2584 ao2_ref(aor_options, -1);
2585
2586 return CLI_SUCCESS;
2587}
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 2494 of file pjsip_options.c.

2495{
2496 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2497 const char *endpoint_name;
2498 char *aors;
2499 char *aor_name;
2500
2501 switch (cmd) {
2502 case CLI_INIT:
2503 e->command = "pjsip show qualify endpoint";
2504 e->usage =
2505 "Usage: pjsip show qualify endpoint <id>\n"
2506 " Show the current qualify options for all Aors on the PJSIP endpoint.\n";
2507 return NULL;
2508 case CLI_GENERATE:
2509 return NULL;
2510 }
2511
2512 if (a->argc != 5) {
2513 return CLI_SHOWUSAGE;
2514 }
2515
2516 endpoint_name = a->argv[4];
2517
2518 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2519 endpoint_name);
2520 if (!endpoint) {
2521 ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
2522 return CLI_FAILURE;
2523 }
2524
2525 if (ast_strlen_zero(endpoint->aors)) {
2526 ast_cli(a->fd, "No AORs configured for endpoint '%s'\n", endpoint_name);
2527 return CLI_FAILURE;
2528 }
2529
2530 aors = ast_strdupa(endpoint->aors);
2531 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2532 struct sip_options_aor *aor_options;
2533
2534 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2535 if (!aor_options) {
2536 continue;
2537 }
2538
2539 ast_cli(a->fd, " * AOR '%s' on endpoint '%s'\n", aor_name, endpoint_name);
2540 ast_cli(a->fd, " Qualify frequency : %d sec\n", aor_options->qualify_frequency);
2541 ast_cli(a->fd, " Qualify timeout : %d ms\n", (int)(aor_options->qualify_timeout / 1000));
2542 ast_cli(a->fd, " Qualify 2xx only : %s\n", aor_options->qualify_2xx_only ? "yes" : "no");
2543 ast_cli(a->fd, " Authenticate qualify : %s\n", aor_options->authenticate_qualify?"yes":"no");
2544 ast_cli(a->fd, "\n");
2545 ao2_ref(aor_options, -1);
2546 }
2547
2548 return CLI_SUCCESS;
2549}

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

2199{
2202}
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 2344 of file pjsip_options.c.

2345{
2348}
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 2236 of file pjsip_options.c.

2237{
2238 const struct ast_sip_contact *contact = obj;
2239 struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY);
2240
2241 if (has_qualify_changed(contact, aor_options)) {
2242 struct ast_sip_aor *aor;
2243
2245 contact->aor);
2246 if (aor) {
2247 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2248 contact->aor);
2251 ao2_ref(aor, -1);
2252 }
2253 }
2254
2257
2258 task_data = ast_malloc(sizeof(*task_data));
2259 if (!task_data) {
2260 ao2_ref(aor_options, -1);
2261 return;
2262 }
2263
2264 task_data->contact = (struct ast_sip_contact *) contact;
2265 /* task_data takes ownership of aor_options and will take care of releasing the ref */
2266 task_data->aor_options = aor_options;
2267
2268 ao2_ref(task_data->contact, +1);
2269 if (ast_sip_push_task(task_data->aor_options->serializer,
2271 ao2_ref(task_data->contact, -1);
2272 ao2_ref(task_data->aor_options, -1);
2274 }
2275 } else {
2276 ao2_cleanup(aor_options);
2277 }
2278}
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
#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 438 of file pjsip_options.c.

439{
440 struct ast_sip_contact_status *contact_status = obj;
441 struct sip_options_aor *aor_options;
442
443 aor_options = ao2_find(sip_options_aors, contact_status->aor, OBJ_SEARCH_KEY);
444 if (aor_options) {
445 sip_options_publish_contact_state(aor_options, contact_status);
446 ao2_ref(aor_options, -1);
447 }
448 ao2_ref(contact_status, -1);
449
450 return 0;
451}
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 1893 of file pjsip_options.c.

1894{
1897}
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 1925 of file pjsip_options.c.

1926{
1929}
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 2795 of file pjsip_options.c.

2797{
2798 ami->arg = (void *)endpoint;
2800}
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:1080

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

2428{
2429 struct ast_sip_contact *contact = obj;
2430 struct ast_sip_ami *ami = arg;
2431 struct ast_str *buf;
2433
2434 buf = ast_sip_create_ami_event("ContactList", ami);
2435 if (!buf) {
2436 return CMP_STOP;
2437 }
2438
2439 if (sip_contact_to_ami(contact, &buf)) {
2440 ast_free(buf);
2441 return CMP_STOP;
2442 }
2443
2444 /* Add extra info */
2446 ast_str_append(&buf, 0, "Status: %s\r\n",
2448 if (!status || status->status != AVAILABLE) {
2449 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2450 } else {
2451 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2452 }
2454
2455 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2456
2457 ami->count++;
2458
2459 ast_free(buf);
2460
2461 return 0;
2462}
@ 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 2788 of file pjsip_options.c.

2789{
2790 struct ast_sip_aor *aor = obj;
2791
2793}
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 2411 of file pjsip_options.c.

2412{
2413 struct ao2_container *contacts;
2414
2417
2418 return contacts;
2419}
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1897

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

2082{
2083 if (!contact) {
2084 return 0;
2085 }
2086
2087 if (!aor_options) {
2088 if (contact->qualify_frequency) {
2089 return 1;
2090 }
2091 } else if (contact->qualify_frequency != aor_options->qualify_frequency
2092 || contact->authenticate_qualify != aor_options->authenticate_qualify
2093 || contact->qualify_2xx_only != aor_options->qualify_2xx_only
2094 || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
2095 return 1;
2096 }
2097
2098 return 0;
2099}

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

270{
271 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
272 pjsip_uri *ruri;
273 char exten[AST_MAX_EXTENSION];
274
275 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
276 return PJ_FALSE;
277 }
278
279 if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
280 return PJ_FALSE;
281 }
282
283 ruri = rdata->msg_info.msg->line.req.uri;
284 if (!ast_sip_is_allowed_uri(ruri)) {
285 send_options_response(rdata, 416);
286 return PJ_TRUE;
287 }
288
289 ast_copy_pj_str(exten, ast_sip_pjsip_uri_get_username(ruri), sizeof(exten));
290
291 /*
292 * We may want to match in the dialplan without any user
293 * options getting in the way.
294 */
296
297 if (ast_shutting_down()) {
298 /*
299 * Not taking any new calls at this time.
300 * Likely a server availability OPTIONS poll.
301 */
302 send_options_response(rdata, 503);
303 } else if (!ast_strlen_zero(exten)
304 && !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
305 send_options_response(rdata, 404);
306 } else {
307 send_options_response(rdata, 200);
308 }
309 return PJ_TRUE;
310}
int ast_shutting_down(void)
Definition: asterisk.c:1886
#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:4190
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:3477
int ast_sip_is_allowed_uri(pjsip_uri *uri)
Check whether a pjsip_uri is allowed or not.
Definition: res_pjsip.c:3472
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3504
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:2201

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 when we get a result from a SIP OPTIONS request (a response or a timeout)

Definition at line 790 of file pjsip_options.c.

791{
792 struct sip_options_contact_callback_data *contact_callback_data = token;
794
795 switch(e->body.tsx_state.type) {
796 default:
797 ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type);
798 /* Fall through */
799 case PJSIP_EVENT_TRANSPORT_ERROR:
800 case PJSIP_EVENT_TIMER:
802 break;
803 case PJSIP_EVENT_RX_MSG:
804 if (contact_callback_data->aor_options->qualify_2xx_only &&
805 (e->body.tsx_state.tsx->status_code < 200 || e->body.tsx_state.tsx->status_code >= 300)) {
807 } else {
809 }
810 break;
811 }
812
813 /* Update the callback data with the new status, this will get handled in the AOR serializer */
814 contact_callback_data->status = status;
815
816 if (ast_sip_push_task(contact_callback_data->aor_options->serializer,
817 sip_options_contact_status_notify_task, contact_callback_data)) {
818 ast_log(LOG_WARNING, "Unable to queue contact status update for '%s' on AOR '%s', state will be incorrect\n",
819 ast_sorcery_object_get_id(contact_callback_data->contact),
820 contact_callback_data->aor_options->name);
821 ao2_ref(contact_callback_data, -1);
822 }
823
824 /* The task inherited our reference so we don't unreference here */
825}
#define LOG_ERROR
static int sip_options_contact_status_notify_task(void *obj)
Task to notify an AOR of a contact status change.
ast_sip_contact_status_type
Status type for a contact.
Definition: res_pjsip.h:434
@ UNAVAILABLE
Definition: res_pjsip.h:436
char name[0]
The name of the AOR.
Structure used to contain information for an OPTIONS callback.
struct ast_sip_contact * contact
The contact we qualified.
enum ast_sip_contact_status_type status
The new status of the contact.
struct sip_options_aor * aor_options
The AOR options.

References ao2_ref, sip_options_contact_callback_data::aor_options, ast_log, ast_sip_push_task(), ast_sorcery_object_get_id(), AVAILABLE, sip_options_contact_callback_data::contact, LOG_ERROR, LOG_WARNING, sip_options_aor::name, sip_options_aor::qualify_2xx_only, sip_options_aor::serializer, sip_options_contact_status_notify_task(), status, sip_options_contact_callback_data::status, and UNAVAILABLE.

Referenced by sip_options_qualify_contact().

◆ send_options_response()

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

Definition at line 217 of file pjsip_options.c.

218{
219 pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
220 pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
221 pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
222 pjsip_tx_data *tdata;
223 const pjsip_hdr *hdr;
224 pj_status_t status;
225
226 /* Make the response object */
227 status = ast_sip_create_response(rdata, code, NULL, &tdata);
228 if (status != PJ_SUCCESS) {
229 ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
230 return status;
231 }
232
233 /* Add appropriate headers */
234 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, 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_ALLOW, NULL))) {
238 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
239 }
240 if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
241 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
242 }
243
244 /*
245 * XXX TODO: pjsip doesn't care a lot about either of these headers -
246 * while it provides specific methods to create them, they are defined
247 * to be the standard string header creation. Hard coded here.
248 */
249 ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
250 ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);
251
252 if (dlg && trans) {
253 status = pjsip_dlg_send_response(dlg, trans, tdata);
254 } else {
255 struct ast_sip_endpoint *endpoint;
256
257 endpoint = ast_pjsip_rdata_get_endpoint(rdata);
258 status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
259 ao2_cleanup(endpoint);
260 }
261
262 if (status != PJ_SUCCESS) {
263 ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
264 }
265
266 return status;
267}
#define DEFAULT_ENCODING
Definition: pjsip_options.c:97
#define DEFAULT_LANGUAGE
Definition: pjsip_options.c:96
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:2468
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:2008
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:2424

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

358{
359 struct ast_sip_contact_status *contact_status;
360 size_t size = sizeof(*contact_status) + strlen(name) + 1;
361
362 contact_status = ao2_alloc_options(size, sip_contact_status_dtor,
364 if (!contact_status) {
365 return NULL;
366 }
367 if (ast_string_field_init(contact_status, 256)) {
368 ao2_ref(contact_status, -1);
369 return NULL;
370 }
371 AST_VECTOR_INIT(&contact_status->security_mechanisms, 0);
372 strcpy(contact_status->name, name); /* SAFE */
373 return contact_status;
374}
@ 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.
Definition: stringfields.h:359
struct ast_sip_security_mechanism_vector security_mechanisms
Definition: res_pjsip.h:466
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

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

377{
378 struct ast_sip_contact_status *dst;
379
380 dst = sip_contact_status_alloc(src->name);
381 if (!dst) {
382 return NULL;
383 }
384
385 if (ast_string_fields_copy(dst, src)) {
386 ao2_ref(dst, -1);
387 return NULL;
388 }
389 dst->rtt = src->rtt;
390 dst->status = src->status;
391 dst->last_status = src->last_status;
392
394 return dst;
395}
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.
Definition: stringfields.h:630

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

349{
350 struct ast_sip_contact_status *contact_status = obj;
351
353
354 ast_string_field_free_memory(contact_status);
355}
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
Definition: stringfields.h:374

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

2423{
2424 return ast_sip_sorcery_object_to_ami(contact, buf);
2425}
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 972 of file pjsip_options.c.

973{
974 struct sip_options_aor *aor_options;
975 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
976
977 aor_options = ao2_alloc_options(sizeof(*aor_options) + strlen(ast_sorcery_object_get_id(aor)) + 1,
979 if (!aor_options) {
980 return NULL;
981 }
982
983 strcpy(aor_options->name, ast_sorcery_object_get_id(aor)); /* SAFE */
984
985 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/options/%s",
987 aor_options->serializer = ast_sip_create_serializer_group(tps_name,
989 if (!aor_options->serializer) {
990 ao2_ref(aor_options, -1);
991 return NULL;
992 }
993
995 ao2_ref(aor_options, -1);
996 return NULL;
997 }
998
1002 if (!aor_options->contacts) {
1003 ao2_ref(aor_options, -1);
1004 return NULL;
1005 }
1006
1010 if (!aor_options->dynamic_contacts) {
1011 ao2_ref(aor_options, -1);
1012 return NULL;
1013 }
1014
1015 return aor_options;
1016}
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188
struct ast_taskprocessor * ast_sip_create_serializer_group(const char *name, struct ast_serializer_shutdown_group *shutdown_group)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:2089
#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:2464
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition: sorcery.c:2440
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
Definition: sorcery.c:2475
struct sip_options_aor::@457 compositors
The endpoint state compositors we are feeding, a reference is held to each.
struct ao2_container * contacts
All contacts associated with this AOR.
struct ao2_container * dynamic_contacts
Only dynamic contacts associated with this AOR.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:61

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_container_alloc_hash, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, ao2_ref, ast_sip_create_serializer_group(), ast_sorcery_object_get_id(), ast_sorcery_object_id_compare(), ast_sorcery_object_id_hash(), ast_sorcery_object_id_sort(), ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, 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, shutdown_group, 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 950 of file pjsip_options.c.

951{
952 struct sip_options_aor *aor_options = obj;
953
954 /*
955 * Any contacts are unreachable since the AOR is being destroyed
956 * so remove their contact status
957 */
958 if (aor_options->contacts) {
960 sip_options_remove_contact, aor_options);
961 ao2_ref(aor_options->contacts, -1);
962 }
963 ao2_cleanup(aor_options->dynamic_contacts);
964
966
967 ast_assert(AST_VECTOR_SIZE(&aor_options->compositors) == 0);
968 AST_VECTOR_FREE(&aor_options->compositors);
969}
@ 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:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174

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

2036{
2037 struct ast_sip_aor *aor = obj;
2038 struct sip_options_aor *aor_options;
2039
2042 if (!aor_options) {
2043 return 0;
2044 }
2045
2046 ast_debug(3, "AOR '%s' has been deleted, removing it\n", aor_options->name);
2047
2049 aor_options);
2050 ao2_ref(aor_options, -1);
2051
2052 return 0;
2053}
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 1970 of file pjsip_options.c.

1971{
1972 struct ast_sip_aor *aor = obj;
1973 struct sip_options_aor *aor_options;
1974
1977 if (!aor_options) {
1978 struct ao2_container *endpoints;
1979
1980 aor_options = sip_options_aor_alloc(aor);
1981 if (!aor_options) {
1982 return 0;
1983 }
1984
1985 /*
1986 * This is a newly added AOR and we need to establish any
1987 * endpoint state compositors that may reference only the
1988 * AOR. If these need to be updated later then they'll
1989 * be done by modifying the endpoint or issuing a reload.
1990 */
1991 sip_options_apply_aor_configuration(aor_options, aor, 1);
1992 ao2_link(sip_options_aors, aor_options);
1993
1994 /*
1995 * Using LIKE doesn't seem to work very well with non-realtime so we
1996 * fetch everything right now and do a filter on our side.
1997 */
2000 if (endpoints) {
2002 ao2_ref(endpoints, -1);
2003 }
2004 } else {
2006 .aor_options = aor_options,
2007 .aor = aor,
2008 };
2009
2010 /*
2011 * If this AOR was modified we have to do our work in its serializer
2012 * instead of this thread to ensure that things aren't modified by
2013 * multiple threads.
2014 */
2017 }
2018
2019 ao2_ref(aor_options, -1);
2020
2021 return 0;
2022}
#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 1698 of file pjsip_options.c.

1699{
1700 struct sip_options_aor *aor_options = obj;
1701
1703
1704 if (aor_options->sched_task) {
1706 ao2_ref(aor_options->sched_task, -1);
1707 aor_options->sched_task = NULL;
1708 }
1709
1710 return 0;
1711}
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:443
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 1249 of file pjsip_options.c.

1251{
1252 struct ao2_container *existing_contacts;
1253 struct ast_sip_contact *contact;
1254 struct ao2_iterator iter;
1255
1256 ast_debug(3, "Configuring AOR '%s' with current state of configuration and world\n",
1257 aor_options->name);
1258
1259 /*
1260 * Permanent contacts, since we receive no notification that they
1261 * are gone, follow the same approach as AORs. We create a copy
1262 * of the existing container and any reused contacts are removed
1263 * from it. Any contacts remaining in the container after
1264 * processing no longer exist so we need to remove their state.
1265 */
1266 existing_contacts = ao2_container_clone(aor_options->contacts, 0);
1267 if (!existing_contacts) {
1268 ast_log(LOG_WARNING, "Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1269 aor_options->name);
1270 return;
1271 }
1272
1274 NULL, NULL);
1275
1276 /* Process permanent contacts */
1277 if (aor->permanent_contacts) {
1278 iter = ao2_iterator_init(aor->permanent_contacts, 0);
1279 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1280 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1282 ao2_link(aor_options->contacts, contact);
1283 }
1284 ao2_iterator_destroy(&iter);
1285 }
1286
1287 /*
1288 * If this is newly added we need to see if there are any
1289 * existing dynamic contacts to add. Ones that are added
1290 * after creation will occur as a result of the contact
1291 * observer creation callback.
1292 */
1293 if (is_new) {
1294 size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
1295 char prefix[prefix_len + 1];
1296 struct ao2_container *contacts;
1297
1298 sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
1300 prefix, prefix_len);
1301 if (contacts) {
1302 ao2_container_dup(aor_options->dynamic_contacts, contacts, 0);
1303 ao2_ref(contacts, -1);
1304 }
1305 }
1306
1307 /* Process dynamic contacts */
1308 iter = ao2_iterator_init(aor_options->dynamic_contacts, 0);
1309 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1310 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1312 ao2_link(aor_options->contacts, contact);
1313 }
1314 ao2_iterator_destroy(&iter);
1315
1316 /* Any contacts left no longer exist, so raise events and make them disappear */
1317 ao2_callback(existing_contacts, OBJ_NODATA | OBJ_UNLINK,
1318 sip_options_remove_contact, aor_options);
1319 ao2_ref(existing_contacts, -1);
1320
1321 /*
1322 * Update the available count if we transition between qualified
1323 * and unqualified. In the qualified case we need to start with
1324 * 0 available as the qualify process will take care of it. In
1325 * the unqualified case it is based on the number of contacts
1326 * present.
1327 */
1328 if (!aor->qualify_frequency) {
1329 ao2_callback(aor_options->contacts, OBJ_NODATA,
1331 aor_options->available = ao2_container_count(aor_options->contacts);
1332 ast_debug(3, "AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1333 aor_options->name, aor_options->available);
1334 } else if (!aor_options->qualify_frequency) {
1335 ao2_callback(aor_options->contacts, OBJ_NODATA,
1337 aor_options->available = 0;
1338 ast_debug(3, "AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1339 aor_options->name);
1340 } else {
1341 /*
1342 * Count the number of AVAILABLE qualified contacts to ensure
1343 * the count is in sync with reality.
1344 */
1345 aor_options->available = 0;
1346 ao2_callback(aor_options->contacts, OBJ_NODATA,
1348 }
1349
1350 aor_options->authenticate_qualify = aor->authenticate_qualify;
1351 aor_options->qualify_2xx_only = aor->qualify_2xx_only;
1352 aor_options->qualify_timeout = aor->qualify_timeout;
1353
1354 /*
1355 * If we need to stop or start the scheduled callback then do so.
1356 * This occurs due to the following:
1357 * 1. The qualify frequency has changed
1358 * 2. Contacts were added when previously there were none
1359 * 3. There are no contacts but previously there were some
1360 */
1361 if (aor_options->qualify_frequency != aor->qualify_frequency
1362 || (!aor_options->sched_task && ao2_container_count(aor_options->contacts))
1363 || (aor_options->sched_task && !ao2_container_count(aor_options->contacts))) {
1364 if (aor_options->sched_task) {
1366 ao2_ref(aor_options->sched_task, -1);
1367 aor_options->sched_task = NULL;
1368 }
1369
1370 /* If there is still a qualify frequency then schedule this */
1371 aor_options->qualify_frequency = aor->qualify_frequency;
1372 if (aor_options->qualify_frequency
1373 && ao2_container_count(aor_options->contacts)) {
1374 aor_options->sched_task = ast_sip_schedule_task(aor_options->serializer,
1378 if (!aor_options->sched_task) {
1379 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
1380 aor_options->name);
1381 }
1382 }
1383 }
1384
1385 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1386 aor_options->available);
1387}
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 thread pool.
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition: res_pjsip.h:2217
@ AST_SIP_SCHED_TASK_VARIABLE
Definition: res_pjsip.h:2200
static char prefix[MAX_PREFIX]
Definition: http.c:144
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:1989
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:506
int qualify_2xx_only
Definition: res_pjsip.h:512
struct ao2_container * permanent_contacts
Definition: res_pjsip.h:502
int authenticate_qualify
Definition: res_pjsip.h:496
unsigned int qualify_frequency
Definition: res_pjsip.h:494
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_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 2810 of file pjsip_options.c.

2811{
2812 struct sip_options_aor *aor_options = obj;
2813
2814 ast_debug(2, "Cleaning up AOR '%s' for shutdown\n", aor_options->name);
2815
2816 aor_options->qualify_frequency = 0;
2817 if (aor_options->sched_task) {
2819 ao2_ref(aor_options->sched_task, -1);
2820 aor_options->sched_task = NULL;
2821 }
2823
2824 return 0;
2825}
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625

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

2832{
2833 struct ao2_iterator it_aor;
2834 struct sip_options_aor *aor_options;
2835
2836 if (!sip_options_aors) {
2837 /* Nothing to do */
2838 return 0;
2839 }
2840
2842 for (; (aor_options = ao2_iterator_next(&it_aor)); ao2_ref(aor_options, -1)) {
2844 sip_options_cleanup_aor_task, aor_options);
2845 }
2846 ao2_iterator_destroy(&it_aor);
2847
2848 return 0;
2849}
@ 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 2165 of file pjsip_options.c.

2166{
2168
2169 task_data.contact = obj;
2170 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2172
2173 if (has_qualify_changed(task_data.contact, task_data.aor_options)) {
2174 struct ast_sip_aor *aor;
2175
2177 task_data.contact->aor);
2178 if (aor) {
2179 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2180 task_data.contact->aor);
2182 ao2_ref(aor, -1);
2183 }
2184 }
2185
2186 if (!task_data.aor_options) {
2187 return 0;
2188 }
2189
2190 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2192 ao2_ref(task_data.aor_options, -1);
2193
2194 return 0;
2195}
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 2105 of file pjsip_options.c.

2106{
2108 struct ast_sip_contact_status *contact_status;
2109
2110 ao2_link(task_data->aor_options->dynamic_contacts, task_data->contact);
2111 ao2_link(task_data->aor_options->contacts, task_data->contact);
2112
2113 contact_status = ast_res_pjsip_find_or_create_contact_status(task_data->contact);
2114 ao2_cleanup(contact_status);
2115
2116 if (task_data->aor_options->qualify_frequency) {
2117 /* There will always be a contact here, and we need to immediately schedule
2118 * a qualify so that contacts are not waiting for the qualify_frequency
2119 * timer duration before qualifying.
2120 */
2121 ast_debug(3, "Starting scheduled callback on AOR '%s' for qualifying as there is now a contact on it\n",
2122 task_data->aor_options->name);
2123 /*
2124 * We immediately schedule the initial qualify so that we get
2125 * reachable/unreachable as soon as possible. Realistically
2126 * since they pretty much just registered they should be
2127 * reachable.
2128 */
2129 if (task_data->aor_options->sched_task) {
2130 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2131 ao2_ref(task_data->aor_options->sched_task, -1);
2132 task_data->aor_options->sched_task = NULL;
2133 }
2134 task_data->aor_options->sched_task = ast_sip_schedule_task(
2135 task_data->aor_options->serializer, 1, sip_options_qualify_aor,
2136 ast_taskprocessor_name(task_data->aor_options->serializer),
2137 task_data->aor_options,
2139 if (!task_data->aor_options->sched_task) {
2140 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
2141 task_data->aor_options->name);
2142 }
2143 } else {
2144 /*
2145 * If this was the first contact added to a non-qualified AOR then
2146 * it should become available.
2147 */
2148 task_data->aor_options->available =
2149 ao2_container_count(task_data->aor_options->contacts);
2150 if (task_data->aor_options->available == 1) {
2151 ast_debug(3, "An unqualified contact has been added to AOR '%s' so it is now available\n",
2152 task_data->aor_options->name);
2154 AVAILABLE);
2155 }
2156 }
2157
2158 return 0;
2159}
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 
)
static

Contact callback data allocator.

Definition at line 837 of file pjsip_options.c.

839{
840 struct sip_options_contact_callback_data *contact_callback_data;
841
842 contact_callback_data = ao2_alloc_options(sizeof(*contact_callback_data),
844 if (!contact_callback_data) {
845 return NULL;
846 }
847
848 contact_callback_data->contact = ao2_bump(contact);
849 contact_callback_data->aor_options = ao2_bump(aor_options);
850 contact_callback_data->rtt_start = ast_tvnow();
851
852 return contact_callback_data;
853}
#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.
struct timeval rtt_start
The time at which this OPTIONS attempt was started.
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, sip_options_contact_callback_data::aor_options, ast_tvnow(), sip_options_contact_callback_data::contact, NULL, sip_options_contact_callback_data::rtt_start, and sip_options_contact_callback_data_dtor().

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

829{
830 struct sip_options_contact_callback_data *contact_callback_data = obj;
831
832 ao2_cleanup(contact_callback_data->contact);
833 ao2_cleanup(contact_callback_data->aor_options);
834}

References ao2_cleanup, sip_options_contact_callback_data::aor_options, and sip_options_contact_callback_data::contact.

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

2325{
2327
2328 task_data.contact = obj;
2329 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2331 if (!task_data.aor_options) {
2332 /* For contacts that are deleted we don't really care if there is no AOR locally */
2333 return 0;
2334 }
2335
2336 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2338 ao2_ref(task_data.aor_options, -1);
2339
2340 return 0;
2341}
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 2284 of file pjsip_options.c.

2285{
2287
2288 ao2_find(task_data->aor_options->dynamic_contacts, task_data->contact,
2290 ao2_find(task_data->aor_options->contacts, task_data->contact,
2292
2294
2295 if (task_data->aor_options->qualify_frequency) {
2296 /* If this is the last contact then we need to stop the scheduled callback */
2297 if (!ao2_container_count(task_data->aor_options->contacts)) {
2298 ast_debug(3, "Terminating scheduled callback on AOR '%s' as there are no contacts to qualify\n",
2299 task_data->aor_options->name);
2300 if (task_data->aor_options->sched_task) {
2301 ast_sip_sched_task_cancel(task_data->aor_options->sched_task);
2302 ao2_ref(task_data->aor_options->sched_task, -1);
2303 task_data->aor_options->sched_task = NULL;
2304 }
2305 }
2306 } else {
2307 task_data->aor_options->available =
2308 ao2_container_count(task_data->aor_options->contacts);
2309 if (!task_data->aor_options->available) {
2310 ast_debug(3, "An unqualified contact has been removed from AOR '%s' leaving no remaining contacts\n",
2311 task_data->aor_options->name);
2313 UNAVAILABLE);
2314 }
2315 }
2316
2317 return 0;
2318}
@ 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 1217 of file pjsip_options.c.

1218{
1219 struct ast_sip_contact *contact = obj;
1220 unsigned int *available = arg;
1221 struct ast_sip_contact_status *contact_status;
1222
1223 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1224 if (!contact_status) {
1225 return 0;
1226 }
1227
1228 /* Count qualified available contacts. */
1229 switch (contact_status->status) {
1230 case AVAILABLE:
1231 ++*available;
1232 break;
1233 case UNAVAILABLE:
1234 case UNKNOWN:
1235 case CREATED:
1236 case REMOVED:
1237 break;
1238 }
1239
1240 ao2_ref(contact_status, -1);
1241
1242 return 0;
1243}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13574

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

666{
667 struct sip_options_contact_callback_data *contact_callback_data = obj;
668 struct ast_sip_contact *contact;
669 struct ast_sip_contact_status *cs_old;
670 struct ast_sip_contact_status *cs_new;
671
672 /*
673 * Determine if this is a late arriving notification, as it is
674 * possible that we get a callback from PJSIP giving us contact
675 * status but in the mean time said contact has been removed
676 * from the controlling AOR.
677 */
678
679 if (!contact_callback_data->aor_options->qualify_frequency) {
680 /* Contact qualify response is late */
681 ao2_ref(contact_callback_data, -1);
682 return 0;
683 }
684
685 contact = ao2_find(contact_callback_data->aor_options->contacts,
686 contact_callback_data->contact, OBJ_SEARCH_OBJECT);
687 if (!contact) {
688 /* Contact qualify response is late */
689 ao2_ref(contact_callback_data, -1);
690 return 0;
691 }
692 ao2_ref(contact, -1);
693
695 ast_sorcery_object_get_id(contact_callback_data->contact), OBJ_SEARCH_KEY);
696 if (!cs_old) {
697 /* Contact qualify response is late */
698 ao2_ref(contact_callback_data, -1);
699 return 0;
700 }
701
702 /* Update the contact specific status information */
703 cs_new = sip_contact_status_copy(cs_old);
704 ao2_ref(cs_old, -1);
705 if (!cs_new) {
706 ao2_ref(contact_callback_data, -1);
707 return 0;
708 }
709 cs_new->last_status = cs_new->status;
710 cs_new->status = contact_callback_data->status;
711 cs_new->rtt =
712 cs_new->status == AVAILABLE
713 ? ast_tvdiff_us(ast_tvnow(), contact_callback_data->rtt_start)
714 : 0;
716
717 /*
718 * If the status has changed then notify the endpoint state compositors
719 * and publish our events.
720 */
721 if (cs_new->last_status != cs_new->status) {
722 if (cs_new->status == AVAILABLE) {
723 /* If this is the first available contact then the AOR has become available */
724 ++contact_callback_data->aor_options->available;
725 if (contact_callback_data->aor_options->available == 1) {
727 contact_callback_data->aor_options, AVAILABLE);
728 }
729 } else if (cs_new->last_status == AVAILABLE) {
730 ast_assert(cs_new->status == UNAVAILABLE);
731
732 /* If there are no more available contacts then this AOR is unavailable */
733 --contact_callback_data->aor_options->available;
734 if (!contact_callback_data->aor_options->available) {
736 contact_callback_data->aor_options, UNAVAILABLE);
737 }
738 }
739
740 ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n",
741 cs_new->aor,
742 cs_new->uri,
744 cs_new->rtt / 1000.0);
745
746 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
748 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
749 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
750
752
753 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
754 "Contact: %s\r\n"
755 "Status: %s",
756 cs_new->name,
758 } else {
759 ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
760 cs_new->aor,
761 cs_new->uri,
763 cs_new->rtt / 1000.0);
764 }
765
766 ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
767 cs_new->status != AVAILABLE ? -1 : cs_new->rtt / 1000,
768 1.0,
769 cs_new->name);
770
771 ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
772 "Contact: %s\r\n"
773 "Status: %s\r\n"
774 "RTT: %" PRId64,
775 cs_new->name,
777 cs_new->rtt);
778
779 ast_debug(3, "AOR '%s' now has %d available contacts\n",
780 contact_callback_data->aor_options->name,
781 contact_callback_data->aor_options->available);
782
783 ao2_ref(cs_new, -1);
784 ao2_ref(contact_callback_data, -1);
785
786 return 0;
787}
#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_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
#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 qualify_contact_cb().

◆ sip_options_contact_status_update()

static void sip_options_contact_status_update ( struct ast_sip_contact_status contact_status)
static

Definition at line 453 of file pjsip_options.c.

454{
455 struct ast_taskprocessor *mgmt_serializer = management_serializer;
456
457 if (mgmt_serializer) {
458 ao2_ref(contact_status, +1);
460 contact_status)) {
461 ao2_ref(contact_status, -1);
462 }
463 }
464}
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 407 of file pjsip_options.c.

408{
409 /*
410 * Replace duplicate objects so we can update the immutable
411 * contact status objects by simply linking in a new object.
412 */
415 ast_sip_contact_status_hash_fn, ast_sip_contact_status_sort_fn,
416 ast_sip_contact_status_cmp_fn);
417}
@ 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 2208 of file pjsip_options.c.

2209{
2211 struct ast_sip_contact_status *contact_status;
2212
2213 contact_status = ast_sip_get_contact_status(task_data->contact);
2214 if (contact_status) {
2215 switch (contact_status->status) {
2216 case CREATED:
2217 case UNAVAILABLE:
2218 case AVAILABLE:
2219 case UNKNOWN:
2220 /* Refresh the ContactStatus AMI events. */
2221 sip_options_contact_status_update(contact_status);
2222 break;
2223 case REMOVED:
2224 break;
2225 }
2226 ao2_ref(contact_status, -1);
2227 }
2228
2229 ao2_ref(task_data->contact, -1);
2230 ao2_ref(task_data->aor_options, -1);
2232 return 0;
2233}

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

1104{
1105 int initial_interval;
1106 int max_time = ast_sip_get_max_initial_qualify_time();
1107
1108 if (max_time && max_time < qualify_frequency) {
1109 initial_interval = max_time;
1110 } else {
1111 initial_interval = qualify_frequency;
1112 }
1113
1114 initial_interval = (int)((initial_interval * 1000) * ast_random_double());
1115 return 0 < initial_interval ? initial_interval : 1;
1116}
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:624

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

1538{
1540
1541 ast_debug(3, "Adding endpoint compositor '%s' to AOR '%s'\n",
1542 task_data->endpoint_state_compositor->name, task_data->aor_options->name);
1543
1544 ao2_ref(task_data->endpoint_state_compositor, +1);
1545 if (AST_VECTOR_APPEND(&task_data->aor_options->compositors,
1546 task_data->endpoint_state_compositor)) {
1547 /* Failed to add so no need to update the endpoint status. Nothing changed. */
1548 ao2_ref(task_data->endpoint_state_compositor, -1);
1549 return 0;
1550 }
1551
1552 ao2_lock(task_data->endpoint_state_compositor);
1554 task_data->aor_options->name,
1555 task_data->aor_options->available ? AVAILABLE : UNAVAILABLE);
1556 ao2_unlock(task_data->endpoint_state_compositor);
1557
1558 return 0;
1559}
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:256

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

1566{
1568 int i;
1569
1570 ast_debug(3, "Removing endpoint compositor '%s' from AOR '%s'\n",
1571 task_data->endpoint_state_compositor->name,
1572 task_data->aor_options->name);
1573
1574 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1575 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1576
1577 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1578 if (endpoint_state_compositor != task_data->endpoint_state_compositor) {
1579 continue;
1580 }
1581
1582 AST_VECTOR_REMOVE(&task_data->aor_options->compositors, i, 0);
1583 ao2_ref(endpoint_state_compositor, -1);
1584 break;
1585 }
1586
1587 return 0;
1588}
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:412
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

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

1874{
1875 struct ast_sip_endpoint *endpoint = obj;
1876 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1877
1878 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1880 if (!endpoint_state_compositor) {
1881 return 0;
1882 }
1883
1884 ast_debug(3, "Endpoint '%s' has been deleted, removing endpoint state compositor from AORs\n",
1885 ast_sorcery_object_get_id(endpoint));
1886 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1887 ao2_ref(endpoint_state_compositor, -1);
1888
1889 return 0;
1890}
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 1903 of file pjsip_options.c.

1904{
1905 struct ast_sip_endpoint *endpoint = obj;
1906 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1907
1908 ast_debug(3, "Endpoint '%s' has been created or modified, updating state\n",
1909 ast_sorcery_object_get_id(endpoint));
1910
1911 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1913 if (endpoint_state_compositor) {
1914 /* Unlink the AORs currently feeding the endpoint. */
1915 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1916 ao2_ref(endpoint_state_compositor, -1);
1917 }
1918
1919 /* Connect the AORs that now feed the endpoint. */
1921 return 0;
1922}

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

1469{
1470 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1471
1472 ao2_cleanup(endpoint_state_compositor->aor_statuses);
1473}
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 1482 of file pjsip_options.c.

1483{
1484 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1485
1487 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1489 if (endpoint_state_compositor) {
1491 return endpoint_state_compositor;
1492 }
1493
1494 endpoint_state_compositor = ao2_alloc(sizeof(*endpoint_state_compositor)
1495 + strlen(ast_sorcery_object_get_id(endpoint)) + 1,
1497 if (!endpoint_state_compositor) {
1499 return NULL;
1500 }
1501
1502 /*
1503 * NOTE: The endpoint_state_compositor->aor_statuses container is
1504 * externally protected by the endpoint_state_compositor lock.
1505 */
1506 endpoint_state_compositor->aor_statuses = ao2_container_alloc_hash(
1508 sip_options_endpoint_aor_status_hash_fn, NULL,
1509 sip_options_endpoint_aor_status_cmp_fn);
1510 if (!endpoint_state_compositor->aor_statuses) {
1512 ao2_ref(endpoint_state_compositor, -1);
1513 return NULL;
1514 }
1515
1516 strcpy(endpoint_state_compositor->name, ast_sorcery_object_get_id(endpoint)); /* SAFE */
1517
1518 ao2_link_flags(sip_options_endpoint_state_compositors, endpoint_state_compositor,
1519 OBJ_NOLOCK);
1521
1522 return endpoint_state_compositor;
1523}
#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 1829 of file pjsip_options.c.

1831{
1832 struct ao2_iterator it_aor_statuses;
1833 struct sip_options_endpoint_aor_status *aor_status;
1835 .endpoint_state_compositor = endpoint_state_compositor,
1836 };
1837
1840
1841 /* Unlink AOR feeders pointing to endpoint */
1843 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
1844 task_data.aor_options = ao2_find(sip_options_aors, aor_status->name,
1846 if (!task_data.aor_options) {
1847 continue;
1848 }
1849
1850 ast_debug(3, "Removing endpoint state compositor '%s' from AOR '%s'\n",
1851 ast_sorcery_object_get_id(endpoint), aor_status->name);
1853 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1856 ao2_ref(task_data.aor_options, -1);
1857 }
1858 ao2_iterator_destroy(&it_aor_statuses);
1859
1860 /*
1861 * We do not need to remove the AOR feeder status memory from the
1862 * aor_statuses container. The endpoint_state_compositor is about
1863 * to die and do it for us.
1864 */
1865
1867}
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 561 of file pjsip_options.c.

563{
564 struct ao2_iterator it_aor_statuses;
565 struct sip_options_endpoint_aor_status *aor_status;
567
568 it_aor_statuses = ao2_iterator_init(endpoint_state_compositor->aor_statuses, 0);
569 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
570 if (aor_status->available) {
572 ao2_ref(aor_status, -1);
573 break;
574 }
575 }
576 ao2_iterator_destroy(&it_aor_statuses);
577
578 return state;
579}
enum cc_state state
Definition: ccss.c:399
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, sip_options_endpoint_aor_status::available, and state.

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

2902{
2903 management_serializer = mgmt_serializer;
2904
2906 if (!shutdown_group) {
2907 return -1;
2908 }
2909
2912 return -1;
2913 }
2916 return -1;
2917 }
2920 return -1;
2921 }
2922
2924
2925 return 0;
2926}
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:2391
struct ast_serializer_shutdown_group * ast_serializer_shutdown_group_alloc(void)
Create a serializer group shutdown control object.
Definition: threadpool.c:1229

References aor_observer_callbacks, ast_serializer_shutdown_group_alloc(), ast_sip_get_sorcery(), ast_sorcery_observer_add(), contact_observer_callbacks, endpoint_observer_callbacks, management_serializer, shutdown_group, 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 639 of file pjsip_options.c.

641{
642 int i;
643
644 /* Iterate through the associated endpoint state compositors updating them */
645 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
646 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
647
648 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
649
650 ao2_lock(endpoint_state_compositor);
651 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
652 aor_options->name, status);
653 ao2_unlock(endpoint_state_compositor);
654 }
655
656 if (status == REMOVED) {
658 }
659}

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

422{
423 int i;
424
425 for (i = 0; i < AST_VECTOR_SIZE(&aor_options->compositors); ++i) {
426 const struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
427
428 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, i);
430 contact_status);
431 }
432}
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 932 of file pjsip_options.c.

933{
934 struct sip_options_aor *aor_options = obj;
935
936 ast_debug(3, "Qualifying all contacts on AOR '%s'\n", aor_options->name);
937
938 /* Attempt to send an OPTIONS request to every contact on this AOR */
940 (struct sip_options_aor *) aor_options);
941
942 /* Always reschedule to the frequency we should go */
943 return aor_options->qualify_frequency * 1000;
944}
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 856 of file pjsip_options.c.

857{
858 struct ast_sip_contact *contact = obj;
859 struct sip_options_aor *aor_options = arg;
860 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
861 pjsip_tx_data *tdata;
862 struct ast_sip_contact_status *contact_status;
863 struct sip_options_contact_callback_data *contact_callback_data;
864
865 ast_debug(3, "Qualifying contact '%s' on AOR '%s'\n",
867
869 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
871 }
872 if (!endpoint && AST_VECTOR_SIZE(&aor_options->compositors)) {
873 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
874
875 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, 0);
876 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
877 endpoint_state_compositor->name);
878 }
879 if (!endpoint) {
880 ast_debug(3, "Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
881 ast_sorcery_object_get_id(contact), aor_options->name);
882 return 0;
883 }
884
885 if (ast_sip_create_request("OPTIONS", NULL, endpoint, NULL, contact, &tdata)) {
886 ast_log(LOG_ERROR, "Unable to create request to qualify contact %s on AOR %s\n",
887 contact->uri, aor_options->name);
888 return 0;
889 }
890
891 /* If an outbound proxy is specified set it on this request */
892 if (!ast_strlen_zero(contact->outbound_proxy) &&
894 ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
895 contact->uri);
896 pjsip_tx_data_dec_ref(tdata);
897 return 0;
898 }
899
900 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
901 if (!contact_status) {
902 ast_log(LOG_ERROR, "Unable to retrieve contact status information for contact %s on AOR %s\n",
903 contact->uri, aor_options->name);
904 pjsip_tx_data_dec_ref(tdata);
905 return 0;
906 }
907 ao2_ref(contact_status, -1);
908
909 contact_callback_data = sip_options_contact_callback_data_alloc(contact, aor_options);
910 if (!contact_callback_data) {
911 ast_log(LOG_ERROR, "Unable to create object to contain callback data for contact %s on AOR %s\n",
912 contact->uri, aor_options->name);
913 pjsip_tx_data_dec_ref(tdata);
914 return 0;
915 }
916
917 if (ast_sip_send_out_of_dialog_request(tdata, endpoint,
918 (int)(aor_options->qualify_timeout * 1000), contact_callback_data,
920 ast_log(LOG_ERROR, "Unable to send request to qualify contact %s on AOR %s\n",
921 contact->uri, aor_options->name);
922 ao2_ref(contact_callback_data, -1);
923 }
924
925 return 0;
926}
static void qualify_contact_cb(void *token, pjsip_event *e)
Callback for when we get a result from a SIP OPTIONS request (a response or a timeout)
static struct sip_options_contact_callback_data * sip_options_contact_callback_data_alloc(struct ast_sip_contact *contact, struct sip_options_aor *aor_options)
Contact callback data allocator.
int ast_sip_send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint, int timeout, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending an Out-Of-Dialog SIP request.
Definition: res_pjsip.c:1938
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:1992
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:1435

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_sorcery(), ast_sip_send_out_of_dialog_request(), 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, ast_sip_contact::endpoint_name, LOG_ERROR, sip_options_endpoint_state_compositor::name, sip_options_aor::name, NULL, ast_sip_contact::outbound_proxy, qualify_contact_cb(), sip_options_aor::qualify_timeout, RAII_VAR, sip_options_contact_callback_data_alloc(), and ast_sip_contact::uri.

Referenced by sip_options_qualify_aor().

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

1093{
1094 struct ast_sip_contact *contact = obj;
1095 struct sip_options_aor *aor_options = arg;
1096
1097 sip_options_remove_contact_status(aor_options, contact);
1098
1099 return CMP_MATCH;
1100}
@ 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 1019 of file pjsip_options.c.

1021{
1022 struct ast_sip_contact_status *cs_new;
1023 struct ast_sip_contact_status *cs_old;
1024
1027 if (!cs_old) {
1028 ast_debug(3, "Attempted to remove contact status for '%s' but it does not exist\n",
1029 ast_sorcery_object_get_id(contact));
1030 return;
1031 }
1032
1033 ast_verb(2, "Contact %s/%s has been deleted\n", contact->aor, contact->uri);
1034
1035 /* Update the contact status to reflect its new state */
1036 cs_new = sip_contact_status_copy(cs_old);
1037 if (!cs_new) {
1038 /*
1039 * We'll have to violate the immutable property because we
1040 * couldn't create a new one to modify and we are deleting
1041 * the contact status anyway.
1042 */
1043 cs_new = cs_old;
1044 } else {
1045 ao2_ref(cs_old, -1);
1046 }
1047 cs_new->last_status = cs_new->status;
1048 cs_new->status = REMOVED;
1049 cs_new->rtt = 0;
1050
1051 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1052 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1053 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1054 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1055
1057
1058 /*
1059 * The only time we need to update the AOR is if this contact was
1060 * available and qualify is in use, otherwise we can just stop
1061 * early.
1062 */
1063 if (!aor_options->qualify_frequency || cs_new->last_status != AVAILABLE) {
1064 ao2_ref(cs_new, -1);
1065 return;
1066 }
1067
1068 --aor_options->available;
1069 if (!aor_options->available) {
1071 }
1072
1073 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1074 aor_options->available);
1075
1076 ao2_ref(cs_new, -1);
1077}

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

1121{
1122 struct ast_sip_contact_status *cs_new;
1123
1124 /* Update the contact specific status information */
1125 cs_new = sip_contact_status_copy(contact_status);
1126 if (!cs_new) {
1127 return;
1128 }
1129 cs_new->last_status = cs_new->status;
1130 cs_new->status = status;
1131
1132 /*
1133 * We need to always set the RTT to zero because we haven't completed
1134 * an OPTIONS ping so RTT is unknown. If the OPTIONS ping were still
1135 * running it will be refreshed on the next go round anyway.
1136 */
1137 cs_new->rtt = 0;
1138
1140
1141 if (cs_new->status != cs_new->last_status) {
1142 ast_verb(3, "Contact %s/%s is now %s.\n",
1143 cs_new->aor, cs_new->uri,
1145
1146 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1147 "-1", 1.0, ast_sip_get_contact_status_label(cs_new->last_status));
1148 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
1149 "+1", 1.0, ast_sip_get_contact_status_label(cs_new->status));
1150
1152
1153 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
1154 "Contact: %s\r\n"
1155 "Status: %s",
1156 cs_new->name,
1158 }
1159 ao2_ref(cs_new, -1);
1160}

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

1191{
1192 struct ast_sip_contact *contact = obj;
1193 struct ast_sip_contact_status *contact_status;
1194
1195 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1196 if (!contact_status) {
1197 return 0;
1198 }
1199
1200 switch (contact_status->status) {
1201 case AVAILABLE:
1203 break;
1204 case UNAVAILABLE:
1205 case UNKNOWN:
1206 case CREATED:
1207 case REMOVED:
1208 break;
1209 }
1210
1211 ao2_ref(contact_status, -1);
1212
1213 return 0;
1214}
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 1163 of file pjsip_options.c.

1164{
1165 struct ast_sip_contact *contact = obj;
1166 struct ast_sip_contact_status *contact_status;
1167
1168 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1169 if (!contact_status) {
1170 return 0;
1171 }
1172
1173 switch (contact_status->status) {
1174 case AVAILABLE:
1175 case UNAVAILABLE:
1176 case UNKNOWN:
1177 sip_options_set_contact_status(contact_status, CREATED);
1178 break;
1179 case CREATED:
1180 case REMOVED:
1181 break;
1182 }
1183
1184 ao2_ref(contact_status, -1);
1185
1186 return 0;
1187}

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

1816{
1818 .reload = reload,
1819 };
1820
1822 &task_data);
1823}
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 1431 of file pjsip_options.c.

1432{
1434 .aor = obj,
1435 .existing = arg,
1436 };
1437
1438 task_data.aor_options = ao2_find(sip_options_aors,
1440 if (!task_data.aor_options) {
1441 task_data.aor_options = sip_options_aor_alloc(task_data.aor);
1442 if (!task_data.aor_options) {
1443 return 0;
1444 }
1445
1446 task_data.added = 1;
1447
1448 /* Nothing is aware of this AOR yet so we can just update it in this thread */
1450 ao2_link(sip_options_aors, task_data.aor_options);
1451 } else {
1452 /* This AOR already exists so we have to do manipulation in its serializer */
1453 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1455 }
1456
1457 ao2_ref(task_data.aor_options, -1);
1458
1459 if (task_data.existing) {
1462 }
1463
1464 return 0;
1465}
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 1393 of file pjsip_options.c.

1394{
1396 int i;
1397
1398 ast_debug(3, "Synchronizing AOR '%s' with current state of configuration and world\n",
1399 task_data->aor_options->name);
1400
1402 task_data->added);
1403
1404 /*
1405 * Endpoint state compositors are removed in this operation but not
1406 * added. To reduce the amount of work done they are done later. In
1407 * the mean time things can still qualify and once an endpoint state
1408 * compositor is added to the AOR it will be updated with the current
1409 * state.
1410 */
1411 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1412 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1413
1414 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1415
1416 ao2_lock(endpoint_state_compositor);
1417 endpoint_state_compositor->active = 0;
1418 sip_options_update_endpoint_state_compositor_aor(endpoint_state_compositor,
1419 task_data->aor_options->name, REMOVED);
1420 ao2_unlock(endpoint_state_compositor);
1421 }
1422 AST_VECTOR_RESET(&task_data->aor_options->compositors, ao2_cleanup);
1423
1424 return 0;
1425}

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

1595{
1596 struct ast_sip_endpoint *endpoint = obj;
1597 struct ast_sip_aor *aor = arg;
1598 char *aors;
1599 char *aor_name;
1601
1602 if (ast_strlen_zero(endpoint->aors)) {
1603 /* There are no AORs, so really... who the heck knows */
1604 ast_debug(3, "Endpoint '%s' is not interested in any AORs so not creating endpoint state compositor\n",
1605 ast_sorcery_object_get_id(endpoint));
1606 return 0;
1607 }
1608
1609 ast_debug(3, "Synchronizing endpoint '%s' with AORs '%s'\n",
1610 ast_sorcery_object_get_id(endpoint), endpoint->aors);
1611
1612 aors = ast_strdupa(endpoint->aors);
1613 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
1614 if (ast_strlen_zero(aor_name)) {
1615 continue;
1616 }
1617 if (aor && strcasecmp(ast_sorcery_object_get_id(aor), aor_name)) {
1618 ast_debug(3, "Filtered AOR '%s' on endpoint '%s' as we are looking for '%s'\n",
1619 aor_name, ast_sorcery_object_get_id(endpoint),
1621 continue;
1622 }
1623
1624 task_data.aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
1625 if (!task_data.aor_options) {
1626 /*
1627 * They have referenced an invalid AOR. If that's all they've
1628 * done we will set them to offline at the end.
1629 */
1630 ast_debug(3, "Endpoint '%s' referenced invalid AOR '%s'\n",
1631 ast_sorcery_object_get_id(endpoint), aor_name);
1632 continue;
1633 }
1634
1635 if (!task_data.endpoint_state_compositor) {
1636 /*
1637 * We create an endpoint state compositor only after we know
1638 * for sure we need it.
1639 */
1640 task_data.endpoint_state_compositor =
1642 if (!task_data.endpoint_state_compositor) {
1644 "Could not create endpoint state compositor for '%s', endpoint state will be incorrect\n",
1645 ast_sorcery_object_get_id(endpoint));
1646 ao2_ref(task_data.aor_options, -1);
1649 return 0;
1650 }
1651 }
1652
1653 /* We use a synchronous task so that we don't flood the system */
1654 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1656
1657 ao2_ref(task_data.aor_options, -1);
1658
1659 /*
1660 * If we filtered on a specific AOR name then the endpoint can
1661 * only reference it once so break early.
1662 */
1663 if (aor) {
1664 break;
1665 }
1666 }
1667
1668 if (task_data.endpoint_state_compositor) {
1669 /*
1670 * If an endpoint state compositor is present determine the current state
1671 * of the endpoint and update it.
1672 */
1673 ao2_lock(task_data.endpoint_state_compositor);
1674 task_data.endpoint_state_compositor->active = 1;
1677 ao2_unlock(task_data.endpoint_state_compositor);
1678
1679 ao2_ref(task_data.endpoint_state_compositor, -1);
1680 } else if (!aor) {
1681 /* If no explicit AOR is specified we are updating the endpoint itself, so then set
1682 * it to offline if no endpoint compositor exists as they referenced an invalid AOR
1683 * or none at all
1684 */
1685 ast_debug(3, "Endpoint '%s' has no AORs feeding it, setting it to offline state as default\n",
1686 ast_sorcery_object_get_id(endpoint));
1689 }
1690
1691 return 0;
1692}
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 1759 of file pjsip_options.c.

1760{
1762 struct ao2_container *existing = NULL;
1763 struct ao2_container *objects;
1764
1765 /*
1766 * When reloading we keep track of the existing AORs so we can
1767 * terminate old ones that are no longer referenced or used.
1768 */
1769 if (task_data->reload) {
1771 if (!existing) {
1772 return 0;
1773 }
1774 }
1775
1778 if (objects) {
1779 /* Go through the returned AORs and synchronize with our local state */
1781 ao2_ref(objects, -1);
1782 }
1783
1784 /*
1785 * Any AORs remaining in existing are no longer referenced by
1786 * the current container of AORs we retrieved, so remove them.
1787 */
1788 if (existing) {
1791 ao2_ref(existing, -1);
1792 }
1793
1796 if (objects) {
1797 /* Go through the provided endpoints and update AORs */
1799 ao2_ref(objects, -1);
1800 }
1801
1802 /*
1803 * All endpoint state compositors that don't have any AORs
1804 * feeding them information can be removed. If they end
1805 * up getting needed later they'll just be recreated.
1806 */
1810
1811 return 0;
1812}
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_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 1717 of file pjsip_options.c.

1718{
1719 struct sip_options_aor *aor_options = obj;
1720
1721 ast_debug(3, "AOR '%s' is no longer configured, removing it\n", aor_options->name);
1722
1724 aor_options);
1725 ao2_unlink(sip_options_aors, aor_options);
1726
1727 return CMP_MATCH;
1728}
#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 1734 of file pjsip_options.c.

1735{
1736 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1737
1738 if (ao2_container_count(endpoint_state_compositor->aor_statuses)) {
1739 return 0;
1740 }
1741
1742 /* No AORs are feeding this endpoint state compositor */
1743 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
1745
1746 return CMP_MATCH;
1747}

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

1943{
1945 int available = task_data->aor_options->available;
1946
1947 ast_debug(3, "Individually updating AOR '%s' with current state of configuration and world\n",
1948 task_data->aor_options->name);
1949
1951 task_data->added);
1952
1953 if (!available && task_data->aor_options->available) {
1954 ast_debug(3, "After modifying AOR '%s' it has now become available\n",
1955 task_data->aor_options->name);
1957 } else if (available && !task_data->aor_options->available) {
1958 ast_debug(3, "After modifying AOR '%s' it has become unavailable\n",
1959 task_data->aor_options->name);
1961 }
1962
1963 return 0;
1964}

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

587{
588 struct sip_options_endpoint_aor_status *aor_status;
589 enum ast_endpoint_state endpoint_state;
590
591 aor_status = ao2_find(endpoint_state_compositor->aor_statuses, name,
593 if (!aor_status) {
594 /* The AOR status doesn't exist already so we don't need to go any further */
595 if (status == REMOVED) {
596 return;
597 }
598
599 aor_status = ao2_alloc_options(sizeof(*aor_status) + strlen(name) + 1, NULL,
601 if (!aor_status) {
602 return;
603 }
604
605 strcpy(aor_status->name, name); /* SAFE */
606 ao2_link(endpoint_state_compositor->aor_statuses, aor_status);
607 }
608
609 if (status == REMOVED) {
610 /*
611 * If the AOR is being removed then remove its AOR status
612 * from the endpoint compositor.
613 */
614 ao2_unlink(endpoint_state_compositor->aor_statuses, aor_status);
615 } else {
616 aor_status->available = (status == AVAILABLE ? 1 : 0);
617 }
618 ao2_ref(aor_status, -1);
619
620 if (!endpoint_state_compositor->active) {
621 return;
622 }
623
624 /* If this AOR is available then the endpoint itself has to be online */
625 if (status == AVAILABLE) {
626 ast_debug(3, "Endpoint state compositor '%s' is online as AOR '%s' is available\n",
627 endpoint_state_compositor->name, name);
628 endpoint_state = AST_ENDPOINT_ONLINE;
629 } else {
630 endpoint_state =
631 sip_options_get_endpoint_state_compositor_state(endpoint_state_compositor);
632 }
633
634 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
635 endpoint_state);
636}

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

Referenced by ast_res_pjsip_cleanup_options_handling(), and sip_options_init_task().

◆ cli_options

struct ast_cli_entry cli_options[]
static

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

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

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

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

◆ short_status_map

const char* short_status_map[]
static

Definition at line 327 of file pjsip_options.c.

Referenced by ast_sip_get_contact_short_status_label().

◆ shutdown_group

struct ast_serializer_shutdown_group* shutdown_group
static

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

Referenced by ast_sip_get_contact_status_label().