summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2010-03-30 11:13:59 +0000
committerNanang Izzuddin <nanang@teluu.com>2010-03-30 11:13:59 +0000
commitbfce50ca66e811fa21aec4385ce14ea46ce1f84e (patch)
tree85cf4edadfa19d5af42dcaaf57b918bef1f2f032 /pjsip
parentfacb259a9ea6415daa5a8eb4130d459f194d06eb (diff)
Ticket #1044:
- Added initial version of automatic re-registration after registration failure and automatic call disconnection after re-registration attempt fails. - Published auto re-registration setting to pjsua app. - Updated pjsip_regc_send() to retrieve the transport earlier (was only in tsx_callback()). - Fixed TCP and TLS transport to prevent transport deletion in transport disconnection callback. - Fixed wrong keep-alive settings used by TLS transport (was using TCP keep-alive settings). git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3128 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/include/pjsip-ua/sip_regc.h1
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h30
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h7
-rw-r--r--pjsip/src/pjsip-ua/sip_reg.c22
-rw-r--r--pjsip/src/pjsip/sip_transport_tcp.c9
-rw-r--r--pjsip/src/pjsip/sip_transport_tls.c32
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c157
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c6
8 files changed, 255 insertions, 9 deletions
diff --git a/pjsip/include/pjsip-ua/sip_regc.h b/pjsip/include/pjsip-ua/sip_regc.h
index eb8b33c0..a003641a 100644
--- a/pjsip/include/pjsip-ua/sip_regc.h
+++ b/pjsip/include/pjsip-ua/sip_regc.h
@@ -94,6 +94,7 @@ struct pjsip_regc_info
pj_bool_t auto_reg; /**< Will register automatically? */
int interval; /**< Registration interval (seconds). */
int next_reg; /**< Time until next registration (seconds). */
+ pjsip_transport *transport; /**< Last transport used. */
};
/**
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 451b8c9c..5d228083 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -1865,6 +1865,18 @@ PJ_DECL(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
/**
+ * Default auto retry re-registration interval, in seconds. Set to 0
+ * to disable this. Application can set the timer on per account basis
+ * by setting the pjsua_acc_config.reg_retry_interval field instead.
+ *
+ * Default: 300 (5 minutes)
+ */
+#ifndef PJSUA_REG_RETRY_INTERVAL
+# define PJSUA_REG_RETRY_INTERVAL 300
+#endif
+
+
+/**
* This structure describes account configuration to be specified when
* adding a new account with #pjsua_acc_add(). Application MUST initialize
* this structure first by calling #pjsua_acc_config_default().
@@ -2116,6 +2128,24 @@ typedef struct pjsua_acc_config
int srtp_secure_signaling;
#endif
+ /**
+ * Specify interval of auto registration retry upon registration failure
+ * (including caused by transport problem), in second. Set to 0 to
+ * disable auto re-registration.
+ *
+ * Default: #PJSUA_REG_RETRY_INTERVAL
+ */
+ unsigned reg_retry_interval;
+
+ /**
+ * Specify whether calls of the configured account should be dropped
+ * after registration failure and an attempt of re-registration has
+ * also failed.
+ *
+ * Default: PJ_FALSE (disabled)
+ */
+ pj_bool_t drop_calls_on_reg_fail;
+
} pjsua_acc_config;
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index 527b53ae..647adc06 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -128,6 +128,13 @@ typedef struct pjsua_acc
pj_status_t reg_last_err; /**< Last registration error. */
int reg_last_code; /**< Last status last register. */
+ struct {
+ pj_bool_t active; /**< Flag of reregister status. */
+ pj_timer_entry timer; /**< Timer for reregistration. */
+ void *reg_tp; /**< Transport for registration. */
+ unsigned attempt_cnt; /**< Attempt counter. */
+ } auto_rereg; /**< Reregister/reconnect data. */
+
pj_timer_entry ka_timer; /**< Keep-alive timer for UDP. */
pjsip_transport *ka_transport; /**< Transport for keep-alive. */
pj_sockaddr ka_target; /**< Destination address for K-A */
diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c
index 3975028f..5190bb0f 100644
--- a/pjsip/src/pjsip-ua/sip_reg.c
+++ b/pjsip/src/pjsip-ua/sip_reg.c
@@ -203,6 +203,7 @@ PJ_DEF(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc,
info->is_busy = (pj_atomic_get(regc->busy_ctr) || regc->has_tsx);
info->auto_reg = regc->auto_reg;
info->interval = regc->expires;
+ info->transport = regc->last_transport;
if (regc->has_tsx)
info->next_reg = 0;
@@ -1202,12 +1203,33 @@ PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
else
regc->current_op = REGC_REGISTERING;
+ /* Prevent deletion of tdata, e.g: when something wrong in sending,
+ * we need tdata to retrieve the transport.
+ */
+ pjsip_tx_data_add_ref(tdata);
+
status = pjsip_endpt_send_request(regc->endpt, tdata, REGC_TSX_TIMEOUT,
regc, &tsx_callback);
if (status!=PJ_SUCCESS) {
PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
}
+ /* Get last transport used and add reference to it */
+ if (tdata->tp_info.transport != regc->last_transport) {
+ if (regc->last_transport) {
+ pjsip_transport_dec_ref(regc->last_transport);
+ regc->last_transport = NULL;
+ }
+
+ if (tdata->tp_info.transport) {
+ regc->last_transport = tdata->tp_info.transport;
+ pjsip_transport_add_ref(regc->last_transport);
+ }
+ }
+
+ /* Release tdata */
+ pjsip_tx_data_dec_ref(tdata);
+
pj_lock_release(regc->lock);
/* Delete the record if user destroy regc during the callback. */
diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c
index d8f74a9d..fa03f143 100644
--- a/pjsip/src/pjsip/sip_transport_tcp.c
+++ b/pjsip/src/pjsip/sip_transport_tcp.c
@@ -177,6 +177,12 @@ static void tcp_init_shutdown(struct tcp_transport *tcp, pj_status_t status)
if (tcp->base.is_shutdown)
return;
+ /* Prevent immediate transport destroy by application, as transport
+ * state notification callback may be stacked and transport instance
+ * must remain valid at any point in the callback.
+ */
+ pjsip_transport_add_ref(&tcp->base);
+
/* Notify application of transport disconnected state */
state_cb = pjsip_tpmgr_get_status_cb(tcp->base.tpmgr);
if (state_cb) {
@@ -193,6 +199,9 @@ static void tcp_init_shutdown(struct tcp_transport *tcp, pj_status_t status)
* procedure for this transport.
*/
pjsip_transport_shutdown(&tcp->base);
+
+ /* Now, it is ok to destroy the transport. */
+ pjsip_transport_dec_ref(&tcp->base);
}
diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c
index 1fd5c7bd..fa5cd2b1 100644
--- a/pjsip/src/pjsip/sip_transport_tls.c
+++ b/pjsip/src/pjsip/sip_transport_tls.c
@@ -184,6 +184,12 @@ static void tls_init_shutdown(struct tls_transport *tls, pj_status_t status)
if (tls->base.is_shutdown)
return;
+ /* Prevent immediate transport destroy by application, as transport
+ * state notification callback may be stacked and transport instance
+ * must remain valid at any point in the callback.
+ */
+ pjsip_transport_add_ref(&tls->base);
+
/* Notify application of transport disconnected state */
state_cb = pjsip_tpmgr_get_status_cb(tls->base.tpmgr);
if (state_cb) {
@@ -200,6 +206,9 @@ static void tls_init_shutdown(struct tls_transport *tls, pj_status_t status)
* procedure for this transport.
*/
pjsip_transport_shutdown(&tls->base);
+
+ /* Now, it is ok to destroy the transport. */
+ pjsip_transport_dec_ref(&tls->base);
}
@@ -517,7 +526,7 @@ static pj_status_t tls_create( struct tls_listener *listener,
struct tls_transport **p_tls)
{
struct tls_transport *tls;
- const pj_str_t ka_pkt = PJSIP_TCP_KEEP_ALIVE_DATA;
+ const pj_str_t ka_pkt = PJSIP_TLS_KEEP_ALIVE_DATA;
pj_status_t status;
@@ -578,7 +587,12 @@ static pj_status_t tls_create( struct tls_listener *listener,
sockaddr_to_host_port(pool, &tls->base.local_name,
(pj_sockaddr_in*)&tls->base.local_addr);
- sockaddr_to_host_port(pool, &tls->base.remote_name, remote);
+ if (tls->remote_name.slen) {
+ tls->base.remote_name.host = tls->remote_name;
+ tls->base.remote_name.port = pj_sockaddr_in_get_port(remote);
+ } else {
+ sockaddr_to_host_port(pool, &tls->base.remote_name, remote);
+ }
tls->base.endpt = listener->endpt;
tls->base.tpmgr = listener->tpmgr;
@@ -1075,8 +1089,8 @@ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock,
tls_destroy(&tls->base, status);
} else {
/* Start keep-alive timer */
- if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
- pj_time_val delay = {PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0};
+ if (PJSIP_TLS_KEEP_ALIVE_INTERVAL) {
+ pj_time_val delay = {PJSIP_TLS_KEEP_ALIVE_INTERVAL, 0};
pjsip_endpt_schedule_timer(listener->endpt,
&tls->ka_timer,
&delay);
@@ -1507,8 +1521,8 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
tls_flush_pending_tx(tls);
/* Start keep-alive timer */
- if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
- pj_time_val delay = { PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0 };
+ if (PJSIP_TLS_KEEP_ALIVE_INTERVAL) {
+ pj_time_val delay = { PJSIP_TLS_KEEP_ALIVE_INTERVAL, 0 };
pjsip_endpt_schedule_timer(tls->base.endpt, &tls->ka_timer,
&delay);
tls->ka_timer.id = PJ_TRUE;
@@ -1540,9 +1554,9 @@ static void tls_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e)
pj_gettimeofday(&now);
PJ_TIME_VAL_SUB(now, tls->last_activity);
- if (now.sec > 0 && now.sec < PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
+ if (now.sec > 0 && now.sec < PJSIP_TLS_KEEP_ALIVE_INTERVAL) {
/* There has been activity, so don't send keep-alive */
- delay.sec = PJSIP_TCP_KEEP_ALIVE_INTERVAL - now.sec;
+ delay.sec = PJSIP_TLS_KEEP_ALIVE_INTERVAL - now.sec;
delay.msec = 0;
pjsip_endpt_schedule_timer(tls->base.endpt, &tls->ka_timer,
@@ -1570,7 +1584,7 @@ static void tls_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e)
}
/* Register next keep-alive */
- delay.sec = PJSIP_TCP_KEEP_ALIVE_INTERVAL;
+ delay.sec = PJSIP_TLS_KEEP_ALIVE_INTERVAL;
delay.msec = 0;
pjsip_endpt_schedule_timer(tls->base.endpt, &tls->ka_timer,
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index 18096629..8c2b942e 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -24,6 +24,8 @@
#define THIS_FILE "pjsua_acc.c"
+static void schedule_reregistration(pjsua_acc *acc);
+
/*
* Get number of current accounts.
*/
@@ -442,6 +444,9 @@ PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id)
PJSUA_LOCK();
+ /* Cancel any re-registration timer */
+ pjsua_cancel_timer(&pjsua_var.acc[acc_id].auto_rereg.timer);
+
/* Delete registration */
if (pjsua_var.acc[acc_id].regc != NULL) {
pjsua_acc_set_registration(acc_id, PJ_FALSE);
@@ -1031,6 +1036,10 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
} else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
+ /* Update auto registration flag */
+ acc->auto_rereg.active = PJ_FALSE;
+ acc->auto_rereg.attempt_cnt = 0;
+
if (param->expiration < 1) {
pjsip_regc_destroy(acc->regc);
acc->regc = NULL;
@@ -1082,6 +1091,21 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
if (pjsua_var.ua_cfg.cb.on_reg_state)
(*pjsua_var.ua_cfg.cb.on_reg_state)(acc->index);
+ /* Check if we need to auto retry registration. Basically, registration
+ * failure codes triggering auto-retry are those of temporal failures
+ * considered to be recoverable in relatively short term.
+ */
+ if (acc->cfg.reg_retry_interval &&
+ (param->code == PJSIP_SC_REQUEST_TIMEOUT ||
+ param->code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
+ param->code == PJSIP_SC_BAD_GATEWAY ||
+ param->code == PJSIP_SC_SERVICE_UNAVAILABLE ||
+ param->code == PJSIP_SC_SERVER_TIMEOUT ||
+ PJSIP_IS_STATUS_IN_CLASS(param->code, 600))) /* Global failure */
+ {
+ schedule_reregistration(acc);
+ }
+
PJSUA_UNLOCK();
}
@@ -1220,6 +1244,12 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
PJSUA_LOCK();
+ /* Cancel any re-registration timer */
+ pjsua_cancel_timer(&pjsua_var.acc[acc_id].auto_rereg.timer);
+
+ /* Reset pointer to registration transport */
+ pjsua_var.acc[acc_id].auto_rereg.reg_tp = NULL;
+
if (renew) {
if (pjsua_var.acc[acc_id].regc == NULL) {
status = pjsua_regc_init(acc_id);
@@ -1275,6 +1305,14 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
status = pjsip_regc_send( pjsua_var.acc[acc_id].regc, tdata );
}
+ /* Update pointer to registration transport */
+ if (status == PJ_SUCCESS) {
+ pjsip_regc_info reg_info;
+
+ pjsip_regc_get_info(pjsua_var.acc[acc_id].regc, &reg_info);
+ pjsua_var.acc[acc_id].auto_rereg.reg_tp = reg_info.transport;
+ }
+
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create/send REGISTER",
status);
@@ -1925,3 +1963,122 @@ PJ_DEF(pj_status_t) pjsua_acc_set_transport( pjsua_acc_id acc_id,
return PJ_SUCCESS;
}
+
+/* Auto re-registration timeout callback */
+static void auto_rereg_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te)
+{
+ pjsua_acc *acc;
+ pj_status_t status;
+
+ PJ_UNUSED_ARG(th);
+ acc = (pjsua_acc*) te->user_data;
+ pj_assert(acc);
+
+ PJSUA_LOCK();
+
+ if (!acc->valid || !acc->auto_rereg.active)
+ goto on_return;
+
+ /* Start re-registration */
+ acc->auto_rereg.attempt_cnt++;
+ status = pjsua_acc_set_registration(acc->index, PJ_TRUE);
+ if (status != PJ_SUCCESS)
+ schedule_reregistration(acc);
+
+ /* If configured, disconnect calls of this account after the first
+ * reregistration attempt failed.
+ */
+ if (acc->cfg.drop_calls_on_reg_fail && acc->auto_rereg.attempt_cnt > 1)
+ {
+ unsigned i, cnt;
+
+ for (i = 0, cnt = 0; i < pjsua_var.ua_cfg.max_calls; ++i) {
+ if (pjsua_var.calls[i].acc_id == acc->index) {
+ pjsua_call_hangup(i, 0, NULL, NULL);
+ ++cnt;
+ }
+ }
+
+ if (cnt) {
+ PJ_LOG(3, (THIS_FILE, "Disconnecting %d call(s) of account #%d "
+ "after reregistration attempt failed",
+ cnt, acc->index));
+ }
+ }
+
+on_return:
+
+ PJSUA_UNLOCK();
+}
+
+
+/* Schedule reregistration for specified account. Note that the first
+ * re-registration after a registration failure will be done immediately.
+ * Also note that this function should be called within PJSUA mutex.
+ */
+static void schedule_reregistration(pjsua_acc *acc)
+{
+ pj_time_val delay;
+
+ pj_assert(acc && acc->valid && acc->cfg.reg_retry_interval);
+
+ /* Cancel any re-registration timer */
+ pjsua_cancel_timer(&acc->auto_rereg.timer);
+
+ /* Update re-registration flag */
+ acc->auto_rereg.active = PJ_TRUE;
+
+ /* Set up timer for reregistration */
+ acc->auto_rereg.timer.cb = &auto_rereg_timer_cb;
+ acc->auto_rereg.timer.user_data = acc;
+
+ /* Reregistration attempt. The first attempt will be done immediately. */
+ delay.sec = acc->auto_rereg.attempt_cnt? acc->cfg.reg_retry_interval : 0;
+ delay.msec = 0;
+ pjsua_schedule_timer(&acc->auto_rereg.timer, &delay);
+}
+
+
+/* Internal function to perform auto-reregistration on transport
+ * connection/disconnection events.
+ */
+void pjsua_acc_on_tp_state_changed(pjsip_transport *tp,
+ pjsip_transport_state state,
+ const pjsip_transport_state_info *info)
+{
+ unsigned i;
+
+ PJ_UNUSED_ARG(info);
+
+ /* Only care for transport disconnection events */
+ if (state != PJSIP_TP_STATE_DISCONNECTED)
+ return;
+
+ /* Shutdown this transport, to make sure that the transport manager
+ * will create a new transport for reconnection.
+ */
+ pjsip_transport_shutdown(tp);
+
+ PJSUA_LOCK();
+
+ /* Enumerate accounts using this transport and perform actions
+ * based on the transport state.
+ */
+ for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ pjsua_acc *acc = &pjsua_var.acc[i];
+
+ /* Skip if this account is not valid OR auto re-registration
+ * feature is disabled OR this transport is not used by this account.
+ */
+ if (!acc->valid || !acc->cfg.reg_retry_interval ||
+ tp != acc->auto_rereg.reg_tp)
+ {
+ continue;
+ }
+
+ /* Schedule reregistration for this account */
+ schedule_reregistration(acc);
+ }
+
+ PJSUA_UNLOCK();
+}
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 41eda871..f25d2e51 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -176,6 +176,7 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
cfg->use_srtp = pjsua_var.ua_cfg.use_srtp;
cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling;
#endif
+ cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL;
}
PJ_DEF(void) pjsua_buddy_config_default(pjsua_buddy_config *cfg)
@@ -1525,6 +1526,10 @@ static const char *addr_string(const pj_sockaddr_t *addr)
return str;
}
+void pjsua_acc_on_tp_state_changed(pjsip_transport *tp,
+ pjsip_transport_state state,
+ const pjsip_transport_state_info *info);
+
/* Callback to receive transport state notifications */
static void on_tp_state_callback(pjsip_transport *tp,
pjsip_transport_state state,
@@ -1536,6 +1541,7 @@ static void on_tp_state_callback(pjsip_transport *tp,
if (pjsua_var.old_tp_cb) {
(*pjsua_var.old_tp_cb)(tp, state, info);
}
+ pjsua_acc_on_tp_state_changed(tp, state, info);
}
/*