Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
Data Structures | Macros | Functions | Variables
pjsip_options.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include <pjlib.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/astobj2.h"
#include "asterisk/cli.h"
#include "asterisk/time.h"
#include "asterisk/test.h"
#include "asterisk/statsd.h"
#include "include/res_pjsip_private.h"
#include "asterisk/taskprocessor.h"
Include 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.
 
#define AOR_STATUS_BUCKETS   3
 These are the number of buckets (per endpoint state compositor) to use to store AOR statuses.
 
#define CONTACT_BUCKETS   13
 These are the number of buckets (per AOR) to use to store contacts.
 
#define CONTACT_STATUS_BUCKETS   1567
 These are the number of contact status buckets.
 
#define DEFAULT_ENCODING   "identity"
 
#define DEFAULT_LANGUAGE   "en"
 
#define ENDPOINT_STATE_COMPOSITOR_BUCKETS   13
 These are the number of buckets to store endpoint state compositors.
 
#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE   1
 The initial vector size for the endpoint state compositors on an AOR.
 
#define MAX_UNLOAD_TIMEOUT_TIME   10 /* Seconds */
 Maximum wait time to join the below shutdown group.
 

Functions

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

Variables

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

Macro Definition Documentation

◆ AOR_BUCKETS

#define AOR_BUCKETS   1567

These are the number of buckets to store AORs in.

Definition at line 102 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 122 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 113 of file pjsip_options.c.

◆ CONTACT_STATUS_BUCKETS

#define CONTACT_STATUS_BUCKETS   1567

These are the number of contact status buckets.

Definition at line 109 of file pjsip_options.c.

◆ DEFAULT_ENCODING

#define DEFAULT_ENCODING   "identity"

Definition at line 96 of file pjsip_options.c.

◆ DEFAULT_LANGUAGE

#define DEFAULT_LANGUAGE   "en"

Definition at line 95 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 116 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 119 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 125 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 2456 of file pjsip_options.c.

2457{
2458 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2459 struct ao2_container *contacts;
2460
2461 contacts = get_all_contacts();
2462 if (!contacts) {
2463 astman_send_error(s, m, "Could not get Contacts\n");
2464 return 0;
2465 }
2466
2467 if (!ao2_container_count(contacts)) {
2468 astman_send_error(s, m, "No Contacts found\n");
2469 ao2_ref(contacts, -1);
2470 return 0;
2471 }
2472
2473 astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events",
2474 "start");
2475
2477
2478 astman_send_list_complete_start(s, m, "ContactListComplete", ami.count);
2480
2481 ao2_ref(contacts, -1);
2482
2483 return 0;
2484}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
@ OBJ_NODATA
Definition astobj2.h:1044
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition manager.c:1963
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition manager.c:1921
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition manager.c:1999
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1582
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2007
static struct ao2_container * get_all_contacts(void)
static int format_ami_contactlist_handler(void *obj, void *arg, int flags)
Generic container type.
AMI variable container.
Definition res_pjsip.h:3257
struct mansession * s
Definition res_pjsip.h:3259
const struct message * m
Definition res_pjsip.h:3261

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

2672{
2673 const char *endpoint_name = astman_get_header(m, "Endpoint");
2674 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
2675 char *aors;
2676 char *aor_name;
2677
2678 if (ast_strlen_zero(endpoint_name)) {
2679 astman_send_error(s, m, "Endpoint parameter missing.");
2680 return 0;
2681 }
2682
2683 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
2684 endpoint_name);
2685 if (!endpoint) {
2686 astman_send_error(s, m, "Unable to retrieve endpoint\n");
2687 return 0;
2688 }
2689
2690 /* send a qualify for all contacts registered with the endpoint */
2691 if (ast_strlen_zero(endpoint->aors)) {
2692 astman_send_error(s, m, "No AoRs configured for endpoint\n");
2693 return 0;
2694 }
2695
2696 aors = ast_strdupa(endpoint->aors);
2697 while ((aor_name = ast_strip(strsep(&aors, ",")))) {
2698 struct sip_options_aor *aor_options;
2699
2700 aor_options = ao2_find(sip_options_aors, aor_name, OBJ_SEARCH_KEY);
2701 if (!aor_options) {
2702 continue;
2703 }
2704
2706 aor_options);
2707 ao2_ref(aor_options, -1);
2708 }
2709
2710 astman_send_ack(s, m, "Endpoint found, will qualify");
2711 return 0;
2712}
char * strsep(char **str, const char *delims)
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition manager.c:1953
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2221
static struct ao2_container * sip_options_aors
static int sip_options_qualify_aor(void *obj)
Task to qualify contacts of an AOR.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define NULL
Definition resample.c:96
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition sorcery.c:1917
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
An entity with which Asterisk communicates.
Definition res_pjsip.h:1067
Structure which contains an AOR and contacts for qualifying purposes.
struct ast_taskprocessor * serializer
The serializer for this AOR.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981

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

Referenced by ast_res_pjsip_init_options_handling().

◆ AO2_STRING_FIELD_CMP_FN() [1/4]

AO2_STRING_FIELD_CMP_FN ( ast_sip_contact_status  ,
name   
)

Comparator function for contact statuses.

◆ AO2_STRING_FIELD_CMP_FN() [2/4]

AO2_STRING_FIELD_CMP_FN ( sip_options_aor  ,
name   
)

Comparator function for SIP OPTIONS AORs.

◆ AO2_STRING_FIELD_CMP_FN() [3/4]

AO2_STRING_FIELD_CMP_FN ( sip_options_endpoint_aor_status  ,
name   
)

Comparator function for endpoint AOR status.

◆ AO2_STRING_FIELD_CMP_FN() [4/4]

AO2_STRING_FIELD_CMP_FN ( sip_options_endpoint_state_compositor  ,
name   
)

Comparator function for endpoint state compositors.

◆ AO2_STRING_FIELD_HASH_FN() [1/4]

AO2_STRING_FIELD_HASH_FN ( ast_sip_contact_status  ,
name   
)

Hashing function for contact statuses.

◆ AO2_STRING_FIELD_HASH_FN() [2/4]

AO2_STRING_FIELD_HASH_FN ( sip_options_aor  ,
name   
)

Hashing function for OPTIONS AORs.

◆ AO2_STRING_FIELD_HASH_FN() [3/4]

AO2_STRING_FIELD_HASH_FN ( sip_options_endpoint_aor_status  ,
name   
)

Hashing function for endpoint AOR status.

◆ AO2_STRING_FIELD_HASH_FN() [4/4]

AO2_STRING_FIELD_HASH_FN ( sip_options_endpoint_state_compositor  ,
name   
)

Hashing function for endpoint state compositors.

◆ AO2_STRING_FIELD_SORT_FN()

AO2_STRING_FIELD_SORT_FN ( ast_sip_contact_status  ,
name   
)

Sort function for contact statuses.

◆ aor_observer_deleted()

static void aor_observer_deleted ( const void *  obj)
static

Observer callback invoked on AOR deletion.

Definition at line 2048 of file pjsip_options.c.

2049{
2052}
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 2017 of file pjsip_options.c.

2018{
2021}
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 2843 of file pjsip_options.c.

