Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Data Structures | Macros | Enumerations | Functions | Variables
res_pjsip_outbound_registration.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_cli.h"
#include "asterisk/module.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/cli.h"
#include "asterisk/stasis_system.h"
#include "asterisk/threadstorage.h"
#include "asterisk/threadpool.h"
#include "asterisk/statsd.h"
#include "res_pjsip/include/res_pjsip_private.h"
#include "asterisk/vector.h"
#include "asterisk/pbx.h"
Include dependency graph for res_pjsip_outbound_registration.c:

Go to the source code of this file.

Data Structures

struct  registration_response
 Structure for registration response. More...
 
struct  sip_ami_outbound
 
struct  sip_outbound_registration
 Outbound registration information. More...
 
struct  sip_outbound_registration_client_state
 Outbound registration client state information (persists for lifetime of regc) More...
 
struct  sip_outbound_registration_state
 Outbound registration state information (persists for lifetime that registration should exist) More...
 

Macros

#define DEFAULT_STATE_BUCKETS   53
 Default number of state container buckets. More...
 
#define LINE_PARAMETER_SIZE   8
 Size of the buffer for creating a unique string for the line. More...
 
#define MAX_UNLOAD_TIMEOUT_TIME   35 /* Seconds */
 
#define REGISTRATION_URI_FIELD_LEN   53
 
#define REREGISTER_BUFFER_TIME   10
 Amount of buffer time (in seconds) before expiration that we re-register at. More...
 

Enumerations

enum  sip_outbound_registration_status {
  SIP_REGISTRATION_UNREGISTERED = 0 , SIP_REGISTRATION_REGISTERED , SIP_REGISTRATION_REJECTED_TEMPORARY , SIP_REGISTRATION_REJECTED_PERMANENT ,
  SIP_REGISTRATION_STOPPING , SIP_REGISTRATION_STOPPED
}
 Various states that an outbound registration may be in. More...
 

Functions

