From 0f35f91aec1c7e7c4d84cb6bc21d74926566f7c4 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Mon, 5 Feb 2007 18:59:31 +0000 Subject: [PATCH] Fixed ticket #89: implement transaction timeout in REGISTER request (thanks Frank Wiersma for reporting the problem) git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@932 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsip/sip_util.h | 3 +- pjsip/src/pjsip-ua/sip_reg.c | 9 +++- pjsip/src/pjsip/sip_util_statefull.c | 68 +++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/pjsip/include/pjsip/sip_util.h b/pjsip/include/pjsip/sip_util.h index 8a030fd6b..4ae1a5f35 100644 --- a/pjsip/include/pjsip/sip_util.h +++ b/pjsip/include/pjsip/sip_util.h @@ -426,6 +426,7 @@ PJ_DECL(pj_status_t) pjsip_endpt_respond( pjsip_endpoint *endpt, * @param tdata The transmit data to be sent. * @param timeout Optional timeout for final response to be received, or -1 * if the transaction should not have a timeout restriction. + * The value is in miliseconds. * @param token Optional token to be associated with the transaction, and * to be passed to the callback. * @param cb Optional callback to be called when the transaction has @@ -437,7 +438,7 @@ PJ_DECL(pj_status_t) pjsip_endpt_respond( pjsip_endpoint *endpt, */ PJ_DECL(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, pjsip_tx_data *tdata, - int timeout, + pj_int32_t timeout, void *token, void (*cb)(void*,pjsip_event*)); diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c index 45d2020c9..9b6a68be2 100644 --- a/pjsip/src/pjsip-ua/sip_reg.c +++ b/pjsip/src/pjsip-ua/sip_reg.c @@ -38,6 +38,12 @@ #define DELAY_BEFORE_REFRESH 5 #define THIS_FILE "sip_regc.c" +/* Outgoing transaction timeout when server sends 100 but never replies + * with final response. Value is in MILISECONDS! + */ +#define REGC_TSX_TIMEOUT 33000 + + /** * SIP client registration structure. */ @@ -742,7 +748,8 @@ PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata) */ regc->has_tsx = PJ_TRUE; ++regc->busy; - status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback); + 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)); } diff --git a/pjsip/src/pjsip/sip_util_statefull.c b/pjsip/src/pjsip/sip_util_statefull.c index 133dce326..8056989f7 100644 --- a/pjsip/src/pjsip/sip_util_statefull.c +++ b/pjsip/src/pjsip/sip_util_statefull.c @@ -22,11 +22,16 @@ #include #include #include -#include #include +#include +#include +#include struct tsx_data { + pj_time_val delay; + pj_timer_entry timeout_timer; + void *token; void (*cb)(void*, pjsip_event*); }; @@ -66,6 +71,12 @@ static void mod_util_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) if (tsx->status_code < 200) return; + /* Cancel timer if any */ + if (tsx_data->timeout_timer.id != 0) { + tsx_data->timeout_timer.id = 0; + pjsip_endpt_cancel_timer(tsx->endpt, &tsx_data->timeout_timer); + } + /* Call the callback, if any, and prevent the callback to be called again * by clearing the transaction's module_data. */ @@ -77,9 +88,32 @@ static void mod_util_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) } +static void mod_util_on_timeout(pj_timer_heap_t *th, pj_timer_entry *te) +{ + pjsip_transaction *tsx = (pjsip_transaction*) te->user_data; + struct tsx_data *tsx_data; + + PJ_UNUSED_ARG(th); + + tsx_data = tsx->mod_data[mod_stateful_util.id]; + if (tsx_data == NULL) { + pj_assert(!"Shouldn't happen"); + return; + } + + tsx_data->timeout_timer.id = 0; + + PJ_LOG(4,(tsx->obj_name, "Transaction timed out by user timer (%d.%d sec)", + (int)tsx_data->delay.sec, (int)tsx_data->delay.msec)); + + /* Terminate the transaction. This will call mod_util_on_tsx_state() */ + pjsip_tsx_terminate(tsx, PJSIP_SC_TSX_TIMEOUT); +} + + PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, pjsip_tx_data *tdata, - int timeout, + pj_int32_t timeout, void *token, void (*cb)(void*,pjsip_event*)) { @@ -99,16 +133,38 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, return status; } - tsx_data = pj_pool_alloc(tsx->pool, sizeof(struct tsx_data)); + tsx_data = pj_pool_zalloc(tsx->pool, sizeof(struct tsx_data)); tsx_data->token = token; tsx_data->cb = cb; + + if (timeout >= 0) { + tsx_data->delay.sec = 0; + tsx_data->delay.msec = timeout; + pj_time_val_normalize(&tsx_data->delay); + + tsx_data->timeout_timer.id = PJ_TRUE; + tsx_data->timeout_timer.user_data = tsx; + tsx_data->timeout_timer.cb = &mod_util_on_timeout; + + status = pjsip_endpt_schedule_timer(endpt, &tsx_data->timeout_timer, + &tsx_data->delay); + if (status != PJ_SUCCESS) { + pjsip_tsx_terminate(tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); + pjsip_tx_data_dec_ref(tdata); + return status; + } + } + tsx->mod_data[mod_stateful_util.id] = tsx_data; - PJ_TODO(IMPLEMENT_TIMEOUT_FOR_SEND_REQUEST); - status = pjsip_tsx_send_msg(tsx, NULL); - if (status != PJ_SUCCESS) + if (status != PJ_SUCCESS) { + if (tsx_data->timeout_timer.id != 0) { + pjsip_endpt_cancel_timer(endpt, &tsx_data->timeout_timer); + tsx_data->timeout_timer.id = PJ_FALSE; + } pjsip_tx_data_dec_ref(tdata); + } return status; }