2844{
2845 struct ast_taskprocessor *mgmt_serializer;
2846
2848 ast_manager_unregister("PJSIPQualify");
2849 ast_manager_unregister("PJSIPShowContacts");
2851
2858
2859 mgmt_serializer = management_serializer;
2861 if (mgmt_serializer) {
2863 ast_taskprocessor_unreference(mgmt_serializer);
2864 }
2865
2872
2873 pjsip_endpt_unregister_module(ast_sip_get_pjsip_endpoint(), &options_module);
2874}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7782
static pjsip_module options_module
static const struct ast_sorcery_observer endpoint_observer_callbacks
Observer callbacks for endpoints.
static struct ao2_container * sip_options_contact_statuses
static struct ao2_container * sip_options_endpoint_state_compositors
static struct ast_cli_entry cli_options[]
static int sip_options_cleanup_task(void *obj)
Management task to clean up the environment.
static const struct ast_sorcery_observer aor_observer_callbacks
Observer callbacks for AORs.
static const struct ast_sorcery_observer contact_observer_callbacks
Observer callbacks for contacts.
static struct ast_sip_endpoint_formatter contact_status_formatter
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:518
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
Definition res_pjsip.c:485
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition sorcery.c:2487
A ast_taskprocessor structure is a singleton by name.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
#define ARRAY_LEN(a)
Definition utils.h:706

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

Referenced by ast_res_pjsip_init_options_handling(), and unload_pjsip().

◆ ast_res_pjsip_find_or_create_contact_status()

struct ast_sip_contact_status * ast_res_pjsip_find_or_create_contact_status ( const struct ast_sip_contact contact)

Definition at line 462 of file pjsip_options.c.

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

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

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

◆ ast_res_pjsip_init_options_handling()

int ast_res_pjsip_init_options_handling ( int  reload)

Definition at line 2908 of file pjsip_options.c.

2909{
2910 struct ast_taskprocessor *mgmt_serializer;
2911
2912 static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
2913
2914 if (reload) {
2916 return 0;
2917 }
2918
2919 if (pjsip_endpt_register_module(ast_sip_get_pjsip_endpoint(), &options_module)
2920 != PJ_SUCCESS) {
2921 return -1;
2922 }
2923
2924 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW,
2925 NULL, 1, &STR_OPTIONS) != PJ_SUCCESS) {
2927 return -1;
2928 }
2929
2931 sip_options_aor_hash_fn, NULL, sip_options_aor_cmp_fn);
2932 if (!sip_options_aors) {
2934 return -1;
2935 }
2939 sip_options_endpoint_state_compositor_hash_fn, NULL,
2940 sip_options_endpoint_state_compositor_cmp_fn);
2943 return -1;
2944 }
2945
2946 mgmt_serializer = ast_sip_create_serializer("pjsip/options/manage");
2947 if (!mgmt_serializer) {
2949 return -1;
2950 }
2951
2952 /*
2953 * Set the water mark levels high because we can get a flood of
2954 * contact status updates from sip_options_synchronize() that
2955 * quickly clears on initial load or reload.
2956 */
2957 ast_taskprocessor_alert_set_levels(mgmt_serializer, -1,
2959
2960 /*
2961 * We make sure that the environment is completely setup before we allow
2962 * any other threads to post contact_status updates to the
2963 * management_serializer.
2964 */
2966 mgmt_serializer)) {
2967 /* Set management_serializer in case pushing the task actually failed. */
2968 management_serializer = mgmt_serializer;
2970 return -1;
2971 }
2972
2978
2979 return 0;
2980}
@ 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:2092
#define EVENT_FLAG_REPORTING
Definition manager.h:84
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:193
static void sip_options_synchronize(int reload)
Synchronize our local container of AORs and endpoint state compositors with the current configuration...
static int ami_sip_qualify(struct mansession *s, const struct message *m)
void ast_res_pjsip_cleanup_options_handling(void)
#define ENDPOINT_STATE_COMPOSITOR_BUCKETS
These are the number of buckets to store endpoint state compositors.
#define AOR_BUCKETS
These are the number of buckets to store AORs in.
static int ami_show_contacts(struct mansession *s, const struct message *m)
static int sip_options_init_task(void *mgmt_serializer)
Management task to finish setting up the environment.
static int reload(void)
void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Register an endpoint formatter.
Definition res_pjsip.c:479
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water)
Set the high and low alert water marks of the given taskprocessor queue.

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

Referenced by load_module(), and reload_configuration_task().

◆ ast_res_pjsip_preinit_options_handling()

int ast_res_pjsip_preinit_options_handling ( void  )

Definition at line 2902 of file pjsip_options.c.

2903{
2905 return sip_options_contact_statuses ? 0 : -1;
2906}
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 2722 of file pjsip_options.c.

2723{
2724 struct ast_sip_contact_wrapper *wrapper = obj;
2725 struct ast_sip_contact *contact = wrapper->contact;
2726 struct ast_sip_ami *ami = arg;
2728 struct ast_str *buf;
2729 const struct ast_sip_endpoint *endpoint = ami->arg;
2730 char secs[AST_TIME_T_LEN];
2731
2732 buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
2733 if (!buf) {
2734 return -1;
2735 }
2736
2738
2739 ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
2740 ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
2741 ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
2742 ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
2743 ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
2744 if (!ast_strlen_zero(contact->via_addr)) {
2745 ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
2746 if (contact->via_port) {
2747 ast_str_append(&buf, 0, ":%d", contact->via_port);
2748 }
2749 ast_str_append(&buf, 0, "\r\n");
2750 }
2751 if (!ast_strlen_zero(contact->call_id)) {
2752 ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id);
2753 }
2754 ast_str_append(&buf, 0, "Status: %s\r\n",
2756 if (!status || status->status != AVAILABLE) {
2757 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2758 } else {
2759 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2760 }
2761 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
2762 endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
2763
2764 ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
2765 ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
2766 ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
2767 ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
2768 ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
2769 ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
2770 ast_str_append(&buf, 0, "Qualify2xxOnly: %d\r\n", contact->qualify_2xx_only);
2771
2772 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2773 ami->count++;
2774
2775 ast_free(buf);
2777 return 0;
2778}
jack_status_t status
Definition app_jack.c:149
#define ast_free(a)
Definition astmm.h:180
char buf[BUFSIZE]
Definition eagi_proxy.c:66
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1842
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
@ AVAILABLE
Definition res_pjsip.h:440
@ UNKNOWN
Definition res_pjsip.h:442
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
A wrapper for contact that adds the aor_id and a consistent contact id. Used by ast_sip_for_each_cont...
Definition res_pjsip.h:521
struct ast_sip_contact * contact
Definition res_pjsip.h:527
Contact associated with an address of record.
Definition res_pjsip.h:392
double qualify_timeout
Definition res_pjsip.h:422
const ast_string_field via_addr
Definition res_pjsip.h:414
const ast_string_field call_id
Definition res_pjsip.h:414
const ast_string_field outbound_proxy
Definition res_pjsip.h:414
struct timeval expiration_time
Definition res_pjsip.h:416
const ast_string_field path
Definition res_pjsip.h:414
int authenticate_qualify
Definition res_pjsip.h:420
const ast_string_field user_agent
Definition res_pjsip.h:414
unsigned int qualify_frequency
Definition res_pjsip.h:418
Support for dynamic strings.
Definition strings.h:623
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
Definition time.c:152
#define AST_TIME_T_LEN
Definition time.h:45

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