static void __init_register_callback_invoked (void)
 Some thread local storage used to determine if the running thread invoked the callback. More...
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int add_configured_supported_headers (struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
 Helper function to add configured supported headers. More...
 
static int add_to_supported_header (pjsip_tx_data *tdata, pj_str_t *name)
 Helper function to add string to Supported header. More...
 
static int ami_outbound_registration_detail (void *obj, void *arg, int flags)
 
static int ami_outbound_registration_task (void *obj)
 
static int ami_register (struct mansession *s, const struct message *m)
 
static int ami_show_outbound_registrations (struct mansession *s, const struct message *m)
 
static int ami_unregister (struct mansession *s, const struct message *m)
 
static AO2_GLOBAL_OBJ_STATIC (current_states)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void auth_observer (const char *type)
 
static int can_reuse_registration (struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
 
static void cancel_registration (struct sip_outbound_registration_client_state *client_state)
 Helper function which cancels the timer on a client. More...
 
static int check_state (void *obj, void *arg, int flags)
 
static char * cli_complete_registration (const char *line, const char *word, int pos, int state)
 
static struct ao2_containercli_get_container (const char *regex)
 
static int cli_iterator (void *container, ao2_callback_fn callback, void *args)
 
static int cli_print_body (void *obj, void *arg, int flags)
 
static int cli_print_header (void *obj, void *arg, int flags)
 
static char * cli_register (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void * cli_retrieve_by_id (const char *id)
 
static char * cli_unregister (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static const char * fetch_google_access_token (const struct ast_sip_auth *auth)
 Get google oauth2 access token using refresh token. More...
 
static struct ao2_containerget_registrations (void)
 
static struct sip_outbound_registration_stateget_state (const char *id)
 
static struct pjsip_param * get_uri_option_line (const void *uri)
 
static int handle_client_registration (void *data)
 Callback function for registering. More...
 
static int handle_client_state_destruction (void *data)
 Callback function for unregistering (potentially) and destroying state. More...
 
static int handle_registration_response (void *data)
 Callback function for handling a response to a registration attempt. More...
 
static struct ast_sip_endpointline_identify (pjsip_rx_data *rdata)
 Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing registration. More...
 
static int line_identify_relationship (void *obj, void *arg, int flags)
 Callback function for matching an outbound registration based on line. More...
 
static int load_module (void)
 
static int monitor_matcher (void *a, void *b)
 
static char * my_cli_traverse_objects (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static void network_change_stasis_cb (void *data, struct stasis_subscription *sub, struct stasis_message *message)
 
static int outbound_auth_handler (const struct aco_option *opt, struct ast_variable *var, void *obj)
 
static int outbound_auths_to_str (const void *obj, const intptr_t *args, char **buf)
 
static int outbound_auths_to_var_list (const void *obj, struct ast_variable **fields)
 
static int queue_register (struct sip_outbound_registration_state *state)
 
static int queue_unregister (struct sip_outbound_registration_state *state)
 
static pj_status_t registration_client_send (struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
 Helper function which sends a message and cleans up, if needed, on failure. More...
 
static void registration_deleted_observer (const void *obj)
 
static void registration_loaded_observer (const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
 
static void registration_response_destroy (void *obj)
 Registration response structure destructor. More...
 
static int registration_state_cmp (void *obj, void *arg, int flags)
 comparator function for state objects More...
 
static int registration_state_hash (const void *obj, const int flags)
 hashing function for state objects More...
 
static void registration_transport_monitor_setup (pjsip_transport *transport, const char *registration_name)
 
static void registration_transport_shutdown_cb (void *obj)
 
static int reload_module (void)
 
static void reregister_all (void)
 
static int reregister_immediately_cb (void *obj)
 
static void save_response_fields_to_transport (struct registration_response *response)
 
static void schedule_registration (struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
 Helper function which sets up the timer to re-register in a specific amount of time. More...
 
static void schedule_retry (struct registration_response *response, unsigned int interval, const char *server_uri, const char *client_uri)
 
static int set_outbound_initial_authentication_credentials (pjsip_regc *regc, const struct ast_sip_auth_vector *auth_vector)
 
static int sip_dialog_create_contact (pj_pool_t *pool, pj_str_t *contact, const char *user, const pj_str_t *target, pjsip_tpselector *selector, const char *line, const char *header_params)
 Helper function which populates a pj_str_t with a contact header. More...
 
static void * sip_outbound_registration_alloc (const char *name)
 Allocator function for registration information. More...
 
static int sip_outbound_registration_apply (const struct ast_sorcery *sorcery, void *obj)
 Apply function which finds or allocates a state structure. More...
 
static void sip_outbound_registration_client_state_destroy (void *obj)
 Destructor function for client registration state. More...
 
static void sip_outbound_registration_destroy (void *obj)
 Destructor function for registration information. More...
 
static int sip_outbound_registration_is_temporal (unsigned int code, struct sip_outbound_registration_client_state *client_state)
 Helper function which determines if a response code is temporal or not. More...
 
static int sip_outbound_registration_perform (void *data)
 Helper function which performs a single registration. More...
 
static int sip_outbound_registration_regc_alloc (void *data)
 Helper function that allocates a pjsip registration client and configures it. More...
 
static void sip_outbound_registration_response_cb (struct pjsip_regc_cbparam *param)
 Callback function for outbound registration client. More...
 
static struct sip_outbound_registration_statesip_outbound_registration_state_alloc (struct sip_outbound_registration *registration)
 Allocator function for registration state. More...
 
static void sip_outbound_registration_state_destroy (void *obj)
 Destructor function for registration state. More...
 
static const char * sip_outbound_registration_status_str (enum sip_outbound_registration_status state)
 
static void sip_outbound_registration_timer_cb (pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
 Timer callback function, used just for registrations. More...
 
static int unload_module (void)
 
static void unregister_all (void)
 
static int unregister_task (void *obj)
 
static void update_client_state_status (struct sip_outbound_registration_client_state *client_state, enum sip_outbound_registration_status status)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Outbound Registration Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", .optional_modules = "res_statsd", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_sip_cli_formatter_entrycli_formatter
 
static struct ast_cli_entry cli_outbound_registration []
 
static struct ast_sip_endpoint_identifier line_identifier
 
static struct stasis_subscriptionnetwork_change_sub
 
static const struct ast_sorcery_observer observer_callbacks_auth
 
static const struct ast_sorcery_instance_observer observer_callbacks_registrations
 
static pj_str_t OUTBOUND_NAME = { "outbound", 8 }
 
static pj_str_t PATH_NAME = { "path", 4 }
 
static struct ast_threadstorage register_callback_invoked = { .once = PTHREAD_ONCE_INIT , .key_init = __init_register_callback_invoked , .custom_init = NULL , }
 
static const struct ast_sorcery_observer registration_observer
 
static struct ast_serializer_shutdown_groupshutdown_group
 

Macro Definition Documentation

◆ DEFAULT_STATE_BUCKETS

#define DEFAULT_STATE_BUCKETS   53

Default number of state container buckets.

Definition at line 412 of file res_pjsip_outbound_registration.c.

◆ LINE_PARAMETER_SIZE

#define LINE_PARAMETER_SIZE   8

Size of the buffer for creating a unique string for the line.

Definition at line 251 of file res_pjsip_outbound_registration.c.

◆ MAX_UNLOAD_TIMEOUT_TIME

#define MAX_UNLOAD_TIMEOUT_TIME   35 /* Seconds */

Time needs to be long enough for a transaction to timeout if nothing replies.

Definition at line 406 of file res_pjsip_outbound_registration.c.

◆ REGISTRATION_URI_FIELD_LEN

#define REGISTRATION_URI_FIELD_LEN   53

◆ REREGISTER_BUFFER_TIME

#define REREGISTER_BUFFER_TIME   10

Amount of buffer time (in seconds) before expiration that we re-register at.

Definition at line 248 of file res_pjsip_outbound_registration.c.

Enumeration Type Documentation

◆ sip_outbound_registration_status

Various states that an outbound registration may be in.

Enumerator
SIP_REGISTRATION_UNREGISTERED 

Currently unregistered.

SIP_REGISTRATION_REGISTERED 

Registered, yay!

SIP_REGISTRATION_REJECTED_TEMPORARY 

Registration was rejected, but response was temporal.

SIP_REGISTRATION_REJECTED_PERMANENT 

Registration was rejected, permanently.

SIP_REGISTRATION_STOPPING 

Registration is stopping.

SIP_REGISTRATION_STOPPED 

Registration has been stopped.

Definition at line 254 of file res_pjsip_outbound_registration.c.

254  {
255  /*! \brief Currently unregistered */
257  /*! \brief Registered, yay! */
259  /*! \brief Registration was rejected, but response was temporal */
261  /*! \brief Registration was rejected, permanently */
263  /*! \brief Registration is stopping. */
265  /*! \brief Registration has been stopped */
267 };
@ SIP_REGISTRATION_REGISTERED
Registered, yay!
@ SIP_REGISTRATION_REJECTED_PERMANENT
Registration was rejected, permanently.
@ SIP_REGISTRATION_STOPPED
Registration has been stopped.
@ SIP_REGISTRATION_STOPPING
Registration is stopping.
@ SIP_REGISTRATION_UNREGISTERED
Currently unregistered.
@ SIP_REGISTRATION_REJECTED_TEMPORARY
Registration was rejected, but response was temporal.

Function Documentation

◆ __init_register_callback_invoked()

static void __init_register_callback_invoked ( void  )
static

Some thread local storage used to determine if the running thread invoked the callback.

Definition at line 245 of file res_pjsip_outbound_registration.c.

254 {

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2624 of file res_pjsip_outbound_registration.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2624 of file res_pjsip_outbound_registration.c.

◆ add_configured_supported_headers()

static int add_configured_supported_headers ( struct sip_outbound_registration_client_state client_state,
pjsip_tx_data *  tdata 
)
static

Helper function to add configured supported headers.

Definition at line 650 of file res_pjsip_outbound_registration.c.

651 {
652  if (client_state->support_path) {
653  if (!add_to_supported_header(tdata, &PATH_NAME)) {
654  return 0;
655  }
656  }
657 
658  if (client_state->support_outbound) {
659  if (!add_to_supported_header(tdata, &OUTBOUND_NAME)) {
660  return 0;
661  }
662  }
663 
664  return 1;
665 }
static pj_str_t PATH_NAME
static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)
Helper function to add string to Supported header.
static pj_str_t OUTBOUND_NAME
unsigned int support_outbound
Determines whether SIP Outbound support should be advertised.
unsigned int support_path
Determines whether SIP Path support should be advertised.

References add_to_supported_header(), OUTBOUND_NAME, PATH_NAME, sip_outbound_registration_client_state::support_outbound, and sip_outbound_registration_client_state::support_path.

Referenced by handle_client_registration(), handle_client_state_destruction(), and unregister_task().

◆ add_to_supported_header()

static int add_to_supported_header ( pjsip_tx_data *  tdata,
pj_str_t *  name 
)
static

Helper function to add string to Supported header.

Definition at line 615 of file res_pjsip_outbound_registration.c.

616 {
617  pjsip_supported_hdr *hdr;
618  int i;
619 
620  hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
621  if (!hdr) {
622  /* insert a new Supported header */
623  hdr = pjsip_supported_hdr_create(tdata->pool);
624  if (!hdr) {
625  pjsip_tx_data_dec_ref(tdata);
626  return 0;
627  }
628 
629  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
630  }
631 
632  /* Don't add the value if it's already there */
633  for (i = 0; i < hdr->count; ++i) {
634  if (pj_stricmp(&hdr->values[i], name) == 0) {
635  return 1;
636  }
637  }
638 
639  if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
640  return 0;
641  }
642 
643  /* add on to the existing Supported header */
644  pj_strassign(&hdr->values[hdr->count++], name);
645 
646  return 1;
647 }
static const char name[]
Definition: format_mp3.c:68
#define NULL
Definition: resample.c:96

References name, and NULL.

Referenced by add_configured_supported_headers().

◆ ami_outbound_registration_detail()

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

Definition at line 2169 of file res_pjsip_outbound_registration.c.

2170 {
2171  struct sip_ami_outbound *ami = arg;
2172 
2173  ami->registration = obj;
2175 }
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:1999
static int ami_outbound_registration_task(void *obj)

References sip_ami_outbound::ami, ami_outbound_registration_task(), ast_sip_push_task_wait_servant(), and NULL.

Referenced by ami_show_outbound_registrations().

◆ ami_outbound_registration_task()

static int ami_outbound_registration_task ( void *  obj)
static

Definition at line 2133 of file res_pjsip_outbound_registration.c.

2134 {
2135  struct sip_ami_outbound *ami = obj;
2136  struct ast_str *buf;
2138 
2139  buf = ast_sip_create_ami_event("OutboundRegistrationDetail", ami->ami);
2140  if (!buf) {
2141  return -1;
2142  }
2143 
2145 
2147  pjsip_regc_info info;
2148 
2149  if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
2150  ++ami->registered;
2151  } else {
2152  ++ami->not_registered;
2153  }
2154 
2155  ast_str_append(&buf, 0, "Status: %s\r\n",
2156  sip_outbound_registration_status_str(state->client_state->status));
2157 
2158  pjsip_regc_get_info(state->client_state->client, &info);
2159  ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
2160  ao2_ref(state, -1);
2161  }
2162 
2163  astman_append(ami->ami->s, "%s\r\n", ast_str_buffer(buf));
2164  ast_free(buf);
2165 
2167 }
#define ast_free(a)
Definition: astmm.h:180
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
enum sip_cc_notify_state state
Definition: chan_sip.c:966
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3087
def info(msg)
int ast_sip_format_auths_ami(const struct ast_sip_auth_vector *auths, struct ast_sip_ami *ami)
Format auth details for AMI.
Definition: config_auth.c:195
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.
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
static const char * sip_outbound_registration_status_str(enum sip_outbound_registration_status state)
static struct sip_outbound_registration_state * get_state(const char *id)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
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:1117
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
struct mansession * s
Definition: res_pjsip.h:2821
Support for dynamic strings.
Definition: strings.h:604
struct sip_outbound_registration * registration
Outbound registration state information (persists for lifetime that registration should exist)
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.

References sip_ami_outbound::ami, ao2_ref, ast_free, ast_sip_create_ami_event(), ast_sip_format_auths_ami(), ast_sip_sorcery_object_to_ami(), ast_sorcery_object_get_id(), ast_str_append(), ast_str_buffer(), astman_append(), buf, get_state(), sip_to_pjsip::info(), sip_ami_outbound::not_registered, sip_outbound_registration::outbound_auths, sip_ami_outbound::registered, sip_ami_outbound::registration, ast_sip_ami::s, sip_outbound_registration_status_str(), SIP_REGISTRATION_REGISTERED, and state.

Referenced by ami_outbound_registration_detail().

◆ ami_register()

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

Definition at line 2089 of file res_pjsip_outbound_registration.c.

2090 {
2091  const char *registration_name = astman_get_header(m, "Registration");
2093 
2094  if (ast_strlen_zero(registration_name)) {
2095  astman_send_error(s, m, "Registration parameter missing.");
2096  return 0;
2097  }
2098 
2099  if (strcmp(registration_name, "*all") == 0) {
2100  reregister_all();
2101  astman_send_ack(s, m, "Reregistrations queued.");
2102  return 0;
2103  }
2104 
2105  state = get_state(registration_name);
2106  if (!state) {
2107  astman_send_error(s, m, "Unable to retrieve registration entry\n");
2108  return 0;
2109  }
2110 
2111  /* We need to serialize the unregister and register so they need
2112  * to be queued as separate tasks.
2113  */
2114  if (queue_unregister(state)) {
2115  astman_send_ack(s, m, "Failed to queue unregistration");
2116  } else if (queue_register(state)) {
2117  astman_send_ack(s, m, "Failed to queue unregistration");
2118  } else {
2119  astman_send_ack(s, m, "Reregistration sent");
2120  }
2121 
2122  ao2_ref(state, -1);
2123  return 0;
2124 }
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3166
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3198
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:2827
static int queue_unregister(struct sip_outbound_registration_state *state)
static int queue_register(struct sip_outbound_registration_state *state)
static void reregister_all(void)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65

References ao2_ref, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), get_state(), queue_register(), queue_unregister(), reregister_all(), and state.

Referenced by load_module().

◆ ami_show_outbound_registrations()

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

Definition at line 2177 of file res_pjsip_outbound_registration.c.

2179 {
2180  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
2181  struct sip_ami_outbound ami_outbound = { .ami = &ami };
2182  struct ao2_container *regs;
2183 
2184  regs = get_registrations();
2185  if (!regs) {
2186  astman_send_error(s, m, "Unable to retrieve "
2187  "outbound registrations\n");
2188  return -1;
2189  }
2190 
2191  astman_send_listack(s, m, "Following are Events for each Outbound registration",
2192  "start");
2193 
2195 
2196  astman_send_list_complete_start(s, m, "OutboundRegistrationDetailComplete",
2197  ami_outbound.registered + ami_outbound.not_registered);
2198  astman_append(s,
2199  "Registered: %d\r\n"
2200  "NotRegistered: %d\r\n",
2201  ami_outbound.registered,
2202  ami_outbound.not_registered);
2204 
2205  ao2_ref(regs, -1);
2206  return 0;
2207 }
#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
@ 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:3208
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:3244
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3252
static int ami_outbound_registration_detail(void *obj, void *arg, int flags)
static struct ao2_container * get_registrations(void)
Generic container type.
AMI variable container.
Definition: res_pjsip.h:2819
const struct message * m
Definition: res_pjsip.h:2823

References sip_ami_outbound::ami, ami_outbound_registration_detail(), ao2_callback, ao2_ref, astman_append(), astman_get_header(), astman_send_error(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), get_registrations(), ast_sip_ami::m, sip_ami_outbound::not_registered, OBJ_NODATA, sip_ami_outbound::registered, and ast_sip_ami::s.

Referenced by load_module().

◆ ami_unregister()

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

Definition at line 2057 of file res_pjsip_outbound_registration.c.

2058 {
2059  const char *registration_name = astman_get_header(m, "Registration");
2061 
2062  if (ast_strlen_zero(registration_name)) {
2063  astman_send_error(s, m, "Registration parameter missing.");
2064  return 0;
2065  }
2066 
2067  if (strcmp(registration_name, "*all") == 0) {
2068  unregister_all();
2069  astman_send_ack(s, m, "Unregistrations queued.");
2070  return 0;
2071  }
2072 
2073  state = get_state(registration_name);
2074  if (!state) {
2075  astman_send_error(s, m, "Unable to retrieve registration entry\n");
2076  return 0;
2077  }
2078 
2079  if (queue_unregister(state)) {
2080  astman_send_ack(s, m, "Failed to queue unregistration");
2081  } else {
2082  astman_send_ack(s, m, "Unregistration sent");
2083  }
2084 
2085  ao2_ref(state, -1);
2086  return 0;
2087 }
static void unregister_all(void)

References ao2_ref, ast_strlen_zero(), astman_get_header(), astman_send_ack(), astman_send_error(), get_state(), queue_unregister(), state, and unregister_all().

Referenced by load_module().

◆ AO2_GLOBAL_OBJ_STATIC()

static AO2_GLOBAL_OBJ_STATIC ( current_states  )
static

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 2624 of file res_pjsip_outbound_registration.c.

◆ auth_observer()

static void auth_observer ( const char *  type)
static

Definition at line 2330 of file res_pjsip_outbound_registration.c.

2331 {
2332  struct sip_outbound_registration *registration;
2334  struct ao2_container *regs;
2335  const char *registration_id;
2336  struct ao2_iterator i;
2337 
2338  ast_debug(4, "Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
2339 
2340  regs = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration",
2342  if (!regs || ao2_container_count(regs) == 0) {
2343  ao2_cleanup(regs);
2344  return;
2345  }
2346 
2347  i = ao2_iterator_init(regs, 0);
2348  for (; (registration = ao2_iterator_next(&i)); ao2_ref(registration, -1)) {
2349  registration_id = ast_sorcery_object_get_id(registration);
2350  state = get_state(registration_id);
2351  if (state && state->client_state->status == SIP_REGISTRATION_REJECTED_PERMANENT) {
2352  ast_debug(4, "Trying outbound registration '%s' again\n", registration_id);
2353 
2354  if (ast_sip_push_task(state->client_state->serializer,
2356  ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", registration_id);
2357  ao2_ref(state, -1);
2358  }
2359  }
2360  ao2_cleanup(state);
2361  }
2363  ao2_cleanup(regs);
2364 }
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:1933
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static int sip_outbound_registration_perform(void *data)
Helper function which performs a single registration.
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition: sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition: sorcery.h:123
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1897
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Outbound registration information.

References ao2_bump, ao2_cleanup, ao2_container_count(), ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_debug, ast_log, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_sorcery(), ast_sip_push_task(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_fields(), get_state(), LOG_ERROR, NULL, sip_outbound_registration_perform(), SIP_REGISTRATION_REJECTED_PERMANENT, and state.

◆ can_reuse_registration()

static int can_reuse_registration ( struct sip_outbound_registration existing,
struct sip_outbound_registration applied 
)
static

Definition at line 1459 of file res_pjsip_outbound_registration.c.

1461 {
1462  int rc = 1;
1464  struct ast_variable *ve = ast_sorcery_objectset_create(sorcery, existing);
1465  struct ast_variable *va = ast_sorcery_objectset_create(sorcery, applied);
1466  struct ast_variable *vc = NULL;
1467 
1468  if (ast_sorcery_changeset_create(ve, va, &vc) || vc != NULL) {
1469  rc = 0;
1470  ast_debug(4, "Registration '%s' changed. Can't re-use.\n", ast_sorcery_object_get_id(existing));
1471  } else {
1472  ast_debug(4, "Registration '%s' didn't change. Can re-use\n", ast_sorcery_object_get_id(existing));
1473  }
1474 
1478 
1479  return rc;
1480 }
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
static struct ast_sorcery * sorcery
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1137
int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
Create a changeset given two object sets.
Definition: sorcery.c:1663
Full structure for sorcery.
Definition: sorcery.c:230
Structure for variables, used for configurations and for channel variables.

References ast_debug, ast_sip_get_sorcery(), ast_sorcery_changeset_create(), ast_sorcery_object_get_id(), ast_sorcery_objectset_create, ast_variables_destroy(), NULL, and sorcery.

Referenced by sip_outbound_registration_apply().

◆ cancel_registration()

static void cancel_registration ( struct sip_outbound_registration_client_state client_state)
static

Helper function which cancels the timer on a client.

Definition at line 544 of file res_pjsip_outbound_registration.c.

545 {
546  if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
547  &client_state->timer, client_state->timer.id)) {
548  /* The timer was successfully cancelled, drop the refcount of client_state */
549  ao2_ref(client_state, -1);
550  }
551 }
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:513
pj_timer_entry timer
Timer entry for retrying on temporal responses.

References ao2_ref, ast_sip_get_pjsip_endpoint(), and sip_outbound_registration_client_state::timer.

Referenced by handle_client_state_destruction(), reregister_immediately_cb(), schedule_registration(), and unregister_task().

◆ check_state()

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

Definition at line 2370 of file res_pjsip_outbound_registration.c.

2371 {
2372  struct sip_outbound_registration_state *state = obj;
2373  struct sip_outbound_registration *registration;
2374 
2375  registration = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",
2376  ast_sorcery_object_get_id(state->registration));
2377  if (!registration) {
2378  /* This is a dead registration */
2379  return CMP_MATCH;
2380  }
2381 
2382  ao2_ref(registration, -1);
2383  return 0;
2384 }
@ CMP_MATCH
Definition: astobj2.h:1027
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853

References ao2_ref, ast_sip_get_sorcery(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_id(), and CMP_MATCH.

◆ cli_complete_registration()

static char* cli_complete_registration ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Definition at line 1922 of file res_pjsip_outbound_registration.c.

1924 {
1925  char *result = NULL;
1926  int wordlen;
1927  int which = 0;
1928  struct sip_outbound_registration *registration;
1929  struct ao2_container *registrations;
1930  struct ao2_iterator i;
1931 
1932  if (pos != 3) {
1933  return NULL;
1934  }
1935 
1936  wordlen = strlen(word);
1937  if (wordlen == 0 && ++which > state) {
1938  return ast_strdup("*all");
1939  }
1940 
1943  if (!registrations) {
1944  return NULL;
1945  }
1946 
1948  while ((registration = ao2_iterator_next(&i))) {
1949  const char *name = ast_sorcery_object_get_id(registration);
1950 
1951  if (!strncasecmp(word, name, wordlen) && ++which > state) {
1952  result = ast_strdup(name);
1953  }
1954 
1955  ao2_ref(registration, -1);
1956  if (result) {
1957  break;
1958  }
1959  }
1961 
1962  ao2_ref(registrations, -1);
1963  return result;
1964 }
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
static PGresult * result
Definition: cel_pgsql.c:84
static struct registrations registrations
short word

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_sorcery(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_fields(), ast_strdup, name, NULL, registrations, and result.

Referenced by cli_register(), and cli_unregister().

◆ cli_get_container()

static struct ao2_container* cli_get_container ( const char *  regex)
static

Definition at line 2209 of file res_pjsip_outbound_registration.c.

2210 {
2212  struct ao2_container *s_container;
2213 
2215  if (!container) {
2216  return NULL;
2217  }
2218 
2221  if (!s_container) {
2222  return NULL;
2223  }
2224 
2225  if (ao2_container_dup(s_container, container, 0)) {
2226  ao2_ref(s_container, -1);
2227  return NULL;
2228  }
2229 
2230  return s_container;
2231 }
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.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
struct ao2_container * container
Definition: res_fax.c:501
struct ao2_container * ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
Retrieve multiple objects using a regular expression on their id.
Definition: sorcery.c:1949
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2459
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition: sorcery.c:2435
#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:936

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_cleanup, ao2_container_alloc_list, ao2_container_dup(), ao2_ref, ast_sip_get_sorcery(), ast_sorcery_object_id_compare(), ast_sorcery_object_id_sort(), ast_sorcery_retrieve_by_regex(), container, NULL, RAII_VAR, and regex().

Referenced by load_module().

◆ cli_iterator()

static int cli_iterator ( void *  container,
ao2_callback_fn  callback,
void *  args 
)
static

Definition at line 2233 of file res_pjsip_outbound_registration.c.

2234 {
2235  ao2_callback(container, OBJ_NODATA, callback, args);
2236 
2237  return 0;
2238 }
const char * args

References ao2_callback, args, container, and OBJ_NODATA.

Referenced by load_module().

◆ cli_print_body()

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

Definition at line 2269 of file res_pjsip_outbound_registration.c.

2270 {
2271  struct sip_outbound_registration *registration = obj;
2272  struct ast_sip_cli_context *context = arg;
2273  const char *id = ast_sorcery_object_get_id(registration);
2275 #define REGISTRATION_URI_FIELD_LEN 53
2276 
2277  ast_assert(context->output_buffer != NULL);
2278 
2279  ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s\n",
2280  id,
2281  (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2282  (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
2286  : "n/a",
2287  (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered"));
2288  ao2_cleanup(state);
2289 
2290  if (context->show_details
2291  || (context->show_details_only_level_0 && context->indent_level == 0)) {
2292  ast_str_append(&context->output_buffer, 0, "\n");
2294  }
2295 
2296  return 0;
2297 }
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
Prints a sorcery object's ast_variable list.
Definition: pjsip_cli.c:36
#define REGISTRATION_URI_FIELD_LEN
CLI Formatter Context passed to all formatters.
Definition: res_pjsip_cli.h:34
struct sip_outbound_registration * registration
Outbound registration configuration object.
#define ast_assert(a)
Definition: utils.h:734
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References ao2_cleanup, ast_assert, ast_sip_cli_print_sorcery_objectset(), ast_sorcery_object_get_id(), ast_str_append(), AST_VECTOR_GET, AST_VECTOR_SIZE, context, get_state(), NULL, sip_outbound_registration::outbound_auths, sip_outbound_registration_state::registration, REGISTRATION_URI_FIELD_LEN, sip_outbound_registration::server_uri, and sip_outbound_registration_status_str().

Referenced by load_module().

◆ cli_print_header()

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

Definition at line 2257 of file res_pjsip_outbound_registration.c.

2258 {
2259  struct ast_sip_cli_context *context = arg;
2260 
2261  ast_assert(context->output_buffer != NULL);
2262 
2263  ast_str_append(&context->output_buffer, 0,
2264  " <Registration/ServerURI..............................> <Auth..........> <Status.......>\n");
2265 
2266  return 0;
2267 }

References ast_assert, ast_str_append(), context, and NULL.

Referenced by load_module().

◆ cli_register()

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

Definition at line 2009 of file res_pjsip_outbound_registration.c.

2010 {
2012  const char *registration_name;
2013 
2014  switch (cmd) {
2015  case CLI_INIT:
2016  e->command = "pjsip send register";
2017  e->usage =
2018  "Usage: pjsip send register <registration> | *all \n"
2019  " Unregisters the specified (or all) outbound "
2020  "registration(s) then starts registration(s) and schedules re-registrations.\n";
2021  return NULL;
2022  case CLI_GENERATE:
2023  return cli_complete_registration(a->line, a->word, a->pos, a->n);
2024  }
2025 
2026  if (a->argc != 4) {
2027  return CLI_SHOWUSAGE;
2028  }
2029 
2030  registration_name = a->argv[3];
2031 
2032  if (strcmp(registration_name, "*all") == 0) {
2033  reregister_all();
2034  ast_cli(a->fd, "Re-register all queued\n");
2035  return CLI_SUCCESS;
2036  }
2037 
2038  state = get_state(registration_name);
2039  if (!state) {
2040  ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
2041  return CLI_FAILURE;
2042  }
2043 
2044  /* We need to serialize the unregister and register so they need
2045  * to be queued as separate tasks.
2046  */
2047  if (queue_unregister(state)) {
2048  ast_cli(a->fd, "Failed to queue unregistration\n");
2049  } else if (queue_register(state)) {
2050  ast_cli(a->fd, "Failed to queue registration\n");
2051  }
2052 
2053  ao2_ref(state, -1);
2054  return CLI_SUCCESS;
2055 }
#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
static char * cli_complete_registration(const char *line, const char *word, int pos, int state)
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
static struct test_val a

References a, ao2_ref, ast_cli(), cli_complete_registration(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, get_state(), NULL, queue_register(), queue_unregister(), reregister_all(), state, and ast_cli_entry::usage.

◆ cli_retrieve_by_id()

static void* cli_retrieve_by_id ( const char *  id)
static

Definition at line 2240 of file res_pjsip_outbound_registration.c.

2241 {
2242  struct ao2_container *states;
2243  void *obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
2244 
2245  if (!obj) {
2246  /* if the object no longer exists then remove its state */
2247  states = ao2_global_obj_ref(current_states);
2248  if (states) {
2249  ao2_find(states, id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
2250  ao2_ref(states, -1);
2251  }
2252  }
2253 
2254  return obj;
2255 }
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101

References ao2_find, ao2_global_obj_ref, ao2_ref, ast_sip_get_sorcery(), ast_sorcery_retrieve_by_id(), OBJ_NODATA, OBJ_SEARCH_KEY, and OBJ_UNLINK.

Referenced by load_module().

◆ cli_unregister()

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

Definition at line 1966 of file res_pjsip_outbound_registration.c.

1967 {
1969  const char *registration_name;
1970 
1971  switch (cmd) {
1972  case CLI_INIT:
1973  e->command = "pjsip send unregister";
1974  e->usage =
1975  "Usage: pjsip send unregister <registration> | *all\n"
1976  " Unregisters the specified (or all) outbound registration(s) "
1977  "and stops future registration attempts.\n";
1978  return NULL;
1979  case CLI_GENERATE:
1980  return cli_complete_registration(a->line, a->word, a->pos, a->n);
1981  }
1982 
1983  if (a->argc != 4) {
1984  return CLI_SHOWUSAGE;
1985  }
1986 
1987  registration_name = a->argv[3];
1988 
1989  if (strcmp(registration_name, "*all") == 0) {
1990  unregister_all();
1991  ast_cli(a->fd, "Unregister all queued\n");
1992  return CLI_SUCCESS;
1993  }
1994 
1995  state = get_state(registration_name);
1996  if (!state) {
1997  ast_cli(a->fd, "Unable to retrieve registration %s\n", registration_name);
1998  return CLI_FAILURE;
1999  }
2000 
2001  if (queue_unregister(state)) {
2002  ast_cli(a->fd, "Failed to queue unregistration\n");
2003  }
2004 
2005  ao2_ref(state, -1);
2006  return CLI_SUCCESS;
2007 }

References a, ao2_ref, ast_cli(), cli_complete_registration(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, get_state(), NULL, queue_unregister(), state, unregister_all(), and ast_cli_entry::usage.

◆ fetch_google_access_token()

static const char* fetch_google_access_token ( const struct ast_sip_auth auth)
static

Get google oauth2 access token using refresh token.

Definition at line 1483 of file res_pjsip_outbound_registration.c.

1484 {
1485  char *cmd = NULL;
1486  const char *token;
1487  const char *url = "https://www.googleapis.com/oauth2/v3/token";
1488  char buf[4096];
1489  int res;
1490  struct ast_json_error error;
1491  struct ast_json *json;
1492 
1493  /* set timeout to be shorter than default 180s (also checks func_curl is available) */
1494  if (ast_func_write(NULL, "CURLOPT(conntimeout)", "10")) {
1495  ast_log(LOG_ERROR, "CURL is unavailable. This is required for Google OAuth 2.0 authentication. Please ensure it is loaded.\n");
1496  return NULL;
1497  }
1498 
1499  res = ast_asprintf(&cmd,
1500  "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",
1501  url, auth->oauth_clientid, auth->oauth_secret, auth->refresh_token);
1502  if (res < 0) {
1503  return NULL;
1504  }
1505 
1506  ast_debug(2, "Performing Google OAuth 2.0 authentication using command: %s\n", cmd);
1507 
1508  buf[0] = '\0';
1509  res = ast_func_read(NULL, cmd, buf, sizeof(buf));
1510  ast_free(cmd);
1511  if (res) {
1512  ast_log(LOG_ERROR, "Could not retrieve Google OAuth 2.0 authentication\n");
1513  return NULL;
1514  }
1515 
1516  ast_debug(2, "Google OAuth 2.0 authentication returned: %s\n", buf);
1517 
1518  json = ast_json_load_string(buf, &error);
1519  if (!json) {
1520  ast_log(LOG_ERROR, "Could not parse Google OAuth 2.0 authentication: %d(%d) %s: '%s'\n",
1521  error.line, error.column, error.text, buf);
1522  return NULL;
1523  }
1524 
1525  token = ast_json_string_get(ast_json_object_get(json, "access_token"));
1526  if (!token) {
1527  ast_log(LOG_ERROR, "Could not find Google OAuth 2.0 access_token in: '%s'\n",
1528  buf);
1529  }
1530  token = ast_strdup(token);
1531  ast_json_unref(json);
1532  return token;
1533 }
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
Definition: json.c:546
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
static char url[512]
JSON parsing error information.
Definition: json.h:849
Abstract JSON element (object, array, string, int, ...).
const ast_string_field oauth_clientid
Definition: res_pjsip.h:481
const ast_string_field oauth_secret
Definition: res_pjsip.h:481
const ast_string_field refresh_token
Definition: res_pjsip.h:481
int error(const char *format,...)
Definition: utils/frame.c:999

References ast_asprintf, ast_debug, ast_free, ast_func_read(), ast_func_write(), ast_json_load_string(), ast_json_object_get(), ast_json_string_get(), ast_json_unref(), ast_log, ast_strdup, buf, error(), LOG_ERROR, NULL, ast_sip_auth::oauth_clientid, ast_sip_auth::oauth_secret, ast_sip_auth::refresh_token, and url.

Referenced by set_outbound_initial_authentication_credentials().

◆ get_registrations()

static struct ao2_container* get_registrations ( void  )
static

◆ get_state()

static struct sip_outbound_registration_state* get_state ( const char *  id)
static

Definition at line 468 of file res_pjsip_outbound_registration.c.

469 {
471  struct ao2_container *states;
472 
473  states = ao2_global_obj_ref(current_states);
474  if (states) {
475  state = ao2_find(states, id, OBJ_SEARCH_KEY);
476  ao2_ref(states, -1);
477  }
478  return state;
479 }

References ao2_find, ao2_global_obj_ref, ao2_ref, NULL, OBJ_SEARCH_KEY, and state.

Referenced by ami_outbound_registration_task(), ami_register(), ami_unregister(), auth_observer(), cli_print_body(), cli_register(), cli_unregister(), and registration_transport_shutdown_cb().

◆ get_uri_option_line()

static struct pjsip_param* get_uri_option_line ( const void *  uri)
static

Definition at line 499 of file res_pjsip_outbound_registration.c.

500 {
501  pjsip_sip_uri *pjuri;
502  static const pj_str_t LINE_STR = { "line", 4 };
503 
504  if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
505  return NULL;
506  }
507  pjuri = pjsip_uri_get_uri(uri);
508  return pjsip_param_find(&pjuri->other_param, &LINE_STR);
509 }

References NULL.

◆ handle_client_registration()

static int handle_client_registration ( void *  data)
static

Callback function for registering.

Definition at line 668 of file res_pjsip_outbound_registration.c.

669 {
670  RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
671  pjsip_tx_data *tdata;
672 
673  if (set_outbound_initial_authentication_credentials(client_state->client, &client_state->outbound_auths)) {
674  ast_log(LOG_WARNING, "Failed to set initial authentication credentials\n");
675  }
676 
677  if (client_state->status == SIP_REGISTRATION_STOPPED
678  || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
679  return 0;
680  }
681 
682  if (DEBUG_ATLEAST(1)) {
683  pjsip_regc_info info;
684 
685  pjsip_regc_get_info(client_state->client, &info);
686  ast_log(LOG_DEBUG, "Outbound REGISTER attempt %u to '%.*s' with client '%.*s'\n",
687  client_state->retries + 1,
688  (int) info.server_uri.slen, info.server_uri.ptr,
689  (int) info.client_uri.slen, info.client_uri.ptr);
690  }
691 
692  if (!add_configured_supported_headers(client_state, tdata)) {
693  ast_log(LOG_WARNING, "Failed to set supported headers\n");
694  return -1;
695  }
696 
697  registration_client_send(client_state, tdata);
698 
699  return 0;
700 }
#define DEBUG_ATLEAST(level)
#define LOG_DEBUG
#define LOG_WARNING
static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
Helper function which sends a message and cleans up, if needed, on failure.
static int set_outbound_initial_authentication_credentials(pjsip_regc *regc, const struct ast_sip_auth_vector *auth_vector)
static int add_configured_supported_headers(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)
Helper function to add configured supported headers.
Outbound registration client state information (persists for lifetime of regc)

References add_configured_supported_headers(), ao2_cleanup, ast_log, DEBUG_ATLEAST, sip_to_pjsip::info(), LOG_DEBUG, LOG_WARNING, RAII_VAR, registration_client_send(), set_outbound_initial_authentication_credentials(), and SIP_REGISTRATION_STOPPED.

Referenced by reregister_immediately_cb(), and sip_outbound_registration_timer_cb().

◆ handle_client_state_destruction()

static int handle_client_state_destruction ( void *  data)
static

Callback function for unregistering (potentially) and destroying state.

Definition at line 772 of file res_pjsip_outbound_registration.c.

773 {
774  struct sip_outbound_registration_client_state *client_state = data;
775 
776  cancel_registration(client_state);
777 
778  if (client_state->client) {
779  pjsip_regc_info info;
780  pjsip_tx_data *tdata;
781 
782  pjsip_regc_get_info(client_state->client, &info);
783 
784  if (info.is_busy == PJ_TRUE) {
785  /* If a client transaction is in progress we defer until it is complete */
786  ast_debug(1,
787  "Registration transaction is busy with server '%.*s' from client '%.*s'.\n",
788  (int) info.server_uri.slen, info.server_uri.ptr,
789  (int) info.client_uri.slen, info.client_uri.ptr);
790  client_state->destroy = 1;
791  ao2_ref(client_state, -1);
792  return 0;
793  }
794 
795  switch (client_state->status) {
797  break;
799  ast_debug(1,
800  "Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n",
801  (int) info.server_uri.slen, info.server_uri.ptr,
802  (int) info.client_uri.slen, info.client_uri.ptr);
803 
805  client_state->destroy = 1;
806  if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS
807  && add_configured_supported_headers(client_state, tdata)
808  && registration_client_send(client_state, tdata) == PJ_SUCCESS) {
809  ao2_ref(client_state, -1);
810  return 0;
811  }
812  break;
817  break;
818  }
819 
820  pjsip_regc_destroy(client_state->client);
821  client_state->client = NULL;
822  }
823 
826  ao2_ref(client_state, -1);
827 
828  return 0;
829 }
void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *vector)
Free contents of an auth vector.
static void update_client_state_status(struct sip_outbound_registration_client_state *client_state, enum sip_outbound_registration_status status)
static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
Helper function which cancels the timer on a client.
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.
unsigned int destroy
Registration should be destroyed after completion of transaction.
enum sip_outbound_registration_status status
Current state of this registration.
pjsip_regc * client
Outbound registration client.

References add_configured_supported_headers(), ao2_ref, ast_debug, ast_sip_auth_vector_destroy(), cancel_registration(), sip_outbound_registration_client_state::client, sip_outbound_registration_client_state::destroy, sip_to_pjsip::info(), NULL, sip_outbound_registration_client_state::outbound_auths, registration_client_send(), SIP_REGISTRATION_REGISTERED, SIP_REGISTRATION_REJECTED_PERMANENT, SIP_REGISTRATION_REJECTED_TEMPORARY, SIP_REGISTRATION_STOPPED, SIP_REGISTRATION_STOPPING, SIP_REGISTRATION_UNREGISTERED, sip_outbound_registration_client_state::status, and update_client_state_status().

Referenced by handle_registration_response(), and sip_outbound_registration_state_destroy().

◆ handle_registration_response()

static int handle_registration_response ( void *  data)
static

Callback function for handling a response to a registration attempt.

Definition at line 1054 of file res_pjsip_outbound_registration.c.

1055 {
1056  struct registration_response *response = data;
1057  pjsip_regc_info info;
1058  char server_uri[PJSIP_MAX_URL_SIZE];
1059  char client_uri[PJSIP_MAX_URL_SIZE];
1060 
1061  if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
1062  ao2_ref(response, -1);
1063  return 0;
1064  }
1065 
1066  pjsip_regc_get_info(response->client_state->client, &info);
1067  ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
1068  ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
1069 
1070  ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n",
1071  response->code, server_uri, client_uri);
1072 
1073  if (response->code == 408 || response->code == 503) {
1074  if ((ast_sip_failover_request(response->old_request))) {
1075  int res = registration_client_send(response->client_state, response->old_request);
1076  /* The tdata ref was stolen */
1077  response->old_request = NULL;
1078  if (res == PJ_SUCCESS) {
1079  ao2_ref(response, -1);
1080  return 0;
1081  }
1082  }
1083  } else if ((response->code == 401 || response->code == 407)
1084  && (!response->client_state->auth_attempted
1085  || response->rdata->msg_info.cseq->cseq != response->client_state->auth_cseq)) {
1086  int res;
1087  pjsip_cseq_hdr *cseq_hdr;
1088  pjsip_tx_data *tdata;
1089 
1091  response->rdata, response->old_request, &tdata)) {
1092  response->client_state->auth_attempted = 1;
1093  ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
1094  server_uri, client_uri);
1095  pjsip_tx_data_add_ref(tdata);
1096  res = registration_client_send(response->client_state, tdata);
1097 
1098  /* Save the cseq that actually got sent. */
1099  cseq_hdr = (pjsip_cseq_hdr *) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ,
1100  NULL);
1101  response->client_state->auth_cseq = cseq_hdr->cseq;
1102  pjsip_tx_data_dec_ref(tdata);
1103  if (res == PJ_SUCCESS) {
1104  ao2_ref(response, -1);
1105  return 0;
1106  }
1107  } else {
1108  ast_log(LOG_WARNING, "Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
1109  server_uri, client_uri);
1110  }
1111  /* Otherwise, fall through so the failure is processed appropriately */
1112  }
1113 
1114  response->client_state->auth_attempted = 0;
1115 
1116  if (PJSIP_IS_STATUS_IN_CLASS(response->code, 200)) {
1117  /* Check if this is in regards to registering or unregistering */
1118  if (response->expiration) {
1119  int next_registration_round;
1120 
1121  /* If the registration went fine simply reschedule registration for the future */
1122  ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
1124  response->client_state->retries = 0;
1125  next_registration_round = response->expiration - REREGISTER_BUFFER_TIME;
1126  if (next_registration_round < 0) {
1127  /* Re-register immediately. */
1128  next_registration_round = 0;
1129  }
1130  schedule_registration(response->client_state, next_registration_round);
1131 
1132  /* See if we should monitor for transport shutdown */
1133  registration_transport_monitor_setup(response->rdata->tp_info.transport,
1134  response->client_state->registration_name);
1135  } else {
1136  ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
1138  ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport,
1140  monitor_matcher);
1141  }
1142 
1144  } else if (response->client_state->destroy) {
1145  /* We need to deal with the pending destruction instead. */
1146  } else if (response->retry_after) {
1147  /* If we have been instructed to retry after a period of time, schedule it as such */
1148  schedule_retry(response, response->retry_after, server_uri, client_uri);
1149  } else if (response->client_state->retry_interval
1150  && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
1151  if (response->client_state->retries == response->client_state->max_retries) {
1152  /* If we received enough temporal responses to exceed our maximum give up permanently */
1154  ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
1155  server_uri, client_uri);
1156  } else {
1157  /* On the other hand if we can still try some more do so */
1158  response->client_state->retries++;
1159  schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
1160  }
1161  } else {
1162  if (response->code == 403
1164  && response->client_state->retries < response->client_state->max_retries) {
1165  /* A forbidden response retry interval is configured and there are retries remaining */
1167  response->client_state->retries++;
1169  ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1170  server_uri, client_uri, response->client_state->forbidden_retry_interval);
1171  } else if (response->client_state->fatal_retry_interval
1172  && response->client_state->retries < response->client_state->max_retries) {
1173  /* Some kind of fatal failure response received, so retry according to configured interval */
1175  response->client_state->retries++;
1177  ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1178  response->code, server_uri, client_uri, response->client_state->fatal_retry_interval);
1179  } else {
1180  /* Finally if there's no hope of registering give up */
1182  if (response->rdata) {
1183  ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
1184  response->code, server_uri, client_uri);
1185  } else {
1186  ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
1187  }
1188  }
1189  }
1190 
1191  ast_system_publish_registry("PJSIP", client_uri, server_uri,
1193 
1194  if (response->client_state->destroy) {
1195  /* We have a pending deferred destruction to complete now. */
1196  ao2_ref(response->client_state, +1);
1198  }
1199 
1200  ao2_ref(response, -1);
1201  return 0;
1202 }
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *tdata, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
Definition: res_pjsip.c:207
void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
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:2035
int ast_sip_failover_request(pjsip_tx_data *tdata)
Set a request to use the next value in the list of resolved addresses.
Definition: res_pjsip.c:1666
static void save_response_fields_to_transport(struct registration_response *response)
#define REREGISTER_BUFFER_TIME
Amount of buffer time (in seconds) before expiration that we re-register at.
static void registration_transport_shutdown_cb(void *obj)
static int sip_outbound_registration_is_temporal(unsigned int code, struct sip_outbound_registration_client_state *client_state)
Helper function which determines if a response code is temporal or not.
static int handle_client_state_destruction(void *data)
Callback function for unregistering (potentially) and destroying state.
static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name)
static void schedule_retry(struct registration_response *response, unsigned int interval, const char *server_uri, const char *client_uri)
static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
Helper function which sets up the timer to re-register in a specific amount of time.
static int monitor_matcher(void *a, void *b)
void ast_system_publish_registry(const char *channeltype, const char *username, const char *domain, const char *status, const char *cause)
Publish a channel driver outgoing registration message.
Structure for registration response.
struct sip_outbound_registration_client_state * client_state
Outbound registration client state.
pjsip_rx_data * rdata
The response message.
int code
Response code for the registration attempt.
int expiration
Expiration time for registration.
pjsip_tx_data * old_request
Request for which the response was received.
unsigned int auth_attempted
Non-zero if we have attempted sending a REGISTER with authentication.
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
unsigned int forbidden_retry_interval
Interval at which retries should occur for permanent responses.
unsigned int max_retries
Maximum number of retries permitted.
unsigned int fatal_retry_interval
Interval at which retries should occur for all permanent responses.
char * registration_name
The name of the registration sorcery object.
unsigned int retries
Current number of retries.
static char server_uri[512]

