Index: /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 3137)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 3138)
@@ -125,4 +125,6 @@
 						     pending transport flag
 						     to be set on tsx.	    */
+    pjsip_tp_state_listener_key *tp_st_key;     /**< Transport state listener
+						     key.		    */
 
     /*
Index: /pjproject/trunk/pjsip/include/pjsip/sip_transport.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_transport.h	(revision 3137)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_transport.h	(revision 3138)
@@ -750,4 +750,6 @@
     pjsip_tpmgr		   *tpmgr;	    /**< Transport manager.	    */
     pj_timer_entry	    idle_timer;	    /**< Timer when ref cnt is zero.*/
+
+    void		   *data;	    /**< Internal transport data.   */
 
     /**
@@ -1271,4 +1273,9 @@
 
 /**
+ * Definition of transport state listener key.
+ */
+typedef void pjsip_tp_state_listener_key;
+
+/**
  * Structure of transport state info passed by #pjsip_tp_state_callback.
  */
@@ -1283,4 +1290,11 @@
      */
     void		*ext_info;
+
+    /**
+     * Optional user data. In global transport state notification, this will
+     * always be NULL.
+     */
+    void		*user_data;
+
 } pjsip_transport_state_info;
 
@@ -1302,20 +1316,26 @@
 
 /**
- * Setting callback of transport state notification. The caller will be
- * notified whenever the state of transport is changed. The type of
- * events are defined in #pjsip_transport_state.
+ * Set callback of global transport state notification. The caller will be
+ * notified whenever the state of any transport is changed. The type of events
+ * are defined in #pjsip_transport_state.
+ *
+ * Note that this function will override the existing callback, if any, so
+ * application is recommended to keep the old callback and manually forward
+ * the notification to the old callback, otherwise other component that 
+ * concerns about the transport state will no longer receive transport state 
+ * events.
  * 
  * @param mgr	    Transport manager.
  * @param cb	    Callback to be called to notify caller about transport 
- *		    status changing.
+ *		    state changing.
  *
  * @return	    PJ_SUCCESS on success, or the appropriate error code.
  */
-PJ_DECL(pj_status_t) pjsip_tpmgr_set_status_cb(pjsip_tpmgr *mgr,
-					       pjsip_tp_state_callback cb);
-
-
-/**
- * Getting the callback of transport state notification.
+PJ_DECL(pj_status_t) pjsip_tpmgr_set_state_cb(pjsip_tpmgr *mgr,
+					      pjsip_tp_state_callback cb);
+
+
+/**
+ * Get the callback of global transport state notification.
  * 
  * @param mgr	    Transport manager.
@@ -1323,6 +1343,40 @@
  * @return	    The transport state callback or NULL if it is not set.
  */
-PJ_DECL(pjsip_tp_state_callback) pjsip_tpmgr_get_status_cb(
-					       const pjsip_tpmgr *mgr);
+PJ_DECL(pjsip_tp_state_callback) pjsip_tpmgr_get_state_cb(
+					      const pjsip_tpmgr *mgr);
+
+
+/**
+ * Add a listener to the specified transport for transport state notification.
+ * 
+ * @param tp	    The transport.
+ * @param cb	    Callback to be called to notify listener about transport 
+ *		    state changing.
+ * @param user_data The user data.
+ * @param key	    Output key, used to remove this listener.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_transport_add_state_listener (
+					    pjsip_transport *tp,
+					    pjsip_tp_state_callback cb,
+					    void *user_data,
+					    pjsip_tp_state_listener_key **key);
+
+
+/**
+ * Remove a listener from the specified transport for transport state 
+ * notification.
+ * 
+ * @param tp	    The transport.
+ * @param key	    The listener key.
+ * @param user_data The user data, for validation purpose.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_transport_remove_state_listener (
+				    pjsip_transport *tp,
+				    pjsip_tp_state_listener_key *key,
+				    const void *user_data);
 
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 3137)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 3138)
@@ -181,4 +181,8 @@
 static void        tsx_timer_callback( pj_timer_heap_t *theap, 
 			               pj_timer_entry *entry);
+static void	   tsx_tp_state_callback(
+				       pjsip_transport *tp,
+				       pjsip_transport_state state,
+				       const pjsip_transport_state_info *info);
 static pj_status_t tsx_create( pjsip_module *tsx_user,
 			       pjsip_transaction **p_tsx);
@@ -188,4 +192,6 @@
 static int         tsx_send_msg( pjsip_transaction *tsx, 
                                  pjsip_tx_data *tdata);
+static void        tsx_update_transport( pjsip_transaction *tsx, 
+					 pjsip_transport *tp);
 
 
@@ -986,9 +992,7 @@
     struct tsx_lock_data *lck;
 
-    /* Decrement transport reference counter. */
-    if (tsx->transport) {
-	pjsip_transport_dec_ref( tsx->transport );
-	tsx->transport = NULL;
-    }
+    /* Release the transport */
+    tsx_update_transport(tsx, NULL);
+
     /* Decrement reference counter in transport selector */
     pjsip_tpselector_dec_ref(&tsx->tp_sel);