Referenced by ami_show_registration_contact_statuses(), and format_contact_status_for_aor().

◆ ast_sip_get_contact_short_status_label()

const char * ast_sip_get_contact_short_status_label ( const enum ast_sip_contact_status_type  status)

Definition at line 337 of file pjsip_options.c.

338{
340 return short_status_map[status];
341}
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 2349 of file pjsip_options.c.

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

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

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

◆ cli_reload_qualify_endpoint()

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

Definition at line 2581 of file pjsip_options.c.

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

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

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

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

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

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

2337{
2340}
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 2228 of file pjsip_options.c.

2229{
2230 const struct ast_sip_contact *contact = obj;
2231 struct sip_options_aor *aor_options = ao2_find(sip_options_aors, contact->aor, OBJ_SEARCH_KEY);
2232
2233 if (has_qualify_changed(contact, aor_options)) {
2234 struct ast_sip_aor *aor;
2235
2237 contact->aor);
2238 if (aor) {
2239 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2240 contact->aor);
2243 ao2_ref(aor, -1);
2244 }
2245 }
2246
2249
2250 task_data = ast_malloc(sizeof(*task_data));
2251 if (!task_data) {
2252 ao2_ref(aor_options, -1);
2253 return;
2254 }
2255
2256 task_data->contact = (struct ast_sip_contact *) contact;
2257 /* task_data takes ownership of aor_options and will take care of releasing the ref */
2258 task_data->aor_options = aor_options;
2259
2260 ao2_ref(task_data->contact, +1);
2261 if (ast_sip_push_task(task_data->aor_options->serializer,
2263 ao2_ref(task_data->contact, -1);
2264 ao2_ref(task_data->aor_options, -1);
2266 }
2267 } else {
2268 ao2_cleanup(aor_options);
2269 }
2270}
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_sip_push_task(serializer, sip_task, task_data)
Definition res_pjsip.h:2126
#define ast_debug(level,...)
Log a DEBUG message.
static int sip_options_contact_update_task(void *obj)
Task which updates a dynamic contact to an AOR.
static int has_qualify_changed(const struct ast_sip_contact *contact, const struct sip_options_aor *aor_options)
Check if the contact qualify options are different than local aor qualify options.
unsigned int ast_sip_get_send_contact_status_on_update_registration(void)
Retrieve the global setting 'send_contact_status_on_update_registration'.
Task details for adding an AOR to an endpoint state compositor.
struct sip_options_aor * aor_options
The AOR options that the contact is referring to.
userdata associated with baseline taskprocessor test

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

◆ contact_status_publish_update_task()

static int contact_status_publish_update_task ( void *  obj)
static

Task to notify endpoints of a contact status change.

Note
Run by management_serializer

Definition at line 434 of file pjsip_options.c.

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

1886{
1889}
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 1917 of file pjsip_options.c.

1918{
1921}
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 2787 of file pjsip_options.c.

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

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

◆ format_ami_contactlist_handler()

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

Definition at line 2419 of file pjsip_options.c.

2420{
2421 struct ast_sip_contact *contact = obj;
2422 struct ast_sip_ami *ami = arg;
2423 struct ast_str *buf;
2425
2426 buf = ast_sip_create_ami_event("ContactList", ami);
2427 if (!buf) {
2428 return CMP_STOP;
2429 }
2430
2431 if (sip_contact_to_ami(contact, &buf)) {
2432 ast_free(buf);
2433 return CMP_STOP;
2434 }
2435
2436 /* Add extra info */
2438 ast_str_append(&buf, 0, "Status: %s\r\n",
2440 if (!status || status->status != AVAILABLE) {
2441 ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n");
2442 } else {
2443 ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
2444 }
2446
2447 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
2448
2449 ami->count++;
2450
2451 ast_free(buf);
2452
2453 return 0;
2454}
@ 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 2780 of file pjsip_options.c.

2781{
2782 struct ast_sip_aor *aor = obj;
2783
2785}
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 2403 of file pjsip_options.c.

2404{
2405 struct ao2_container *contacts;
2406
2409
2410 return contacts;
2411}
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition sorcery.h:123
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition sorcery.c:1961

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

Referenced by ami_show_contacts().

◆ has_qualify_changed()

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

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

Definition at line 2073 of file pjsip_options.c.

2074{
2075 if (!contact) {
2076 return 0;
2077 }
2078
2079 if (!aor_options) {
2080 if (contact->qualify_frequency) {
2081 return 1;
2082 }
2083 } else if (contact->qualify_frequency != aor_options->qualify_frequency
2084 || contact->authenticate_qualify != aor_options->authenticate_qualify
2085 || contact->qualify_2xx_only != aor_options->qualify_2xx_only
2086 || ((int)(contact->qualify_timeout * 1000)) != ((int)(aor_options->qualify_timeout * 1000))) {
2087 return 1;
2088 }
2089
2090 return 0;
2091}

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

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

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

787{
788 struct sip_options_contact_callback_data *contact_callback_data = token;
790
791 switch(e->body.tsx_state.type) {
792 default:
793 ast_log(LOG_ERROR, "Unexpected PJSIP event %u\n", e->body.tsx_state.type);
794 /* Fall through */
795 case PJSIP_EVENT_TRANSPORT_ERROR:
796 case PJSIP_EVENT_TIMER:
798 break;
799 case PJSIP_EVENT_RX_MSG:
800 if (contact_callback_data->aor_options->qualify_2xx_only &&
801 (e->body.tsx_state.tsx->status_code < 200 || e->body.tsx_state.tsx->status_code >= 300)) {
803 } else {
805 }
806 break;
807 }
808
809 /* Update the callback data with the new status, this will get handled in the AOR serializer */
810 contact_callback_data->status = status;
811
812 if (ast_sip_push_task(contact_callback_data->aor_options->serializer,
813 sip_options_contact_status_notify_task, contact_callback_data)) {
814 ast_log(LOG_WARNING, "Unable to queue contact status update for '%s' on AOR '%s', state will be incorrect\n",
815 ast_sorcery_object_get_id(contact_callback_data->contact),
816 contact_callback_data->aor_options->name);
817 ao2_ref(contact_callback_data, -1);
818 }
819
820 /* The task inherited our reference so we don't unreference here */
821}
#define ast_log
Definition astobj2.c:42
#define LOG_ERROR
#define LOG_WARNING
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:436
@ UNAVAILABLE
Definition res_pjsip.h:438
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 213 of file pjsip_options.c.

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

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

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

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

Referenced by ast_res_pjsip_find_or_create_contact_status(), and sip_contact_status_copy().

◆ sip_contact_status_copy()

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

Definition at line 372 of file pjsip_options.c.

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

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

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

◆ sip_contact_status_dtor()

static void sip_contact_status_dtor ( void *  obj)
static

Destructor for contact statuses.

Definition at line 344 of file pjsip_options.c.

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

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

Referenced by sip_contact_status_alloc().

◆ sip_contact_to_ami()

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

Definition at line 2413 of file pjsip_options.c.

2415{
2416 return ast_sip_sorcery_object_to_ami(contact, buf);
2417}
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 968 of file pjsip_options.c.

969{
970 struct sip_options_aor *aor_options;
971
972 aor_options = ao2_alloc_options(sizeof(*aor_options) + strlen(ast_sorcery_object_get_id(aor)) + 1,
974 if (!aor_options) {
975 return NULL;
976 }
977
978 strcpy(aor_options->name, ast_sorcery_object_get_id(aor)); /* SAFE */
979
981 if (!aor_options->serializer) {
982 ao2_ref(aor_options, -1);
983 return NULL;
984 }
985
987 ao2_ref(aor_options, -1);
988 return NULL;
989 }
990
994 if (!aor_options->contacts) {
995 ao2_ref(aor_options, -1);
996 return NULL;
997 }
998
1002 if (!aor_options->dynamic_contacts) {
1003 ao2_ref(aor_options, -1);
1004 return NULL;
1005 }
1006
1007 return aor_options;
1008}
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition astobj2.h:1188
struct ast_taskprocessor * ast_sip_get_distributor_serializer_hash(int hash)
Determine the distributor serializer for a given hash.
#define ENDPOINT_STATE_COMPOSITOR_INITIAL_SIZE
The initial vector size for the endpoint state compositors on an AOR.
static void sip_options_aor_dtor(void *obj)
Destructor function for SIP OPTIONS AORs.
#define CONTACT_BUCKETS
These are the number of buckets (per AOR) to use to store contacts.
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition sorcery.c:2528
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition sorcery.c:2504
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
Definition sorcery.c:2539
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition strings.h:1259
struct ao2_container * contacts
All contacts associated with this AOR.
struct sip_options_aor::@491 compositors
The endpoint state compositors we are feeding, a reference is held to each.
struct ao2_container * dynamic_contacts
Only dynamic contacts associated with this AOR.

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

Referenced by sip_options_aor_observer_modified_task(), and sip_options_synchronize_aor().

◆ sip_options_aor_dtor()

static void sip_options_aor_dtor ( void *  obj)
static

Destructor function for SIP OPTIONS AORs.

Definition at line 946 of file pjsip_options.c.

947{
948 struct sip_options_aor *aor_options = obj;
949
950 /*
951 * Any contacts are unreachable since the AOR is being destroyed
952 * so remove their contact status
953 */
954 if (aor_options->contacts) {
956 sip_options_remove_contact, aor_options);
957 ao2_ref(aor_options->contacts, -1);
958 }
959 ao2_cleanup(aor_options->dynamic_contacts);
960
962
963 ast_assert(AST_VECTOR_SIZE(&aor_options->compositors) == 0);
964 AST_VECTOR_FREE(&aor_options->compositors);
965}
@ OBJ_UNLINK
Definition astobj2.h:1039
static int sip_options_remove_contact(void *obj, void *arg, int flags)
Forward declaration of this helpful function.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185

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