References ao2_ref, ast_copy_pj_str(), ast_debug, ast_log, ast_sip_create_request_with_auth(), ast_sip_failover_request(), ast_sip_transport_monitor_unregister(), ast_system_publish_registry(), sip_outbound_registration_client_state::auth_attempted, sip_outbound_registration_client_state::auth_cseq, sip_outbound_registration_client_state::client, registration_response::client_state, registration_response::code, sip_outbound_registration_client_state::destroy, registration_response::expiration, sip_outbound_registration_client_state::fatal_retry_interval, sip_outbound_registration_client_state::forbidden_retry_interval, handle_client_state_destruction(), sip_to_pjsip::info(), LOG_WARNING, sip_outbound_registration_client_state::max_retries, monitor_matcher(), NULL, registration_response::old_request, sip_outbound_registration_client_state::outbound_auths, registration_response::rdata, registration_client_send(), sip_outbound_registration_client_state::registration_name, registration_transport_monitor_setup(), registration_transport_shutdown_cb(), REREGISTER_BUFFER_TIME, sip_outbound_registration_client_state::retries, registration_response::retry_after, sip_outbound_registration_client_state::retry_interval, save_response_fields_to_transport(), schedule_registration(), schedule_retry(), server_uri, sip_outbound_registration_is_temporal(), sip_outbound_registration_status_str(), SIP_REGISTRATION_REGISTERED, SIP_REGISTRATION_REJECTED_PERMANENT, SIP_REGISTRATION_REJECTED_TEMPORARY, SIP_REGISTRATION_STOPPED, SIP_REGISTRATION_UNREGISTERED, sip_outbound_registration_client_state::status, and update_client_state_status().

