[Asterisk-code-review] pjproject_bundled: Revert pjproject 2.9 commits causing leaks (...asterisk[13])

George Joseph asteriskteam at digium.com
Tue Sep 24 15:37:13 CDT 2019


George Joseph has submitted this change and it was merged. ( https://gerrit.asterisk.org/c/asterisk/+/12894 )

Change subject: pjproject_bundled:  Revert pjproject 2.9 commits causing leaks
......................................................................

pjproject_bundled:  Revert pjproject 2.9 commits causing leaks

We've found a connection re-use regression in pjproject 2.9
introduced by commit
"Close #1019: Support for multiple listeners."
https://trac.pjsip.org/repos/changeset/6002
https://trac.pjsip.org/repos/ticket/1019

Normally, multiple SSL requests should reuse the same connection
if one already exists to the remote server.  When a transport
error occurs, the next request should establish a new connection
and any following requests should use that same one.  With this
patch, when a transport error occurs, every new request creates
a new connection so you can wind up with thousands of open tcp
sockets, possibly exhausting file handles, and increasing memory
usage.

Reverting pjproject commit 6002 (and related 6021) restores the
expected behavior.

We also found a memory leak in SSL processing that was introduced by
commit
"Fixed #2204: Add OpenSSL remote certificate chain info"
https://trac.pjsip.org/repos/changeset/6014
https://trac.pjsip.org/repos/ticket/2204

Apparently the remote certificate chain is continually recreated
causing the leak.

Reverting pjproject commit 6014 (and related 6022) restores the
expected behavior.

Both of these issues have been acknowledged by Teluu.

ASTERISK-28521

Change-Id: I8ae7233c3ac4ec29a3b991f738e655dabcaba9f1
---
A third-party/pjproject/patches/0030-Revert-Misc-re-2147-Fixed-warnings-in-SSL-socket-red.patch
A third-party/pjproject/patches/0031-Revert-Fixed-2204-Add-OpenSSL-remote-certificate-cha.patch
A third-party/pjproject/patches/0032-Revert-Re-2147-misc-Fix-failed-pjsip-test-transport_.patch
A third-party/pjproject/patches/0033-Revert-Close-1019-Support-for-multiple-listeners.patch
4 files changed, 1,302 insertions(+), 0 deletions(-)

Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  Sean Bright: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit



diff --git a/third-party/pjproject/patches/0030-Revert-Misc-re-2147-Fixed-warnings-in-SSL-socket-red.patch b/third-party/pjproject/patches/0030-Revert-Misc-re-2147-Fixed-warnings-in-SSL-socket-red.patch
new file mode 100644
index 0000000..4c39fc0
--- /dev/null
+++ b/third-party/pjproject/patches/0030-Revert-Misc-re-2147-Fixed-warnings-in-SSL-socket-red.patch
@@ -0,0 +1,60 @@
+From 8d0652d4a02c7b8da58b1b98421cfda57056184d Mon Sep 17 00:00:00 2001
+From: George Joseph <gjoseph at digium.com>
+Date: Tue, 24 Sep 2019 06:41:16 -0600
+Subject: [PATCH 30/33] Revert "Misc (re #2147): Fixed warnings in SSL socket:
+ redefinition of typedef 'pj_ssl_sock_t' and unused 'get_pem'."
+
+This reverts commit 688a9b0de685328f62b2df86304b44c21e4460ae.
+---
+ pjlib/src/pj/ssl_sock_imp_common.h | 4 ++--
+ pjlib/src/pj/ssl_sock_ossl.c       | 5 +----
+ 2 files changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/pjlib/src/pj/ssl_sock_imp_common.h b/pjlib/src/pj/ssl_sock_imp_common.h
+index 09f259ef7..4edbb3b82 100644
+--- a/pjlib/src/pj/ssl_sock_imp_common.h
++++ b/pjlib/src/pj/ssl_sock_imp_common.h
+@@ -93,7 +93,7 @@ typedef struct circ_buf_t {
+ /*
+  * Secure socket structure definition.
+  */
+-struct pj_ssl_sock_t
++typedef struct pj_ssl_sock_t
+ {
+     pj_pool_t		 *pool;
+     pj_ssl_sock_t	 *parent;
+@@ -139,7 +139,7 @@ struct pj_ssl_sock_t
+ 
+     circ_buf_t            circ_buf_output;
+     pj_lock_t            *circ_buf_output_mutex;
+-};
++} pj_ssl_sock_t;
+ 
+ 
+ /*
+diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
+index b4ac5c15f..debb105b1 100644
+--- a/pjlib/src/pj/ssl_sock_ossl.c
++++ b/pjlib/src/pj/ssl_sock_ossl.c
+@@ -37,6 +37,7 @@
+ #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
+     (PJ_SSL_SOCK_IMP == PJ_SSL_SOCK_IMP_OPENSSL)
+ 
++#include "ssl_sock_imp_common.h"
+ #include "ssl_sock_imp_common.c"
+ 
+ #define THIS_FILE		"ssl_sock_ossl.c"
+@@ -1575,10 +1576,6 @@ static void ssl_update_remote_cert_chain_info(pj_pool_t *pool,
+ {
+     int i;
+ 
+-    /* For now, get_pem has to be PJ_TRUE */
+-    pj_assert(get_pem);
+-    PJ_UNUSED_ARG(get_pem);
+-
+     ci->raw_chain.cert_raw = (pj_str_t *)pj_pool_calloc(pool,
+        				    			sk_X509_num(chain),
+        				    			sizeof(pj_str_t));
+-- 
+2.21.0
+
diff --git a/third-party/pjproject/patches/0031-Revert-Fixed-2204-Add-OpenSSL-remote-certificate-cha.patch b/third-party/pjproject/patches/0031-Revert-Fixed-2204-Add-OpenSSL-remote-certificate-cha.patch
new file mode 100644
index 0000000..b39c4d7
--- /dev/null
+++ b/third-party/pjproject/patches/0031-Revert-Fixed-2204-Add-OpenSSL-remote-certificate-cha.patch
@@ -0,0 +1,84 @@
+From 616a13933f33a6d74f84d85b5bfb858279a09e2d Mon Sep 17 00:00:00 2001
+From: George Joseph <gjoseph at digium.com>
+Date: Tue, 24 Sep 2019 06:42:04 -0600
+Subject: [PATCH 31/33] Revert "Fixed #2204: Add OpenSSL remote certificate
+ chain info"
+
+This reverts commit f71d60c866c4572a7c8398fe982416771fc6a7f5.
+---
+ pjlib/src/pj/ssl_sock_ossl.c | 45 ------------------------------------
+ 1 file changed, 45 deletions(-)
+
+diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
+index debb105b1..109c5c1e2 100644
+--- a/pjlib/src/pj/ssl_sock_ossl.c
++++ b/pjlib/src/pj/ssl_sock_ossl.c
+@@ -1566,41 +1566,6 @@ static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci, X509 *x,
+     }	 
+ }
+ 
+-/* Update remote certificates chain info. This function should be
+- * called after handshake or renegotiation successfully completed.
+- */
+-static void ssl_update_remote_cert_chain_info(pj_pool_t *pool,
+-					      pj_ssl_cert_info *ci,
+-					      STACK_OF(X509) *chain,
+-					      pj_bool_t get_pem)
+-{
+-    int i;
+-
+-    ci->raw_chain.cert_raw = (pj_str_t *)pj_pool_calloc(pool,
+-       				    			sk_X509_num(chain),
+-       				    			sizeof(pj_str_t));
+-    ci->raw_chain.cnt = sk_X509_num(chain);
+-
+-    for (i = 0; i < sk_X509_num(chain); i++) {
+-        BIO *bio;
+-        BUF_MEM *ptr;
+-	X509 *x = sk_X509_value(chain, i);
+-
+-        bio = BIO_new(BIO_s_mem());
+-        
+-        if (!PEM_write_bio_X509(bio, x)) {
+-            PJ_LOG(3, (THIS_FILE, "Error retrieving raw certificate info"));
+-            ci->raw_chain.cert_raw[i].ptr  = NULL;
+-            ci->raw_chain.cert_raw[i].slen = 0;
+-        } else {
+-            BIO_write(bio, "\0", 1);
+-            BIO_get_mem_ptr(bio, &ptr);
+-            pj_strdup2(pool, &ci->raw_chain.cert_raw[i], ptr->data );
+-        }
+-        
+-        BIO_free(bio);
+-    }
+-}
+ 
+ /* Update local & remote certificates info. This function should be
+  * called after handshake or renegotiation successfully completed.
+@@ -1609,7 +1574,6 @@ static void ssl_update_certs_info(pj_ssl_sock_t *ssock)
+ {
+     ossl_sock_t *ossock = (ossl_sock_t *)ssock;
+     X509 *x;
+-    STACK_OF(X509) *chain;
+ 
+     pj_assert(ssock->ssl_state == SSL_STATE_ESTABLISHED);
+ 
+@@ -1631,15 +1595,6 @@ static void ssl_update_certs_info(pj_ssl_sock_t *ssock)
+     } else {
+ 	pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
+     }
+-
+-    chain = SSL_get_peer_cert_chain(ossock->ossl_ssl);
+-    if (chain) {
+-       ssl_update_remote_cert_chain_info(ssock->pool,
+-       					 &ssock->remote_cert_info,
+-       					 chain, PJ_TRUE);
+-    } else {
+-       ssock->remote_cert_info.raw_chain.cnt = 0;
+-    }
+ }
+ 
+ 
+-- 
+2.21.0
+
diff --git a/third-party/pjproject/patches/0032-Revert-Re-2147-misc-Fix-failed-pjsip-test-transport_.patch b/third-party/pjproject/patches/0032-Revert-Re-2147-misc-Fix-failed-pjsip-test-transport_.patch
new file mode 100644
index 0000000..df8f817
--- /dev/null
+++ b/third-party/pjproject/patches/0032-Revert-Re-2147-misc-Fix-failed-pjsip-test-transport_.patch
@@ -0,0 +1,64 @@
+From 17cd744e19cd332a219a512770fa6e18453044ba Mon Sep 17 00:00:00 2001
+From: George Joseph <gjoseph at digium.com>
+Date: Tue, 24 Sep 2019 06:45:25 -0600
+Subject: [PATCH 32/33] Revert "Re #2147 (misc): Fix failed pjsip-test
+ (transport_loop_test) caused by r6002."
+
+This reverts commit 342148f5bcf3a6b0029ce834b8567c2cd691b15b.
+---
+ pjsip/src/pjsip/sip_transport.c      | 12 +++++-------
+ pjsip/src/pjsip/sip_transport_loop.c |  2 +-
+ pjsip/src/test/transport_loop_test.c |  1 -
+ 3 files changed, 6 insertions(+), 9 deletions(-)
+
+diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
+index 65ac823d4..d63823a98 100644
+--- a/pjsip/src/pjsip/sip_transport.c
++++ b/pjsip/src/pjsip/sip_transport.c
+@@ -1222,13 +1222,11 @@ PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
+ 
+     pj_lock_release(mgr->lock);
+ 
+-    TRACE_((THIS_FILE, "Transport %s registered: type=%s, remote=%s:%d",
+-	    tp->obj_name,
+-	    pjsip_transport_get_type_name(tp->key.type),
+-	    pj_sockaddr_has_addr(&tp->key.rem_addr)?
+-				addr_string(&tp->key.rem_addr):"",
+-	    pj_sockaddr_has_addr(&tp->key.rem_addr)?
+-				pj_sockaddr_get_port(&tp->key.rem_addr):0));
++    TRACE_((THIS_FILE,"Transport %s registered: type=%s, remote=%s:%d",
++		       tp->obj_name,
++		       pjsip_transport_get_type_name(tp->key.type),
++		       addr_string(&tp->key.rem_addr),
++		       pj_sockaddr_get_port(&tp->key.rem_addr)));
+ 
+     return PJ_SUCCESS;
+ }
+diff --git a/pjsip/src/pjsip/sip_transport_loop.c b/pjsip/src/pjsip/sip_transport_loop.c
+index 37e20e69b..24e1a5f69 100644
+--- a/pjsip/src/pjsip/sip_transport_loop.c
++++ b/pjsip/src/pjsip/sip_transport_loop.c
+@@ -376,7 +376,7 @@ PJ_DEF(pj_status_t) pjsip_loop_start( pjsip_endpoint *endpt,
+     if (status != PJ_SUCCESS)
+ 	goto on_error;
+     loop->base.key.type = PJSIP_TRANSPORT_LOOP_DGRAM;
+-    //loop->base.key.rem_addr.addr.sa_family = pj_AF_INET();
++    loop->base.key.rem_addr.addr.sa_family = pj_AF_INET();
+     loop->base.type_name = "LOOP-DGRAM";
+     loop->base.info = "LOOP-DGRAM";
+     loop->base.flag = PJSIP_TRANSPORT_DATAGRAM;
+diff --git a/pjsip/src/test/transport_loop_test.c b/pjsip/src/test/transport_loop_test.c
+index 5f2f03904..efa2ea116 100644
+--- a/pjsip/src/test/transport_loop_test.c
++++ b/pjsip/src/test/transport_loop_test.c
+@@ -36,7 +36,6 @@ static int datagram_loop_test()
+ 
+     PJ_LOG(3,(THIS_FILE, "testing datagram loop transport"));
+ 
+-    pj_sockaddr_in_init(&addr, NULL, 0);
+     /* Test acquire transport. */
+     status = pjsip_endpt_acquire_transport( endpt, PJSIP_TRANSPORT_LOOP_DGRAM,
+ 					    &addr, sizeof(addr), NULL, &loop);
+-- 
+2.21.0
+
diff --git a/third-party/pjproject/patches/0033-Revert-Close-1019-Support-for-multiple-listeners.patch b/third-party/pjproject/patches/0033-Revert-Close-1019-Support-for-multiple-listeners.patch
new file mode 100644
index 0000000..8a8f99a
--- /dev/null
+++ b/third-party/pjproject/patches/0033-Revert-Close-1019-Support-for-multiple-listeners.patch
@@ -0,0 +1,1094 @@
+From a720f3ffd538d3baef6f8daf78d9d320a4a5c0a0 Mon Sep 17 00:00:00 2001
+From: George Joseph <gjoseph at digium.com>
+Date: Tue, 24 Sep 2019 06:45:59 -0600
+Subject: [PATCH 33/33] Revert "Close #1019: Support for multiple listeners."
+
+This reverts commit 142dd0e96edad15b6b9554636043b5255d5d8adf.
+---
+ pjsip/include/pjsip/sip_config.h     |  10 +-
+ pjsip/src/pjsip/sip_transport.c      | 318 ++++++++++-----------------
+ pjsip/src/pjsip/sip_transport_loop.c |   2 +-
+ pjsip/src/test/test.c                |   3 -
+ pjsip/src/test/transport_tcp_test.c  | 193 ++++------------
+ pjsip/src/test/transport_udp_test.c  | 148 +++++--------
+ 6 files changed, 215 insertions(+), 459 deletions(-)
+
+diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
+index 585aa722c..904df24e1 100644
+--- a/pjsip/include/pjsip/sip_config.h
++++ b/pjsip/include/pjsip/sip_config.h
+@@ -433,7 +433,7 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
+  * This option can also be controlled at run-time by the
+  * \a accept_multiple_sdp_answers setting in pjsip_cfg_t.
+  *
+- * Default is PJ_TRUE.
++ * Default is PJ_FALSE.
+  */
+ #ifndef PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS
+ #   define PJSIP_ACCEPT_MULTIPLE_SDP_ANSWERS        PJ_TRUE
+@@ -692,7 +692,7 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
+  * will be used as the default value for the "reuse_addr" field in the
+  * pjsip_tcp_transport_cfg structure.
+  *
+- * Default is 0 on Windows and 1 on non-Windows.
++ * Default is FALSE on Windows and TRUE on non-Windows.
+  *
+  * @see PJSIP_TLS_TRANSPORT_REUSEADDR
+  */
+@@ -718,7 +718,7 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
+  * pj_getipinterface()/pj_gethostip(), but the address will not be
+  * able to accept connections. 
+  *
+- * Default is 0 (listener will be created).
++ * Default is FALSE (listener will be created).
+  */
+ #ifndef PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER
+ #   define PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER 0
+@@ -738,7 +738,7 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
+  * pj_getipinterface()/pj_gethostip(), but the address will not be
+  * able to accept connections.
+  *
+- * Default is 0 (listener will be created).
++ * Default is FALSE (listener will be created).
+  */
+ #ifndef PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER
+ #   define PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER 0
+@@ -881,7 +881,7 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
+ /**
+  * Specify whether TLS listener should use SO_REUSEADDR option.
+  *
+- * Default is 0 on Windows and 1 on non-Windows.
++ * Default is FALSE on Windows and TRUE on non-Windows.
+  *
+  * @see PJSIP_TCP_TRANSPORT_REUSEADDR
+  */
+diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
+index d63823a98..54e8be380 100644
+--- a/pjsip/src/pjsip/sip_transport.c
++++ b/pjsip/src/pjsip/sip_transport.c
+@@ -54,25 +54,6 @@ static const char *addr_string(const pj_sockaddr_t *addr)
+ #   define TRACE_(x)
+ #endif
+ 
+-/* Specify the initial size of the transport manager's pool. */
+-#ifndef  TPMGR_POOL_INIT_SIZE
+-#   define TPMGR_POOL_INIT_SIZE	64
+-#endif
+-
+-/* Specify the increment size of the transport manager's pool. */
+-#ifndef TPMGR_POOL_INC_SIZE
+-    #define TPMGR_POOL_INC_SIZE	64
+-#endif
+-
+-/* Specify transport entry allocation count. When registering a new transport,
+- * a new entry will be picked from a free list. This setting will determine
+- * the size of the free list size. If all entry is used, then the same number
+- * of entry will be allocated.
+- */
+-#ifndef PJSIP_TRANSPORT_ENTRY_ALLOC_CNT
+-#   define PJSIP_TRANSPORT_ENTRY_ALLOC_CNT  16
+-#endif
+-
+ /* Prototype. */
+ static pj_status_t mod_on_tx_msg(pjsip_tx_data *tdata);
+ 
+@@ -100,7 +81,6 @@ static pjsip_module mod_msg_print =
+ typedef struct transport
+ {
+     PJ_DECL_LIST_MEMBER(struct transport);
+-    pj_hash_entry_buf tp_buf;
+     pjsip_transport *tp;
+ } transport;
+ 
+@@ -113,7 +93,6 @@ struct pjsip_tpmgr
+     pj_lock_t	    *lock;
+     pjsip_endpoint  *endpt;
+     pjsip_tpfactory  factory_list;
+-    pj_pool_t	    *pool;
+ #if defined(PJ_DEBUG) && PJ_DEBUG!=0
+     pj_atomic_t	    *tdata_counter;
+ #endif
+@@ -126,9 +105,12 @@ struct pjsip_tpmgr
+      * is destroyed.
+      */
+     pjsip_tx_data    tdata_list;
+-
+-    /* List of free transport entry. */
+-    transport	     tp_entry_freelist;
++    
++    /* List of transports which are NOT stored in the hash table, so
++     * that it can be properly cleaned up when transport manager
++     * is destroyed.
++     */
++    transport        tp_list;
+ };
+ 
+ 
+@@ -1042,18 +1024,18 @@ static pj_bool_t is_transport_valid(pjsip_transport *tp, pjsip_tpmgr *tpmgr,
+ 				    const pjsip_transport_key *key,
+ 				    int key_len)
+ {
+-    transport *tp_entry;
++    transport *tp_iter;
+ 
+-    tp_entry = (transport *)pj_hash_get(tpmgr->table, key, key_len, NULL);
+-    if (tp_entry != NULL) {
++    if (pj_hash_get(tpmgr->table, key, key_len, NULL) == (void*)tp) {
++        return PJ_TRUE;
++    }
+ 
+-	transport *tp_iter = tp_entry;
+-	do {
+-	    if (tp_iter->tp == tp) {
+-		return PJ_TRUE;
+-	    }
+-	    tp_iter = tp_iter->next;
+-	} while (tp_iter != tp_entry);
++    tp_iter = tpmgr->tp_list.next;
++    while (tp_iter != &tpmgr->tp_list) {
++        if (tp_iter->tp == tp) {
++            return PJ_TRUE;
++        }
++        tp_iter = tp_iter->next;
+     }
+ 
+     return PJ_FALSE;
+@@ -1153,9 +1135,8 @@ PJ_DEF(pj_status_t) pjsip_transport_dec_ref( pjsip_transport *tp )
+     }
+ 
+     /* Dec ref transport group lock, if any */
+-    if (tp->grp_lock) {
++    if (tp->grp_lock)
+ 	pj_grp_lock_dec_ref(tp->grp_lock);
+-    }
+ 
+     return PJ_SUCCESS;
+ }
+@@ -1169,8 +1150,7 @@ PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
+ {
+     int key_len;
+     pj_uint32_t hval;
+-    transport *tp_ref = NULL;
+-    transport *tp_add = NULL;
++    void *entry;
+ 
+     /* Init. */
+     tp->tpmgr = mgr;
+@@ -1178,43 +1158,31 @@ PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
+     tp->idle_timer.user_data = tp;
+     tp->idle_timer.cb = &transport_idle_callback;
+ 
+-    /*
++    /* 
+      * Register to hash table (see Trac ticket #42).
+      */
+     key_len = sizeof(tp->key.type) + tp->addr_len;
+     pj_lock_acquire(mgr->lock);
+ 
++    /* If entry already occupied, unregister previous entry */
+     hval = 0;
+-    tp_ref = (transport *)pj_hash_get(mgr->table, &tp->key, key_len, &hval);
+-
+-    /* Get an empty entry from the freelist. */
+-    if (pj_list_empty(&mgr->tp_entry_freelist)) {
+-	unsigned i = 0;
+-
+-	TRACE_((THIS_FILE, "Transport list is full, allocate new entry"));
+-	/* Allocate new entry for the freelist. */
+-	for (; i < PJSIP_TRANSPORT_ENTRY_ALLOC_CNT; ++i) {
+-	    tp_add = PJ_POOL_ZALLOC_T(mgr->pool, transport);
+-	    if (!tp_add)
+-		return PJ_ENOMEM;
+-	    pj_list_init(tp_add);
+-	    pj_list_push_back(&mgr->tp_entry_freelist, tp_add);
+-	}
++    entry = pj_hash_get(mgr->table, &tp->key, key_len, &hval);
++    if (entry != NULL) {
++        transport *tp_ref;
++        
++        tp_ref = PJ_POOL_ZALLOC_T(((pjsip_transport *)entry)->pool, transport);
++        
++        /*
++         * Add transport to the list before removing it from the hash table.
++         * See ticket #1774 for more details.
++         */
++        tp_ref->tp = (pjsip_transport *)entry;
++        pj_list_push_back(&mgr->tp_list, tp_ref);
++	pj_hash_set(NULL, mgr->table, &tp->key, key_len, hval, NULL);
+     }
+-    tp_add = mgr->tp_entry_freelist.next;
+-    tp_add->tp = tp;
+-    pj_list_erase(tp_add);
+ 
+-    if (tp_ref) {
+-	/* There'a already a transport list from the hash table. Add the 
+-	 * new transport to the list.
+-	 */
+-	pj_list_push_back(tp_ref, tp_add);
+-    } else {
+-	/* Transport list not found, add it to the hash table. */
+-	pj_hash_set_np(mgr->table, &tp->key, key_len, hval, tp_add->tp_buf,
+-		       tp_add);
+-    }
++    /* Register new entry */
++    pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, hval, tp);
+ 
+     /* Add ref transport group lock, if any */
+     if (tp->grp_lock)
+@@ -1261,46 +1229,26 @@ static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
+     key_len = sizeof(tp->key.type) + tp->addr_len;
+     hval = 0;
+     entry = pj_hash_get(mgr->table, &tp->key, key_len, &hval);
+-    if (entry) {
+-	transport *tp_ref = (transport *)entry;
+-	transport *tp_iter = tp_ref;
+-	/* Search the matching entry from the transport list. */
+-	do {
+-	    if (tp_iter->tp == tp) {
+-		transport *tp_next = tp_iter->next;
+-
+-		/* Update hash table :
+-		 * - transport list only contain single element, or
+-		 * - the entry is the first element of the transport list.
+-		 */
+-		if (tp_iter == tp_ref) {
+-		    pj_hash_set(NULL, mgr->table, &tp->key, key_len, hval,
+-				NULL);
+-
+-		    if (tp_ref->next != tp_ref) {
+-			/* The transport list has multiple entry. */
+-			pj_hash_set_np(mgr->table, &tp_next->tp->key, key_len,
+-				       hval, tp_next->tp_buf, tp_next);
+-		    }
+-		}
+-
+-		pj_list_erase(tp_iter);
+-		/* Put back to the transport freelist. */
+-		pj_list_push_back(&mgr->tp_entry_freelist, tp_iter);
+-
+-		break;
+-	    }
+-	    tp_iter = tp_iter->next;
+-	} while (tp_iter != tp_ref);
++    if (entry == (void*)tp) {
++	pj_hash_set(NULL, mgr->table, &tp->key, key_len, hval, NULL);
++    } else {
++        /* If not found in hash table, remove from the tranport list. */
++        transport *tp_iter = mgr->tp_list.next;
++        while (tp_iter != &mgr->tp_list) {
++            if (tp_iter->tp == tp) {
++                pj_list_erase(tp_iter);
++                break;
++            }
++            tp_iter = tp_iter->next;
++        }
+     }
+ 
+     pj_lock_release(mgr->lock);
+     pj_lock_release(tp->lock);
+ 
+     /* Dec ref transport group lock, if any */
+-    if (tp->grp_lock) {
++    if (tp->grp_lock)
+ 	pj_grp_lock_dec_ref(tp->grp_lock);
+-    }
+ 
+     /* Destroy. */
+     return tp->destroy(tp);
+@@ -1414,9 +1362,13 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_register_tpfactory( pjsip_tpmgr *mgr,
+ 
+     pj_lock_acquire(mgr->lock);
+ 
+-    /* Check that no same factory has been registered. */
++    /* Check that no factory with the same type has been registered. */
+     status = PJ_SUCCESS;
+     for (p=mgr->factory_list.next; p!=&mgr->factory_list; p=p->next) {
++	if (p->type == tpf->type) {
++	    status = PJSIP_ETYPEEXISTS;
++	    break;
++	}
+ 	if (p == tpf) {
+ 	    status = PJ_EEXISTS;
+ 	    break;
+@@ -1491,8 +1443,6 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool,
+ {
+     pjsip_tpmgr *mgr;
+     pj_status_t status;
+-    unsigned i = 0;
+-    pj_pool_t *mgr_pool;
+ 
+     PJ_ASSERT_RETURN(pool && endpt && rx_cb && p_mgr, PJ_EINVAL);
+ 
+@@ -1502,42 +1452,24 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool,
+ 	return status;
+ 
+     /* Create and initialize transport manager. */
+-    mgr_pool = pjsip_endpt_create_pool(endpt, "tpmgr",
+-				       TPMGR_POOL_INIT_SIZE,
+-				       TPMGR_POOL_INC_SIZE);
+-    mgr = PJ_POOL_ZALLOC_T(mgr_pool, pjsip_tpmgr);
++    mgr = PJ_POOL_ZALLOC_T(pool, pjsip_tpmgr);
+     mgr->endpt = endpt;
+     mgr->on_rx_msg = rx_cb;
+     mgr->on_tx_msg = tx_cb;
+-    mgr->pool = mgr_pool;
+-
+-    if (!mgr->pool)
+-	return PJ_ENOMEM;
+-
+     pj_list_init(&mgr->factory_list);
+     pj_list_init(&mgr->tdata_list);
+-    pj_list_init(&mgr->tp_entry_freelist);
++    pj_list_init(&mgr->tp_list);
+ 
+-    mgr->table = pj_hash_create(mgr->pool, PJSIP_TPMGR_HTABLE_SIZE);
++    mgr->table = pj_hash_create(pool, PJSIP_TPMGR_HTABLE_SIZE);
+     if (!mgr->table)
+ 	return PJ_ENOMEM;
+ 
+-    status = pj_lock_create_recursive_mutex(mgr->pool, "tmgr%p", &mgr->lock);
++    status = pj_lock_create_recursive_mutex(pool, "tmgr%p", &mgr->lock);
+     if (status != PJ_SUCCESS)
+ 	return status;
+ 
+-    for (; i < PJSIP_TRANSPORT_ENTRY_ALLOC_CNT; ++i) {
+-	transport *tp_add = NULL;
+-
+-	tp_add = PJ_POOL_ZALLOC_T(mgr->pool, transport);
+-	if (!tp_add)
+-	    return PJ_ENOMEM;
+-	pj_list_init(tp_add);
+-	pj_list_push_back(&mgr->tp_entry_freelist, tp_add);
+-    }
+-
+ #if defined(PJ_DEBUG) && PJ_DEBUG!=0
+-    status = pj_atomic_create(mgr->pool, 0, &mgr->tdata_counter);
++    status = pj_atomic_create(pool, 0, &mgr->tdata_counter);
+     if (status != PJ_SUCCESS) {
+     	pj_lock_destroy(mgr->lock);
+     	return status;
+@@ -1765,16 +1697,15 @@ PJ_DEF(unsigned) pjsip_tpmgr_get_transport_count(pjsip_tpmgr *mgr)
+     pj_hash_iterator_t itr_val;
+     pj_hash_iterator_t *itr;
+     int nr_of_transports = 0;
+-
++    
+     pj_lock_acquire(mgr->lock);
+-
++    
+     itr = pj_hash_first(mgr->table, &itr_val);
+     while (itr) {
+-	transport *tp_entry = (transport *)pj_hash_this(mgr->table, itr);
+-	nr_of_transports += pj_list_size(tp_entry);
++	nr_of_transports++;
+ 	itr = pj_hash_next(mgr->table, itr);
+     }
+-
++    
+     pj_lock_release(mgr->lock);
+ 
+     return nr_of_transports;
+@@ -1791,7 +1722,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_destroy( pjsip_tpmgr *mgr )
+     pj_hash_iterator_t *itr;
+     pjsip_tpfactory *factory;
+     pjsip_endpoint *endpt = mgr->endpt;
+-
++    
+     PJ_LOG(5, (THIS_FILE, "Destroying transport manager"));
+ 
+     pj_lock_acquire(mgr->lock);
+@@ -1799,21 +1730,39 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_destroy( pjsip_tpmgr *mgr )
+     /*
+      * Destroy all transports in the hash table.
+      */
+-    for (itr = pj_hash_first(mgr->table, &itr_val); itr;
+-	 itr = pj_hash_first(mgr->table, &itr_val))
+-    {
+-	transport *tp_ref;
+-	tp_ref = pj_hash_this(mgr->table, itr);
+-	destroy_transport(mgr, tp_ref->tp);
++    itr = pj_hash_first(mgr->table, &itr_val);
++    while (itr != NULL) {
++	pj_hash_iterator_t *next;
++	pjsip_transport *transport;
++	
++	transport = (pjsip_transport*) pj_hash_this(mgr->table, itr);
++
++	next = pj_hash_next(mgr->table, itr);
++
++	destroy_transport(mgr, transport);
++
++	itr = next;
+     }
+ 
++    /*
++     * Destroy transports in the list.
++     */
++    if (!pj_list_empty(&mgr->tp_list)) {
++        transport *tp_iter = mgr->tp_list.next;
++        while (tp_iter != &mgr->tp_list) {
++	    transport *next = tp_iter->next;
++	    destroy_transport(mgr, tp_iter->tp);
++	    tp_iter = next;
++        }
++    }
++    
+     /*
+      * Destroy all factories/listeners.
+      */
+     factory = mgr->factory_list.next;
+     while (factory != &mgr->factory_list) {
+ 	pjsip_tpfactory *next = factory->next;
+-
++	
+ 	factory->destroy(factory);
+ 
+ 	factory = next;
+@@ -1857,10 +1806,6 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_destroy( pjsip_tpmgr *mgr )
+ 	pjsip_endpt_unregister_module(endpt, &mod_msg_print);
+     }
+ 
+-    if (mgr->pool) {
+-	pjsip_endpt_release_pool( mgr->endpt, mgr->pool );
+-    }
+-
+     return PJ_SUCCESS;
+ }
+ 
+@@ -2221,9 +2166,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+ 	 */
+ 	pjsip_transport_key key;
+ 	int key_len;
+-	pjsip_transport *tp_ref = NULL;
+-	transport *tp_entry = NULL;
+-
++	pjsip_transport *transport = NULL;
+ 
+ 	/* If listener is specified, verify that the listener type matches
+ 	 * the destination type.
+@@ -2244,28 +2187,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+ 	    key.type = type;
+ 	    pj_memcpy(&key.rem_addr, remote, addr_len);
+ 
+-	    tp_entry = (transport *)pj_hash_get(mgr->table, &key, key_len,
+-						NULL);
+-	    if (tp_entry) {
+-		if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER) {
+-		    transport *tp_iter = tp_entry;
+-		    do {
+-			if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER &&
+-			    sel->u.listener &&
+-			    tp_iter->tp->factory == sel->u.listener)
+-			{
+-			    tp_ref = tp_iter->tp;
+-			    break;
+-			}
+-			tp_iter = tp_iter->next;
+-		    } while (tp_iter != tp_entry);
+-		} else {
+-		    tp_ref = tp_entry->tp;
+-		}
+-	    }
++	    transport = (pjsip_transport*)
++		        pj_hash_get(mgr->table, &key, key_len, NULL);
+ 	}
+ 
+-	if (tp_ref == NULL &&
++	if (transport == NULL &&
+ 	    (!sel || sel->disable_connection_reuse == PJ_FALSE))
+ 	{
+ 	    unsigned flag = pjsip_transport_get_flag_from_type(type);
+@@ -2280,11 +2206,8 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+ 
+ 		pj_bzero(addr, addr_len);
+ 		key_len = sizeof(key.type) + addr_len;
+-		tp_entry = (transport *) pj_hash_get(mgr->table, &key,
+-						     key_len, NULL);
+-		if (tp_entry) {
+-		    tp_ref = tp_entry->tp;
+-		}
++		transport = (pjsip_transport*) 
++			    pj_hash_get(mgr->table, &key, key_len, NULL);
+ 	    }
+ 	    /* For datagram transports, try lookup with zero address.
+ 	     */
+@@ -2296,34 +2219,31 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+ 		addr->addr.sa_family = remote_addr->addr.sa_family;
+ 
+ 		key_len = sizeof(key.type) + addr_len;
+-		tp_entry = (transport *) pj_hash_get(mgr->table, &key,
+-						     key_len, NULL);
+-		if (tp_entry) {
+-		    tp_ref = tp_entry->tp;
+-		}
++		transport = (pjsip_transport*)
++			    pj_hash_get(mgr->table, &key, key_len, NULL);
+ 	    }
+ 	}
+ 
+ 	/* If transport is found and listener is specified, verify listener */
+ 	else if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER &&
+-		 sel->u.listener && tp_ref->factory != sel->u.listener)
++		 sel->u.listener && transport->factory != sel->u.listener)
+ 	{
+-	    tp_ref = NULL;
++	    transport = NULL;
+ 	    /* This will cause a new transport to be created which will be a
+ 	     * 'duplicate' of the existing transport (same type & remote addr,
+ 	     * but different factory).
+ 	     */
+ 	}
+ 
+-	if (tp_ref!=NULL && !tp_ref->is_shutdown) {
++	if (transport!=NULL && !transport->is_shutdown) {
+ 	    /*
+ 	     * Transport found!
+ 	     */
+-	    pjsip_transport_add_ref(tp_ref);
++	    pjsip_transport_add_ref(transport);
+ 	    pj_lock_release(mgr->lock);
+-	    *tp = tp_ref;
++	    *tp = transport;
+ 
+-	    TRACE_((THIS_FILE, "Transport %s acquired", tp_ref->obj_name));
++	    TRACE_((THIS_FILE, "Transport %s acquired", transport->obj_name));
+ 	    return PJ_SUCCESS;
+ 	}
+ 
+@@ -2385,15 +2305,15 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+     /* Request factory to create transport. */
+     if (factory->create_transport2) {
+ 	status = factory->create_transport2(factory, mgr, mgr->endpt,
+-					    (const pj_sockaddr*) remote,
++					    (const pj_sockaddr*) remote, 
+ 					    addr_len, tdata, tp);
+     } else {
+ 	status = factory->create_transport(factory, mgr, mgr->endpt,
+-					   (const pj_sockaddr*) remote,
++					   (const pj_sockaddr*) remote, 
+ 					   addr_len, tp);
+     }
+     if (status == PJ_SUCCESS) {
+-	PJ_ASSERT_ON_FAIL(tp!=NULL,
++	PJ_ASSERT_ON_FAIL(tp!=NULL, 
+ 	    {pj_lock_release(mgr->lock); return PJ_EBUG;});
+ 	pjsip_transport_add_ref(*tp);
+ 	(*tp)->factory = factory;
+@@ -2436,25 +2356,15 @@ PJ_DEF(void) pjsip_tpmgr_dump_transports(pjsip_tpmgr *mgr)
+ 	PJ_LOG(3, (THIS_FILE, " Dumping transports:"));
+ 
+ 	do {
+-	    transport *tp_entry = (transport *) pj_hash_this(mgr->table, itr);
+-	    if (tp_entry) {
+-		transport *tp_iter = tp_entry;
+-
+-		do {
+-		    pjsip_transport *tp_ref = tp_iter->tp;
+-
+-		    PJ_LOG(3, (THIS_FILE, "  %s %s%s%s%s(refcnt=%d%s)",
+-			       tp_ref->obj_name,
+-			       tp_ref->info,
+-			       (tp_ref->factory)?" listener[":"",
+-			       (tp_ref->factory)?tp_ref->factory->obj_name:"",
+-			       (tp_ref->factory)?"]":"",
+-			       pj_atomic_get(tp_ref->ref_cnt),
+-			       (tp_ref->idle_timer.id ? " [idle]" : "")));
+-
+-		    tp_iter = tp_iter->next;
+-		} while (tp_iter != tp_entry);
+-	    }
++	    pjsip_transport *t = (pjsip_transport*) 
++	    			 pj_hash_this(mgr->table, itr);
++
++	    PJ_LOG(3, (THIS_FILE, "  %s %s (refcnt=%d%s)", 
++		       t->obj_name,
++		       t->info,
++		       pj_atomic_get(t->ref_cnt),
++		       (t->idle_timer.id ? " [idle]" : "")));
++
+ 	    itr = pj_hash_next(mgr->table, itr);
+ 	} while (itr);
+     }
+diff --git a/pjsip/src/pjsip/sip_transport_loop.c b/pjsip/src/pjsip/sip_transport_loop.c
+index 24e1a5f69..5cbe26a97 100644
+--- a/pjsip/src/pjsip/sip_transport_loop.c
++++ b/pjsip/src/pjsip/sip_transport_loop.c
+@@ -376,7 +376,7 @@ PJ_DEF(pj_status_t) pjsip_loop_start( pjsip_endpoint *endpt,
+     if (status != PJ_SUCCESS)
+ 	goto on_error;
+     loop->base.key.type = PJSIP_TRANSPORT_LOOP_DGRAM;
+-    loop->base.key.rem_addr.addr.sa_family = pj_AF_INET();
++    //loop->base.key.rem_addr.sa_family = pj_AF_INET();
+     loop->base.type_name = "LOOP-DGRAM";
+     loop->base.info = "LOOP-DGRAM";
+     loop->base.flag = PJSIP_TRANSPORT_DATAGRAM;
+diff --git a/pjsip/src/test/test.c b/pjsip/src/test/test.c
+index 3898d45ff..0361e6178 100644
+--- a/pjsip/src/test/test.c
++++ b/pjsip/src/test/test.c
+@@ -379,9 +379,6 @@ int test_main(void)
+ on_return:
+     flush_events(500);
+ 
+-    /* Show additional info on the log. e.g: not released memory pool. */
+-    pj_log_set_level(4);
+-
+     /* Dumping memory pool usage */
+     PJ_LOG(3,(THIS_FILE, "Peak memory size=%u MB",
+ 		         caching_pool.peak_used_size / 1000000));
+diff --git a/pjsip/src/test/transport_tcp_test.c b/pjsip/src/test/transport_tcp_test.c
+index b10455664..3ff5f8ff4 100644
+--- a/pjsip/src/test/transport_tcp_test.c
++++ b/pjsip/src/test/transport_tcp_test.c
+@@ -29,154 +29,64 @@
+  * TCP transport test.
+  */
+ #if PJ_HAS_TCP
+-
+-static pj_status_t multi_listener_test(pjsip_tpfactory *factory[],
+-				       unsigned num_factory,
+-				       pjsip_transport *tp[],
+-				       unsigned *num_tp)
++int transport_tcp_test(void)
+ {
+-    pj_status_t status;
+-    unsigned i = 0;
+-    pj_str_t s;
++    enum { SEND_RECV_LOOP = 8 };
++    pjsip_tpfactory *tpfactory;
+     pjsip_transport *tcp;
+-    pjsip_tpfactory *tpfactory = NULL;
+     pj_sockaddr_in rem_addr;
+-    pjsip_tpselector tp_sel;
+-    unsigned ntp = 0;
+-
+-    for (;i<num_factory;++i)
+-    {
+-	/* Start TCP listener on arbitrary port. */
+-	status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory);
+-	if (status != PJ_SUCCESS) {
+-	    app_perror("   Error: unable to start TCP transport", status);
+-	    return -10;
+-	}
++    pj_status_t status;
++    char url[PJSIP_MAX_URL_SIZE];
++    char addr[PJ_INET_ADDRSTRLEN];
++    int rtt[SEND_RECV_LOOP], min_rtt;
++    int i, pkt_lost;
+ 
+-	factory[i] = tpfactory;
++    /* Start TCP listener on arbitrary port. */
++    status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory);
++    if (status != PJ_SUCCESS) {
++	app_perror("   Error: unable to start TCP transport", status);
++	return -10;
+     }
+ 
+-    /* Get the last listener address */
++
++    /* Get the listener address */
+     status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host,
+ 				 (pj_uint16_t)tpfactory->addr_name.port);
+     if (status != PJ_SUCCESS) {
+ 	app_perror("   Error: possibly invalid TCP address name", status);
+-	return -11;
++	return -14;
+     }
+ 
+-    /* Acquire transport without selector. */
+-    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP,
+-					   &rem_addr, sizeof(rem_addr),
+-					   NULL, &tcp);
+-    if (status != PJ_SUCCESS || tcp == NULL) {
+-	app_perror("   Error: unable to acquire TCP transport", status);
+-	return -12;
+-    }
+-    tp[ntp++] = tcp;
++    pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp",
++		    pj_inet_ntop2(pj_AF_INET(), &rem_addr.sin_addr, addr,
++		    		  sizeof(addr)),
++		    pj_ntohs(rem_addr.sin_port));
+ 
+-    /* After pjsip_endpt_acquire_transport, TCP transport must have
+-     * reference counter 1.
+-     */
+-    if (pj_atomic_get(tcp->ref_cnt) != 1)
+-	return -13;
+ 
+-    /* Acquire with the same remote address, should return the same tp. */
+-    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP,
++    /* Acquire one TCP transport. */
++    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, 
+ 					   &rem_addr, sizeof(rem_addr),
+ 					   NULL, &tcp);
+     if (status != PJ_SUCCESS || tcp == NULL) {
+ 	app_perror("   Error: unable to acquire TCP transport", status);
+-	return -14;
+-    }
+-
+-    /* Should return existing transport. */
+-    if (tp[ntp-1] != tcp) {
+-	return -15;
++	return -17;
+     }
+ 
+-    /* Using the same TCP transport, it must have reference counter 2.
++    /* After pjsip_endpt_acquire_transport, TCP transport must have
++     * reference counter 1. 
+      */
+-    if (pj_atomic_get(tcp->ref_cnt) != 2)
+-	return -16;
+-
+-    /* Decrease the reference. */
+-    pjsip_transport_dec_ref(tcp);
++    if (pj_atomic_get(tcp->ref_cnt) != 1)
++	return -20;
+ 
+     /* Test basic transport attributes */
+     status = generic_transport_test(tcp);
+     if (status != PJ_SUCCESS)
+ 	return status;
+ 
++
+     /* Check again that reference counter is 1. */
+     if (pj_atomic_get(tcp->ref_cnt) != 1)
+-	return -17;
+-
+-    /* Acquire transport test with selector. */
+-    pj_bzero(&tp_sel, sizeof(tp_sel));
+-    tp_sel.type = PJSIP_TPSELECTOR_LISTENER;
+-    tp_sel.u.listener = factory[num_factory/2];
+-    pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80);
+-    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP,
+-					   &rem_addr, sizeof(rem_addr),
+-					   &tp_sel, &tcp);
+-    if (status != PJ_SUCCESS) {
+-	app_perror("   Error: unable to acquire TCP transport", status);
+-	return -18;
+-    }
+-
+-    /* The transport should have the same factory set on the selector. */
+-    if (tcp->factory != factory[num_factory/2])
+-	return -19;
+-
+-    /* The transport should be newly created. */
+-    for (i = 0; i < ntp; ++i) {
+-	if (tp[i] == tcp) {
+-	    break;
+-	}
+-    }
+-    if (i != ntp)
+-	return -20;
+-
+-    tp[ntp++] = tcp;
+-
+-    for (i = 0; i<ntp; ++i) {
+-	if (pj_atomic_get(tp[i]->ref_cnt) != 1)
+-	    return -21;
+-    }
+-    *num_tp = ntp;
+-
+-    return PJ_SUCCESS;
+-}
+-
+-int transport_tcp_test(void)
+-{
+-    enum { SEND_RECV_LOOP = 8 };
+-    enum { NUM_LISTENER = 4 };
+-    enum { NUM_TP = 8 };
+-    pjsip_tpfactory *tpfactory[NUM_LISTENER];
+-    pjsip_transport *tcp[NUM_TP];
+-    pj_sockaddr_in rem_addr;
+-    pj_status_t status;
+-    char url[PJSIP_MAX_URL_SIZE];
+-    char addr[PJ_INET_ADDRSTRLEN];
+-    int rtt[SEND_RECV_LOOP], min_rtt;
+-    int pkt_lost;
+-    unsigned i;
+-    unsigned num_listener = NUM_LISTENER;
+-    unsigned num_tp = NUM_TP;
+-
+-    status = multi_listener_test(tpfactory, num_listener, tcp, &num_tp);
+-    if (status != PJ_SUCCESS)
+-	return status;
+-
+-    /* Get the last listener address */
+-    status = pj_sockaddr_in_init(&rem_addr, &tpfactory[0]->addr_name.host,
+-				 (pj_uint16_t)tpfactory[0]->addr_name.port);
+-
+-    pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp",
+-		    pj_inet_ntop2(pj_AF_INET(), &rem_addr.sin_addr, addr,
+-				  sizeof(addr)),
+-		    pj_ntohs(rem_addr.sin_port));
++	return -40;
+ 
+     /* Load test */
+     if (transport_load_test(url) != 0)
+@@ -184,13 +94,10 @@ int transport_tcp_test(void)
+ 
+     /* Basic transport's send/receive loopback test. */
+     for (i=0; i<SEND_RECV_LOOP; ++i) {
+-	status = transport_send_recv_test(PJSIP_TRANSPORT_TCP, tcp[0], url,
+-					  &rtt[i]);
++	status = transport_send_recv_test(PJSIP_TRANSPORT_TCP, tcp, url, &rtt[i]);
+ 
+ 	if (status != 0) {
+-	    for (i = 0; i < num_tp ; ++i) {
+-		pjsip_transport_dec_ref(tcp[i]);
+-	    }
++	    pjsip_transport_dec_ref(tcp);
+ 	    flush_events(500);
+ 	    return -72;
+ 	}
+@@ -208,11 +115,9 @@ int transport_tcp_test(void)
+ 
+ 
+     /* Multi-threaded round-trip test. */
+-    status = transport_rt_test(PJSIP_TRANSPORT_TCP, tcp[0], url, &pkt_lost);
++    status = transport_rt_test(PJSIP_TRANSPORT_TCP, tcp, url, &pkt_lost);
+     if (status != 0) {
+-	for (i = 0; i < num_tp ; ++i) {
+-	    pjsip_transport_dec_ref(tcp[i]);
+-	}
++	pjsip_transport_dec_ref(tcp);
+ 	return status;
+     }
+ 
+@@ -220,28 +125,22 @@ int transport_tcp_test(void)
+ 	PJ_LOG(3,(THIS_FILE, "   note: %d packet(s) was lost", pkt_lost));
+ 
+     /* Check again that reference counter is still 1. */
+-    for (i = 0; i < num_tp; ++i) {
+-	if (pj_atomic_get(tcp[i]->ref_cnt) != 1)
+-	    return -80;
+-    }
++    if (pj_atomic_get(tcp->ref_cnt) != 1)
++	return -80;
+ 
+-    for (i = 0; i < num_tp; ++i) {
+-	/* Destroy this transport. */
+-	pjsip_transport_dec_ref(tcp[i]);
++    /* Destroy this transport. */
++    pjsip_transport_dec_ref(tcp);
+ 
+-	/* Force destroy this transport. */
+-	status = pjsip_transport_destroy(tcp[i]);
+-	if (status != PJ_SUCCESS)
+-	    return -90;
+-    }
++    /* Force destroy this transport. */
++    status = pjsip_transport_destroy(tcp);
++    if (status != PJ_SUCCESS)
++	return -90;
+ 
+-    for (i = 0; i < num_listener; ++i) {
+-	/* Unregister factory */
+-	status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt),
+-						  tpfactory[i]);
+-	if (status != PJ_SUCCESS)
+-	    return -95;
+-    }
++    /* Unregister factory */
++    status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt), 
++					      tpfactory);
++    if (status != PJ_SUCCESS)
++	return -95;
+ 
+     /* Flush events. */
+     PJ_LOG(3,(THIS_FILE, "   Flushing events, 1 second..."));
+diff --git a/pjsip/src/test/transport_udp_test.c b/pjsip/src/test/transport_udp_test.c
+index 579c7f071..bc0831a38 100644
+--- a/pjsip/src/test/transport_udp_test.c
++++ b/pjsip/src/test/transport_udp_test.c
+@@ -24,88 +24,6 @@
+ 
+ #define THIS_FILE   "transport_udp_test.c"
+ 
+-static pj_status_t multi_transport_test(pjsip_transport *tp[], unsigned num_tp)
+-{
+-    pj_status_t status;
+-    pj_uint16_t i = 0;
+-    pj_str_t s;
+-    pjsip_transport *udp_tp;
+-    pj_sockaddr_in rem_addr;    
+-    pjsip_tpselector tp_sel;
+-
+-    for (;i<num_tp;++i)
+-    {
+-	pj_sockaddr_in addr;
+-
+-	pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT+i);
+-
+-	/* Start UDP transport. */
+-	status = pjsip_udp_transport_start( endpt, &addr, NULL, 1, &udp_tp);
+-	if (status != PJ_SUCCESS) {
+-	    app_perror("   Error: unable to start UDP transport", status);
+-	    return -110;
+-	}
+-
+-	/* UDP transport must have initial reference counter set to 1. */
+-	if (pj_atomic_get(udp_tp->ref_cnt) != 1)
+-	    return -120;
+-
+-	/* Test basic transport attributes */
+-	status = generic_transport_test(udp_tp);
+-	if (status != PJ_SUCCESS)
+-	    return status;
+-
+-	tp[i] = udp_tp;
+-    }
+-
+-    for (i = 0; i < num_tp; ++i) {
+-	udp_tp = tp[i];
+-	if (pj_atomic_get(udp_tp->ref_cnt) != 1)
+-	    return -130;
+-    }
+-
+-    /* Acquire transport test without selector. */
+-    pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80);
+-    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP,
+-					   &rem_addr, sizeof(rem_addr),
+-					   NULL, &udp_tp);
+-    if (status != PJ_SUCCESS)
+-	return -140;
+-
+-    for (i = 0; i < num_tp; ++i) {
+-	if (udp_tp == tp[i]) {
+-	    break;
+-	}
+-    }
+-    if (i == num_tp)
+-	return -150;
+-
+-    pjsip_transport_dec_ref(udp_tp);
+-
+-    if (pj_atomic_get(udp_tp->ref_cnt) != 1)
+-	return -160;
+-
+-    /* Acquire transport test with selector. */
+-    pj_bzero(&tp_sel, sizeof(tp_sel));
+-    tp_sel.type = PJSIP_TPSELECTOR_TRANSPORT;
+-    tp_sel.u.transport = tp[num_tp-1];
+-    pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80);
+-    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP,
+-					   &rem_addr, sizeof(rem_addr),
+-					   &tp_sel, &udp_tp);
+-    if (status != PJ_SUCCESS)
+-	return -170;
+-
+-    if (udp_tp != tp[num_tp-1])
+-	return -180;
+-
+-    pjsip_transport_dec_ref(udp_tp);
+-
+-    if (pj_atomic_get(udp_tp->ref_cnt) != 1)
+-	return -190;
+-
+-    return PJ_SUCCESS;
+-}
+ 
+ /*
+  * UDP transport test.
+@@ -113,22 +31,56 @@ static pj_status_t multi_transport_test(pjsip_transport *tp[], unsigned num_tp)
+ int transport_udp_test(void)
+ {
+     enum { SEND_RECV_LOOP = 8 };
+-    enum { NUM_TP = 4 };
+-    pjsip_transport *tp[NUM_TP], *udp_tp;
+-    pj_sockaddr_in rem_addr;
++    pjsip_transport *udp_tp, *tp;
++    pj_sockaddr_in addr, rem_addr;
+     pj_str_t s;
+     pj_status_t status;
+     int rtt[SEND_RECV_LOOP], min_rtt;
+     int i, pkt_lost;
+ 
+-    status = multi_transport_test(&tp[0], NUM_TP);
++    pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT);
++
++    /* Start UDP transport. */
++    status = pjsip_udp_transport_start( endpt, &addr, NULL, 1, &udp_tp);
++    if (status != PJ_SUCCESS) {
++	app_perror("   Error: unable to start UDP transport", status);
++	return -10;
++    }
++
++    /* UDP transport must have initial reference counter set to 1. */
++    if (pj_atomic_get(udp_tp->ref_cnt) != 1)
++	return -20;
++
++    /* Test basic transport attributes */
++    status = generic_transport_test(udp_tp);
+     if (status != PJ_SUCCESS)
+ 	return status;
+ 
++    /* Test that transport manager is returning the correct
++     * transport.
++     */
++    pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "1.1.1.1"), 80);
++    status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_UDP, 
++					   &rem_addr, sizeof(rem_addr),
++					   NULL, &tp);
++    if (status != PJ_SUCCESS)
++	return -50;
++    if (tp != udp_tp)
++	return -60;
++
++    /* pjsip_endpt_acquire_transport() adds reference, so we need
++     * to decrement it.
++     */
++    pjsip_transport_dec_ref(tp);
++
++    /* Check again that reference counter is 1. */
++    if (pj_atomic_get(udp_tp->ref_cnt) != 1)
++	return -70;
++
+     /* Basic transport's send/receive loopback test. */
+     pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "127.0.0.1"), TEST_UDP_PORT);
+     for (i=0; i<SEND_RECV_LOOP; ++i) {
+-	status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp[0], 
++	status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp, 
+ 					  "sip:alice at 127.0.0.1:"TEST_UDP_PORT_STR,
+ 					  &rtt[i]);
+ 	if (status != 0)
+@@ -146,7 +98,7 @@ int transport_udp_test(void)
+ 
+ 
+     /* Multi-threaded round-trip test. */
+-    status = transport_rt_test(PJSIP_TRANSPORT_UDP, tp[0], 
++    status = transport_rt_test(PJSIP_TRANSPORT_UDP, tp, 
+ 			       "sip:alice at 127.0.0.1:"TEST_UDP_PORT_STR, 
+ 			       &pkt_lost);
+     if (status != 0)
+@@ -155,19 +107,17 @@ int transport_udp_test(void)
+     if (pkt_lost != 0)
+ 	PJ_LOG(3,(THIS_FILE, "   note: %d packet(s) was lost", pkt_lost));
+ 
+-    for (i = 0; i < NUM_TP; ++i) {
+-	udp_tp = tp[i];
++    /* Check again that reference counter is 1. */
++    if (pj_atomic_get(udp_tp->ref_cnt) != 1)
++	return -80;
+ 
+-        /* Check again that reference counter is 1. */
+-	if (pj_atomic_get(udp_tp->ref_cnt) != 1)
+-	    return -80;
++    /* Destroy this transport. */
++    pjsip_transport_dec_ref(udp_tp);
+ 
+-	/* Destroy this transport. */
+-	pjsip_transport_dec_ref(udp_tp);
+-	status = pjsip_transport_destroy(udp_tp);
+-	if (status != PJ_SUCCESS)
+-	    return -90;
+-    }
++    /* Force destroy this transport. */
++    status = pjsip_transport_destroy(udp_tp);
++    if (status != PJ_SUCCESS)
++	return -90;
+ 
+     /* Flush events. */
+     PJ_LOG(3,(THIS_FILE, "   Flushing events, 1 second..."));
+-- 
+2.21.0
+

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/12894
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Change-Id: I8ae7233c3ac4ec29a3b991f738e655dabcaba9f1
Gerrit-Change-Number: 12894
Gerrit-PatchSet: 2
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Sean Bright <sean.bright at gmail.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20190924/f118572c/attachment-0001.html>


More information about the asterisk-code-review mailing list