Referenced by sip_options_aor_alloc().

◆ sip_options_aor_observer_deleted_task()

static int sip_options_aor_observer_deleted_task ( void *  obj)
static

Task to delete an AOR from the known universe.

Note
Run by management_serializer

Definition at line 2027 of file pjsip_options.c.

2028{
2029 struct ast_sip_aor *aor = obj;
2030 struct sip_options_aor *aor_options;
2031
2034 if (!aor_options) {
2035 return 0;
2036 }
2037
2038 ast_debug(3, "AOR '%s' has been deleted, removing it\n", aor_options->name);
2039
2041 aor_options);
2042 ao2_ref(aor_options, -1);
2043
2044 return 0;
2045}
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 1962 of file pjsip_options.c.

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

1691{
1692 struct sip_options_aor *aor_options = obj;
1693
1695
1696 if (aor_options->sched_task) {
1698 ao2_ref(aor_options->sched_task, -1);
1699 aor_options->sched_task = NULL;
1700 }
1701
1702 return 0;
1703}
int ast_sip_sched_task_cancel(struct ast_sip_sched_task *schtd)
Cancels the next invocation of a task.
static void sip_options_notify_endpoint_state_compositors(struct sip_options_aor *aor_options, enum ast_sip_contact_status_type status)
Function which notifies endpoint state compositors of a state change of an AOR.
@ REMOVED
Definition res_pjsip.h:445
struct ast_sip_sched_task * sched_task
The scheduler task for this AOR.

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

Referenced by sip_options_aor_observer_deleted_task(), and sip_options_unused_aor().

◆ sip_options_apply_aor_configuration()

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

Function which applies configuration to an AOR options structure.

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

Definition at line 1241 of file pjsip_options.c.