Referenced by sip_outbound_registration_response_cb().

◆ line_identify()

static struct ast_sip_endpoint* line_identify ( pjsip_rx_data *  rdata)
static

Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing registration.

Definition at line 512 of file res_pjsip_outbound_registration.c.

513 {
514  pjsip_param *line;
515  RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);
517 
518  if (!(line = get_uri_option_line(rdata->msg_info.to->uri))
519  && !(line = get_uri_option_line(rdata->msg_info.msg->line.req.uri))) {
520  return NULL;
521  }
522 
523  states = ao2_global_obj_ref(current_states);
524  if (!states) {
525  return NULL;
526  }
527 
528  state = ao2_callback(states, 0, line_identify_relationship, line);
529  if (!state || ast_strlen_zero(state->registration->endpoint)) {
530  return NULL;
531  }
532 
533  ast_debug(3, "Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
534  ast_sorcery_object_get_id(state->registration), state->client_state->line, state->registration->endpoint);
535 
536  return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint);
537 }
static struct pjsip_param * get_uri_option_line(const void *uri)
static int line_identify_relationship(void *obj, void *arg, int flags)
Callback function for matching an outbound registration based on line.

◆ line_identify_relationship()

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

Callback function for matching an outbound registration based on line.

Definition at line 491 of file res_pjsip_outbound_registration.c.

492 {
494  pjsip_param *line = arg;
495 
496  return !pj_strcmp2(&line->value, state->client_state->line) ? CMP_MATCH : 0;
497 }

References CMP_MATCH.

◆ load_module()

static int load_module ( void  )
static

Definition at line 2504 of file res_pjsip_outbound_registration.c.

2505 {
2506  struct ao2_container *new_states;
2507 
2509  if (!shutdown_group) {
2510  return AST_MODULE_LOAD_DECLINE;
2511  }
2512 
2513  /* Create outbound registration states container. */
2516  if (!new_states) {
2517  ast_log(LOG_ERROR, "Unable to allocate registration states container\n");
2518  unload_module();
2519  return AST_MODULE_LOAD_DECLINE;
2520  }
2521  ao2_global_obj_replace_unref(current_states, new_states);
2522  ao2_ref(new_states, -1);
2523 
2524  /*
2525  * Register sorcery object descriptions.
2526  */
2527  ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_outbound_registration");
2528  ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
2529 
2531  unload_module();
2532  return AST_MODULE_LOAD_DECLINE;
2533  }
2534 
2535  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "type", "", OPT_NOOP_T, 0, 0);
2537  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));
2538  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));
2539  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_header_params", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_header_params));
2540  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));
2541  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));
2542  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));
2543  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "retry_interval", "60", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, retry_interval));
2544  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "forbidden_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, forbidden_retry_interval));
2545  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "fatal_retry_interval", "0", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, fatal_retry_interval));
2547  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));
2549  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
2550  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_outbound", "no", OPT_YESNO_T, 1, FLDSET(struct sip_outbound_registration, support_outbound));
2551  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
2552  ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
2553 
2554  /*
2555  * Register sorcery observers.
2556  */
2561  || ast_sorcery_observer_add(ast_sip_get_sorcery(), "registration",
2563  ast_log(LOG_ERROR, "Unable to register observers.\n");
2564  unload_module();
2565  return AST_MODULE_LOAD_DECLINE;
2566  }
2567 
2568  /* Register how this module identifies endpoints. */
2570 
2571  /* Register CLI commands. */
2573  if (!cli_formatter) {
2574  ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
2575  unload_module();
2576  return AST_MODULE_LOAD_DECLINE;
2577  }
2578  cli_formatter->name = "registration";
2587 
2588  /* Register AMI actions. */
2592 
2593  /* Clear any previous statsd gauges in case we weren't shutdown cleanly */
2594  ast_statsd_log("PJSIP.registrations.count", AST_STATSD_GAUGE, 0);
2595  ast_statsd_log("PJSIP.registrations.state.Registered", AST_STATSD_GAUGE, 0);
2596  ast_statsd_log("PJSIP.registrations.state.Unregistered", AST_STATSD_GAUGE, 0);
2597  ast_statsd_log("PJSIP.registrations.state.Rejected", AST_STATSD_GAUGE, 0);
2598 
2599  /* Load configuration objects */
2600  ast_sorcery_load_object(ast_sip_get_sorcery(), "registration");
2601 
2606 
2607  return AST_MODULE_LOAD_SUCCESS;
2608 }
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#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
static int max_retries
Definition: chan_iax2.c:325
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
#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:191
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Register a SIP endpoint identifier.
Definition: res_pjsip.c:303
int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Registers a CLI formatter.
Definition: pjsip_cli.c:310
static struct ao2_container * new_states
Used on [re]loads to hold new state data.
static int ami_show_outbound_registrations(struct mansession *s, const struct message *m)
static const struct ast_sorcery_instance_observer observer_callbacks_registrations
static void * cli_retrieve_by_id(const char *id)
static int cli_print_header(void *obj, void *arg, int flags)
static struct ast_serializer_shutdown_group * shutdown_group
static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
static void * sip_outbound_registration_alloc(const char *name)
Allocator function for registration information.
static int registration_state_cmp(void *obj, void *arg, int flags)
comparator function for state objects
#define DEFAULT_STATE_BUCKETS
Default number of state container buckets.
static const struct ast_sorcery_observer registration_observer
static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
static int ami_register(struct mansession *s, const struct message *m)
static int ami_unregister(struct mansession *s, const struct message *m)
static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj)
Apply function which finds or allocates a state structure.
static const struct ast_sorcery_observer observer_callbacks_auth
static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
static struct ast_sip_endpoint_identifier line_identifier
static int outbound_auths_to_var_list(const void *obj, struct ast_variable **fields)
static struct stasis_subscription * network_change_sub
static struct ao2_container * cli_get_container(const char *regex)
static int cli_print_body(void *obj, void *arg, int flags)
static int unload_module(void)
static struct ast_cli_entry cli_outbound_registration[]
static struct ast_sip_cli_formatter_entry * cli_formatter
static int registration_state_hash(const void *obj, const int flags)
hashing function for state objects
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
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:2386
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to load persistent objects.
Definition: sorcery.c:1393
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
Definition: sorcery.h:1005
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:455
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Add an observer to a sorcery instance.
Definition: sorcery.c:520
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1025
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1079
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
struct stasis_topic * ast_system_topic(void)
A Stasis Message Bus API topic which publishes messages regarding system changes.
struct stasis_message_type * ast_network_change_type(void)
A stasis_message_type for network changes.
#define AST_STATSD_GAUGE
Support for publishing to a statsd server.
Definition: statsd.h:32
void ast_statsd_log(const char *metric_name, const char *metric_type, intmax_t value)
Send a stat to the configured statsd server.
Definition: res_statsd.c:232
CLI Formatter Registry Entry.
Definition: res_pjsip_cli.h:52
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Definition: res_pjsip_cli.h:66
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
const char * name
Definition: res_pjsip_cli.h:58
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
struct ast_serializer_shutdown_group * ast_serializer_shutdown_group_alloc(void)
Create a serializer group shutdown control object.
Definition: threadpool.c:1229
#define ARRAY_LEN(a)
Definition: utils.h:661

