summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Joseph <gjoseph@digium.com>2017-08-14 12:20:57 -0500
committerGerrit Code Review <gerrit2@gerrit.digium.api>2017-08-14 12:20:57 -0500
commit0442fcb5869df3ba9e37fac5428897d2374f7e77 (patch)
treede23e97c5d0862b698d1861014a2c4b8ee6c0063
parent6a736c3c0d7624bb65edd7c426b2368e18cf55c2 (diff)
parentaef38f07d3ca1399ec0e751fc3917a4d74f048df (diff)
Merge "res_pjsip_outbound_registration.c: Re-REGISTER on transport shutdown." into 15
-rw-r--r--res/res_pjsip_outbound_registration.c114
1 files changed, 105 insertions, 9 deletions
diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 7b605b982..bbb286acf 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -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) */
@@ -795,6 +797,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)
{
@@ -863,9 +941,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. */
@@ -1008,12 +1092,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 */
@@ -1033,6 +1118,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));
@@ -1043,14 +1145,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;
@@ -2054,6 +2148,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);