Ticket #833:
 - Renamed pjsip_timer_default_setting() to pjsip_timer_setting_default().
 - Updated session timer settings in pjsua-lib as whole session timer setting struct (pyhton version remains using se & min_se).
 - Added output param SIP status code in pjsip_timer_process_resp() and pjsip_timer_process_req() to specify the corresponding SIP status code when function returning non-PJ_SUCCESS.
 - Fixed print header functions in sip_timer.c to have buffer check.
 - Added PJSIP_SESS_TIMER_DEF_SE setting to specify the default value of session timer interval.
 - Fixed role reference of the refresher, it is transaction role, not dialog role.




git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2859 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/include/pjsip-ua/sip_timer.h b/pjsip/include/pjsip-ua/sip_timer.h
index cb77fae..f4aa5dc 100644
--- a/pjsip/include/pjsip-ua/sip_timer.h
+++ b/pjsip/include/pjsip-ua/sip_timer.h
@@ -125,7 +125,7 @@
  *
  * @return		PJ_SUCCESS on successful.
  */
-PJ_DECL(pj_status_t) pjsip_timer_default_setting(pjsip_timer_setting *setting);
+PJ_DECL(pj_status_t) pjsip_timer_setting_default(pjsip_timer_setting *setting);
 
 
 /**
@@ -191,11 +191,14 @@
  *
  * @param inv		The invite session.
  * @param rdata		Incoming response data.
+ * @param st_code	Output buffer to store corresponding SIP status code 
+ *			when function returning non-PJ_SUCCESS.
  *
  * @return		PJ_SUCCESS on successful.
  */
 PJ_DECL(pj_status_t) pjsip_timer_process_resp(pjsip_inv_session *inv,
-					      const pjsip_rx_data *rdata);
+					      const pjsip_rx_data *rdata,
+					      pjsip_status_code *st_code);
 
 
 /**
@@ -207,11 +210,14 @@
  *
  * @param inv		The invite session.
  * @param rdata		Incoming INVITE or UPDATE request.
+ * @param st_code	Output buffer to store corresponding SIP status code 
+ *			when function returning non-PJ_SUCCESS.
  *
  * @return		PJ_SUCCESS on successful.
  */
 PJ_DECL(pj_status_t) pjsip_timer_process_req(pjsip_inv_session *inv,
-					     const pjsip_rx_data *rdata);
+					     const pjsip_rx_data *rdata,
+					     pjsip_status_code *st_code);
 
 
 /**
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index 22eb061..af38c04 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -883,6 +883,19 @@
 #endif
 
 
+/**
+ * Default session interval for Session Timer (RFC 4028) extension, in
+ * seconds. As specified in RFC 4028 Section 4, this value must not be 
+ * less than the absolute minimum for the Session-Expires header field
+ * 90 seconds, and the recommended value is 1800 seconds.
+ *
+ * Default: 1800 seconds
+ */
+#ifndef PJSIP_SESS_TIMER_DEF_SE
+#   define PJSIP_SESS_TIMER_DEF_SE		1800
+#endif
+
+
 PJ_END_DECL
 
 /**
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 0b257c7..43db66e 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -936,22 +936,11 @@
     pj_bool_t	    require_timer;
 
     /**
-     * Specify session expiration period of Session Timers, in seconds. 
+     * Specify Session Timer settings, see #pjsip_timer_setting. 
      * Note that this setting can be further customized in account 
      * configuration (#pjsua_acc_config).
-     *
-     * Default: 1800 (seconds)
      */
-    unsigned	    timer_se;
-
-    /**
-     * Specify minimum session expiration period of Session Timers, 
-     * in seconds. Note that this setting can be further customized in 
-     * account configuration (#pjsua_acc_config).
-     *
-     * Default: 90 (seconds)
-     */
-    unsigned	    timer_min_se;
+    pjsip_timer_setting timer_setting;
 
     /** 
      * Number of credentials in the credential array.
@@ -1733,20 +1722,9 @@
     pj_bool_t	    require_timer;
 
     /**
-     * Specify session expiration period of Session Timers, in seconds,
-     * for this account. 
-     *
-     * Default: 1800 (seconds)
+     * Specify Session Timer settings, see #pjsip_timer_setting. 
      */
