summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiza Sulistyo <riza@teluu.com>2014-01-24 09:32:27 +0000
committerRiza Sulistyo <riza@teluu.com>2014-01-24 09:32:27 +0000
commit514863030ea7a28b84d7880c848d2c3c8bcbf1fa (patch)
treed7a7b36bd84eb61e23ed7f7ba1264e0f319803e4
parent57460ee1295dfb681fcfeeeeaa16785aab571751 (diff)
Re #1722:
- add handler for 502/503 response to refresh request. - add expire timer for refresher. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4715 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip/include/pjsip-ua/sip_timer.h13
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c20
-rw-r--r--pjsip/src/pjsip-ua/sip_timer.c127
3 files changed, 141 insertions, 19 deletions
diff --git a/pjsip/include/pjsip-ua/sip_timer.h b/pjsip/include/pjsip-ua/sip_timer.h
index aac4e689..1d40675d 100644
--- a/pjsip/include/pjsip-ua/sip_timer.h
+++ b/pjsip/include/pjsip-ua/sip_timer.h
@@ -200,6 +200,19 @@ PJ_DECL(pj_status_t) pjsip_timer_process_resp(pjsip_inv_session *inv,
const pjsip_rx_data *rdata,
pjsip_status_code *st_code);
+/**
+ * Process Session Timers refresh error, this function will process
+ * error from refresh request. The error will be handle according the
+ * error code, i.e : BYE will be sent after error 503 (Transport Error).
+ *
+ * @param inv The invite session.
+ * @param event The event that trigger the error.
+ *
+ * @return PJ_SUCCESS on successful.
+ */
+PJ_DECL(pj_status_t) pjsip_timer_handle_refresh_error(
+ pjsip_inv_session *inv,
+ pjsip_event *event);
/**
* Process Session Timers headers in incoming request, this function
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index c489d6fc..89fc5510 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -3334,6 +3334,15 @@ static pj_bool_t inv_handle_update_response( pjsip_inv_session *inv,
e->body.tsx_state.src.rdata);
handled = PJ_TRUE;
}
+
+ /* Process 502/503 error */
+ else if ((tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
+ (tsx->status_code == 503 || tsx->status_code == 502))
+ {
+ status = pjsip_timer_handle_refresh_error(inv, e);
+
+ handled = PJ_TRUE;
+ }
/* Get/attach invite session's transaction data */
else
@@ -3606,7 +3615,16 @@ static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
return PJ_TRUE; /* Handled */
- } else {
+ }
+ /* Process 502/503 error */
+ else if ((tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
+ (tsx->status_code == 503 || tsx->status_code == 502))
+ {
+ pjsip_timer_handle_refresh_error(inv, e);
+
+ return PJ_TRUE;
+ }
+ else {
return PJ_FALSE; /* Unhandled */
}
}
diff --git a/pjsip/src/pjsip-ua/sip_timer.c b/pjsip/src/pjsip-ua/sip_timer.c
index 0d6ed36b..c1831587 100644
--- a/pjsip/src/pjsip-ua/sip_timer.c
+++ b/pjsip/src/pjsip-ua/sip_timer.c
@@ -19,6 +19,8 @@
#include <pjsip-ua/sip_timer.h>
#include <pjsip/print_util.h>
#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_transaction.h>
#include <pj/log.h>
#include <pj/math.h>
#include <pj/os.h>
@@ -28,8 +30,8 @@
/* Constant of Session Timers */
-#define ABS_MIN_SE 90 /* Absolute Min-SE, in seconds */
-
+#define ABS_MIN_SE 90 /* Absolute Min-SE, in seconds */
+#define REFRESHER_EXPIRE_TIMER_ID 2 /* Refresher expire timer id */
/* String definitions */
static const pj_str_t STR_SE = {"Session-Expires", 15};
@@ -61,8 +63,11 @@ struct pjsip_timer
refresh the session */
pj_bool_t with_sdp; /**< SDP in UPDATE? */
pjsip_role_e role; /**< Role in last INVITE/
- UPDATE transaction. */
-
+ UPDATE transaction. */
+ void *refresh_tdata; /**< The tdata of refresh
+ request */
+ pj_timer_entry expire_timer; /**< Timer entry for expire
+ refresher */
};
/* External global vars */
@@ -331,8 +336,6 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
pj_assert(inv);
- inv->timer->timer.id = 0;
-
PJ_UNUSED_ARG(timer_heap);
/* Lock dialog. */
@@ -341,18 +344,27 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
/* Check our role */
as_refresher =
(inv->timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
- (inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS);
-
- /* Do action based on role, refresher or refreshee */
- if (as_refresher) {
+ (inv->timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS);
+
+ /* Do action based on role(refresher or refreshee).
+ * As refresher:
+ * - send refresh, or
+ * - end session if there is no response to the refresh request.
+ * As refreshee:
+ * - end session if there is no refresh request received.
+ */
+ if (as_refresher && (entry->id != REFRESHER_EXPIRE_TIMER_ID)) {
pj_time_val now;
/* As refresher, reshedule the refresh request on the following:
- * - msut not send re-INVITE if another INVITE or SDP negotiation
+ * - must not send re-INVITE if another INVITE or SDP negotiation
* is in progress.
* - must not send UPDATE with SDP if SDP negotiation is in progress
*/
pjmedia_sdp_neg_state neg_state = pjmedia_sdp_neg_get_state(inv->neg);
+
+ inv->timer->timer.id = 0;
+
if ( (!inv->timer->use_update && (
inv->invite_tsx != NULL ||
neg_state != PJMEDIA_SDP_NEG_STATE_DONE)
@@ -410,16 +422,23 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
pj_time_val now;
- /* Refreshee, terminate the session */
+ if (as_refresher)
+ inv->timer->expire_timer.id = 0;
+ else
+ inv->timer->timer.id = 0;
+
+ /* Terminate the session */
status = pjsip_inv_end_session(inv, PJSIP_SC_REQUEST_TIMEOUT,
NULL, &tdata);
pj_gettimeofday(&now);
PJ_LOG(3, (inv->pool->obj_name,
- "No session refresh received after %ds "
+ "No session %s received after %ds "
"(expiration period=%ds), stopping session now!",
+ (as_refresher?"refresh response":"refresh"),
(now.sec-inv->timer->last_refresh.sec),
inv->timer->setting.sess_expires));
+
}
/* Unlock dialog. */
@@ -427,14 +446,17 @@ static void timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
/* Send message, if any */
if (tdata && status == PJ_SUCCESS) {
- status = pjsip_inv_send_msg(inv, tdata);
+ inv->timer->refresh_tdata = tdata;
+
+ status = pjsip_inv_send_msg(inv, tdata);
}
/* Print error message, if any */
if (status != PJ_SUCCESS) {
PJ_PERROR(2, (inv->pool->obj_name, status,
- "Error in %s session timer",
- (as_refresher? "refreshing" : "terminating")));
+ "Error in %s session timer",
+ ((as_refresher && entry->id != REFRESHER_EXPIRE_TIMER_ID)?
+ "refreshing" : "terminating")));
}
}
@@ -466,6 +488,17 @@ static void start_timer(pjsip_inv_session *inv)
if ((timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
(timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS))
{
+ /* Add refresher expire timer */
+ pj_timer_entry_init(&timer->expire_timer,
+ REFRESHER_EXPIRE_TIMER_ID, /* id */
+ inv, /* user data */
+ timer_cb); /* callback */
+
+ delay.sec = timer->setting.sess_expires;
+ /* Schedule the timer */
+ pjsip_endpt_schedule_timer(inv->dlg->endpt, &timer->expire_timer,
+ &delay);
+
/* Next refresh, the delay is half of session expire */
delay.sec = timer->setting.sess_expires / 2;
} else {
@@ -490,7 +523,12 @@ static void stop_timer(pjsip_inv_session *inv)
{
if (inv->timer->timer.id != 0) {
pjsip_endpt_cancel_timer(inv->dlg->endpt, &inv->timer->timer);
- inv->timer->timer.id = 0;
+ inv->timer->timer.id = 0;
+ }
+
+ if (inv->timer->expire_timer.id != 0) {
+ pjsip_endpt_cancel_timer(inv->dlg->endpt, &inv->timer->expire_timer);
+ inv->timer->expire_timer.id = 0;
}
}
@@ -709,7 +747,7 @@ PJ_DEF(pj_status_t) pjsip_timer_process_resp(pjsip_inv_session *inv,
{
return PJ_SUCCESS;
}
-
+
if (msg->line.status.code == PJSIP_SC_SESSION_TIMER_TOO_SMALL) {
/* Our Session-Expires is too small, let's update it based on
* Min-SE header in the response.
@@ -892,6 +930,59 @@ PJ_DEF(pj_status_t) pjsip_timer_process_resp(pjsip_inv_session *inv,
return PJ_SUCCESS;
}
+PJ_DEF(pj_status_t) pjsip_timer_handle_refresh_error(
+ pjsip_inv_session *inv,
+ pjsip_event *event)
+{
+ PJ_ASSERT_RETURN(inv && event, PJ_EINVAL);
+
+ /* Check if Session Timers is supported */
+ if ((inv->options & PJSIP_INV_SUPPORT_TIMER) == 0)
+ return PJ_SUCCESS;
+
+ pj_assert(is_initialized);
+
+ if (inv->timer && inv->timer->active) {
+ pj_bool_t as_refresher;
+
+ /* Check our role */
+ as_refresher = ((inv->timer->refresher == TR_UAC) &&
+ (inv->timer->role == PJSIP_ROLE_UAC)) ||
+ ((inv->timer->refresher == TR_UAS) &&
+ (inv->timer->role == PJSIP_ROLE_UAS));
+
+
+ if ((as_refresher) && (event->type == PJSIP_EVENT_TSX_STATE) &&
+ (inv->timer->refresh_tdata == event->body.tsx_state.tsx->last_tx))
+ {
+ pjsip_status_code st_code;
+ pjsip_tx_data *bye;
+ pj_status_t status;
+
+ st_code =
+ (pjsip_status_code)event->body.tsx_state.tsx->status_code;
+
+ PJ_LOG(3, (inv->pool->obj_name,
+ "Receive error %d for refresh request %.*s/cseq=%d, "
+ "stopping session now", st_code,
+ event->body.tsx_state.tsx->method.name.slen,
+ event->body.tsx_state.tsx->method.name.ptr,
+ event->body.tsx_state.tsx->cseq));
+
+ status = pjsip_inv_end_session(inv,
+ event->body.tsx_state.tsx->status_code,
+ pjsip_get_status_text(st_code),
+ &bye);
+
+ if (status == PJ_SUCCESS && bye)
+ status = pjsip_inv_send_msg(inv, bye);
+
+ }
+ }
+
+ return PJ_SUCCESS;
+}
+
/*
* Handle incoming INVITE or UPDATE request.
*/