summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-02-13 02:52:37 +0000
committerBenny Prijono <bennylp@teluu.com>2007-02-13 02:52:37 +0000
commit9451220daa74b4cd87e0567e33bb29464c8825df (patch)
treec97eee5a52cf59793d7aa98fab19873d92a82cc3
parent4e08dac382d28c026ea22e8c1b073bee59bab737 (diff)
Implement ticket #99: a more generic mechanism to implement UAC transaction timeout after provisional response is received
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@942 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip/include/pjsip/sip_transaction.h58
-rw-r--r--pjsip/src/pjsip/sip_transaction.c59
-rw-r--r--pjsip/src/pjsip/sip_util_statefull.c58
3 files changed, 115 insertions, 60 deletions
diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h
index 0b5eee10..5148ca06 100644
--- a/pjsip/include/pjsip/sip_transaction.h
+++ b/pjsip/include/pjsip/sip_transaction.h
@@ -74,6 +74,21 @@ typedef enum pjsip_tsx_state_e
/**
+ * Transaction timeout timer policy, to control the UAC transaction timeout
+ * scheduling (see #pjsip_tsx_set_uac_timeout()).
+ */
+typedef enum pjsip_tsx_timeout_policy
+{
+ PJSIP_TSX_IGNORE_100 = 1, /**< To make the UAC transaction NOT to cancel
+ the timeout timer when 100 response is
+ received.*/
+ PJSIP_TSX_IGNORE_1xx = 3 /**< To make the UAC transaction NOT to cancel
+ the timeout timer when any 1xx responses
+ are received. */
+} pjsip_tsx_timeout_policy;
+
+
+/**
* This structure describes SIP transaction object. The transaction object
* is used to handle both UAS and UAC transaction.
*/
@@ -130,6 +145,9 @@ struct pjsip_transaction
pj_timer_entry retransmit_timer;/**< Retransmit timer. */
pj_timer_entry timeout_timer; /**< Timeout timer. */
+ unsigned msec_timeout; /**< User set timeout. */
+ pjsip_tsx_timeout_policy timeout_policy; /**< Timeout policy. */
+
/** Module specific data. */
void *mod_data[PJSIP_MAX_MODULE];
};
@@ -232,6 +250,46 @@ PJ_DECL(pj_status_t) pjsip_tsx_set_transport(pjsip_transaction *tsx,
/**
+ * Set the UAC absolute transaction timeout. Normally UAC transaction will
+ * stop its timeout timer (timer B for INVITE and timer F for non-INVITE
+ * transactions) after a provisional response is received.
+ *
+ * When this timer is set, the transaction's timer B and F will use this
+ * value, and if the \a flag flag is set, the transaction will continue
+ * the scheduling of the timeout timer even when provisional response has
+ * been received.
+ *
+ * Note that this function MUST be called AFTER the transaction has been
+ * created AND BEFORE any request is transmitted.
+ *
+ * @param tsx The client/UAC transaction.
+ * @param msec_time The timeout value, in miliseconds. Currently this
+ * value must be non-zero (value zero is reserved for
+ * future use).
+ * @param flag Option flags to control whether the transaction should
+ * cancel the timeout timer on arrival of provisional
+ * responses (which is yes according to RFC 3261).
+ * The valid values are:
+ * - PJSIP_TSX_IGNORE_100, to make the UAC transaction
+ * NOT to cancel the timeout timer when 100 response
+ * is received.
+ * - PJSIP_TSX_IGNORE_1xx, to make the UAC transaction
+ * NOT to cancel the timeout timer when any 1xx
+ * responses are received.
+ *
+ * Note that regardless of the values in the \a flag
+ * argument, the provisional response would still be
+ * delivered to transaction user and it will still
+ * affect the transaction state. The \a flag flag only
+ * changes the behavior of the timeout timer of the
+ * transaction.
+ */
+PJ_DECL(pj_status_t) pjsip_tsx_set_uac_timeout(pjsip_transaction *tsx,
+ unsigned msec_time,
+ pjsip_tsx_timeout_policy flag);
+
+
+/**
* Call this function to manually feed a message to the transaction.
* For UAS transaction, application MUST call this function after
* UAS transaction has been created.
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index 4dc46520..fcf0646c 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -1396,6 +1396,23 @@ PJ_DEF(pj_status_t) pjsip_tsx_set_transport(pjsip_transaction *tsx,
/*
+ * Set the UAC absolute transaction timeout.
+ */
+PJ_DEF(pj_status_t) pjsip_tsx_set_uac_timeout(pjsip_transaction *tsx,
+ unsigned msec_time,
+ pjsip_tsx_timeout_policy policy)
+{
+ PJ_ASSERT_RETURN(tsx && tsx->role==PJSIP_ROLE_UAC &&
+ tsx->state==PJSIP_TSX_STATE_NULL, PJ_EINVALIDOP);
+
+ tsx->msec_timeout = msec_time;
+ tsx->timeout_policy = policy;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
* Set transaction status code and reason.
*/
static void tsx_set_status_code(pjsip_transaction *tsx,
@@ -1896,10 +1913,22 @@ static pj_status_t tsx_on_state_null( pjsip_transaction *tsx,
}
/* Start Timer B (or called timer F for non-INVITE) for transaction
- * timeout.
+ * timeout. If user has configured the timeout value with
+ * pjsip_tsx_set_uac_timeout(), use the timeout value there.
*/
- pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer,
- &timeout_timer_val);
+ if (tsx->msec_timeout > 0) {
+ pj_time_val timeout;
+
+ timeout.sec = tsx->msec_timeout / 1000;
+ timeout.msec = tsx->msec_timeout % 1000;
+
+ pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer,
+ &timeout);
+
+ } else {
+ pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer,
+ &timeout_timer_val);
+ }
/* Start Timer A (or timer E) for retransmission only if unreliable
* transport is being used.
@@ -1967,7 +1996,7 @@ static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx,
} else if (event->type == PJSIP_EVENT_RX_MSG) {
pjsip_msg *msg;
- //int code;
+ int code;
/* Get message instance */
msg = event->body.rx_msg.rdata->msg_info.msg;
@@ -1984,8 +2013,18 @@ static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx,
tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);
- /* Cancel timer B (transaction timeout) */
- pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
+ /* Cancel timer B (transaction timeout) but look at the timeout policy
+ * as set by pjsip_tsx_set_uac_timeout().
+ */
+ code = msg->line.status.code;
+ if ((code==100 && tsx->timeout_policy==PJSIP_TSX_IGNORE_100) ||
+ (code<200 && tsx->timeout_policy==PJSIP_TSX_IGNORE_1xx))
+ {
+ /* Don't cancel the timeout timer */
+ }
+ else {
+ pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
+ }
/* Discard retransmission message if it is not INVITE.
* The INVITE tdata is needed in case we have to generate ACK for
@@ -2372,6 +2411,14 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx,
PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
}
+ } else if (event->type == PJSIP_EVENT_TIMER &&
+ event->body.timer.entry == &tsx->timeout_timer) {
+
+ /* Inform TU. */
+ tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
+ PJSIP_EVENT_TIMER, &tsx->timeout_timer);
+
+
} else if (tsx->status_code >= 300 && tsx->status_code <= 699) {
diff --git a/pjsip/src/pjsip/sip_util_statefull.c b/pjsip/src/pjsip/sip_util_statefull.c
index 8056989f..80c4aa74 100644
--- a/pjsip/src/pjsip/sip_util_statefull.c
+++ b/pjsip/src/pjsip/sip_util_statefull.c
@@ -29,9 +29,6 @@
struct tsx_data
{
- pj_time_val delay;
- pj_timer_entry timeout_timer;
-
void *token;
void (*cb)(void*, pjsip_event*);
};
@@ -71,12 +68,6 @@ 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.
*/
@@ -88,29 +79,6 @@ 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,
pj_int32_t timeout,
@@ -133,38 +101,20 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt,
return status;
}
- tsx_data = pj_pool_zalloc(tsx->pool, sizeof(struct tsx_data));
+ tsx_data = pj_pool_alloc(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;
- }
+ status = pjsip_tsx_set_uac_timeout(tsx, timeout, PJSIP_TSX_IGNORE_1xx);
+ pj_assert(status == PJ_SUCCESS);
}
tsx->mod_data[mod_stateful_util.id] = tsx_data;
status = pjsip_tsx_send_msg(tsx, NULL);
- 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;
- }
+ if (status != PJ_SUCCESS)
pjsip_tx_data_dec_ref(tdata);
- }
return status;
}