@@ -1405,6 +1409,5 @@
      */
     if (tsx->res_addr.transport) {
-	tsx->transport = tsx->res_addr.transport;
-	pjsip_transport_add_ref(tsx->transport);
+	tsx_update_transport(tsx, tsx->res_addr.transport);
 	pj_memcpy(&tsx->addr, &tsx->res_addr.addr, tsx->res_addr.addr_len);
 	tsx->addr_len = tsx->res_addr.addr_len;
@@ -1676,10 +1679,5 @@
 	if (tsx->transport != send_state->cur_transport) {
 	    /* Update transport. */
-	    if (tsx->transport) {
-		pjsip_transport_dec_ref(tsx->transport);
-		tsx->transport = NULL;
-	    }
-	    tsx->transport = send_state->cur_transport;
-	    pjsip_transport_add_ref(tsx->transport);
+	    tsx_update_transport(tsx, send_state->cur_transport);
 
 	    /* Update remote address. */
@@ -1730,10 +1728,6 @@
 	 * release the transport.
 	 */
-	if (send_state->cur_transport==tsx->transport &&
-	    tsx->transport != NULL)
-	{
-	    pjsip_transport_dec_ref(tsx->transport);
-	    tsx->transport = NULL;
-	}
+	if (send_state->cur_transport==tsx->transport)
+	    tsx_update_transport(tsx, NULL);
 
 	/* Also stop processing if transaction has been flagged with
@@ -1837,7 +1831,6 @@
 	lock_tsx(tsx, &lck);
 
-	/* Dereference transport. */
-	pjsip_transport_dec_ref(tsx->transport);
-	tsx->transport = NULL;
+	/* Release transport. */
+	tsx_update_transport(tsx, NULL);
 
 	/* Terminate transaction. */
@@ -1849,4 +1842,38 @@
    }
 }
+
+
+/*
+ * Callback when transport state changes.
+ */
+static void tsx_tp_state_callback( pjsip_transport *tp,
+				   pjsip_transport_state state,
+				   const pjsip_transport_state_info *info)
+{
+    if (state == PJSIP_TP_STATE_DISCONNECTED) {
+	pjsip_transaction *tsx;
+	struct tsx_lock_data lck;
+
+	pj_assert(tp && info && info->user_data);
+
+	tsx = (pjsip_transaction*)info->user_data;
+
+	lock_tsx(tsx, &lck);
+
+	/* 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);
+	}
+
+	unlock_tsx(tsx, &lck);
+    }
+}
+
 
 /*
@@ -1887,8 +1914,6 @@
 	     * resolution procedure.
 	     */
-	    if (tsx->transport) {
-		pjsip_transport_dec_ref(tsx->transport);
-		tsx->transport = NULL;
-	    }
+	    tsx_update_transport(tsx, NULL);
+
 	    tsx->addr_len = 0;
 	    tsx->res_addr.transport = NULL;
@@ -2096,4 +2121,24 @@
 
     return PJ_SUCCESS;
+}
+
+static void tsx_update_transport( pjsip_transaction *tsx, 
+				  pjsip_transport *tp)
+{
+    pj_assert(tsx);
+
+    if (tsx->transport) {
+	pjsip_transport_remove_state_listener(tsx->transport, 
+					       tsx->tp_st_key, tsx);
+	pjsip_transport_dec_ref( tsx->transport );
+	tsx->transport = NULL;
+    }
+
+    if (tp) {
+	tsx->transport = tp;
+	pjsip_transport_add_ref(tp);
+	pjsip_transport_add_state_listener(tp, &tsx_tp_state_callback, tsx,
+					    &tsx->tp_st_key);
+    }
 }
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 3137)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 3138)
@@ -34,4 +34,5 @@
 #include <pj/assert.h>
 #include <pj/lock.h>
+#include <pj/list.h>
 
 
@@ -91,6 +92,26 @@
     pj_status_t	   (*on_tx_msg)(pjsip_endpoint*, pjsip_tx_data*);
     pjsip_tp_state_callback tp_state_cb;
-    void *tp_state_user_data;
 };
