Index: pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 4438)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 4444)
@@ -134,6 +134,8 @@
 					 (64*PJSIP_T1_TIMEOUT)%1000 };
 
-#define TIMER_INACTIVE	0
-#define TIMER_ACTIVE	1
+#define TIMER_INACTIVE		0
+#define RETRANSMIT_TIMER	1
+#define TIMEOUT_TIMER		2
+#define TRANSPORT_ERR_TIMER	3
 
 
@@ -165,4 +167,14 @@
 				       pjsip_transport_state state,
 				       const pjsip_transport_state_info *info);
+static void 	   tsx_set_state( pjsip_transaction *tsx,
+            	                  pjsip_tsx_state_e state,
+            	                  pjsip_event_id_e event_src_type,
+            	                  void *event_src );
+static void 	   tsx_set_state_no_notify( pjsip_transaction *tsx,
+            	                            pjsip_tsx_state_e state,
+            	                            pjsip_event_id_e event_src_type,
+            	                            void *event_src );
+static void 	   tsx_set_status_code(pjsip_transaction *tsx,
+            	                       int code, const pj_str_t *reason);
 static pj_status_t tsx_create( pjsip_module *tsx_user,
                                pj_grp_lock_t *grp_lock,
@@ -921,4 +933,29 @@
 }
 
+/* Utility: schedule a timer */
+static pj_status_t tsx_schedule_timer(pjsip_transaction *tsx,
+                                      pj_timer_entry *entry,
+                                      const pj_time_val *delay,
+                                      int active_id)
+{
+    pj_timer_heap_t *timer_heap = pjsip_endpt_get_timer_heap(tsx->endpt);
+    pj_status_t status;
+
+    pj_assert(active_id != 0);
+    status = pj_timer_heap_schedule_w_grp_lock(timer_heap, entry,
+                                               delay, active_id,
+                                               tsx->grp_lock);
+
+    return status;
+}
+
+/* Utility: cancel a timer */
+static int tsx_cancel_timer(pjsip_transaction *tsx,
+                            pj_timer_entry *entry)
+{
+    pj_timer_heap_t *timer_heap = pjsip_endpt_get_timer_heap(tsx->endpt);
+    return pj_timer_heap_cancel_if_active(timer_heap, entry, TIMER_INACTIVE);
+}
+
 /* Create and initialize basic transaction structure.
  * This function is called by both UAC and UAS creation.
@@ -947,8 +984,8 @@
 
     tsx->handle_200resp = 1;
-    tsx->retransmit_timer.id = 0;
+    tsx->retransmit_timer.id = TIMER_INACTIVE;
     tsx->retransmit_timer.user_data = tsx;
     tsx->retransmit_timer.cb = &tsx_timer_callback;
-    tsx->timeout_timer.id = 0;
+    tsx->timeout_timer.id = TIMER_INACTIVE;
     tsx->timeout_timer.user_data = tsx;
     tsx->timeout_timer.cb = &tsx_timer_callback;
@@ -1006,13 +1043,8 @@
     }
     /* Cancel timeout timer. */
-    if (tsx->timeout_timer.id != 0) {
-	pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
-	tsx->timeout_timer.id = 0;
-    }
+    tsx_cancel_timer(tsx, &tsx->timeout_timer);
+
     /* Cancel retransmission timer. */
-    if (tsx->retransmit_timer.id != 0) {
-	pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-	tsx->retransmit_timer.id = 0;
-    }
+    tsx_cancel_timer(tsx, &tsx->retransmit_timer);
 
     /* Clear some pending flags. */
