Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 2856)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 2858)
@@ -20,4 +20,5 @@
 #include <pjsip-ua/sip_inv.h>
 #include <pjsip-ua/sip_100rel.h>
+#include <pjsip-ua/sip_timer.h>
 #include <pjsip/sip_module.h>
 #include <pjsip/sip_endpoint.h>
@@ -232,4 +233,5 @@
 	}
 	pjsip_100rel_end_session(inv);
+	pjsip_timer_end_session(inv);
 	pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
     }
@@ -482,4 +484,5 @@
     pjsip_inv_session *inv;
     pjsip_msg *msg = rdata->msg_info.msg;
+    pj_status_t status;
 
     dlg = pjsip_rdata_get_dlg(rdata);
@@ -507,4 +510,21 @@
 	return PJ_TRUE;
 
+    }
+
+    /* Pass response to timer session module */
+    status = pjsip_timer_process_resp(inv, rdata);
+    if (status != PJ_SUCCESS) {
+	pjsip_event e;
+	pjsip_tx_data *tdata;
+
+	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);
+	if (tdata && status == PJ_SUCCESS)
+	    pjsip_inv_send_msg(inv, tdata);
+
+	return PJ_TRUE;
     }
 
@@ -635,5 +655,4 @@
     if (options & PJSIP_INV_REQUIRE_100REL)
 	options |= PJSIP_INV_SUPPORT_100REL;
-
     if (options & PJSIP_INV_REQUIRE_TIMER)
 	options |= PJSIP_INV_SUPPORT_TIMER;
@@ -717,5 +736,4 @@
     if (*options & PJSIP_INV_REQUIRE_100REL)
 	*options |= PJSIP_INV_SUPPORT_100REL;
-
     if (*options & PJSIP_INV_REQUIRE_TIMER)
 	*options |= PJSIP_INV_SUPPORT_TIMER;
@@ -868,11 +886,11 @@
     if (sup_hdr) {
 	unsigned i;
-	pj_str_t STR_100REL = { "100rel", 6};
-	pj_str_t STR_TIMER = { "timer", 5 };
+	const pj_str_t STR_100REL = { "100rel", 6};
+	const pj_str_t STR_TIMER = { "timer", 5};
 
 	for (i=0; i<sup_hdr->count; ++i) {
 	    if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
 		rem_option |= PJSIP_INV_SUPPORT_100REL;
-	    else if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
+	    if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
 		rem_option |= PJSIP_INV_SUPPORT_TIMER;
 	}
@@ -885,6 +903,6 @@
 	unsigned i;
 	const pj_str_t STR_100REL = { "100rel", 6};
+	const pj_str_t STR_REPLACES = { "replaces", 8 };
 	const pj_str_t STR_TIMER = { "timer", 5 };
-	const pj_str_t STR_REPLACES = { "replaces", 8 };
 	unsigned unsupp_cnt = 0;
 	pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
@@ -896,6 +914,6 @@
 		rem_option |= PJSIP_INV_REQUIRE_100REL;
 
-	    } else if ((*options && PJSIP_INV_SUPPORT_TIMER) &&
-		       pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
+	    } else if ((*options & PJSIP_INV_SUPPORT_TIMER) && 
+		pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
 	    {
 		rem_option |= PJSIP_INV_REQUIRE_TIMER;
@@ -957,6 +975,6 @@
     if ( ((*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))
+	 ((*options & PJSIP_INV_REQUIRE_100REL)!=0 && 
+	  (rem_option & PJSIP_INV_SUPPORT_100REL)==0))
     {
 	code = PJSIP_SC_EXTENSION_REQUIRED;
@@ -972,5 +990,4 @@
 	    if (*options & PJSIP_INV_REQUIRE_100REL)
 		req_hdr->values[req_hdr->count++] = pj_str("100rel");
-
 	    if (*options & PJSIP_INV_REQUIRE_TIMER)
 		req_hdr->values[req_hdr->count++] = pj_str("timer");
@@ -1098,5 +1115,4 @@
     if (options & PJSIP_INV_REQUIRE_100REL)
 	options |= PJSIP_INV_SUPPORT_100REL;
-
     if (options & PJSIP_INV_REQUIRE_TIMER)
 	options |= PJSIP_INV_SUPPORT_TIMER;
@@ -1170,5 +1186,5 @@
     /* Create 100rel handler */
     if (inv->options & PJSIP_INV_REQUIRE_100REL) {
-	    pjsip_100rel_attach(inv);
+	pjsip_100rel_attach(inv);
     }
 
@@ -1395,13 +1411,22 @@
 
     /* Add Require header. */
-    if (inv->options & PJSIP_INV_REQUIRE_100REL) {
-	    const pj_str_t HREQ = { "Require", 7 };
-	    const pj_str_t tag_100rel = { "100rel", 6 };
-	    pjsip_generic_string_hdr *hreq;
-
-	    hreq = pjsip_generic_string_hdr_create(tdata->pool, &HREQ, 
-						   &tag_100rel);
-	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
-    }
+    if ((inv->options & PJSIP_INV_REQUIRE_100REL) ||
+	(inv->options & PJSIP_INV_REQUIRE_TIMER)) 
+    {
+	pjsip_require_hdr *hreq;
+
+	hreq = pjsip_require_hdr_create(tdata->pool);
+
+	if (inv->options & PJSIP_INV_REQUIRE_100REL)
+	    hreq->values[hreq->count++] = pj_str("100rel");
+	if (inv->options & PJSIP_INV_REQUIRE_TIMER)
+	    hreq->values[hreq->count++] = pj_str("timer");
+
+	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
+    }
+
+    status = pjsip_timer_update_req(inv, tdata);
+    if (status != PJ_SUCCESS)
+	goto on_return;
 
     /* Done. */
@@ -1746,4 +1771,25 @@
 	goto on_return;
 
+    /* Invoke Session Timers module */
+    status = pjsip_timer_process_req(inv, rdata);
+    if (status != PJ_SUCCESS) {
+	pj_status_t status2;
+
+	status2 = pjsip_dlg_modify_response(inv->dlg, tdata, 
+					    PJSIP_ERRNO_TO_SIP_STATUS(status),
+					    NULL);
+	if (status2 != PJ_SUCCESS) {
+	    pjsip_tx_data_dec_ref(tdata);
+	    goto on_return;
+	}
+	status2 = pjsip_timer_update_resp(inv, tdata);
+	if (status2 == PJ_SUCCESS)
+	    *p_tdata = tdata;
+	else
+	    pjsip_tx_data_dec_ref(tdata);
+
+	goto on_return;
+    }
+
     /* Process SDP in answer */
     status = process_answer(inv, st_code, tdata, sdp);
@@ -1758,4 +1804,7 @@
     PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
 	      pjsip_tx_data_get_info(inv->last_answer)));
+
+    /* Invoke Session Timers */
+    pjsip_timer_update_resp(inv, tdata);
 
     *p_tdata = tdata;
@@ -1809,4 +1858,6 @@
     }
 