References ami_register(), ami_show_outbound_registrations(), ami_unregister(), ao2_alloc, AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ao2_global_obj_replace_unref, ao2_ref, ARRAY_LEN, ast_cli_register_multiple, ast_log, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_network_change_type(), ast_serializer_shutdown_group_alloc(), ast_sip_get_sorcery(), ast_sip_register_cli_formatter(), ast_sip_register_endpoint_identifier(), ast_sorcery_apply_config, ast_sorcery_apply_default, ast_sorcery_instance_observer_add(), ast_sorcery_load_object(), ast_sorcery_object_field_register, ast_sorcery_object_field_register_custom, ast_sorcery_object_get_id(), ast_sorcery_object_register, ast_sorcery_observer_add(), AST_STATSD_GAUGE, ast_statsd_log(), ast_system_topic(), cli_formatter, cli_get_container(), cli_iterator(), cli_outbound_registration, cli_print_body(), cli_print_header(), cli_retrieve_by_id(), DEFAULT_STATE_BUCKETS, EVENT_FLAG_REPORTING, EVENT_FLAG_SYSTEM, FLDSET, ast_sip_cli_formatter_entry::get_container, ast_sip_cli_formatter_entry::get_id, ast_sip_cli_formatter_entry::iterate, line_identifier, LOG_ERROR, max_retries, ast_sip_cli_formatter_entry::name, network_change_stasis_cb(), network_change_sub, new_states, NULL, observer_callbacks_auth, observer_callbacks_registrations, OPT_BOOL_T, OPT_NOOP_T, OPT_STRINGFIELD_T, OPT_UINT_T, OPT_YESNO_T, outbound_auth_handler(), outbound_auths_to_str(), outbound_auths_to_var_list(), ast_sip_cli_formatter_entry::print_body, ast_sip_cli_formatter_entry::print_header, registration_observer, registration_state_cmp(), registration_state_hash(), ast_sip_cli_formatter_entry::retrieve_by_id, server_uri, shutdown_group, sip_outbound_registration_alloc(), sip_outbound_registration_apply(), stasis_subscribe, stasis_subscription_accept_message_type(), STASIS_SUBSCRIPTION_FILTER_SELECTIVE, stasis_subscription_set_filter(), STRFLDSET, and unload_module().

◆ monitor_matcher()

static int monitor_matcher ( void *  a,
void *  b 
)
static

Definition at line 952 of file res_pjsip_outbound_registration.c.

953 {
954  char *ma = a;
955  char *mb = b;
956 
957  return strcmp(ma, mb) == 0;
958 }
static struct test_val b

References a, and b.

Referenced by handle_registration_response().

◆ my_cli_traverse_objects()

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

Definition at line 2304 of file res_pjsip_outbound_registration.c.

2305 {
2306  return ast_sip_cli_traverse_objects(e, cmd, a);
2307 }
char * ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pjsip_cli.c:109

◆ network_change_stasis_cb()

static void network_change_stasis_cb ( void *  data,
struct stasis_subscription sub,
struct stasis_message message 
)
static

Definition at line 2446 of file res_pjsip_outbound_registration.c.

2447 {
2448  /* This callback is only concerned with network change messages from the system topic. */
2450  return;
2451  }
2452  ast_debug(3, "Received network change event\n");
2453 
2454  reregister_all();
2455 }
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.

References ast_debug, ast_network_change_type(), reregister_all(), and stasis_message_type().

Referenced by load_module().

◆ outbound_auth_handler()

static int outbound_auth_handler ( const struct aco_option opt,
struct ast_variable var,
void *  obj 
)
static

Definition at line 1826 of file res_pjsip_outbound_registration.c.

1827 {
1828  struct sip_outbound_registration *registration = obj;
1829 
1830  return ast_sip_auth_vector_init(&registration->outbound_auths, var->value);
1831 }
#define var
Definition: ast_expr2f.c:614
int ast_sip_auth_vector_init(struct ast_sip_auth_vector *vector, const char *auth_names)
Initialize an auth vector with the configured values.

References ast_sip_auth_vector_init(), sip_outbound_registration::outbound_auths, and var.

Referenced by load_module().

◆ outbound_auths_to_str()

static int outbound_auths_to_str ( const void *  obj,
const intptr_t *  args,
char **  buf 
)
static

Definition at line 1833 of file res_pjsip_outbound_registration.c.

1834 {
1835  const struct sip_outbound_registration *registration = obj;
1836 
1837  return ast_sip_auths_to_str(&registration->outbound_auths, buf);
1838 }
int ast_sip_auths_to_str(const struct ast_sip_auth_vector *auths, char **buf)
Converts an auths array to a string of comma separated values.

References ast_sip_auths_to_str(), buf, and sip_outbound_registration::outbound_auths.

Referenced by load_module().

◆ outbound_auths_to_var_list()

static int outbound_auths_to_var_list ( const void *  obj,
struct ast_variable **  fields 
)
static

Definition at line 1840 of file res_pjsip_outbound_registration.c.

1841 {
1842  const struct sip_outbound_registration *registration = obj;
1843  int i;
1844  struct ast_variable *head = NULL;
1845 
1846  for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths) ; i++) {
1847  ast_variable_list_append(&head, ast_variable_new("outbound_auth",
1848  AST_VECTOR_GET(&registration->outbound_auths, i), ""));
1849  }
1850 
1851  if (head) {
1852  *fields = head;
1853  }
1854 
1855  return 0;
1856 }
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)

References ast_variable_list_append, ast_variable_new, AST_VECTOR_GET, AST_VECTOR_SIZE, NULL, and sip_outbound_registration::outbound_auths.

Referenced by load_module().

◆ queue_register()

static int queue_register ( struct sip_outbound_registration_state state)
static

Definition at line 1891 of file res_pjsip_outbound_registration.c.

1892 {
1893  ao2_ref(state, +1);
1894  if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) {
1895  ao2_ref(state, -1);
1896  return -1;
1897  }
1898 
1899  return 0;
1900 }

References ao2_ref, ast_sip_push_task(), and sip_outbound_registration_perform().

Referenced by ami_register(), and cli_register().

◆ queue_unregister()

static int queue_unregister ( struct sip_outbound_registration_state state)
static

Definition at line 1880 of file res_pjsip_outbound_registration.c.

1881 {
1882  ao2_ref(state, +1);
1883  if (ast_sip_push_task(state->client_state->serializer, unregister_task, state)) {
1884  ao2_ref(state, -1);
1885  return -1;
1886  }
1887 
1888  return 0;
1889 }
static int unregister_task(void *obj)

References ao2_ref, ast_sip_push_task(), and unregister_task().

Referenced by ami_register(), ami_unregister(), cli_register(), and cli_unregister().

◆ registration_client_send()

static pj_status_t registration_client_send ( struct sip_outbound_registration_client_state client_state,
pjsip_tx_data *  tdata 
)
static

Helper function which sends a message and cleans up, if needed, on failure.

Definition at line 557 of file res_pjsip_outbound_registration.c.

559 {
560  pj_status_t status;
561  int *callback_invoked;
562  pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
563 
564  callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
565  if (!callback_invoked) {
566  pjsip_tx_data_dec_ref(tdata);
567  return PJ_ENOMEM;
568  }
569  *callback_invoked = 0;
570 
571  /* Due to the message going out the callback may now be invoked, so bump the count */
572  ao2_ref(client_state, +1);
573  /*
574  * We also bump tdata in expectation of saving it to client_state->last_tdata.
575  * We have to do it BEFORE pjsip_regc_send because if it succeeds, it decrements
576  * the ref count on its own.
577  */
578  pjsip_tx_data_add_ref(tdata);
579 
580  /*
581  * Set the transport in case transports were reloaded.
582  * When pjproject removes the extraneous error messages produced,
583  * we can check status and only set the transport and resend if there was an error
584  */
586  pjsip_regc_set_transport(client_state->client, &selector);
587  ast_sip_tpselector_unref(&selector);
588 
589  status = pjsip_regc_send(client_state->client, tdata);
590 
591  /*
592  * If the attempt to send the message failed and the callback was not invoked we need to
593  * drop the references we just added
594  */
595  if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
596  pjsip_tx_data_dec_ref(tdata);
597  ao2_ref(client_state, -1);
598  return status;
599  }
600 
601  /*
602  * Decref the old last_data before replacing it.
603  * BTW, it's quite possible that last_data == tdata
604  * if we're trying successive servers in an SRV set.
605  */
606  if (client_state->last_tdata) {
607  pjsip_tx_data_dec_ref(client_state->last_tdata);
608  }
609  client_state->last_tdata = tdata;
610 
611  return status;
612 }
jack_status_t status
Definition: app_jack.c:146
void ast_sip_tpselector_unref(pjsip_tpselector *selector)
Unreference a pjsip_tpselector.
Definition: res_pjsip.c:782
int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip_tpselector *selector)
Sets pjsip_tpselector from ast_sip_transport.
Definition: res_pjsip.c:752
static struct ast_threadstorage register_callback_invoked
char * transport_name
The name of the transport to be used for the registration.
pjsip_tx_data * last_tdata
Last tdata sent We need the original tdata to resend a request on auth failure or timeout....
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.

References ao2_ref, ast_sip_set_tpselector_from_transport_name(), ast_sip_tpselector_unref(), ast_threadstorage_get(), sip_outbound_registration_client_state::client, sip_outbound_registration_client_state::last_tdata, register_callback_invoked, status, and sip_outbound_registration_client_state::transport_name.

Referenced by handle_client_registration(), handle_client_state_destruction(), handle_registration_response(), and unregister_task().

◆ registration_deleted_observer()

static void registration_deleted_observer ( const void *  obj)
static

Definition at line 2426 of file res_pjsip_outbound_registration.c.

2427 {
2428  const struct sip_outbound_registration *registration = obj;
2429  struct ao2_container *states;
2430 
2431  states = ao2_global_obj_ref(current_states);
2432  if (!states) {
2433  /* Global container has gone. Likely shutting down. */
2434  return;
2435  }
2436 
2438 
2439  ao2_ref(states, -1);
2440 }

References ao2_find, ao2_global_obj_ref, ao2_ref, ast_sorcery_object_get_id(), OBJ_NODATA, OBJ_SEARCH_KEY, and OBJ_UNLINK.

◆ registration_loaded_observer()

static void registration_loaded_observer ( const char *  name,
const struct ast_sorcery sorcery,
const char *  object_type,
int  reloaded 
)
static

Definition at line 2395 of file res_pjsip_outbound_registration.c.

2396 {
2397  struct ao2_container *states;
2398 
2399  if (strcmp(object_type, "registration")) {
2400  /* Not interested */
2401  return;
2402  }
2403 
2404  states = ao2_global_obj_ref(current_states);
2405  if (!states) {
2406  /* Global container has gone. Likely shutting down. */
2407  return;
2408  }
2409 
2410  /*
2411  * Refresh the current configured registrations. We don't need to hold
2412  * onto the objects, as the apply handler will cause their states to
2413  * be created appropriately.
2414  */
2416 
2417  /* Now to purge dead registrations. */
2419  ao2_ref(states, -1);
2420 }
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
static int check_state(void *obj, void *arg, int flags)

◆ registration_response_destroy()

static void registration_response_destroy ( void *  obj)
static

Registration response structure destructor.

Definition at line 848 of file res_pjsip_outbound_registration.c.

849 {
850  struct registration_response *response = obj;
851 
852  if (response->rdata) {
853  pjsip_rx_data_free_cloned(response->rdata);
854  }
855 
856  if (response->old_request) {
857  pjsip_tx_data_dec_ref(response->old_request);
858  }
859 
860  ao2_cleanup(response->client_state);
861 }

References ao2_cleanup, registration_response::client_state, registration_response::old_request, and registration_response::rdata.

Referenced by sip_outbound_registration_response_cb().

◆ registration_state_cmp()

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

comparator function for state objects

Definition at line 440 of file res_pjsip_outbound_registration.c.

441 {
442  const struct sip_outbound_registration_state *object_left = obj;
443  const struct sip_outbound_registration_state *object_right = arg;
444  const char *right_key = arg;
445  int cmp;
446 
447  switch (flags & OBJ_SEARCH_MASK) {
448  case OBJ_SEARCH_OBJECT:
449  right_key = ast_sorcery_object_get_id(object_right->registration);
450  /* Fall through */
451  case OBJ_SEARCH_KEY:
452  cmp = strcmp(ast_sorcery_object_get_id(object_left->registration), right_key);
453  break;
455  /* Not supported by container. */
456  ast_assert(0);
457  return 0;
458  default:
459  cmp = 0;
460  break;
461  }
462  if (cmp) {
463  return 0;
464  }
465  return CMP_MATCH;
466 }
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072

References ast_assert, ast_sorcery_object_get_id(), CMP_MATCH, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, OBJ_SEARCH_PARTIAL_KEY, and sip_outbound_registration_state::registration.

Referenced by load_module().

◆ registration_state_hash()

static int registration_state_hash ( const void *  obj,
const int  flags 
)
static

hashing function for state objects

Definition at line 419 of file res_pjsip_outbound_registration.c.

420 {
421  const struct sip_outbound_registration_state *object;
422  const char *key;
423 
424  switch (flags & OBJ_SEARCH_MASK) {
425  case OBJ_SEARCH_KEY:
426  key = obj;
427  break;
428  case OBJ_SEARCH_OBJECT:
429  object = obj;
431  break;
432  default:
433  ast_assert(0);
434  return 0;
435  }
436  return ast_str_hash(key);
437 }
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1237

References ast_assert, ast_sorcery_object_get_id(), ast_str_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and sip_outbound_registration_state::registration.

Referenced by load_module().

◆ registration_transport_monitor_setup()

static void registration_transport_monitor_setup ( pjsip_transport *  transport,
const char *  registration_name 
)
static

Definition at line 960 of file res_pjsip_outbound_registration.c.

961 {
962  char *monitor;
963 
964  if (!PJSIP_TRANSPORT_IS_RELIABLE(transport)) {
965  return;
966  }
967  monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,
969  if (!monitor) {
970  return;
971  }
972  strcpy(monitor, registration_name);/* Safe */
973 
974  /*
975  * We'll ignore if the transport has already been shutdown before we
976  * register the monitor. We might get into a message spamming infinite
977  * loop of registration, shutdown, reregistration...
978  */
980  monitor);
981  ao2_ref(monitor, -1);
982 }
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *ao2_data)
Register a reliable transport shutdown monitor callback.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_ref, ast_sip_transport_monitor_register(), NULL, and registration_transport_shutdown_cb().

Referenced by handle_registration_response().

◆ registration_transport_shutdown_cb()

static void registration_transport_shutdown_cb ( void *  obj)
static

Definition at line 937 of file res_pjsip_outbound_registration.c.

938 {
939  const char *registration_name = obj;
941 
942  state = get_state(registration_name);
943  if (!state) {
944  /* Registration no longer exists or shutting down. */
945  return;
946  }
947  if (ast_sip_push_task(state->client_state->serializer, reregister_immediately_cb, state)) {
948  ao2_ref(state, -1);
949  }
950 }
static int reregister_immediately_cb(void *obj)

References ao2_ref, ast_sip_push_task(), get_state(), reregister_immediately_cb(), and state.