1243{
1244 struct ao2_container *existing_contacts;
1245 struct ast_sip_contact *contact;
1246 struct ao2_iterator iter;
1247
1248 ast_debug(3, "Configuring AOR '%s' with current state of configuration and world\n",
1249 aor_options->name);
1250
1251 /*
1252 * Permanent contacts, since we receive no notification that they
1253 * are gone, follow the same approach as AORs. We create a copy
1254 * of the existing container and any reused contacts are removed
1255 * from it. Any contacts remaining in the container after
1256 * processing no longer exist so we need to remove their state.
1257 */
1258 existing_contacts = ao2_container_clone(aor_options->contacts, 0);
1259 if (!existing_contacts) {
1260 ast_log(LOG_WARNING, "Synchronization of AOR '%s' failed for qualify, retaining existing state\n",
1261 aor_options->name);
1262 return;
1263 }
1264
1266 NULL, NULL);
1267
1268 /* Process permanent contacts */
1269 if (aor->permanent_contacts) {
1270 iter = ao2_iterator_init(aor->permanent_contacts, 0);
1271 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1272 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1274 ao2_link(aor_options->contacts, contact);
1275 }
1276 ao2_iterator_destroy(&iter);
1277 }
1278
1279 /*
1280 * If this is newly added we need to see if there are any
1281 * existing dynamic contacts to add. Ones that are added
1282 * after creation will occur as a result of the contact
1283 * observer creation callback.
1284 */
1285 if (is_new) {
1286 size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
1287 char prefix[prefix_len + 1];
1288 struct ao2_container *contacts;
1289
1290 sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
1292 prefix, prefix_len);
1293 if (contacts) {
1294 ao2_container_dup(aor_options->dynamic_contacts, contacts, 0);
1295 ao2_ref(contacts, -1);
1296 }
1297 }
1298
1299 /* Process dynamic contacts */
1300 iter = ao2_iterator_init(aor_options->dynamic_contacts, 0);
1301 for (; (contact = ao2_iterator_next(&iter)); ao2_ref(contact, -1)) {
1302 ao2_find(existing_contacts, ast_sorcery_object_get_id(contact),
1304 ao2_link(aor_options->contacts, contact);
1305 }
1306 ao2_iterator_destroy(&iter);
1307
1308 /* Any contacts left no longer exist, so raise events and make them disappear */
1309 ao2_callback(existing_contacts, OBJ_NODATA | OBJ_UNLINK,
1310 sip_options_remove_contact, aor_options);
1311 ao2_ref(existing_contacts, -1);
1312
1313 /*
1314 * Update the available count if we transition between qualified
1315 * and unqualified. In the qualified case we need to start with
1316 * 0 available as the qualify process will take care of it. In
1317 * the unqualified case it is based on the number of contacts
1318 * present.
1319 */
1320 if (!aor->qualify_frequency) {
1321 ao2_callback(aor_options->contacts, OBJ_NODATA,
1323 aor_options->available = ao2_container_count(aor_options->contacts);
1324 ast_debug(3, "AOR '%s' is unqualified, number of available contacts is therefore '%d'\n",
1325 aor_options->name, aor_options->available);
1326 } else if (!aor_options->qualify_frequency) {
1327 ao2_callback(aor_options->contacts, OBJ_NODATA,
1329 aor_options->available = 0;
1330 ast_debug(3, "AOR '%s' has transitioned from unqualified to qualified, reset available contacts to 0\n",
1331 aor_options->name);
1332 } else {
1333 /*
1334 * Count the number of AVAILABLE qualified contacts to ensure
1335 * the count is in sync with reality.
1336 */
1337 aor_options->available = 0;
1338 ao2_callback(aor_options->contacts, OBJ_NODATA,
1340 }
1341
1342 aor_options->authenticate_qualify = aor->authenticate_qualify;
1343 aor_options->qualify_2xx_only = aor->qualify_2xx_only;
1344 aor_options->qualify_timeout = aor->qualify_timeout;
1345
1346 /*
1347 * If we need to stop or start the scheduled callback then do so.
1348 * This occurs due to the following:
1349 * 1. The qualify frequency has changed
1350 * 2. Contacts were added when previously there were none
1351 * 3. There are no contacts but previously there were some
1352 */
1353 if (aor_options->qualify_frequency != aor->qualify_frequency
1354 || (!aor_options->sched_task && ao2_container_count(aor_options->contacts))
1355 || (aor_options->sched_task && !ao2_container_count(aor_options->contacts))) {
1356 if (aor_options->sched_task) {
1358 ao2_ref(aor_options->sched_task, -1);
1359 aor_options->sched_task = NULL;
1360 }
1361
1362 /* If there is still a qualify frequency then schedule this */
1363 aor_options->qualify_frequency = aor->qualify_frequency;
1364 if (aor_options->qualify_frequency
1365 && ao2_container_count(aor_options->contacts)) {
1366 aor_options->sched_task = ast_sip_schedule_task(aor_options->serializer,
1370 if (!aor_options->sched_task) {
1371 ast_log(LOG_ERROR, "Unable to schedule qualify for contacts of AOR '%s'\n",
1372 aor_options->name);
1373 }
1374 }
1375 }
1376
1377 ast_debug(3, "AOR '%s' now has %d available contacts\n", aor_options->name,
1378 aor_options->available);
1379}
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_MULTIPLE
Definition astobj2.h:1049
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
Definition astobj2.h:1419
struct ast_sip_sched_task * ast_sip_schedule_task(struct ast_taskprocessor *serializer, int interval, ast_sip_task sip_task, const char *name, void *task_data, enum ast_sip_scheduler_task_flags flags)
Schedule a task to run in the res_pjsip taskpool.
@ AST_SIP_SCHED_TASK_DATA_AO2
Definition res_pjsip.h:2274
@ AST_SIP_SCHED_TASK_VARIABLE
Definition res_pjsip.h:2257
static char prefix[MAX_PREFIX]
Definition http.c:145
static int sip_options_contact_status_available_count(void *obj, void *arg, int flags)
Count AVAILABLE qualified contacts.
static int sip_options_set_contact_status_unqualified(void *obj, void *arg, int flags)
Transition the contact status to unqualified mode.
static int sip_options_set_contact_status_qualified(void *obj, void *arg, int flags)
Transition the contact status to qualified mode.
static int sip_options_determine_initial_qualify_time(int qualify_frequency)
Determine an initial time for scheduling AOR qualifying.
struct ao2_container * ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
Retrieve multiple objects whose id begins with the specified prefix.
Definition sorcery.c:2053
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
double qualify_timeout
Definition res_pjsip.h:508
int qualify_2xx_only
Definition res_pjsip.h:514
struct ao2_container * permanent_contacts
Definition res_pjsip.h:504
int authenticate_qualify
Definition res_pjsip.h:498
unsigned int qualify_frequency
Definition res_pjsip.h:496
unsigned int available
The number of available contacts on this AOR.
const char * ast_taskprocessor_name(struct ast_taskprocessor *tps)
Return the name of the taskprocessor singleton.

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

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

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

2803{
2804 struct sip_options_aor *aor_options = obj;
2805
2806 ast_debug(2, "Cleaning up AOR '%s' for shutdown\n", aor_options->name);
2807
2808 aor_options->qualify_frequency = 0;
2809 if (aor_options->sched_task) {
2811 ao2_ref(aor_options->sched_task, -1);
2812 aor_options->sched_task = NULL;
2813 }
2815
2816 return 0;
2817}
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition vector.h:653

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

Referenced by sip_options_cleanup_task().

◆ sip_options_cleanup_task()

static int sip_options_cleanup_task ( void *  obj)
static

Management task to clean up the environment.

Note
Run by management_serializer

Definition at line 2823 of file pjsip_options.c.

2824{
2825 struct ao2_iterator it_aor;
2826 struct sip_options_aor *aor_options;
2827
2828 if (!sip_options_aors) {
2829 /* Nothing to do */
2830 return 0;
2831 }
2832
2834 for (; (aor_options = ao2_iterator_next(&it_aor)); ao2_ref(aor_options, -1)) {
2836 sip_options_cleanup_aor_task, aor_options);
2837 }
2838 ao2_iterator_destroy(&it_aor);
2839
2840 return 0;
2841}
@ 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 2157 of file pjsip_options.c.

2158{
2160
2161 task_data.contact = obj;
2162 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2164
2165 if (has_qualify_changed(task_data.contact, task_data.aor_options)) {
2166 struct ast_sip_aor *aor;
2167
2169 task_data.contact->aor);
2170 if (aor) {
2171 ast_debug(3, "AOR '%s' qualify options have been modified. Synchronize an AOR local state\n",
2172 task_data.contact->aor);
2174 ao2_ref(aor, -1);
2175 }
2176 }
2177
2178 if (!task_data.aor_options) {
2179 return 0;
2180 }
2181
2182 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2184 ao2_ref(task_data.aor_options, -1);
2185
2186 return 0;
2187}
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 2097 of file pjsip_options.c.

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

835{
836 struct sip_options_contact_callback_data *contact_callback_data;
837
838 contact_callback_data = ao2_alloc_options(sizeof(*contact_callback_data),
840 if (!contact_callback_data) {
841 return NULL;
842 }
843
844 contact_callback_data->contact = ao2_bump(contact);
845 contact_callback_data->aor_options = ao2_bump(aor_options);
846 contact_callback_data->rtt_start = ast_tvnow();
847
848 return contact_callback_data;
849}
#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 824 of file pjsip_options.c.

825{
826 struct sip_options_contact_callback_data *contact_callback_data = obj;
827
828 ao2_cleanup(contact_callback_data->contact);
829 ao2_cleanup(contact_callback_data->aor_options);
830}

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

2317{
2319
2320 task_data.contact = obj;
2321 task_data.aor_options = ao2_find(sip_options_aors, task_data.contact->aor,
2323 if (!task_data.aor_options) {
2324 /* For contacts that are deleted we don't really care if there is no AOR locally */
2325 return 0;
2326 }
2327
2328 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
2330 ao2_ref(task_data.aor_options, -1);
2331
2332 return 0;
2333}
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 2276 of file pjsip_options.c.

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

1210{
1211 struct ast_sip_contact *contact = obj;
1212 unsigned int *available = arg;
1213 struct ast_sip_contact_status *contact_status;
1214
1215 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1216 if (!contact_status) {
1217 return 0;
1218 }
1219
1220 /* Count qualified available contacts. */
1221 switch (contact_status->status) {
1222 case AVAILABLE:
1223 ++*available;
1224 break;
1225 case UNAVAILABLE:
1226 case UNKNOWN:
1227 case CREATED:
1228 case REMOVED:
1229 break;
1230 }
1231
1232 ao2_ref(contact_status, -1);
1233
1234 return 0;
1235}
static int available(struct dahdi_pvt **pvt, int is_specific_channel)

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

Referenced by sip_options_apply_aor_configuration().

◆ sip_options_contact_status_notify_task()

static int sip_options_contact_status_notify_task ( void *  obj)
static

Task to notify an AOR of a contact status change.

Note
Run by aor_options->serializer

Definition at line 661 of file pjsip_options.c.

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

450{
451 struct ast_taskprocessor *mgmt_serializer = management_serializer;
452
453 if (mgmt_serializer) {
454 ao2_ref(contact_status, +1);
456 contact_status)) {
457 ao2_ref(contact_status, -1);
458 }
459 }
460}
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 403 of file pjsip_options.c.

404{
405 /*
406 * Replace duplicate objects so we can update the immutable
407 * contact status objects by simply linking in a new object.
408 */
411 ast_sip_contact_status_hash_fn, ast_sip_contact_status_sort_fn,
412 ast_sip_contact_status_cmp_fn);
413}
@ 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 2200 of file pjsip_options.c.

2201{
2203 struct ast_sip_contact_status *contact_status;
2204
2205 contact_status = ast_sip_get_contact_status(task_data->contact);
2206 if (contact_status) {
2207 switch (contact_status->status) {
2208 case CREATED:
2209 case UNAVAILABLE:
2210 case AVAILABLE:
2211 case UNKNOWN:
2212 /* Refresh the ContactStatus AMI events. */
2213 sip_options_contact_status_update(contact_status);
2214 break;
2215 case REMOVED:
2216 break;
2217 }
2218 ao2_ref(contact_status, -1);
2219 }
2220
2221 ao2_ref(task_data->contact, -1);
2222 ao2_ref(task_data->aor_options, -1);
2224 return 0;
2225}

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

1096{
1097 int initial_interval;
1098 int max_time = ast_sip_get_max_initial_qualify_time();
1099
1100 if (max_time && max_time < qualify_frequency) {
1101 initial_interval = max_time;
1102 } else {
1103 initial_interval = qualify_frequency;
1104 }
1105
1106 initial_interval = (int)((initial_interval * 1000) * ast_random_double());
1107 return 0 < initial_interval ? initial_interval : 1;
1108}
unsigned int ast_sip_get_max_initial_qualify_time(void)
Retrieve the system max initial qualify time.
#define ast_random_double()
Returns a random number between 0.0 and 1.0, inclusive.
Definition utils.h:664

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

Referenced by sip_options_apply_aor_configuration().

◆ sip_options_endpoint_compositor_add_task()

static int sip_options_endpoint_compositor_add_task ( void *  obj)
static

Task which adds an AOR to an endpoint state compositor.

Note
Run by aor_options->serializer

Definition at line 1529 of file pjsip_options.c.

1530{
1532
1533 ast_debug(3, "Adding endpoint compositor '%s' to AOR '%s'\n",
1534 task_data->endpoint_state_compositor->name, task_data->aor_options->name);
1535
1536 ao2_ref(task_data->endpoint_state_compositor, +1);
1537 if (AST_VECTOR_APPEND(&task_data->aor_options->compositors,
1538 task_data->endpoint_state_compositor)) {
1539 /* Failed to add so no need to update the endpoint status. Nothing changed. */
1540 ao2_ref(task_data->endpoint_state_compositor, -1);
1541 return 0;
1542 }
1543
1544 ao2_lock(task_data->endpoint_state_compositor);
1546 task_data->aor_options->name,
1547 task_data->aor_options->available ? AVAILABLE : UNAVAILABLE);
1548 ao2_unlock(task_data->endpoint_state_compositor);
1549
1550 return 0;
1551}
static void sip_options_update_endpoint_state_compositor_aor(struct sip_options_endpoint_state_compositor *endpoint_state_compositor, const char *name, enum ast_sip_contact_status_type status)
Update the AOR status on an endpoint state compositor.
Task details for adding an AOR to an endpoint state compositor.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267

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