@@ -1040,28 +1072,70 @@
 
 /*
- * Callback when timer expires.
+ * Callback when timer expires. Transport error also piggybacks this event
+ * to avoid deadlock (https://trac.pjsip.org/repos/ticket/1646).
  */
 static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry)
 {
-    pjsip_event event;
     pjsip_transaction *tsx = (pjsip_transaction*) entry->user_data;
 
     PJ_UNUSED_ARG(theap);
 
-    entry->id = 0;
-    
-    PJ_LOG(5,(tsx->obj_name, "%s timer event", 
-	     (entry==&tsx->retransmit_timer ? "Retransmit":"Timeout")));
-    pj_log_push_indent();
-
-
-    PJSIP_EVENT_INIT_TIMER(event, entry);
-
-    /* Dispatch event to transaction. */
-    pj_grp_lock_acquire(tsx->grp_lock);
-    (*tsx->state_handler)(tsx, &event);
-    pj_grp_lock_release(tsx->grp_lock);
-
-    pj_log_pop_indent();
+    if (entry->id == TRANSPORT_ERR_TIMER) {
+	/* Posted transport error event */
+	entry->id = 0;
+	if (tsx->state < PJSIP_TSX_STATE_TERMINATED) {
+	    pjsip_tsx_state_e prev_state;
+
+	    pj_grp_lock_acquire(tsx->grp_lock);
+	    prev_state = tsx->state;
+
+	    if (tsx->status_code < 200) {
+		pj_str_t err;
+		char errmsg[PJ_ERR_MSG_SIZE];
+
+		err = pj_strerror(tsx->transport_err, errmsg, sizeof(errmsg));
+		tsx_set_status_code(tsx, PJSIP_SC_TSX_TRANSPORT_ERROR, &err);
+	    }
+
+	    /* Set transaction state etc, but don't notify TU now,
+	     * otherwise we'll get a deadlock. See:
+	     * https://trac.pjsip.org/repos/ticket/1646
+	     */
+	    tsx_set_state_no_notify( tsx, PJSIP_TSX_STATE_TERMINATED,
+	                             PJSIP_EVENT_TRANSPORT_ERROR, NULL);
+	    pj_grp_lock_release(tsx->grp_lock);
+
+	    /* Now notify TU about state change, WITHOUT holding the
+	     * group lock. It should be safe to do so; transaction will
+	     * not get destroyed because group lock reference counter
+	     * has been incremented by the timer heap.
+	     */
+	    if (tsx->tsx_user && tsx->tsx_user->on_tsx_state) {
+		pjsip_event e;
+		PJSIP_EVENT_INIT_TSX_STATE(e, tsx,
+		                           PJSIP_EVENT_TRANSPORT_ERROR, NULL,
+					   prev_state);
+		(*tsx->tsx_user->on_tsx_state)(tsx, &e);
+	    }
+	}
+    } else {
+	pjsip_event event;
+
+	entry->id = 0;
+
+	PJ_LOG(5,(tsx->obj_name, "%s timer event",
+		 (entry==&tsx->retransmit_timer ? "Retransmit":"Timeout")));
+	pj_log_push_indent();
+
+
+	PJSIP_EVENT_INIT_TIMER(event, entry);
+
+	/* Dispatch event to transaction. */
+	pj_grp_lock_acquire(tsx->grp_lock);
+	(*tsx->state_handler)(tsx, &event);
+	pj_grp_lock_release(tsx->grp_lock);
+
+	pj_log_pop_indent();
+    }
 }
 
@@ -1141,15 +1215,6 @@
 
 	lock_timer(tsx);
-
-	/* Cancel timeout timer. */
-	if (tsx->timeout_timer.id != 0) {
-	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
-	    tsx->timeout_timer.id = 0;
-	}
-
-	tsx->timeout_timer.id = TIMER_ACTIVE;
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer,
-				    &timeout);
-
+	tsx_cancel_timer(tsx, &tsx->timeout_timer);
+	tsx_schedule_timer( tsx, &tsx->timeout_timer, &timeout, TIMEOUT_TIMER);
 	unlock_timer(tsx);
 
@@ -1166,4 +1231,15 @@
 }
 