+
+
+/* Transport state listener list type */
+typedef struct tp_state_listener
+{
+    PJ_DECL_LIST_MEMBER(struct tp_state_listener);
+
+    pjsip_tp_state_callback  cb;
+    void *user_data;
+} tp_state_listener;
+
+
+/*
+ * Transport data.
+ */
+typedef struct transport_data
+{
+    /* Transport listeners */
+    tp_state_listener	    st_listeners;
+    tp_state_listener	    st_listeners_empty;
+} transport_data;
 
 
@@ -179,4 +200,9 @@
 };
 
+static void tp_state_callback(pjsip_transport *tp,
+			      pjsip_transport_state state,
+			      const pjsip_transport_state_info *info);
+
+
 struct transport_names_t *get_tpname(pjsip_transport_type_e type)
 {
@@ -1092,4 +1118,9 @@
 #endif
 
+    /* Set transport state callback */
+    status = pjsip_tpmgr_set_state_cb(mgr, &tp_state_callback);
+    if (status != PJ_SUCCESS)
+	return status;
+
     PJ_LOG(5, (THIS_FILE, "Transport manager created."));
 
@@ -1738,6 +1769,9 @@
 }
 
-PJ_DEF(pj_status_t) pjsip_tpmgr_set_status_cb(pjsip_tpmgr *mgr,
-					      pjsip_tp_state_callback cb)
+/**
+ * Set callback of global transport state notification.
+ */
+PJ_DEF(pj_status_t) pjsip_tpmgr_set_state_cb(pjsip_tpmgr *mgr,
+					     pjsip_tp_state_callback cb)
 {
     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
@@ -1748,6 +1782,9 @@
 }
 
-PJ_DEF(pjsip_tp_state_callback) pjsip_tpmgr_get_status_cb(
-					      const pjsip_tpmgr *mgr)
+/**
+ * Get callback of global transport state notification.
+ */
+PJ_DEF(pjsip_tp_state_callback) pjsip_tpmgr_get_state_cb(
+					     const pjsip_tpmgr *mgr)
 {
     PJ_ASSERT_RETURN(mgr, NULL);
@@ -1755,2 +1792,141 @@
     return mgr->tp_state_cb;
 }
+
+
+/**
+ * Allocate and init transport data.
+ */
+static void init_tp_data(pjsip_transport *tp)
+{
+    transport_data *tp_data;
+
+    pj_assert(tp && !tp->data);
+
+    tp_data = PJ_POOL_ZALLOC_T(tp->pool, transport_data);
+    pj_list_init(&tp_data->st_listeners);
+    pj_list_init(&tp_data->st_listeners_empty);
+    tp->data = tp_data;
+}
+
+
+static void tp_state_callback(pjsip_transport *tp,
+			      pjsip_transport_state state,
+			      const pjsip_transport_state_info *info)
+{
+    transport_data *tp_data;
+
+    pj_lock_acquire(tp->lock);
+
+    tp_data = (transport_data*)tp->data;
+
+    /* Notify the transport state listeners, if any. */
+    if (!tp_data || pj_list_empty(&tp_data->st_listeners)) {
+	goto on_return;
+    } else {
+	pjsip_transport_state_info st_info;
+	tp_state_listener *st_listener = tp_data->st_listeners.next;
+
+	/* As we need to put the user data into the transport state info,
+	 * let's use a copy of transport state info.
+	 */
+	pj_memcpy(&st_info, info, sizeof(st_info));
+	while (st_listener != &tp_data->st_listeners) {
+	    st_info.user_data = st_listener->user_data;
+	    (*st_listener->cb)(tp, state, &st_info);
+
+	    st_listener = st_listener->next;
+	}
+    }
+
+on_return:
+    pj_lock_release(tp->lock);
+}
+
+
+/**
+ * Add a listener to the specified transport for transport state notification.
+ */
+PJ_DEF(pj_status_t) pjsip_transport_add_state_listener (
+					    pjsip_transport *tp,
+					    pjsip_tp_state_callback cb,
+					    void *user_data,
+					    pjsip_tp_state_listener_key **key)
+{
+    transport_data *tp_data;
+    tp_state_listener *entry;
+
+    PJ_ASSERT_RETURN(tp && cb && key, PJ_EINVAL);
+
+    pj_lock_acquire(tp->lock);
+
+    /* Init transport data, if it hasn't */
+    if (!tp->data)
+	init_tp_data(tp);
+
+    tp_data = (transport_data*)tp->data;
+
+    /* Init the new listener entry. Use available empty slot, if any,
+     * otherwise allocate it using the transport pool.
+     */
+    if (!pj_list_empty(&tp_data->st_listeners_empty)) {
+	entry = tp_data->st_listeners_empty.next;
+	pj_list_erase(entry);
+    } else {
+	entry = PJ_POOL_ZALLOC_T(tp->pool, tp_state_listener);
+    }
+    entry->cb = cb;
+    entry->user_data = user_data;
+
+    /* Add the new listener entry to the listeners list */
+    pj_list_push_back(&tp_data->st_listeners, entry);
+
+    *key = entry;
+
+    pj_lock_release(tp->lock);
+
+    return PJ_SUCCESS;
+}
+
+/**
+ * Remove a listener from the specified transport for transport state 
+ * notification.
+ */
+PJ_DEF(pj_status_t) pjsip_transport_remove_state_listener (
+				    pjsip_transport *tp,
+				    pjsip_tp_state_listener_key *key,
+				    const void *user_data)
+{
+    transport_data *tp_data;
+    tp_state_listener *entry;
+
+    PJ_ASSERT_RETURN(tp && key, PJ_EINVAL);
+
+    pj_lock_acquire(tp->lock);
+
+    tp_data = (transport_data*)tp->data;
+
+    /* Transport data is NULL or no registered listener? */
+    if (!tp_data || pj_list_empty(&tp_data->st_listeners)) {
+	pj_lock_release(tp->lock);
+	return PJ_ENOTFOUND;
+    }
+
+    entry = (tp_state_listener*)key;
+
+    /* Validate the user data */
+    if (entry->user_data != user_data) {
+	pj_assert(!"Invalid transport state listener key");
+	pj_lock_release(tp->lock);
+	return PJ_EBUG;
+    }
+
+    /* Reset the entry and move it to the empty list */
+    entry->cb = NULL;
+    entry->user_data = NULL;
+    pj_list_erase(entry);
+    pj_list_push_back(&tp_data->st_listeners_empty, entry);
+
+    pj_lock_release(tp->lock);
+
+    return PJ_SUCCESS;
+}
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 3137)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 3138)
@@ -185,5 +185,5 @@
 
     /* Notify application of transport disconnected state */
