|
|
|
@ -358,6 +358,8 @@ struct sip_outbound_registration_client_state {
|
|
|
|
|
unsigned int auth_attempted:1;
|
|
|
|
|
/*! \brief The name of the transport to be used for the registration */
|
|
|
|
|
char *transport_name;
|
|
|
|
|
/*! \brief The name of the registration sorcery object */
|
|
|
|
|
char *registration_name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
|
|
|
|
@ -796,6 +798,82 @@ static void schedule_retry(struct registration_response *response, unsigned int
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int reregister_immediately_cb(void *obj)
|
|
|
|
|
{
|
|
|
|
|
struct sip_outbound_registration_state *state = obj;
|
|
|
|
|
|
|
|
|
|
if (state->client_state->status != SIP_REGISTRATION_REGISTERED) {
|
|
|
|
|
ao2_ref(state, -1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (DEBUG_ATLEAST(1)) {
|
|
|
|
|
pjsip_regc_info info;
|
|
|
|
|
|
|
|
|
|
pjsip_regc_get_info(state->client_state->client, &info);
|
|
|
|
|
ast_log(LOG_DEBUG,
|
|
|
|
|
"Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n",
|
|
|
|
|
(int) info.server_uri.slen, info.server_uri.ptr,
|
|
|
|
|
(int) info.client_uri.slen, info.client_uri.ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cancel_registration(state->client_state);
|
|
|
|
|
|
|
|
|
|
ao2_ref(state->client_state, +1);
|
|
|
|
|
handle_client_registration(state->client_state);
|
|
|
|
|
|
|
|
|
|
ao2_ref(state, -1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* \internal
|
|
|
|
|
* \brief The reliable transport we registered using has shutdown.
|
|
|
|
|
* \since 13.18.0
|
|
|
|
|
*
|
|
|
|
|
* \param obj What is needed to initiate a reregister attempt.
|
|
|
|
|
*
|
|
|
|
|
* \return Nothing
|
|
|
|
|
*/
|
|
|
|
|
static void registration_transport_shutdown_cb(void *obj)
|
|
|
|
|
{
|
|
|
|
|
const char *registration_name = obj;
|
|
|
|
|
struct sip_outbound_registration_state *state;
|
|
|
|
|
|
|
|
|
|
state = get_state(registration_name);
|
|
|
|
|
if (!state) {
|
|
|
|
|
/* Registration no longer exists or shutting down. */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (ast_sip_push_task(state->client_state->serializer, reregister_immediately_cb, state)) {
|
|
|
|
|
ao2_ref(state, -1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name)
|
|
|
|
|
{
|
|
|
|
|
char *monitor;
|
|
|
|
|
|
|
|
|
|
if (!PJSIP_TRANSPORT_IS_RELIABLE(transport)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,
|
|
|
|
|
AO2_ALLOC_OPT_LOCK_NOLOCK);
|
|
|
|
|
if (!monitor) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
strcpy(monitor, registration_name);/* Safe */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We'll ignore if the transport has already been shutdown before we
|
|
|
|
|
* register the monitor. We might get into a message spamming infinite
|
|
|
|
|
* loop of registration, shutdown, reregistration...
|
|
|
|
|
*/
|
|
|
|
|
ast_sip_transport_monitor_register(transport, registration_transport_shutdown_cb,
|
|
|
|
|
monitor);
|
|
|
|
|
ao2_ref(monitor, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! \brief Callback function for handling a response to a registration attempt */
|
|
|
|
|
static int handle_registration_response(void *data)
|
|
|
|
|
{
|
|
|
|
@ -864,9 +942,15 @@ static int handle_registration_response(void *data)
|
|
|
|
|
next_registration_round = 0;
|
|
|
|
|
}
|
|
|
|
|
schedule_registration(response->client_state, next_registration_round);
|
|
|
|
|
|
|
|
|
|
/* See if we should monitor for transport shutdown */
|
|
|
|
|
registration_transport_monitor_setup(response->rdata->tp_info.transport,
|
|
|
|
|
response->client_state->registration_name);
|
|
|
|
|
} else {
|
|
|
|
|
ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
|
|
|
|
|
update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED);
|
|
|
|
|
ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport,
|
|
|
|
|
registration_transport_shutdown_cb);
|
|
|
|
|
}
|
|
|
|
|
} else if (response->client_state->destroy) {
|
|
|
|
|
/* We need to deal with the pending destruction instead. */
|
|
|
|
@ -1009,12 +1093,13 @@ static void sip_outbound_registration_client_state_destroy(void *obj)
|
|
|
|
|
{
|
|
|
|
|
struct sip_outbound_registration_client_state *client_state = obj;
|
|
|
|
|
|
|
|
|
|
ast_free(client_state->transport_name);
|
|
|
|
|
ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0);
|
|
|
|
|
ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
|
|
|
|
|
sip_outbound_registration_status_str(client_state->status));
|
|
|
|
|
|
|
|
|
|
ast_taskprocessor_unreference(client_state->serializer);
|
|
|
|
|
ast_free(client_state->transport_name);
|
|
|
|
|
ast_free(client_state->registration_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*! \brief Allocator function for registration state */
|
|
|
|
@ -1034,6 +1119,23 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
|
|
|
|
|
state->client_state->timer.user_data = state->client_state;
|
|
|
|
|
state->client_state->timer.cb = sip_outbound_registration_timer_cb;
|
|
|
|
|
state->client_state->transport_name = ast_strdup(registration->transport);
|
|
|
|
|
state->client_state->registration_name =
|
|
|
|
|
ast_strdup(ast_sorcery_object_get_id(registration));
|
|
|
|
|
|
|
|
|
|
ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);
|
|
|
|
|
ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
|
|
|
|
|
sip_outbound_registration_status_str(state->client_state->status));
|
|
|
|
|
|
|
|
|
|
if (!state->client_state->transport_name
|
|
|
|
|
|| !state->client_state->registration_name) {
|
|
|
|
|
ao2_cleanup(state);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create name with seq number appended. */
|
|
|
|
|
ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "pjsip/outreg/%s",
|
|
|
|
|
ast_sorcery_object_get_id(registration));
|
|
|
|
@ -1044,14 +1146,6 @@ static struct sip_outbound_registration_state *sip_outbound_registration_state_a
|
|
|
|
|
ao2_cleanup(state);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
|
|
|
|
|
state->client_state->timer.user_data = state->client_state;
|
|
|
|
|
state->client_state->timer.cb = sip_outbound_registration_timer_cb;
|
|
|
|
|
state->client_state->transport_name = ast_strdup(registration->transport);
|
|
|
|
|
|
|
|
|
|
ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "+1", 1.0);
|
|
|
|
|
ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
|
|
|
|
|
sip_outbound_registration_status_str(state->client_state->status));
|
|
|
|
|
|
|
|
|
|
state->registration = ao2_bump(registration);
|
|
|
|
|
return state;
|
|
|
|
@ -2055,6 +2149,8 @@ static int unload_module(void)
|
|
|
|
|
|
|
|
|
|
ao2_global_obj_release(current_states);
|
|
|
|
|
|
|
|
|
|
ast_sip_transport_monitor_unregister_all(registration_transport_shutdown_cb);
|
|
|
|
|
|
|
|
|
|
/* Wait for registration serializers to get destroyed. */
|
|
|
|
|
ast_debug(2, "Waiting for registration transactions to complete for unload.\n");
|
|
|
|
|
remaining = ast_serializer_shutdown_group_join(shutdown_group, MAX_UNLOAD_TIMEOUT_TIME);
|
|
|
|
|