Referenced by handle_registration_response(), registration_transport_monitor_setup(), and unload_module().

◆ reload_module()

static int reload_module ( void  )
static

Definition at line 2610 of file res_pjsip_outbound_registration.c.

2611 {
2613  return 0;
2614 }
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
Definition: sorcery.c:1442

◆ reregister_all()

static void reregister_all ( void  )
static

◆ reregister_immediately_cb()

static int reregister_immediately_cb ( void *  obj)
static

Definition at line 900 of file res_pjsip_outbound_registration.c.

901 {
903 
904  if (state->client_state->status != SIP_REGISTRATION_REGISTERED) {
905  ao2_ref(state, -1);
906  return 0;
907  }
908 
909  if (DEBUG_ATLEAST(1)) {
910  pjsip_regc_info info;
911 
912  pjsip_regc_get_info(state->client_state->client, &info);
914  "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n",
915  (int) info.server_uri.slen, info.server_uri.ptr,
916  (int) info.client_uri.slen, info.client_uri.ptr);
917  }
918 
919  cancel_registration(state->client_state);
920 
921  ao2_ref(state->client_state, +1);
922  handle_client_registration(state->client_state);
923 
924  ao2_ref(state, -1);
925  return 0;
926 }
static int handle_client_registration(void *data)
Callback function for registering.

References ao2_ref, ast_log, cancel_registration(), DEBUG_ATLEAST, handle_client_registration(), sip_to_pjsip::info(), LOG_DEBUG, and SIP_REGISTRATION_REGISTERED.

Referenced by registration_transport_shutdown_cb().

◆ save_response_fields_to_transport()

static void save_response_fields_to_transport ( struct registration_response response)
static

Definition at line 984 of file res_pjsip_outbound_registration.c.

985 {
986  static const pj_str_t associated_uri_str = { "P-Associated-URI", 16 };
987  static const pj_str_t service_route_str = { "Service-Route", 13 };
988  pjsip_hdr *header = NULL;
989  pjsip_msg *msg = response->rdata->msg_info.msg;
990  struct ast_sip_service_route_vector *service_routes = NULL;
991 
992  /* If no transport is specified then we can't update any */
993  if (ast_strlen_zero(response->client_state->transport_name)) {
994  return;
995  }
996 
997  ast_sip_transport_state_set_transport(response->client_state->transport_name, response->rdata->tp_info.transport);
998 
999  while ((header = pjsip_msg_find_hdr_by_name(msg, &service_route_str, header ? header->next : NULL))) {
1000  char *service_route;
1001  size_t size;
1002 
1003  /* The below code takes the approach that if we can't store all service routes then we
1004  * store none at all. This gives a predictable failure condition instead of storing a
1005  * partial list and having partial route headers.
1006  */
1007  size = pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1;
1008  service_route = ast_malloc(size);
1009  if (!service_route) {
1010  if (service_routes) {
1011  ast_sip_service_route_vector_destroy(service_routes);
1012  service_routes = NULL;
1013  }
1014  break;
1015  }
1016 
1017  ast_copy_pj_str(service_route, &((pjsip_generic_string_hdr*)header)->hvalue, size);
1018 
1019  if (!service_routes) {
1020  service_routes = ast_sip_service_route_vector_alloc();
1021  if (!service_routes) {
1022  ast_free(service_route);
1023  break;
1024  }
1025  }
1026 
1027  if (AST_VECTOR_APPEND(service_routes, service_route)) {
1028  ast_free(service_route);
1029  ast_sip_service_route_vector_destroy(service_routes);
1030  service_routes = NULL;
1031  break;
1032  }
1033  }
1034 
1035  /* If any service routes were handled then store them on the transport */
1036  if (service_routes) {
1038  }
1039 
1040  /* If an associated URI is present in the response we need to use it on any outgoing
1041  * traffic on the transport.
1042  */
1043  header = pjsip_msg_find_hdr_by_name(msg, &associated_uri_str, NULL);
1044  if (header) {
1045  char value[pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1];
1046 
1047  ast_copy_pj_str(value, &((pjsip_generic_string_hdr*)header)->hvalue, sizeof(value));
1049  }
1050 }
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
int ast_sip_transport_state_set_transport(const char *transport_name, pjsip_transport *transport)
Sets the PJSIP transport on a child transport.
struct ast_sip_service_route_vector * ast_sip_service_route_vector_alloc(void)
Allocate a vector of service routes.
void ast_sip_service_route_vector_destroy(struct ast_sip_service_route_vector *service_routes)
Destroy a vector of service routes.
int ast_sip_transport_state_set_preferred_identity(const char *transport_name, const char *identity)
Sets the P-Preferred-Identity on a child transport.
int ast_sip_transport_state_set_service_routes(const char *transport_name, struct ast_sip_service_route_vector *service_routes)
Sets the service routes on a child transport.
struct header * next
int value
Definition: syslog.c:37
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256

References ast_copy_pj_str(), ast_free, ast_malloc, ast_sip_service_route_vector_alloc(), ast_sip_service_route_vector_destroy(), ast_sip_transport_state_set_preferred_identity(), ast_sip_transport_state_set_service_routes(), ast_sip_transport_state_set_transport(), ast_strlen_zero(), AST_VECTOR_APPEND, registration_response::client_state, header::next, NULL, registration_response::rdata, sip_outbound_registration_client_state::transport_name, and value.

Referenced by handle_registration_response().

◆ schedule_registration()

static void schedule_registration ( struct sip_outbound_registration_client_state client_state,
unsigned int  seconds 
)
static

Helper function which sets up the timer to re-register in a specific amount of time.

Definition at line 721 of file res_pjsip_outbound_registration.c.

722 {
723  pj_time_val delay = { .sec = seconds, };
724  pjsip_regc_info info;
725 
726  cancel_registration(client_state);
727 
728  pjsip_regc_get_info(client_state->client, &info);
729  ast_debug(1, "Scheduling outbound registration to server '%.*s' from client '%.*s' in %d seconds\n",
730  (int) info.server_uri.slen, info.server_uri.ptr,
731  (int) info.client_uri.slen, info.client_uri.ptr,
732  seconds);
733 
734  ao2_ref(client_state, +1);
735  if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
736  ast_log(LOG_WARNING, "Failed to schedule registration to server '%.*s' from client '%.*s'\n",
737  (int) info.server_uri.slen, info.server_uri.ptr,
738  (int) info.client_uri.slen, info.client_uri.ptr);
739  ao2_ref(client_state, -1);
740  }
741 }

References ao2_ref, ast_debug, ast_log, ast_sip_get_pjsip_endpoint(), cancel_registration(), sip_outbound_registration_client_state::client, sip_to_pjsip::info(), LOG_WARNING, and sip_outbound_registration_client_state::timer.

Referenced by handle_registration_response(), schedule_retry(), and sip_outbound_registration_perform().

◆ schedule_retry()

static void schedule_retry ( struct registration_response response,
unsigned int  interval,
const char *  server_uri,
const char *  client_uri 
)
static

Definition at line 883 of file res_pjsip_outbound_registration.c.

885 {
887  schedule_registration(response->client_state, interval);
888 
889  if (response->rdata) {
890  ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
891  "registration attempt to '%s', retrying in '%u'\n",
892  response->code, server_uri, client_uri, interval);
893  } else {
894  ast_log(LOG_WARNING, "No response received from '%s' on "
895  "registration attempt to '%s', retrying in '%u'\n",
896  server_uri, client_uri, interval);
897  }
898 }

References ast_log, registration_response::client_state, registration_response::code, LOG_WARNING, registration_response::rdata, schedule_registration(), server_uri, SIP_REGISTRATION_REJECTED_TEMPORARY, and update_client_state_status().

Referenced by handle_registration_response().

◆ set_outbound_initial_authentication_credentials()

static int set_outbound_initial_authentication_credentials ( pjsip_regc *  regc,
const struct ast_sip_auth_vector auth_vector 
)
static

Definition at line 1543 of file res_pjsip_outbound_registration.c.

1545 {
1546  size_t auth_size = AST_VECTOR_SIZE(auth_vector);
1547  struct ast_sip_auth *auths[auth_size];
1548  const char *access_token;
1549  pjsip_cred_info auth_creds[1];
1550  pjsip_auth_clt_pref prefs;
1551  int res = 0;
1552  int idx;
1553 
1554  memset(auths, 0, sizeof(auths));
1555  if (ast_sip_retrieve_auths(auth_vector, auths)) {
1556  res = -1;
1557  goto cleanup;
1558  }
1559 
1560  for (idx = 0; idx < auth_size; ++idx) {
1561  switch (auths[idx]->type) {
1563  pj_cstr(&auth_creds[0].username, auths[idx]->auth_user);
1564  pj_cstr(&auth_creds[0].scheme, "Bearer");
1565  pj_cstr(&auth_creds[0].realm, auths[idx]->realm);
1566  ast_debug(2, "Obtaining Google OAuth access token\n");
1567  access_token = fetch_google_access_token(auths[idx]);
1568  if (!access_token) {
1569  ast_log(LOG_WARNING, "Obtaining Google OAuth access token failed\n");
1570  access_token = auths[idx]->auth_pass;
1571  res = -1;
1572  }
1573  ast_debug(2, "Setting data to '%s'\n", access_token);
1574 
1575  pj_cstr(&auth_creds[0].data, access_token);
1576  auth_creds[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
1577 
1578  pjsip_regc_set_credentials(regc, 1, auth_creds);
1579 
1580  /* for oauth, send auth without waiting for unauthorized response */
1581  prefs.initial_auth = PJ_TRUE;
1582  pj_cstr(&prefs.algorithm, "oauth");
1583  pjsip_regc_set_prefs(regc, &prefs);
1584 
1585  if (access_token != auths[idx]->auth_pass) {
1586  ast_free((char *) access_token);
1587  }
1588  break;
1589  default:
1590  /* other cases handled after receiving auth rejection */
1591  break;
1592  }
1593  }
1594 
1595 cleanup:
1596  ast_sip_cleanup_auths(auths, auth_size);
1597  return res;
1598 }
static const char type[]
Definition: chan_ooh323.c:109
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
Clean up retrieved auth structures from memory.
int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
Retrieve relevant SIP auth structures from sorcery.
@ AST_SIP_AUTH_TYPE_GOOGLE_OAUTH
Definition: res_pjsip.h:456
static const char * fetch_google_access_token(const struct ast_sip_auth *auth)
Get google oauth2 access token using refresh token.
const ast_string_field realm
Definition: res_pjsip.h:481
const ast_string_field auth_user
Definition: res_pjsip.h:481
const ast_string_field auth_pass
Definition: res_pjsip.h:481

References ast_debug, ast_free, ast_log, AST_SIP_AUTH_TYPE_GOOGLE_OAUTH, ast_sip_cleanup_auths(), ast_sip_retrieve_auths(), AST_VECTOR_SIZE, ast_sip_auth::auth_pass, ast_sip_auth::auth_user, cleanup(), fetch_google_access_token(), LOG_WARNING, ast_sip_auth::realm, and type.

Referenced by handle_client_registration().

◆ sip_dialog_create_contact()

static int sip_dialog_create_contact ( pj_pool_t *  pool,
pj_str_t *  contact,
const char *  user,
const pj_str_t *  target,
pjsip_tpselector *  selector,
const char *  line,
const char *  header_params 
)
static

Helper function which populates a pj_str_t with a contact header.

Definition at line 1386 of file res_pjsip_outbound_registration.c.

1388 {
1389  pj_str_t tmp, local_addr;
1390  pjsip_uri *uri;
1391  pjsip_sip_uri *sip_uri;
1392  pjsip_transport_type_e type;
1393  int local_port;
1394 
1395  pj_strdup_with_null(pool, &tmp, target);
1396 
1397  if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
1398  (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
1399  return -1;
1400  }
1401 
1402  sip_uri = pjsip_uri_get_uri(uri);
1403 
1404  type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
1405  if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
1406  if (type == PJSIP_TRANSPORT_UNSPECIFIED
1407  || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) {
1408  type = PJSIP_TRANSPORT_TLS;
1409  }
1410  } else if (!sip_uri->transport_param.slen) {
1411  type = PJSIP_TRANSPORT_UDP;
1412  } else if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
1413  return -1;
1414  }
1415 
1416  if (pj_strchr(&sip_uri->host, ':')) {
1417  type |= PJSIP_TRANSPORT_IPV6;
1418  }
1419 
1420  if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
1421  pool, type, selector, &local_addr, &local_port) != PJ_SUCCESS) {
1422  return -1;
1423  }
1424 
1425  if (!pj_strchr(&sip_uri->host, ':') && pj_strchr(&local_addr, ':')) {
1426  type |= PJSIP_TRANSPORT_IPV6;
1427  }
1428 
1429  contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
1430  contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
1431  "<%s:%s@%s%.*s%s:%d%s%s%s%s>%s%s",
1432  ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ? "sips" : "sip",
1433  user,
1434  (type & PJSIP_TRANSPORT_IPV6) ? "[" : "",
1435  (int)local_addr.slen,
1436  local_addr.ptr,
1437  (type & PJSIP_TRANSPORT_IPV6) ? "]" : "",
1438  local_port,
1439  (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
1440  (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "",
1441  !ast_strlen_zero(line) ? ";line=" : "",
1442  S_OR(line, ""),
1443  !ast_strlen_zero(header_params) ? ";" : "",
1444  S_OR(header_params, ""));
1445 
1446  return 0;
1447 }
static int tmp()
Definition: bt_open.c:389
#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
structure to hold users read from users.conf

References ast_sip_get_pjsip_endpoint(), ast_strlen_zero(), sip_outbound_registration::line, S_OR, tmp(), and type.

Referenced by sip_outbound_registration_regc_alloc().

◆ sip_outbound_registration_alloc()

static void* sip_outbound_registration_alloc ( const char *  name)
static

Allocator function for registration information.

Definition at line 1371 of file res_pjsip_outbound_registration.c.