-    unsigned	    timer_se;
-
-    /**
-     * Specify minimum session expiration period of Session Timers, 
-     * in seconds, for this account.
-     *
-     * Default: 90 (seconds)
-     */
-    unsigned	    timer_min_se;
+    pjsip_timer_setting timer_setting;
 
     /**
      * Number of proxies in the proxy array below.
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index 80ae971..736c00c 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -484,6 +484,7 @@
     pjsip_inv_session *inv;
     pjsip_msg *msg = rdata->msg_info.msg;
     pj_status_t status;
+    pjsip_status_code st_code;
 
     dlg = pjsip_rdata_get_dlg(rdata);
 
@@ -512,7 +513,7 @@
     }
 
     /* Pass response to timer session module */
-    status = pjsip_timer_process_resp(inv, rdata);
+    status = pjsip_timer_process_resp(inv, rdata, &st_code);
     if (status != PJ_SUCCESS) {
 	pjsip_event e;
 	pjsip_tx_data *tdata;
@@ -520,8 +521,7 @@
 	PJSIP_EVENT_INIT_RX_MSG(e, rdata);
 	inv_send_ack(inv, &e);
 
-	status = pjsip_inv_end_session(inv, PJSIP_ERRNO_TO_SIP_STATUS(status),
-				       NULL, &tdata);
+	status = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
 	if (tdata && status == PJ_SUCCESS)
 	    pjsip_inv_send_msg(inv, tdata);
 
@@ -974,8 +974,8 @@
      */
     if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 && 
 	  (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
-	 ((*options & PJSIP_INV_REQUIRE_100REL)!=0 && 
-	  (rem_option & PJSIP_INV_SUPPORT_100REL)==0))
+	 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 && 
+	  (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
     {
 	code = PJSIP_SC_EXTENSION_REQUIRED;
 	status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
@@ -1755,6 +1755,7 @@
 {
     pjsip_tx_data *tdata;
     pj_status_t status;
+    pjsip_status_code st_code2;
 
     /* Verify arguments. */
     PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
@@ -1771,13 +1772,11 @@
 	goto on_return;
 
     /* Invoke Session Timers module */
-    status = pjsip_timer_process_req(inv, rdata);
+    status = pjsip_timer_process_req(inv, rdata, &st_code2);
     if (status != PJ_SUCCESS) {
 	pj_status_t status2;
 
-	status2 = pjsip_dlg_modify_response(inv->dlg, tdata, 
-					    PJSIP_ERRNO_TO_SIP_STATUS(status),
-					    NULL);
+	status2 = pjsip_dlg_modify_response(inv->dlg, tdata, st_code2, NULL);
 	if (status2 != PJ_SUCCESS) {
 	    pjsip_tx_data_dec_ref(tdata);
 	    goto on_return;
@@ -2638,12 +2637,12 @@
     pjmedia_sdp_neg_state neg_state;
     pj_status_t status;
     pjsip_tx_data *tdata = NULL;
+    pjsip_status_code st_code;
 
     /* Invoke Session Timers module */
-    status = pjsip_timer_process_req(inv, rdata);
+    status = pjsip_timer_process_req(inv, rdata, &st_code);
     if (status != PJ_SUCCESS) {
-	status = pjsip_dlg_create_response(inv->dlg, rdata, 
-					   PJSIP_ERRNO_TO_SIP_STATUS(status),
+	status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
 					   NULL, &tdata);
 	goto on_return;
     }
@@ -3659,6 +3658,7 @@
 	    pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
 	    pjsip_tx_data *tdata;
 	    pj_status_t status;
+	    pjsip_status_code st_code;
 
 	    /* Check if we have INVITE pending. */
 	    if (inv->invite_tsx && inv->invite_tsx!=tsx) {
@@ -3682,11 +3682,10 @@
 	    inv->invite_tsx = tsx;
 
 	    /* Process session timers headers in the re-INVITE */
-	    status = pjsip_timer_process_req(inv, rdata);
+	    status = pjsip_timer_process_req(inv, rdata, &st_code);
 	    if (status != PJ_SUCCESS) {
-		status = pjsip_dlg_create_response(inv->dlg, rdata, 
-					   PJSIP_ERRNO_TO_SIP_STATUS(status), 
-					   NULL, &tdata);
+		status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
+						   NULL, &tdata);
 		if (status != PJ_SUCCESS)
 		    return;
 
diff --git a/pjsip/src/pjsip-ua/sip_timer.c b/pjsip/src/pjsip-ua/sip_timer.c
index 628e0e2..1200d13 100644
--- a/pjsip/src/pjsip-ua/sip_timer.c
+++ b/pjsip/src/pjsip-ua/sip_timer.c
@@ -27,9 +27,8 @@
 #define THIS_FILE		"sip_timer.c"
 
 
-/* Constant values of Session Timers */
+/* Constant of Session Timers */
 #define ABS_MIN_SE		90	/* Absolute Min-SE, in seconds	    */
-#define DEF_SE			1800	/* Default SE, in seconds	    */
 
 
 /* String definitions */
@@ -60,6 +59,8 @@
     pj_timer_entry		 timer;		/**< Timer entry	    */
     pj_bool_t			 use_update;	/**< Use UPDATE method to
 						     refresh the session    */
+    pjsip_role_e		 role;		/**< Role in last INVITE/
+						     UPDATE transaction.    */
 
 } pjsip_timer;
 
@@ -120,6 +121,10 @@
     const pjsip_parser_const_t *pc = pjsip_parser_const();
     const pj_str_t *hname = pjsip_use_compact_form? &hdr->sname : &hdr->name;
 
+    /* Print header name and value */
+    if ((endbuf - p) < (hname->slen + 16))
+	return -1;
+
     copy_advance(p, (*hname));
     *p++ = ':';
     *p++ = ' ';
@@ -127,14 +132,19 @@
     printed = pj_utoa(hdr->sess_expires, p);
     p += printed;
 
-    if (hdr->refresher.slen && (endbuf-p) > (hdr->refresher.slen + 2))
+    /* Print 'refresher' param */
+    if (hdr->refresher.slen)
     {
+	if  ((endbuf - p) < (STR_REFRESHER.slen + 2 + hdr->refresher.slen))
+	    return -1;
+
 	*p++ = ';';
 	copy_advance(p, STR_REFRESHER);
 	*p++ = '=';
 	copy_advance(p, hdr->refresher);
     }
 
+    /* Print generic params */
     printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
 				   &pc->pjsip_TOKEN_SPEC, 
 				   &pc->pjsip_TOKEN_SPEC, ';');
@@ -176,6 +186,10 @@
     int printed;
     const pjsip_parser_const_t *pc = pjsip_parser_const();
 
+    /* Print header name and value */
+    if ((endbuf - p) < (hdr->name.slen + 16))
+	return -1;
+
     copy_advance(p, hdr->name);
     *p++ = ':';
     *p++ = ' ';
@@ -183,6 +197,7 @@
     printed = pj_utoa(hdr->min_se, p);
     p += printed;
 
+    /* Print generic params */
     printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
 				   &pc->pjsip_TOKEN_SPEC, 
 				   &pc->pjsip_TOKEN_SPEC, ';');
@@ -323,8 +338,8 @@
 
     /* Check our role */
     as_refresher = 
-	(inv->timer->refresher == TR_UAC && inv->role == PJSIP_ROLE_UAC) ||
-	(inv->timer->refresher == TR_UAS && inv->role == PJSIP_ROLE_UAS);
+	(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) {
@@ -417,8 +432,8 @@
 			timer_cb);	    /* callback */
     
     /* Set delay based on role, refresher or refreshee */
-    if ((timer->refresher == TR_UAC && inv->role == PJSIP_ROLE_UAC) ||
-	(timer->refresher == TR_UAS && inv->role == PJSIP_ROLE_UAS))
+    if ((timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) ||
+	(timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS))
     {
 	/* Next refresh, the delay is half of session expire */
 	delay.sec = timer->setting.sess_expires / 2;
@@ -487,11 +502,11 @@
 /*
  * Initialize Session Timers setting with default values.
  */
-PJ_DEF(pj_status_t) pjsip_timer_default_setting(pjsip_timer_setting *setting)
+PJ_DEF(pj_status_t) pjsip_timer_setting_default(pjsip_timer_setting *setting)
 {
     pj_bzero(setting, sizeof(pjsip_timer_setting));
 
-    setting->sess_expires = DEF_SE;
+    setting->sess_expires = PJSIP_SESS_TIMER_DEF_SE;
     setting->min_se = ABS_MIN_SE;
 
     return PJ_SUCCESS;
@@ -526,7 +541,7 @@
 
 	pj_memcpy(s, setting, sizeof(*s));
     } else {
-	pjsip_timer_default_setting(s);
+	pjsip_timer_setting_default(s);
     }
 
     return PJ_SUCCESS;
@@ -604,11 +619,13 @@
  * - 2xx final response
  */
 PJ_DEF(pj_status_t) pjsip_timer_process_resp(pjsip_inv_session *inv,
-					     const pjsip_rx_data *rdata)
+					     const pjsip_rx_data *rdata,
+					     pjsip_status_code *st_code)
 {
     const pjsip_msg *msg;
 
-    PJ_ASSERT_RETURN(inv && rdata, PJ_EINVAL);
+    PJ_ASSERT_ON_FAIL(inv && rdata,
+	{if(st_code)*st_code=PJSIP_SC_INTERNAL_SERVER_ERROR;return PJ_EINVAL;});
 
     /* Check if Session Timers is supported */
     if ((inv->options & PJSIP_INV_SUPPORT_TIMER) == 0)
@@ -704,6 +721,8 @@
 	     * require or force to use Session Timers.
 	     */
 	    if (inv->options & PJSIP_INV_REQUIRE_TIMER) {
+		if (st_code)
+		    *st_code = PJSIP_SC_EXTENSION_REQUIRED;
 		pjsip_timer_end_session(inv);
 		return PJSIP_ERRNO_FROM_SIP_STATUS(
 					    PJSIP_SC_EXTENSION_REQUIRED);
@@ -726,6 +745,8 @@
 	if (se_hdr && 
 	    se_hdr->sess_expires < inv->timer->setting.min_se)
 	{
+	    if (st_code)
+		*st_code = PJSIP_SC_SESSION_TIMER_TOO_SMALL;
 	    pjsip_timer_end_session(inv);
 	    return PJSIP_ERRNO_FROM_SIP_STATUS(
 					    PJSIP_SC_SESSION_TIMER_TOO_SMALL);
@@ -757,6 +778,9 @@
 
 	PJ_TODO(CHECK_IF_REMOTE_SUPPORT_UPDATE);
 
+	/* Remember our role in this transaction */
+	inv->timer->role = PJSIP_ROLE_UAC;
+
 	/* Finally, set active flag and start the Session Timers */
 	inv->timer->active = PJ_TRUE;
 	start_timer(inv);
@@ -769,14 +793,16 @@
  * Handle incoming INVITE or UPDATE request.
  */
 PJ_DEF(pj_status_t) pjsip_timer_process_req(pjsip_inv_session *inv,
-					    const pjsip_rx_data *rdata)
+					    const pjsip_rx_data *rdata,
+					    pjsip_status_code *st_code)
 {
     pjsip_min_se_hdr *min_se_hdr;
     pjsip_sess_expires_hdr *se_hdr;
     const pjsip_msg *msg;
     unsigned min_se;
 
-    PJ_ASSERT_RETURN(inv && rdata, PJ_EINVAL);
+    PJ_ASSERT_ON_FAIL(inv && rdata,
+	{if(st_code)*st_code=PJSIP_SC_INTERNAL_SERVER_ERROR;return PJ_EINVAL;});
 
     /* Check if Session Timers is supported */
     if ((inv->options & PJSIP_INV_SUPPORT_TIMER) == 0)
@@ -827,8 +853,11 @@
     /* Validate SE. Session-Expires cannot be lower than Min-SE 
      * (or 90 seconds if Min-SE is not set).
      */
-    if (se_hdr && se_hdr->sess_expires < min_se)
+    if (se_hdr && se_hdr->sess_expires < min_se) {
+	if (st_code)
+	    *st_code = PJSIP_SC_SESSION_TIMER_TOO_SMALL;
 	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_SESSION_TIMER_TOO_SMALL);
+    }
 
     /* Update SE. Note that there is a case that SE is not available in the
      * request (which means remote doesn't want/support it), but local insists
@@ -881,8 +910,11 @@
 
     if (msg->line.status.code/100 == 2)
     {
-	/* Add Session-Expires header and start the timer */
 	if (inv->timer && inv->timer->active) {
+	    /* Remember our role in this transaction */
+	    inv->timer->role = PJSIP_ROLE_UAS;
+
+	    /* Add Session-Expires header and start the timer */
 	    add_timer_headers(inv, tdata, PJ_TRUE, PJ_FALSE);
 	    start_timer(inv);
 	}
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index 013a249..e244aec 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -492,18 +492,10 @@
     }
 
     /* Init Session Timers */
-    {
-	pjsip_timer_setting timer_setting;
-
-	pjsip_timer_default_setting(&timer_setting);
-	timer_setting.sess_expires = acc->cfg.timer_se;
-	timer_setting.min_se = acc->cfg.timer_min_se;
-
-	status = pjsip_timer_init_session(inv, &timer_setting);
-	if (status != PJ_SUCCESS) {
-	    pjsua_perror(THIS_FILE, "Session Timer init failed", status);
-	    goto on_error;
-	}
+    status = pjsip_timer_init_session(inv, &acc->cfg.timer_setting);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Session Timer init failed", status);
+	goto on_error;
     }
 
     /* Create and associate our data in the session. */
@@ -916,26 +908,19 @@
     }
 
     /* Init Session Timers */
-    {
-	pjsip_timer_setting timer_setting;
+    status = pjsip_timer_init_session(inv, 
+				    &pjsua_var.acc[acc_id].cfg.timer_setting);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Session Timer init failed", status);
+	status = pjsip_inv_end_session(inv, PJSIP_SC_INTERNAL_SERVER_ERROR,
+				       NULL, &response);
+	if (status == PJ_SUCCESS && response)
+	    status = pjsip_inv_send_msg(inv, response);
 
-	pjsip_timer_default_setting(&timer_setting);
-	timer_setting.sess_expires = pjsua_var.acc[acc_id].cfg.timer_se;
-	timer_setting.min_se = pjsua_var.acc[acc_id].cfg.timer_min_se;
+	pjsua_media_channel_deinit(call->index);
 
-	status = pjsip_timer_init_session(inv, &timer_setting);
-	if (status != PJ_SUCCESS) {
-	    pjsua_perror(THIS_FILE, "Session Timer init failed", status);
-	    status = pjsip_inv_end_session(inv, PJSIP_SC_INTERNAL_SERVER_ERROR,
-					   NULL, &response);
-	    if (status == PJ_SUCCESS && response)
-		status = pjsip_inv_send_msg(inv, response);
-
-	    pjsua_media_channel_deinit(call->index);
-
-	    PJSUA_UNLOCK();
-	    return PJ_TRUE;
-	}
+	PJSUA_UNLOCK();
+	return PJ_TRUE;
     }
 
     /* Update NAT type of remote endpoint, only when there is SDP in
@@ -978,7 +963,7 @@
 	    pjsip_inv_terminate(inv, 500, PJ_FALSE);
 	} else {
 	    pjsip_inv_send_msg(inv, response);
-	    pjsip_inv_terminate(inv, PJSIP_ERRNO_TO_SIP_STATUS(status), 
+	    pjsip_inv_terminate(inv, response->msg->line.status.code, 
 				PJ_FALSE);
 	}
 	pjsua_media_channel_deinit(call->index);
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 6cd9cac..c714be7 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -87,8 +87,6 @@
 
 PJ_DEF(void) pjsua_config_default(pjsua_config *cfg)
 {
-    pjsip_timer_setting timer_setting;
-
     pj_bzero(cfg, sizeof(*cfg));
 
     cfg->max_calls = ((PJSUA_MAX_CALLS) < 4) ? (PJSUA_MAX_CALLS) : 4;
@@ -101,9 +99,7 @@
 #endif
     cfg->hangup_forked_call = PJ_TRUE;
 
-    pjsip_timer_default_setting(&timer_setting);
-    cfg->timer_se = timer_setting.sess_expires;
-    cfg->timer_min_se = timer_setting.min_se;
+    pjsip_timer_setting_default(&cfg->timer_setting);
 }
 
 PJ_DEF(void) pjsua_config_dup(pj_pool_t *pool,
@@ -157,8 +153,7 @@
     cfg->allow_contact_rewrite = PJ_TRUE;
     cfg->require_100rel = pjsua_var.ua_cfg.require_100rel;
     cfg->require_timer = pjsua_var.ua_cfg.require_timer;
-    cfg->timer_se = pjsua_var.ua_cfg.timer_se;
-    cfg->timer_min_se = pjsua_var.ua_cfg.timer_min_se;
+    cfg->timer_setting = pjsua_var.ua_cfg.timer_setting;
     cfg->ka_interval = 15;
     cfg->ka_data = pj_str("\r\n");
 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)