+/* Set transaction state without notifying tsx_user */
+static void tsx_set_state_no_notify( pjsip_transaction *tsx,
+                                     pjsip_tsx_state_e state,
+                                     pjsip_event_id_e event_src_type,
+                                     void *event_src )
+{
+    pjsip_module *tsx_user = tsx->tsx_user;
+    tsx->tsx_user = NULL;
+    tsx_set_state(tsx, state, event_src_type, event_src);
+    tsx->tsx_user = tsx_user;
+}
 
 /*
@@ -1551,8 +1627,5 @@
     pj_grp_lock_acquire(tsx->grp_lock);
     /* Cancel retransmission timer. */
-    if (tsx->retransmit_timer.id != 0) {
-	pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-	tsx->retransmit_timer.id = 0;
-    }
+    tsx_cancel_timer(tsx, &tsx->retransmit_timer);
     pj_grp_lock_release(tsx->grp_lock);
 
@@ -1592,8 +1665,5 @@
     }
 
-    if (tsx->timeout_timer.id != 0) {
-	pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
-	tsx->timeout_timer.id = 0;
-    }
+    tsx_cancel_timer(tsx, &tsx->timeout_timer);
 
     timeout.sec = 0;
@@ -1601,8 +1671,5 @@
     pj_time_val_normalize(&timeout);
 
-    tsx->timeout_timer.id = TIMER_ACTIVE;
-    pjsip_endpt_schedule_timer(tsx->endpt, &tsx->timeout_timer,
-			       &timeout);
-
+    tsx_schedule_timer(tsx, &tsx->timeout_timer, &timeout, TIMEOUT_TIMER);
 
     unlock_timer(tsx);
@@ -1829,12 +1896,7 @@
 	    if (tsx->timeout_timer.id) {
 		lock_timer(tsx);
-
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
-		tsx->timeout_timer.id = TIMER_INACTIVE;
-
-		tsx->timeout_timer.id = TIMER_ACTIVE;
-		pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-					    &timeout_timer_val);
-
+		tsx_cancel_timer(tsx, &tsx->timeout_timer);
+		tsx_schedule_timer( tsx, &tsx->timeout_timer,
+				    &timeout_timer_val, TIMEOUT_TIMER);
 		unlock_timer(tsx);
 	    }
@@ -1892,4 +1954,5 @@
     if (state == PJSIP_TP_STATE_DISCONNECTED) {
 	pjsip_transaction *tsx;
+	pj_time_val delay = {0, 0};
 
 	pj_assert(tp && info && info->user_data);
@@ -1897,18 +1960,13 @@
 	tsx = (pjsip_transaction*)info->user_data;
 
-	pj_grp_lock_acquire(tsx->grp_lock);
-
-	/* Terminate transaction when transport disconnected */
-	if (tsx->state < PJSIP_TSX_STATE_TERMINATED) {
-	    pj_str_t err;
-	    char errmsg[PJ_ERR_MSG_SIZE];
-
-	    err = pj_strerror(info->status, errmsg, sizeof(errmsg));
-	    tsx_set_status_code(tsx, PJSIP_SC_TSX_TRANSPORT_ERROR, &err);
-	    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-			   PJSIP_EVENT_TRANSPORT_ERROR, NULL);
-	}
-
-	pj_grp_lock_release(tsx->grp_lock);
+	/* Post the event for later processing, to avoid deadlock.
+	 * See https://trac.pjsip.org/repos/ticket/1646
+	 */
+	lock_timer(tsx);
+	tsx->transport_err = info->status;
+	tsx_cancel_timer(tsx, &tsx->timeout_timer);
+	tsx_schedule_timer(tsx, &tsx->timeout_timer, &delay,
+	                   TRANSPORT_ERR_TIMER);
+	unlock_timer(tsx);
     }
 }
@@ -2119,7 +2177,6 @@
 	timeout.sec = msec_time / 1000;
 	timeout.msec = msec_time % 1000;