1372 {
1373  struct sip_outbound_registration *registration;
1374 
1375  registration = ast_sorcery_generic_alloc(sizeof(*registration),
1377  if (!registration || ast_string_field_init(registration, 256)) {
1378  ao2_cleanup(registration);
1379  return NULL;
1380  }
1381 
1382  return registration;
1383 }
static void sip_outbound_registration_destroy(void *obj)
Destructor function for registration information.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359

References ao2_cleanup, ast_sorcery_generic_alloc(), ast_string_field_init, NULL, and sip_outbound_registration_destroy().

Referenced by load_module().

◆ sip_outbound_registration_apply()

static int sip_outbound_registration_apply ( const struct ast_sorcery sorcery,
void *  obj 
)
static

Apply function which finds or allocates a state structure.

Definition at line 1742 of file res_pjsip_outbound_registration.c.

1743 {
1744  RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup);
1747  struct sip_outbound_registration *applied = obj;
1748 
1749  if (!states) {
1750  /* Global container has gone. Likely shutting down. */
1751  return -1;
1752  }
1754 
1755  ast_debug(4, "Applying configuration to outbound registration '%s'\n", ast_sorcery_object_get_id(applied));
1756 
1757  if (ast_strlen_zero(applied->server_uri)) {
1758  ast_log(LOG_ERROR, "No server URI specified on outbound registration '%s'\n",
1759  ast_sorcery_object_get_id(applied));
1760  return -1;
1761  } else if (ast_sip_validate_uri_length(applied->server_uri)) {
1762  ast_log(LOG_ERROR, "Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
1763  ast_sorcery_object_get_id(applied));
1764  return -1;
1765  } else if (ast_strlen_zero(applied->client_uri)) {
1766  ast_log(LOG_ERROR, "No client URI specified on outbound registration '%s'\n",
1767  ast_sorcery_object_get_id(applied));
1768  return -1;
1769  } else if (ast_sip_validate_uri_length(applied->client_uri)) {
1770  ast_log(LOG_ERROR, "Client URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
1771  ast_sorcery_object_get_id(applied));
1772  return -1;
1773  } else if (applied->line && ast_strlen_zero(applied->endpoint)) {
1774  ast_log(LOG_ERROR, "Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
1775  ast_sorcery_object_get_id(applied));
1776  return -1;
1777  } else if (!ast_strlen_zero(applied->endpoint) && !applied->line) {
1778  ast_log(LOG_ERROR, "An endpoint has been specified on outbound registration '%s' without enabling line support\n",
1779  ast_sorcery_object_get_id(applied));
1780  return -1;
1781  }
1782 
1783  if (state && can_reuse_registration(state->registration, applied)) {
1784  ast_debug(4,
1785  "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
1786  ast_sorcery_object_get_id(applied));
1787 
1788  /*
1789  * This is OK to replace without relinking the state in the
1790  * current_states container since state->registration and
1791  * applied have the same key.
1792  */
1793  ao2_lock(states);
1794  ao2_replace(state->registration, applied);
1795  ao2_unlock(states);
1796  return 0;
1797  }
1798 
1799  if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
1800  return -1;
1801  }
1802 
1803  if (ast_sip_push_task_wait_serializer(new_state->client_state->serializer,
1805  return -1;
1806  }
1807 
1808  if (ast_sip_push_task(new_state->client_state->serializer,
1810  ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n",
1811  ast_sorcery_object_get_id(new_state->registration));
1812  ao2_ref(new_state, -1);
1813  return -1;
1814  }
1815 
1816  ao2_lock(states);
1817  if (state) {
1818  ao2_unlink(states, state);
1819  }
1820  ao2_link(states, new_state);
1821  ao2_unlock(states);
1822 
1823  return 0;
1824 }
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition: astobj2.h:501
#define ao2_lock(a)
Definition: astobj2.h:717
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
Definition: res_pjsip.c:2013
static int sip_outbound_registration_regc_alloc(void *data)
Helper function that allocates a pjsip registration client and configures it.
static struct sip_outbound_registration_state * sip_outbound_registration_state_alloc(struct sip_outbound_registration *registration)
Allocator function for registration state.
static int can_reuse_registration(struct sip_outbound_registration *existing, struct sip_outbound_registration *applied)
int ast_sip_validate_uri_length(const char *uri)
Definition: location.c:528
unsigned int line
Whether to add a line parameter to the outbound Contact or not.

References ao2_bump, ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_link, ao2_lock, ao2_ref, ao2_replace, ao2_unlink, ao2_unlock, ast_debug, ast_log, ast_sip_push_task(), ast_sip_push_task_wait_serializer(), ast_sip_validate_uri_length(), ast_sorcery_object_get_id(), ast_strlen_zero(), can_reuse_registration(), sip_outbound_registration::client_uri, sip_outbound_registration::endpoint, sip_outbound_registration::line, LOG_ERROR, NULL, OBJ_SEARCH_KEY, RAII_VAR, sip_outbound_registration::server_uri, sip_outbound_registration_perform(), sip_outbound_registration_regc_alloc(), and sip_outbound_registration_state_alloc().

Referenced by load_module().

◆ sip_outbound_registration_client_state_destroy()

static void sip_outbound_registration_client_state_destroy ( void *  obj)
static

Destructor function for client registration state.

Definition at line 1295 of file res_pjsip_outbound_registration.c.

1296 {
1297  struct sip_outbound_registration_client_state *client_state = obj;
1298 
1299  ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0);
1300  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
1302 
1304  ast_free(client_state->transport_name);
1305  ast_free(client_state->registration_name);
1306  if (client_state->last_tdata) {
1307  pjsip_tx_data_dec_ref(client_state->last_tdata);
1308  }
1309 }
void ast_statsd_log_string_va(const char *metric_name, const char *metric_type, const char *value, double sample_rate,...)
Send a stat to the configured statsd server.
Definition: res_statsd.c:186
void ast_statsd_log_string(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:117
struct ast_taskprocessor * serializer
Serializer for stuff and things.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.

References ast_free, AST_STATSD_GAUGE, ast_statsd_log_string(), ast_statsd_log_string_va(), ast_taskprocessor_unreference(), sip_outbound_registration_client_state::last_tdata, sip_outbound_registration_client_state::registration_name, sip_outbound_registration_client_state::serializer, sip_outbound_registration_status_str(), sip_outbound_registration_client_state::status, and sip_outbound_registration_client_state::transport_name.

Referenced by sip_outbound_registration_state_alloc().

◆ sip_outbound_registration_destroy()

static void sip_outbound_registration_destroy ( void *  obj)
static

Destructor function for registration information.

Definition at line 1361 of file res_pjsip_outbound_registration.c.

1362 {
1363  struct sip_outbound_registration *registration = obj;
1364 
1366 
1367  ast_string_field_free_memory(registration);
1368 }
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374

References ast_sip_auth_vector_destroy(), ast_string_field_free_memory, and sip_outbound_registration::outbound_auths.

Referenced by sip_outbound_registration_alloc().

◆ sip_outbound_registration_is_temporal()

static int sip_outbound_registration_is_temporal ( unsigned int  code,
struct sip_outbound_registration_client_state client_state 
)
static

Helper function which determines if a response code is temporal or not.

Definition at line 864 of file res_pjsip_outbound_registration.c.

866 {
867  /* Shamelessly taken from pjsua */
868  if (code == PJSIP_SC_REQUEST_TIMEOUT ||
869  code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
870  code == PJSIP_SC_BAD_GATEWAY ||
871  code == PJSIP_SC_SERVICE_UNAVAILABLE ||
872  code == PJSIP_SC_SERVER_TIMEOUT ||
873  ((code == PJSIP_SC_UNAUTHORIZED ||
874  code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
875  !client_state->auth_rejection_permanent) ||
876  PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
877  return 1;
878  } else {
879  return 0;
880  }
881 }
unsigned int auth_rejection_permanent
Treat authentication challenges that we cannot handle as permanent failures.

References sip_outbound_registration_client_state::auth_rejection_permanent, registration_response::client_state, and registration_response::code.

Referenced by handle_registration_response().

◆ sip_outbound_registration_perform()

static int sip_outbound_registration_perform ( void *  data)
static

Helper function which performs a single registration.

Definition at line 1706 of file res_pjsip_outbound_registration.c.

1707 {
1708  struct sip_outbound_registration_state *state = data;
1709  struct sip_outbound_registration *registration = ao2_bump(state->registration);
1710  size_t i;
1711 
1712  /* Just in case the client state is being reused for this registration, free the auth information */
1713  ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
1714 
1715  AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(&registration->outbound_auths));
1716  for (i = 0; i < AST_VECTOR_SIZE(&registration->outbound_auths); ++i) {
1717  char *name = ast_strdup(AST_VECTOR_GET(&registration->outbound_auths, i));
1718 
1719  if (name && AST_VECTOR_APPEND(&state->client_state->outbound_auths, name)) {
1720  ast_free(name);
1721  }
1722  }
1723  state->client_state->retry_interval = registration->retry_interval;
1724  state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
1725  state->client_state->fatal_retry_interval = registration->fatal_retry_interval;
1726  state->client_state->max_retries = registration->max_retries;
1727  state->client_state->retries = 0;
1728  state->client_state->support_path = registration->support_path;
1729  state->client_state->support_outbound = registration->support_outbound;
1730  state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
1731 
1732  pjsip_regc_update_expires(state->client_state->client, registration->expiration);
1733 
1734  schedule_registration(state->client_state, (ast_random() % 10) + 1);
1735 
1736  ao2_ref(registration, -1);
1737  ao2_ref(state, -1);
1738  return 0;
1739 }
unsigned int auth_rejection_permanent
Treat authentication challenges that we cannot handle as permanent failures.
unsigned int expiration
Requested expiration time.
unsigned int support_outbound
Whether Outbound support is enabled.
unsigned int support_path
Whether Path support is enabled.
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
unsigned int forbidden_retry_interval
Interval at which retries should occur for permanent responses.
unsigned int max_retries
Maximum number of retries permitted.
unsigned int fatal_retry_interval
Interval at which retries should occur for all permanent responses.
long int ast_random(void)
Definition: main/utils.c:2210
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

References ao2_bump, ao2_ref, ast_free, ast_random(), ast_sip_auth_vector_destroy(), ast_strdup, AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, sip_outbound_registration::auth_rejection_permanent, sip_outbound_registration::expiration, sip_outbound_registration::fatal_retry_interval, sip_outbound_registration::forbidden_retry_interval, sip_outbound_registration::max_retries, name, sip_outbound_registration::outbound_auths, sip_outbound_registration::retry_interval, schedule_registration(), sip_outbound_registration::support_outbound, and sip_outbound_registration::support_path.

Referenced by auth_observer(), queue_register(), and sip_outbound_registration_apply().

◆ sip_outbound_registration_regc_alloc()

static int sip_outbound_registration_regc_alloc ( void *  data)
static

Helper function that allocates a pjsip registration client and configures it.

Definition at line 1601 of file res_pjsip_outbound_registration.c.

1602 {
1603  struct sip_outbound_registration_state *state = data;
1605  ao2_bump(state->registration), ao2_cleanup);
1606  pj_pool_t *pool;
1607  pj_str_t tmp;
1608  pjsip_uri *uri;
1609  pj_str_t server_uri, client_uri, contact_uri;
1610  pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
1611 
1612  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "URI Validation", 256, 256);
1613  if (!pool) {
1614  ast_log(LOG_ERROR, "Could not create pool for URI validation on outbound registration '%s'\n",
1616  return -1;
1617  }
1618 
1619  pj_strdup2_with_null(pool, &tmp, registration->server_uri);
1620  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1621  if (!uri) {
1622  ast_log(LOG_ERROR, "Invalid server URI '%s' specified on outbound registration '%s'\n",
1624  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1625  return -1;
1626  }
1627 
1628  pj_strdup2_with_null(pool, &tmp, registration->client_uri);
1629  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1630  if (!uri) {
1631  ast_log(LOG_ERROR, "Invalid client URI '%s' specified on outbound registration '%s'\n",
1633  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1634  return -1;
1635  }
1636 
1638  pj_strdup2_with_null(pool, &tmp, registration->outbound_proxy);
1639  uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1640  if (!uri) {
1641  ast_log(LOG_ERROR, "Invalid outbound proxy URI '%s' specified on outbound registration '%s'\n",
1643  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1644  return -1;
1645  }
1646  }
1647 
1648  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1649 
1650 
1651  ast_assert(state->client_state->client == NULL);
1652  if (pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->client_state,
1654  &state->client_state->client) != PJ_SUCCESS) {
1655  return -1;
1656  }
1657 
1659  pjsip_regc_set_transport(state->client_state->client, &selector);
1660 
1662  pjsip_route_hdr route_set, *route;
1663  static const pj_str_t ROUTE_HNAME = { "Route", 5 };
1664  pj_str_t tmp;
1665 
1666  pj_list_init(&route_set);
1667 
1668  pj_strdup2_with_null(pjsip_regc_get_pool(state->client_state->client), &tmp,
1670  route = pjsip_parse_hdr(pjsip_regc_get_pool(state->client_state->client),
1671  &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL);
1672  if (!route) {
1673  ast_sip_tpselector_unref(&selector);
1674  return -1;
1675  }
1676  pj_list_insert_nodes_before(&route_set, route);
1677 
1678  pjsip_regc_set_route_set(state->client_state->client, &route_set);
1679  }
1680 
1681  if (state->registration->line) {
1682  ast_generate_random_string(state->client_state->line, sizeof(state->client_state->line));
1683  }
1684 
1685  pj_cstr(&server_uri, registration->server_uri);
1686 
1687  if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client),
1688  &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
1689  state->client_state->line, registration->contact_header_params)) {
1690  ast_sip_tpselector_unref(&selector);
1691  return -1;
1692  }
1693 
1694  ast_sip_tpselector_unref(&selector);
1695 
1696  pj_cstr(&client_uri, registration->client_uri);
1697  if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri,
1698  &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
1699  return -1;
1700  }
1701 
1702  return 0;
1703 }
static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const char *user, const pj_str_t *target, pjsip_tpselector *selector, const char *line, const char *header_params)
Helper function which populates a pj_str_t with a contact header.
static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *param)
Callback function for outbound registration client.
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
Definition: strings.c:227

References ao2_bump, ao2_cleanup, ast_assert, ast_generate_random_string(), ast_log, ast_sip_get_pjsip_endpoint(), ast_sip_set_tpselector_from_transport_name(), ast_sip_tpselector_unref(), ast_sorcery_object_get_id(), ast_strlen_zero(), sip_outbound_registration::client_uri, sip_outbound_registration::contact_header_params, sip_outbound_registration::contact_user, sip_outbound_registration::expiration, LOG_ERROR, NULL, sip_outbound_registration::outbound_proxy, RAII_VAR, sip_outbound_registration_state::registration, S_OR, sip_outbound_registration::server_uri, server_uri, sip_dialog_create_contact(), sip_outbound_registration_response_cb(), tmp(), and sip_outbound_registration::transport.

Referenced by sip_outbound_registration_apply().

◆ sip_outbound_registration_response_cb()

static void sip_outbound_registration_response_cb ( struct pjsip_regc_cbparam *  param)
static

Callback function for outbound registration client.

Definition at line 1205 of file res_pjsip_outbound_registration.c.

