From bfce50ca66e811fa21aec4385ce14ea46ce1f84e Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Tue, 30 Mar 2010 11:13:59 +0000 Subject: 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 --- pjsip/src/pjsua-lib/pjsua_acc.c | 157 +++++++++++++++++++++++++++++++++++++++ pjsip/src/pjsua-lib/pjsua_core.c | 6 ++ 2 files changed, 163 insertions(+) (limited to 'pjsip/src/pjsua-lib') 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, ®_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); } /* -- cgit v1.2.3