Referenced by sip_options_synchronize_endpoint().

◆ sip_options_endpoint_compositor_remove_task()

static int sip_options_endpoint_compositor_remove_task ( void *  obj)
static

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

Note
Run by aor_options->serializer

Definition at line 1557 of file pjsip_options.c.

1558{
1560 int i;
1561
1562 ast_debug(3, "Removing endpoint compositor '%s' from AOR '%s'\n",
1563 task_data->endpoint_state_compositor->name,
1564 task_data->aor_options->name);
1565
1566 for (i = 0; i < AST_VECTOR_SIZE(&task_data->aor_options->compositors); ++i) {
1567 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1568
1569 endpoint_state_compositor = AST_VECTOR_GET(&task_data->aor_options->compositors, i);
1570 if (endpoint_state_compositor != task_data->endpoint_state_compositor) {
1571 continue;
1572 }
1573
1574 AST_VECTOR_REMOVE(&task_data->aor_options->compositors, i, 0);
1575 ao2_ref(endpoint_state_compositor, -1);
1576 break;
1577 }
1578
1579 return 0;
1580}
Structure which contains composites information for endpoint state.
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition vector.h:440
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708

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

1866{
1867 struct ast_sip_endpoint *endpoint = obj;
1868 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1869
1870 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1872 if (!endpoint_state_compositor) {
1873 return 0;
1874 }
1875
1876 ast_debug(3, "Endpoint '%s' has been deleted, removing endpoint state compositor from AORs\n",
1877 ast_sorcery_object_get_id(endpoint));
1878 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1879 ao2_ref(endpoint_state_compositor, -1);
1880
1881 return 0;
1882}
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 1895 of file pjsip_options.c.

1896{
1897 struct ast_sip_endpoint *endpoint = obj;
1898 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1899
1900 ast_debug(3, "Endpoint '%s' has been created or modified, updating state\n",
1901 ast_sorcery_object_get_id(endpoint));
1902
1903 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1905 if (endpoint_state_compositor) {
1906 /* Unlink the AORs currently feeding the endpoint. */
1907 sip_options_endpoint_unlink_aor_feeders(endpoint, endpoint_state_compositor);
1908 ao2_ref(endpoint_state_compositor, -1);
1909 }
1910
1911 /* Connect the AORs that now feed the endpoint. */
1913 return 0;
1914}

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

1461{
1462 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1463
1464 ao2_cleanup(endpoint_state_compositor->aor_statuses);
1465}
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 1474 of file pjsip_options.c.