-	tsx->retransmit_timer.id = TIMER_ACTIVE;
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer, 
-				    &timeout);
+	tsx_schedule_timer( tsx, &tsx->retransmit_timer, &timeout,
+	                    RETRANSMIT_TIMER);
     }
 }
@@ -2188,5 +2245,4 @@
 }
 
-
 /*
  * Handler for events in state Null.
@@ -2241,7 +2297,6 @@
 	 */
 	lock_timer(tsx);
-	tsx->timeout_timer.id = TIMER_ACTIVE;
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-				    &timeout_timer_val);
+	tsx_schedule_timer( tsx, &tsx->timeout_timer, &timeout_timer_val,
+	                    TIMEOUT_TIMER);
 	unlock_timer(tsx);
 
@@ -2254,7 +2309,6 @@
 		tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
 	    } else {
-	    	tsx->retransmit_timer.id = TIMER_ACTIVE;
-		pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer,
-					   &t1_timer_val);
+		tsx_schedule_timer(tsx, &tsx->retransmit_timer,
+		                   &t1_timer_val, RETRANSMIT_TIMER);
 	    }
 	}
@@ -2293,10 +2347,7 @@
 	       event->body.timer.entry == &tsx->timeout_timer) 
     {
-
 	/* Cancel retransmission timer. */
-	if (tsx->retransmit_timer.id != 0) {
-	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-	    tsx->retransmit_timer.id = 0;
-	}
+	tsx_cancel_timer(tsx, &tsx->retransmit_timer);
+
 	tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);
 
@@ -2305,5 +2356,5 @@
 
 	/* Inform TU. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
                        PJSIP_EVENT_TIMER, &tsx->timeout_timer);
 
@@ -2328,13 +2379,9 @@
 	 */
 	if (code >= 200) {
-	    if (tsx->retransmit_timer.id != 0) {
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-		tsx->retransmit_timer.id = 0;
-	    }
+	    tsx_cancel_timer(tsx, &tsx->retransmit_timer);
 
 	    if (tsx->timeout_timer.id != 0) {
 		lock_timer(tsx);
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
-		tsx->timeout_timer.id = 0;
+		tsx_cancel_timer(tsx, &tsx->timeout_timer);
 		unlock_timer(tsx);
 	    }
@@ -2344,8 +2391,5 @@
 	     * retransmit timer will be rescheduled at T2.
 	     */
-	    if (tsx->retransmit_timer.id != 0) {
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-		tsx->retransmit_timer.id = 0;
-	    }
+	    tsx_cancel_timer(tsx, &tsx->retransmit_timer);
 
 	    /* For provisional response, only cancel retransmit when this
@@ -2359,13 +2403,11 @@
 		/* Cancel timeout timer */
 		lock_timer(tsx);
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
+		tsx_cancel_timer(tsx, &tsx->timeout_timer);
 		unlock_timer(tsx);
 
 	    } else {
 		if (!tsx->is_reliable) {
-		    tsx->retransmit_timer.id = TIMER_ACTIVE;
-		    pjsip_endpt_schedule_timer(tsx->endpt, 
-					       &tsx->retransmit_timer,
-					       &t2_timer_val);
+		    tsx_schedule_timer(tsx, &tsx->retransmit_timer,
+		                       &t2_timer_val, RETRANSMIT_TIMER);
 		}
 	    }
@@ -2525,9 +2567,5 @@
 
 		/* Stop 1xx retransmission timer, if any */
-		if (tsx->retransmit_timer.id) {
-		    pjsip_endpt_cancel_timer(tsx->endpt, 
-					     &tsx->retransmit_timer);
-		    tsx->retransmit_timer.id = 0;
-		}
+		tsx_cancel_timer(tsx, &tsx->retransmit_timer);
 
 		/* Schedule retransmission */