+    /* Invoke Session Timers */
+    pjsip_timer_update_resp(inv, last_res);
 
     *p_tdata = last_res;
@@ -1913,4 +1964,7 @@
     case PJSIP_INV_STATE_CONNECTING:
     case PJSIP_INV_STATE_CONFIRMED:
+	/* End Session Timer */
+	pjsip_timer_end_session(inv);
+
 	/* For established dialog, send BYE */
 	status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(), 
@@ -2300,4 +2354,8 @@
     /* Unlock dialog. */
     pjsip_dlg_dec_lock(inv->dlg);
+
+    status = pjsip_timer_update_req(inv, tdata);
+    if (status != PJ_SUCCESS)
+	goto on_error;
 
     *p_tdata = tdata;
@@ -2582,4 +2640,13 @@
     pjsip_tx_data *tdata = NULL;
 
+    /* Invoke Session Timers module */
+    status = pjsip_timer_process_req(inv, rdata);
+    if (status != PJ_SUCCESS) {
+	status = pjsip_dlg_create_response(inv->dlg, rdata, 
+					   PJSIP_ERRNO_TO_SIP_STATUS(status),
+					   NULL, &tdata);
+	goto on_return;
+    }
+
     neg_state = pjmedia_sdp_neg_get_state(inv->neg);
 
@@ -2634,4 +2701,9 @@
 	}
     }
+
+on_return:
+    /* Invoke Session Timers */
+    if (status == PJ_SUCCESS)
+	status = pjsip_timer_update_resp(inv, tdata);
 
     if (status != PJ_SUCCESS) {
@@ -3610,4 +3682,18 @@
 	    inv->invite_tsx = tsx;
 
+	    /* Process session timers headers in the re-INVITE */
+	    status = pjsip_timer_process_req(inv, rdata);
+	    if (status != PJ_SUCCESS) {
+		status = pjsip_dlg_create_response(inv->dlg, rdata, 
+					   PJSIP_ERRNO_TO_SIP_STATUS(status), 
+					   NULL, &tdata);
+		if (status != PJ_SUCCESS)
+		    return;
+
+		pjsip_timer_update_resp(inv, tdata);
+		status = pjsip_dlg_send_response(dlg, tsx, tdata);
+		return;
+	    }
+
 	    /* Process SDP in incoming message. */
 	    status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
@@ -3717,4 +3803,7 @@
 	    }
 
+	    /* Invoke Session Timers */
+	    pjsip_timer_update_resp(inv, tdata);
+
 	    /* Send 2xx regardless of the status of negotiation */
 	    status = pjsip_inv_send_msg(inv, tdata);