1206 {
1207  struct sip_outbound_registration_client_state *client_state = param->token;
1208  struct registration_response *response;
1209  int *callback_invoked;
1210 
1211  callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
1212 
1213  ast_assert(callback_invoked != NULL);
1215 
1216  *callback_invoked = 1;
1217 
1218  response = ao2_alloc(sizeof(*response), registration_response_destroy);
1219  if (!response) {
1220  ao2_ref(client_state, -1);
1221  return;
1222  }
1223  response->code = param->code;
1224  response->expiration = param->expiration;
1225  /*
1226  * Transfer client_state reference to response so the
1227  * nominal path will not dec the client_state ref in this
1228  * pjproject callback thread.
1229  */
1230  response->client_state = client_state;
1231 
1232  ast_debug(1, "Received REGISTER response %d(%.*s)\n",
1233  param->code, (int) param->reason.slen, param->reason.ptr);
1234 
1235  if (param->rdata) {
1236  struct pjsip_retry_after_hdr *retry_after;
1237  pjsip_transaction *tsx;
1238 
1239  retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER,
1240  NULL);
1241  response->retry_after = retry_after ? retry_after->ivalue : 0;
1242 
1243  /*
1244  * If we got a response from the server, we have to use the tdata
1245  * from the transaction, not the tdata saved when we sent the
1246  * request. If we use the saved tdata, we won't process responses
1247  * like 423 Interval Too Brief correctly and we'll wind up sending
1248  * the bad Expires value again.
1249  */
1250  pjsip_tx_data_dec_ref(client_state->last_tdata);
1251 
1252  tsx = pjsip_rdata_get_tsx(param->rdata);
1253  response->old_request = tsx->last_tx;
1254  pjsip_tx_data_add_ref(response->old_request);
1255  pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
1256  } else {
1257  /* old_request steals the reference */
1258  response->old_request = client_state->last_tdata;
1259  }
1260  client_state->last_tdata = NULL;
1261 
1262  /*
1263  * Transfer response reference to serializer task so the
1264  * nominal path will not dec the response ref in this
1265  * pjproject callback thread.
1266  */
1267  if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
1268  ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
1269  ao2_cleanup(response);
1270  }
1271 }
static int handle_registration_response(void *data)
Callback function for handling a response to a registration attempt.
static void registration_response_destroy(void *obj)
Registration response structure destructor.

References ao2_alloc, ao2_cleanup, ao2_ref, ast_assert, ast_debug, ast_log, ast_sip_push_task(), ast_threadstorage_get(), registration_response::client_state, registration_response::code, registration_response::expiration, handle_registration_response(), sip_outbound_registration_client_state::last_tdata, LOG_WARNING, NULL, registration_response::old_request, registration_response::rdata, register_callback_invoked, registration_response_destroy(), registration_response::retry_after, and sip_outbound_registration_client_state::serializer.

Referenced by sip_outbound_registration_regc_alloc().

◆ sip_outbound_registration_state_alloc()

static struct sip_outbound_registration_state* sip_outbound_registration_state_alloc ( struct sip_outbound_registration registration)
static

Allocator function for registration state.

Definition at line 1312 of file res_pjsip_outbound_registration.c.

1313 {
1315  char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
1316 
1318  if (!state) {
1319  return NULL;
1320  }
1321  state->client_state = ao2_alloc(sizeof(*state->client_state),
1323  if (!state->client_state) {
1324  ao2_cleanup(state);
1325  return NULL;
1326  }
1327 
1328  state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
1329  pj_timer_entry_init(&state->client_state->timer, 0, state->client_state,
1331  state->client_state->transport_name = ast_strdup(registration->transport);
1332  state->client_state->registration_name =
1334 
1335  ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);
1336  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
1337  sip_outbound_registration_status_str(state->client_state->status));
1338 
1339  if (!state->client_state->transport_name
1340  || !state->client_state->registration_name) {
1341  ao2_cleanup(state);
1342  return NULL;
1343  }
1344 
1345  /* Create name with seq number appended. */
1346  ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outreg/%s",
1348 
1349  state->client_state->serializer = ast_sip_create_serializer_group(tps_name,
1350  shutdown_group);
1351  if (!state->client_state->serializer) {
1352  ao2_cleanup(state);
1353  return NULL;
1354  }
1355 
1356  state->registration = ao2_bump(registration);
1357  return state;
1358 }
struct ast_taskprocessor * ast_sip_create_serializer_group(const char *name, struct ast_serializer_shutdown_group *shutdown_group)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:1923
static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
Timer callback function, used just for registrations.
static void sip_outbound_registration_state_destroy(void *obj)
Destructor function for registration state.
static void sip_outbound_registration_client_state_destroy(void *obj)
Destructor function for client registration state.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
Definition: taskprocessor.h:61

References ao2_alloc, ao2_bump, ao2_cleanup, ast_sip_create_serializer_group(), ast_sorcery_object_get_id(), AST_STATSD_GAUGE, ast_statsd_log_string(), ast_statsd_log_string_va(), ast_strdup, ast_taskprocessor_build_name(), AST_TASKPROCESSOR_MAX_NAME, NULL, sip_outbound_registration_state::registration, shutdown_group, sip_outbound_registration_client_state_destroy(), sip_outbound_registration_state_destroy(), sip_outbound_registration_status_str(), sip_outbound_registration_timer_cb(), SIP_REGISTRATION_UNREGISTERED, state, and sip_outbound_registration::transport.

Referenced by sip_outbound_registration_apply().

◆ sip_outbound_registration_state_destroy()

static void sip_outbound_registration_state_destroy ( void *  obj)
static

Destructor function for registration state.

Definition at line 1274 of file res_pjsip_outbound_registration.c.

1275 {
1276  struct sip_outbound_registration_state *state = obj;
1277 
1278  ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n",
1279  state->registration ? state->registration->server_uri : "",
1280  state->registration ? state->registration->client_uri : "");
1281  ao2_cleanup(state->registration);
1282 
1283  if (!state->client_state) {
1284  /* Nothing to do */
1285  } else if (!state->client_state->serializer) {
1286  ao2_ref(state->client_state, -1);
1287  } else if (ast_sip_push_task(state->client_state->serializer,
1288  handle_client_state_destruction, state->client_state)) {
1289  ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
1290  ao2_ref(state->client_state, -1);
1291  }
1292 }

References ao2_cleanup, ao2_ref, ast_debug, ast_log, ast_sip_push_task(), handle_client_state_destruction(), and LOG_WARNING.

Referenced by sip_outbound_registration_state_alloc().

◆ sip_outbound_registration_status_str()

static const char* sip_outbound_registration_status_str ( enum sip_outbound_registration_status  state)
static

◆ sip_outbound_registration_timer_cb()

static void sip_outbound_registration_timer_cb ( pj_timer_heap_t *  timer_heap,
struct pj_timer_entry *  entry 
)
static

Timer callback function, used just for registrations.

Definition at line 703 of file res_pjsip_outbound_registration.c.

704 {
705  struct sip_outbound_registration_client_state *client_state = entry->user_data;
706 
707  entry->id = 0;
708 
709  /*
710  * Transfer client_state reference to serializer task so the
711  * nominal path will not dec the client_state ref in this
712  * pjproject callback thread.
713  */
714  if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
715  ast_log(LOG_WARNING, "Scheduled outbound registration could not be executed.\n");
716  ao2_ref(client_state, -1);
717  }
718 }
Definition: search.h:40

References ao2_ref, ast_log, ast_sip_push_task(), handle_client_registration(), LOG_WARNING, and sip_outbound_registration_client_state::serializer.

Referenced by sip_outbound_registration_state_alloc().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2457 of file res_pjsip_outbound_registration.c.

2458 {
2459  int remaining;
2460 
2462 
2463  ast_manager_unregister("PJSIPShowRegistrationsOutbound");
2464  ast_manager_unregister("PJSIPUnregister");
2465  ast_manager_unregister("PJSIPRegister");
2466 
2469  cli_formatter = NULL;
2470 
2472 
2475 
2477 
2478  ao2_global_obj_release(current_states);
2479 
2481 
2482  /* Wait for registration serializers to get destroyed. */
2483  ast_debug(2, "Waiting for registration transactions to complete for unload.\n");
2485  if (remaining) {
2486  /*
2487  * NOTE: We probably have a sip_outbound_registration_client_state
2488  * ref leak if the remaining count cannot reach zero after a few
2489  * minutes of trying to unload.
2490  */
2491  ast_log(LOG_WARNING, "Unload incomplete. Could not stop %d outbound registrations. Try again later.\n",
2492  remaining);
2493  return -1;
2494  }
2495 
2496  ast_debug(2, "Successful shutdown.\n");
2497 
2499  shutdown_group = NULL;
2500 
2501  return 0;
2502 }
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7268
void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Unregister a SIP endpoint identifier.
Definition: res_pjsip.c:308
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
int ast_sip_unregister_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
Unregisters a CLI formatter.
Definition: pjsip_cli.c:326
#define MAX_UNLOAD_TIMEOUT_TIME
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:2418
void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Remove an observer from a sorcery instance.
Definition: sorcery.c:537
int ast_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
Unregister an object type.
Definition: sorcery.c:1061
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1136
int ast_serializer_shutdown_group_join(struct ast_serializer_shutdown_group *shutdown_group, int timeout)
Wait for the serializers in the group to shutdown with timeout.
Definition: threadpool.c:1241

References ao2_cleanup, ao2_global_obj_release, ARRAY_LEN, ast_cli_unregister_multiple(), ast_debug, ast_log, ast_manager_unregister(), ast_serializer_shutdown_group_join(), ast_sip_get_sorcery(), ast_sip_transport_monitor_unregister_all(), ast_sip_unregister_cli_formatter(), ast_sip_unregister_endpoint_identifier(), ast_sorcery_instance_observer_remove(), ast_sorcery_object_unregister(), ast_sorcery_observer_remove(), cli_formatter, cli_outbound_registration, line_identifier, LOG_WARNING, MAX_UNLOAD_TIMEOUT_TIME, network_change_sub, NULL, observer_callbacks_auth, observer_callbacks_registrations, registration_transport_shutdown_cb(), shutdown_group, and stasis_unsubscribe_and_join().

Referenced by load_module().

◆ unregister_all()

static void unregister_all ( void  )
static

Definition at line 1902 of file res_pjsip_outbound_registration.c.

1903 {
1904  struct ao2_container *states;
1905 
1906  states = ao2_global_obj_ref(current_states);
1907  if (!states) {
1908  return;
1909  }
1910 
1911  /* Clean out all the states and let sorcery handle recreating the registrations */
1913  ao2_ref(states, -1);
1914 }

References ao2_callback, ao2_global_obj_ref, ao2_ref, NULL, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.

Referenced by ami_unregister(), cli_unregister(), and reregister_all().

◆ unregister_task()

static int unregister_task ( void *  obj)
static

Definition at line 1858 of file res_pjsip_outbound_registration.c.

1859 {
1860  struct sip_outbound_registration_state *state = obj;
1861  struct pjsip_regc *client = state->client_state->client;
1862  pjsip_tx_data *tdata;
1863  pjsip_regc_info info;
1864 
1865  pjsip_regc_get_info(client, &info);
1866  ast_debug(1, "Unregistering contacts with server '%s' from client '%s'\n",
1867  state->registration->server_uri, state->registration->client_uri);
1868 
1869  cancel_registration(state->client_state);
1870 
1871  if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS
1872  && add_configured_supported_headers(state->client_state, tdata)) {
1873  registration_client_send(state->client_state, tdata);
1874  }
1875 
1876  ao2_ref(state, -1);
1877  return 0;
1878 }

References add_configured_supported_headers(), ao2_ref, ast_debug, cancel_registration(), sip_to_pjsip::info(), and registration_client_send().

Referenced by queue_unregister().

◆ update_client_state_status()

static void update_client_state_status ( struct sip_outbound_registration_client_state client_state,
enum sip_outbound_registration_status  status 
)
static

Definition at line 743 of file res_pjsip_outbound_registration.c.

744 {
745  const char *status_old;
746  const char *status_new;
747 
748  if (client_state->status == status) {
749  /* Status state did not change at all. */
750  return;
751  }
752 
753  status_old = sip_outbound_registration_status_str(client_state->status);
755  client_state->status = status;
756 
757  if (!strcmp(status_old, status_new)) {
758  /*
759  * The internal status state may have changed but the status
760  * state we tell the world did not change at all.
761  */
762  return;
763  }
764 
765  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
766  status_old);
767  ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
768  status_new);
769 }

References AST_STATSD_GAUGE, ast_statsd_log_string_va(), sip_outbound_registration_status_str(), status, and sip_outbound_registration_client_state::status.

Referenced by handle_client_state_destruction(), handle_registration_response(), and schedule_retry().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Outbound Registration Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .requires = "res_pjsip", .optional_modules = "res_statsd", }
static

Definition at line 2610 of file res_pjsip_outbound_registration.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2624 of file res_pjsip_outbound_registration.c.

◆ cli_formatter

struct ast_sip_cli_formatter_entry* cli_formatter
static

Definition at line 2328 of file res_pjsip_outbound_registration.c.

Referenced by load_module(), and unload_module().

◆ cli_outbound_registration

struct ast_cli_entry cli_outbound_registration[]
static

Definition at line 2304 of file res_pjsip_outbound_registration.c.

Referenced by load_module(), and unload_module().

◆ line_identifier

struct ast_sip_endpoint_identifier line_identifier
static
Initial value:
= {
.identify_endpoint = line_identify,
}
static struct ast_sip_endpoint * line_identify(pjsip_rx_data *rdata)
Endpoint identifier which uses the 'line' parameter to establish a relationship to an outgoing regist...

Definition at line 512 of file res_pjsip_outbound_registration.c.

Referenced by load_module(), and unload_module().

◆ network_change_sub

struct stasis_subscription* network_change_sub
static

subscription id for network change events

Definition at line 416 of file res_pjsip_outbound_registration.c.

Referenced by load_module(), and unload_module().

◆ observer_callbacks_auth

const struct ast_sorcery_observer observer_callbacks_auth
static
Initial value:
= {
.loaded = auth_observer,
}
static void auth_observer(const char *type)

Definition at line 2330 of file res_pjsip_outbound_registration.c.

Referenced by load_module(), and unload_module().

◆ observer_callbacks_registrations

const struct ast_sorcery_instance_observer observer_callbacks_registrations
static
Initial value:
= {
.object_type_loaded = registration_loaded_observer,
}
static void registration_loaded_observer(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)

Definition at line 2395 of file res_pjsip_outbound_registration.c.

Referenced by load_module(), pjsip_outbound_registration_metrics_init(), pjsip_outbound_registration_metrics_unload_cb(), and unload_module().

◆ OUTBOUND_NAME

pj_str_t OUTBOUND_NAME = { "outbound", 8 }
static

Definition at line 554 of file res_pjsip_outbound_registration.c.

Referenced by add_configured_supported_headers().

◆ PATH_NAME

pj_str_t PATH_NAME = { "path", 4 }
static

Definition at line 553 of file res_pjsip_outbound_registration.c.

Referenced by add_configured_supported_headers().

◆ register_callback_invoked

struct ast_threadstorage register_callback_invoked = { .once = PTHREAD_ONCE_INIT , .key_init = __init_register_callback_invoked , .custom_init = NULL , }
static

◆ registration_observer

const struct ast_sorcery_observer registration_observer
static
Initial value:
= {
}
static void registration_deleted_observer(const void *obj)

Definition at line 2426 of file res_pjsip_outbound_registration.c.

Referenced by load_module(), pjsip_outbound_registration_metrics_init(), and pjsip_outbound_registration_metrics_unload_cb().

◆ shutdown_group

struct ast_serializer_shutdown_group* shutdown_group
static

Shutdown group to monitor sip_outbound_registration_client_state serializers.

Definition at line 409 of file res_pjsip_outbound_registration.c.

Referenced by load_module(), sip_outbound_registration_state_alloc(), and unload_module().