@@ -2537,9 +2575,6 @@
 		} else {
 		    pj_time_val delay = {PJSIP_TSX_1XX_RETRANS_DELAY, 0};
-
-		    tsx->retransmit_timer.id = TIMER_ACTIVE;
-		    pjsip_endpt_schedule_timer( tsx->endpt, 
-						&tsx->retransmit_timer,
-						&delay);
+		    tsx_schedule_timer( tsx, &tsx->retransmit_timer, &delay,
+		                        RETRANSMIT_TIMER);
 		}
 	    }
@@ -2548,8 +2583,5 @@
 
 	    /* Stop 1xx retransmission timer, if any */
-	    if (tsx->retransmit_timer.id) {
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-		tsx->retransmit_timer.id = 0;
-	    }
+	    tsx_cancel_timer(tsx, &tsx->retransmit_timer);
 
 	    if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_200resp==0) {
@@ -2572,8 +2604,6 @@
 			tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
 		    } else {
-		    	tsx->retransmit_timer.id = TIMER_ACTIVE;
-			pjsip_endpt_schedule_timer( tsx->endpt, 
-						    &tsx->retransmit_timer,
-						    &t1_timer_val);
+			tsx_schedule_timer( tsx, &tsx->retransmit_timer,
+					    &t1_timer_val, RETRANSMIT_TIMER);
 		    }
 		}
@@ -2612,7 +2642,6 @@
 
 		lock_timer(tsx);
-		tsx->timeout_timer.id = TIMER_ACTIVE;
-		pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-                                            &timeout);
+		tsx_schedule_timer( tsx, &tsx->timeout_timer,
+                                    &timeout, TIMEOUT_TIMER);
 		unlock_timer(tsx);
 
@@ -2625,8 +2654,5 @@
 
 	    /* Stop 1xx retransmission timer, if any */
-	    if (tsx->retransmit_timer.id) {
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-		tsx->retransmit_timer.id = 0;
-	    }
+	    tsx_cancel_timer(tsx, &tsx->retransmit_timer);
 
 	    /* 3xx-6xx class message causes transaction to move to 
@@ -2646,18 +2672,15 @@
 	    if (tsx->method.id == PJSIP_INVITE_METHOD) {
 		/* Start timer H for INVITE */
-		tsx->timeout_timer.id = TIMER_ACTIVE;
-		pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
-					   &timeout_timer_val);
+		tsx_schedule_timer(tsx, &tsx->timeout_timer,
+				   &timeout_timer_val, TIMEOUT_TIMER);
 	    } else if (!tsx->is_reliable) {
 		/* Start timer J on 64*T1 seconds for non-INVITE */
-		tsx->timeout_timer.id = TIMER_ACTIVE;
-		pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
-					   &timeout_timer_val);
+		tsx_schedule_timer(tsx, &tsx->timeout_timer,
+				   &timeout_timer_val, TIMEOUT_TIMER);
 	    } else {
 		/* Start timer J on zero seconds for non-INVITE */
 		pj_time_val zero_time = { 0, 0 };
-		tsx->timeout_timer.id = TIMER_ACTIVE;
-		pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
-					   &zero_time);
+		tsx_schedule_timer(tsx, &tsx->timeout_timer,
+				   &zero_time, TIMEOUT_TIMER);
 	    }
 	    unlock_timer(tsx);
@@ -2675,8 +2698,6 @@
 			tsx->transport_flag |= TSX_HAS_PENDING_RESCHED;
 		    } else {
-		    	tsx->retransmit_timer.id = TIMER_ACTIVE;
-			pjsip_endpt_schedule_timer(tsx->endpt, 
-						   &tsx->retransmit_timer, 
-						   &t1_timer_val);
+			tsx_schedule_timer(tsx, &tsx->retransmit_timer,
+					   &t1_timer_val, RETRANSMIT_TIMER);
 		    }
 		}
@@ -2718,5 +2739,5 @@
 	tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL);
 
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
                        PJSIP_EVENT_TIMER, &tsx->timeout_timer);
 
@@ -2790,5 +2811,5 @@
 	/* Stop timeout timer B/F. */
 	lock_timer(tsx);