1475{
1476 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
1477
1479 endpoint_state_compositor = ao2_find(sip_options_endpoint_state_compositors,
1481 if (endpoint_state_compositor) {
1483 return endpoint_state_compositor;
1484 }
1485
1486 endpoint_state_compositor = ao2_alloc(sizeof(*endpoint_state_compositor)
1487 + strlen(ast_sorcery_object_get_id(endpoint)) + 1,
1489 if (!endpoint_state_compositor) {
1491 return NULL;
1492 }
1493
1494 /*
1495 * NOTE: The endpoint_state_compositor->aor_statuses container is
1496 * externally protected by the endpoint_state_compositor lock.
1497 */
1498 endpoint_state_compositor->aor_statuses = ao2_container_alloc_hash(
1500 sip_options_endpoint_aor_status_hash_fn, NULL,
1501 sip_options_endpoint_aor_status_cmp_fn);
1502 if (!endpoint_state_compositor->aor_statuses) {
1504 ao2_ref(endpoint_state_compositor, -1);
1505 return NULL;
1506 }
1507
1508 strcpy(endpoint_state_compositor->name, ast_sorcery_object_get_id(endpoint)); /* SAFE */
1509
1510 ao2_link_flags(sip_options_endpoint_state_compositors, endpoint_state_compositor,
1511 OBJ_NOLOCK);
1513
1514 return endpoint_state_compositor;
1515}
#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 1821 of file pjsip_options.c.

1823{
1824 struct ao2_iterator it_aor_statuses;
1825 struct sip_options_endpoint_aor_status *aor_status;
1827 .endpoint_state_compositor = endpoint_state_compositor,
1828 };
1829
1832
1833 /* Unlink AOR feeders pointing to endpoint */
1835 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
1836 task_data.aor_options = ao2_find(sip_options_aors, aor_status->name,
1838 if (!task_data.aor_options) {
1839 continue;
1840 }
1841
1842 ast_debug(3, "Removing endpoint state compositor '%s' from AOR '%s'\n",
1843 ast_sorcery_object_get_id(endpoint), aor_status->name);
1845 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1848 ao2_ref(task_data.aor_options, -1);
1849 }
1850 ao2_iterator_destroy(&it_aor_statuses);
1851
1852 /*
1853 * We do not need to remove the AOR feeder status memory from the
1854 * aor_statuses container. The endpoint_state_compositor is about
1855 * to die and do it for us.
1856 */
1857
1859}
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 557 of file pjsip_options.c.

559{
560 struct ao2_iterator it_aor_statuses;
561 struct sip_options_endpoint_aor_status *aor_status;
563
564 it_aor_statuses = ao2_iterator_init(endpoint_state_compositor->aor_statuses, 0);
565 for (; (aor_status = ao2_iterator_next(&it_aor_statuses)); ao2_ref(aor_status, -1)) {
566 if (aor_status->available) {
568 ao2_ref(aor_status, -1);
569 break;
570 }
571 }
572 ao2_iterator_destroy(&it_aor_statuses);
573
574 return state;
575}
ast_endpoint_state
Valid states for an endpoint.
Definition endpoints.h:51
@ AST_ENDPOINT_OFFLINE
Definition endpoints.h:55
@ AST_ENDPOINT_ONLINE
Definition endpoints.h:57
char available
The last contributed available status of the named AOR (1 if available, 0 if not available)

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

Referenced by sip_options_synchronize_endpoint(), and sip_options_update_endpoint_state_compositor_aor().

◆ sip_options_init_task()

static int sip_options_init_task ( void *  mgmt_serializer)
static

Management task to finish setting up the environment.

Note
Run by management_serializer

Definition at line 2880 of file pjsip_options.c.

2881{
2882 management_serializer = mgmt_serializer;
2883
2886 return -1;
2887 }
2890 return -1;
2891 }
2894 return -1;
2895 }
2896
2898
2899 return 0;
2900}
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition sorcery.c:2455

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

Referenced by ast_res_pjsip_init_options_handling().

◆ sip_options_notify_endpoint_state_compositors()

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

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

Definition at line 635 of file pjsip_options.c.

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

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

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

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

853{
854 struct ast_sip_contact *contact = obj;
855 struct sip_options_aor *aor_options = arg;
856 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
857 pjsip_tx_data *tdata;
858 struct ast_sip_contact_status *contact_status;
859 struct sip_options_contact_callback_data *contact_callback_data;
860
861 ast_debug(3, "Qualifying contact '%s' on AOR '%s'\n",
863
865 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
867 }
868 if (!endpoint && AST_VECTOR_SIZE(&aor_options->compositors)) {
869 struct sip_options_endpoint_state_compositor *endpoint_state_compositor;
870
871 endpoint_state_compositor = AST_VECTOR_GET(&aor_options->compositors, 0);
872 endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint",
873 endpoint_state_compositor->name);
874 }
875 if (!endpoint) {
876 ast_debug(3, "Could not find an endpoint to qualify contact '%s' on AOR '%s'\n",
877 ast_sorcery_object_get_id(contact), aor_options->name);
878 return 0;
879 }
880
881 if (ast_sip_create_request("OPTIONS", NULL, endpoint, NULL, contact, &tdata)) {
882 ast_log(LOG_ERROR, "Unable to create request to qualify contact %s on AOR %s\n",
883 contact->uri, aor_options->name);
884 return 0;
885 }
886
887 /* If an outbound proxy is specified set it on this request */
888 if (!ast_strlen_zero(contact->outbound_proxy) &&
890 ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n",
891 contact->uri);
892 pjsip_tx_data_dec_ref(tdata);
893 return 0;
894 }
895
896 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
897 if (!contact_status) {
898 ast_log(LOG_ERROR, "Unable to retrieve contact status information for contact %s on AOR %s\n",
899 contact->uri, aor_options->name);
900 pjsip_tx_data_dec_ref(tdata);
901 return 0;
902 }
903 ao2_ref(contact_status, -1);
904
905 contact_callback_data = sip_options_contact_callback_data_alloc(contact, aor_options);
906 if (!contact_callback_data) {
907 ast_log(LOG_ERROR, "Unable to create object to contain callback data for contact %s on AOR %s\n",
908 contact->uri, aor_options->name);
909 pjsip_tx_data_dec_ref(tdata);
910 return 0;
911 }
912
913 if (ast_sip_send_out_of_dialog_request(tdata, endpoint,
914 (int)(aor_options->qualify_timeout * 1000), contact_callback_data,
916 ast_log(LOG_ERROR, "Unable to send request to qualify contact %s on AOR %s\n",
917 contact->uri, aor_options->name);
918 ao2_ref(contact_callback_data, -1);
919 }
920
921 return 0;
922}
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:1936
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:1990
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
Definition res_pjsip.c:1433
const ast_string_field endpoint_name
Definition res_pjsip.h:414

References ao2_cleanup, ao2_ref, sip_options_contact_callback_data::aor_options, ast_debug, ast_log, ast_res_pjsip_find_or_create_contact_status(), ast_sip_create_request(), ast_sip_get_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 1084 of file pjsip_options.c.

1085{
1086 struct ast_sip_contact *contact = obj;
1087 struct sip_options_aor *aor_options = arg;
1088
1089 sip_options_remove_contact_status(aor_options, contact);
1090
1091 return CMP_MATCH;
1092}
@ 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 1011 of file pjsip_options.c.

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

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

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

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