-    state_cb = pjsip_tpmgr_get_status_cb(tcp->base.tpmgr);
+    state_cb = pjsip_tpmgr_get_state_cb(tcp->base.tpmgr);
     if (state_cb) {
 	pjsip_transport_state_info state_info;
@@ -1010,5 +1010,5 @@
 
 	    /* Notify application of transport state accepted */
-	    state_cb = pjsip_tpmgr_get_status_cb(tcp->base.tpmgr);
+	    state_cb = pjsip_tpmgr_get_state_cb(tcp->base.tpmgr);
 	    if (state_cb) {
 		pjsip_transport_state_info state_info;
@@ -1337,5 +1337,5 @@
 
     /* Notify application of transport state connected */
-    state_cb = pjsip_tpmgr_get_status_cb(tcp->base.tpmgr);
+    state_cb = pjsip_tpmgr_get_state_cb(tcp->base.tpmgr);
     if (state_cb) {
 	pjsip_transport_state_info state_info;
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c	(revision 3137)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c	(revision 3138)
@@ -192,5 +192,5 @@
 
     /* Notify application of transport disconnected state */
-    state_cb = pjsip_tpmgr_get_status_cb(tls->base.tpmgr);
+    state_cb = pjsip_tpmgr_get_state_cb(tls->base.tpmgr);
     if (state_cb) {
 	pjsip_transport_state_info state_info;
@@ -1049,5 +1049,5 @@
 
     /* Notify transport state to application */
-    state_cb = pjsip_tpmgr_get_status_cb(tls->base.tpmgr);
+    state_cb = pjsip_tpmgr_get_state_cb(tls->base.tpmgr);
     if (state_cb) {
 	pjsip_transport_state_info state_info;
@@ -1467,5 +1467,5 @@
 
     /* Notify transport state to application */
-    state_cb = pjsip_tpmgr_get_status_cb(tls->base.tpmgr);
+    state_cb = pjsip_tpmgr_get_state_cb(tls->base.tpmgr);
     if (state_cb) {
 	pjsip_transport_state_info state_info;
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3137)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3138)
@@ -1890,9 +1890,9 @@
 
 	tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt);
-	tpcb = pjsip_tpmgr_get_status_cb(tpmgr);
+	tpcb = pjsip_tpmgr_get_state_cb(tpmgr);
 
 	if (tpcb != &on_tp_state_callback) {
 	    pjsua_var.old_tp_cb = tpcb;
-	    pjsip_tpmgr_set_status_cb(tpmgr, &on_tp_state_callback);
+	    pjsip_tpmgr_set_state_cb(tpmgr, &on_tp_state_callback);
 	}
     }