-	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
+	tsx_cancel_timer( tsx, &tsx->timeout_timer );
 	unlock_timer(tsx);
 
@@ -2816,14 +2837,10 @@
 	    }
 	    lock_timer(tsx);
-	    tsx->timeout_timer.id = TIMER_ACTIVE;
-	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-					&timeout);
+	    tsx_schedule_timer( tsx, &tsx->timeout_timer,
+				&timeout, TIMEOUT_TIMER);
 	    unlock_timer(tsx);
 
 	    /* Cancel retransmission timer */
-	    if (tsx->retransmit_timer.id != 0) {
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-		tsx->retransmit_timer.id = 0;
-	    }
+	    tsx_cancel_timer(tsx, &tsx->retransmit_timer);
 
 	    /* Move state to Completed, inform TU. */
@@ -2836,5 +2853,5 @@
 
 	/* Inform TU. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
 		       PJSIP_EVENT_TIMER, &tsx->timeout_timer);
 
@@ -2852,5 +2869,5 @@
 
 	/* Stop timer B. */
-	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
+	tsx_cancel_timer( tsx, &tsx->timeout_timer );
 
 	/* Generate and send ACK for INVITE. */
@@ -2885,6 +2902,5 @@
 	    timeout.sec = timeout.msec = 0;
 	}
-	tsx->timeout->timer.id = TSX_TIMER_TIMEOUT;
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout);
+	tsx_schedule_timer( tsx, &tsx->timeout_timer, &timeout, TIMEOUT_TIMER);
 
 	/* Inform TU. 
@@ -2905,13 +2921,9 @@
 
 	/* Cancel retransmission timer */
-	if (tsx->retransmit_timer.id != 0) {
-	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-	    tsx->retransmit_timer.id = 0;
-	}
+	tsx_cancel_timer(tsx, &tsx->retransmit_timer);
 
 	/* Stop timer B. */
 	lock_timer(tsx);
-	tsx->timeout_timer.id = 0;
-	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
+	tsx_cancel_timer( tsx, &tsx->timeout_timer );
 	unlock_timer(tsx);
 
@@ -2966,8 +2978,7 @@
 	 *  https://trac.pjsip.org/repos/ticket/1374
 	 */
-	if (tsx->timeout_timer.id)
-	    pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
-	tsx->timeout_timer.id = TIMER_ACTIVE;
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout);
+	tsx_cancel_timer( tsx, &tsx->timeout_timer );
+	tsx_schedule_timer( tsx, &tsx->timeout_timer, &timeout,
+	                    TIMEOUT_TIMER);
 	unlock_timer(tsx);
 
@@ -3021,14 +3032,11 @@
 
 	    /* Cease retransmission. */
-	    if (tsx->retransmit_timer.id != 0) {
-		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-		tsx->retransmit_timer.id = 0;
-	    }
+	    tsx_cancel_timer(tsx, &tsx->retransmit_timer);
+
 	    tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);
 
 	    /* Reschedule timeout timer. */
 	    lock_timer(tsx);
-	    pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
-	    tsx->timeout_timer.id = TIMER_ACTIVE;
+	    tsx_cancel_timer( tsx, &tsx->timeout_timer );
 
 	    /* Timer I is T4 timer for unreliable transports, and
@@ -3042,6 +3050,6 @@
 		timeout.msec = t4_timer_val.msec;
 	    }
-	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-					&timeout);
+	    tsx_schedule_timer( tsx, &tsx->timeout_timer,
+				&timeout, TIMEOUT_TIMER);
 	    unlock_timer(tsx);
 
@@ -3108,5 +3116,5 @@
 
 	/* Move to Terminated state. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
                        PJSIP_EVENT_TIMER, event->body.timer.entry );
 
@@ -3177,5 +3185,5 @@
 
 	/* Move to Terminated state. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
                        PJSIP_EVENT_TIMER, &tsx->timeout_timer );
 