1183{
1184 struct ast_sip_contact *contact = obj;
1185 struct ast_sip_contact_status *contact_status;
1186
1187 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1188 if (!contact_status) {
1189 return 0;
1190 }
1191
1192 switch (contact_status->status) {
1193 case AVAILABLE:
1195 break;
1196 case UNAVAILABLE:
1197 case UNKNOWN:
1198 case CREATED:
1199 case REMOVED:
1200 break;
1201 }
1202
1203 ao2_ref(contact_status, -1);
1204
1205 return 0;
1206}
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 1155 of file pjsip_options.c.

1156{
1157 struct ast_sip_contact *contact = obj;
1158 struct ast_sip_contact_status *contact_status;
1159
1160 contact_status = ast_res_pjsip_find_or_create_contact_status(contact);
1161 if (!contact_status) {
1162 return 0;
1163 }
1164
1165 switch (contact_status->status) {
1166 case AVAILABLE:
1167 case UNAVAILABLE:
1168 case UNKNOWN:
1169 sip_options_set_contact_status(contact_status, CREATED);
1170 break;
1171 case CREATED:
1172 case REMOVED:
1173 break;
1174 }
1175
1176 ao2_ref(contact_status, -1);
1177
1178 return 0;
1179}

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

1808{
1810 .reload = reload,
1811 };
1812
1814 &task_data);
1815}
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 1423 of file pjsip_options.c.

1424{
1426 .aor = obj,
1427 .existing = arg,
1428 };
1429
1430 task_data.aor_options = ao2_find(sip_options_aors,
1432 if (!task_data.aor_options) {
1433 task_data.aor_options = sip_options_aor_alloc(task_data.aor);
1434 if (!task_data.aor_options) {
1435 return 0;
1436 }
1437
1438 task_data.added = 1;
1439
1440 /* Nothing is aware of this AOR yet so we can just update it in this thread */
1442 ao2_link(sip_options_aors, task_data.aor_options);
1443 } else {
1444 /* This AOR already exists so we have to do manipulation in its serializer */
1445 ast_sip_push_task_wait_serializer(task_data.aor_options->serializer,
1447 }
1448
1449 ao2_ref(task_data.aor_options, -1);
1450
1451 if (task_data.existing) {
1454 }
1455
1456 return 0;
1457}
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 1385 of file pjsip_options.c.

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

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

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

1752{
1754 struct ao2_container *existing = NULL;
1755 struct ao2_container *objects;
1756
1757 /*
1758 * When reloading we keep track of the existing AORs so we can
1759 * terminate old ones that are no longer referenced or used.
1760 */
1761 if (task_data->reload) {
1763 if (!existing) {
1764 return 0;
1765 }
1766 }
1767
1770 if (objects) {
1771 /* Go through the returned AORs and synchronize with our local state */
1773 ao2_ref(objects, -1);
1774 }
1775
1776 /*
1777 * Any AORs remaining in existing are no longer referenced by
1778 * the current container of AORs we retrieved, so remove them.
1779 */
1780 if (existing) {
1783 ao2_ref(existing, -1);
1784 }
1785
1788 if (objects) {
1789 /* Go through the provided endpoints and update AORs */
1791 ao2_ref(objects, -1);
1792 }
1793
1794 /*
1795 * All endpoint state compositors that don't have any AORs
1796 * feeding them information can be removed. If they end
1797 * up getting needed later they'll just be recreated.
1798 */
1802
1803 return 0;
1804}
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 1709 of file pjsip_options.c.

1710{
1711 struct sip_options_aor *aor_options = obj;
1712
1713 ast_debug(3, "AOR '%s' is no longer configured, removing it\n", aor_options->name);
1714
1716 aor_options);
1717 ao2_unlink(sip_options_aors, aor_options);
1718
1719 return CMP_MATCH;
1720}
#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 1726 of file pjsip_options.c.

1727{
1728 struct sip_options_endpoint_state_compositor *endpoint_state_compositor = obj;
1729
1730 if (ao2_container_count(endpoint_state_compositor->aor_statuses)) {
1731 return 0;
1732 }
1733
1734 /* No AORs are feeding this endpoint state compositor */
1735 ast_sip_persistent_endpoint_update_state(endpoint_state_compositor->name,
1737
1738 return CMP_MATCH;
1739}

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

1935{
1937 int available = task_data->aor_options->available;
1938
1939 ast_debug(3, "Individually updating AOR '%s' with current state of configuration and world\n",
1940 task_data->aor_options->name);
1941
1943 task_data->added);
1944
1945 if (!available && task_data->aor_options->available) {
1946 ast_debug(3, "After modifying AOR '%s' it has now become available\n",
1947 task_data->aor_options->name);
1949 } else if (available && !task_data->aor_options->available) {
1950 ast_debug(3, "After modifying AOR '%s' it has become unavailable\n",
1951 task_data->aor_options->name);
1953 }
1954
1955 return 0;
1956}

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

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

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

2055 {
2056 .created = aor_observer_modified,
2057 .updated = aor_observer_modified,
2058 .deleted = aor_observer_deleted,
2059};

Referenced by ast_res_pjsip_cleanup_options_handling(), and sip_options_init_task().

◆ cli_options

struct ast_cli_entry cli_options[]
static

Definition at line 2714 of file pjsip_options.c.

2714 {
2715 AST_CLI_DEFINE(cli_qualify, "Send an OPTIONS request to a PJSIP endpoint"),
2716 AST_CLI_DEFINE(cli_show_qualify_endpoint, "Show the current qualify options for all Aors on the PJSIP endpoint"),
2717 AST_CLI_DEFINE(cli_show_qualify_aor, "Show the PJSIP Aor current qualify options"),
2718 AST_CLI_DEFINE(cli_reload_qualify_endpoint, "Synchronize the qualify options for all Aors on the PJSIP endpoint"),
2719 AST_CLI_DEFINE(cli_reload_qualify_aor, "Synchronize the PJSIP Aor qualify options"),
2720};
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
static char * cli_reload_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_reload_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_show_qualify_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * cli_show_qualify_aor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Referenced by ast_res_pjsip_cleanup_options_handling(), and ast_res_pjsip_init_options_handling().

◆ contact_observer_callbacks

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

Observer callbacks for contacts.

Definition at line 2343 of file pjsip_options.c.

2343 {
2344 .created = contact_observer_created,
2345 .updated = contact_observer_updated,
2346 .deleted = contact_observer_deleted,
2347};

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

2794 {
2795 .format_ami = format_ami_contact_status
2796};

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

1924 {
1925 .created = endpoint_observer_modified,
1926 .updated = endpoint_observer_modified,
1927 .deleted = endpoint_observer_deleted,
1928};

Referenced by ast_res_pjsip_cleanup_options_handling(), and sip_options_init_task().

◆ management_serializer

struct ast_taskprocessor* management_serializer
static

◆ options_module

pjsip_module options_module
static

Definition at line 308 of file pjsip_options.c.

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

Referenced by ast_res_pjsip_cleanup_options_handling(), and ast_res_pjsip_init_options_handling().

◆ short_status_map

const char* short_status_map[]
static

Definition at line 323 of file pjsip_options.c.

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

Referenced by ast_sip_get_contact_short_status_label().

◆ sip_options_aors

struct ao2_container* sip_options_aors
static

◆ sip_options_contact_statuses

struct ao2_container* sip_options_contact_statuses
static

◆ sip_options_endpoint_state_compositors

struct ao2_container* sip_options_endpoint_state_compositors
static

◆ status_map

const char* status_map[]
static

Definition at line 315 of file pjsip_options.c.

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