diff --git a/contrib/src/pjproject/0001-rfc6544.patch b/contrib/src/pjproject/0001-rfc6544.patch
index 182478456618d4502fe52b6f55af0c68a1091527..480c6a510302a11e7580ca275302735cee714400 100644
--- a/contrib/src/pjproject/0001-rfc6544.patch
+++ b/contrib/src/pjproject/0001-rfc6544.patch
@@ -1,31 +1,47 @@
-From bbf656dd46216c2551895abfb487b51ff786d1ae Mon Sep 17 00:00:00 2001
-From: jrun <darwinskernel@gmail.com>
-Date: Wed, 26 Feb 2020 13:27:51 -0500
-Subject: [PATCH] rfc6544
+Copyright (C) 2018-2019 Savoir-faire Linux Inc.
+
+ice: rfc6544 support
+
+This patch is an implementation proposal of the RFC 6544 into PJNATH.
+This allow PJNATH to support TCP ICE candidates and open a direct TCP
+connection between peers.
+
++ BUG (semi-fixed with this patch): If an active_sock is busy due to
+a pending packet and receives a new packet to send, the final sent
+packet will be a mix between the pending packet and the new one.
+To avoid this, pj_ice_strans_sendto2 is now introduced.
+
+Written by
+Sébastien Blin <sebastien.blin@savoirfairelinux.com>
+on behalf of Savoir-faire Linux.
+
+Rebased for pjsip 2.10 by Peymane Marandi
+<paymon@savoirfairelinux.com>
+on behalf of Savoir-faire Linux.
 
 ---
- pjnath/include/pjnath/ice_session.h     |  173 +++-
- pjnath/include/pjnath/ice_strans.h      |   21 +
- pjnath/include/pjnath/stun_session.h    |   75 +-
- pjnath/include/pjnath/stun_sock.h       |   67 +-
- pjnath/include/pjnath/turn_sock.h       |   11 +
+ pjnath/include/pjnath/ice_session.h     |  173 ++++++++++++++++++++++++++++++-
+ pjnath/include/pjnath/ice_strans.h      |   21 ++++
+ pjnath/include/pjnath/stun_session.h    |   75 +++++++++++++-
+ pjnath/include/pjnath/stun_sock.h       |   67 +++++++++++-
+ pjnath/include/pjnath/turn_sock.h       |   11 ++
  pjnath/src/pjnath-test/concur_test.c    |    5 +-
- pjnath/src/pjnath-test/sess_auth.c      |   14 +-
+ pjnath/src/pjnath-test/sess_auth.c      |   14 ++-
  pjnath/src/pjnath-test/stun_sock_test.c |    7 +-
- pjnath/src/pjnath/ice_session.c         |  513 ++++++++++-
- pjnath/src/pjnath/ice_strans.c          |  727 ++++++++++++---
+ pjnath/src/pjnath/ice_session.c         |  513 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
+ pjnath/src/pjnath/ice_strans.c          |  759 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
  pjnath/src/pjnath/nat_detect.c          |    7 +-
- pjnath/src/pjnath/stun_session.c        |   15 +-
- pjnath/src/pjnath/stun_sock.c           | 1076 +++++++++++++++++++----
+ pjnath/src/pjnath/stun_session.c        |   15 ++-
+ pjnath/src/pjnath/stun_sock.c           | 1074 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------
  pjnath/src/pjnath/stun_transaction.c    |    3 +
  pjnath/src/pjnath/turn_session.c        |    3 +-
- pjnath/src/pjnath/turn_sock.c           |   17 +
+ pjnath/src/pjnath/turn_sock.c           |   24 +++--
  pjnath/src/pjturn-client/client_main.c  |    2 +-
  pjnath/src/pjturn-srv/allocation.c      |    3 +-
  pjnath/src/pjturn-srv/server.c          |    2 +-
- pjsip-apps/src/samples/icedemo.c        |  116 ++-
+ pjsip-apps/src/samples/icedemo.c        |  116 +++++++++++++++++++--
  pjsip/src/pjsua-lib/pjsua_core.c        |    2 +-
- 21 files changed, 2481 insertions(+), 378 deletions(-)
+ 21 files changed, 2497 insertions(+), 399 deletions(-)
 
 diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h
 index 8971220f0..39c197c29 100644
@@ -1009,14 +1025,22 @@ index 2a4125bc5..cd9e32e25 100644
  }
  
  
-@@ -1892,40 +2067,96 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th,
-     LOG5((ice->obj_name, "Starting checklist periodic check"));
+@@ -1893,39 +2068,95 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th,
      pj_log_push_indent();
  
-+    /* Send STUN Binding request for check with highest priority on
+     /* Send STUN Binding request for check with highest priority on
+-     * Waiting state.
 +     * Retry state.
-+     */
-+
+      */
+-    for (i=0; i<clist->count; ++i) {
+-	pj_ice_sess_check *check = &clist->checks[i];
+ 
+-	if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) {
+-	    status = perform_check(ice, clist, i, ice->is_nominating);
+-	    if (status != PJ_SUCCESS) {
+-		check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
+-				status);
+-		on_check_complete(ice, check);
 +    if (start_count == 0) {
 +	for (i = 0; i < clist->count; ++i) {
 +	    pj_ice_sess_check *check = &clist->checks[i];
@@ -1030,10 +1054,12 @@ index 2a4125bc5..cd9e32e25 100644
 +		}
 +		++start_count;
 +		break;
-+	    }
+ 	    }
 +	}
 +    }
-+
+ 
+-	    ++start_count;
+-	    break;
 +    if (start_count == 0) {
 +	// TODO (sblin) remove - https://github.com/coturn/coturn/issues/408
 +	pj_bool_t inc_counter = PJ_TRUE;
@@ -1058,18 +1084,10 @@ index 2a4125bc5..cd9e32e25 100644
 +	}
 +    }
 +
-     /* Send STUN Binding request for check with highest priority on
-      * Waiting state.
-      */
--    for (i=0; i<clist->count; ++i) {
--	pj_ice_sess_check *check = &clist->checks[i];
- 
--	if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) {
--	    status = perform_check(ice, clist, i, ice->is_nominating);
--	    if (status != PJ_SUCCESS) {
--		check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
--				status);
--		on_check_complete(ice, check);
++    /* Send STUN Binding request for check with highest priority on
++     * Waiting state.
++     */
++
 +    if (start_count == 0) {
 +	for (i = 0; i < clist->count; ++i) {
 +	    pj_ice_sess_check *check = &clist->checks[i];
@@ -1083,10 +1101,7 @@ index 2a4125bc5..cd9e32e25 100644
 +		}
 +		++start_count;
 +		break;
- 	    }
--
--	    ++start_count;
--	    break;
++	    }
  	}
      }
  
@@ -1371,7 +1386,7 @@ index 2a4125bc5..cd9e32e25 100644
  	}
      }
 diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c
-index 3cb350c2a..1cb6a6d14 100644
+index 3cb350c2a..40ae403d0 100644
 --- a/pjnath/src/pjnath/ice_strans.c
 +++ b/pjnath/src/pjnath/ice_strans.c
 @@ -69,6 +69,7 @@ enum tp_type
@@ -1489,7 +1504,24 @@ index 3cb350c2a..1cb6a6d14 100644
      /* Create the TURN transport */
      status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, turn_cfg->af,
  				 turn_cfg->conn_type,
-@@ -481,6 +533,7 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand,
+@@ -465,7 +517,7 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st,
+     return PJ_SUCCESS;
+ }
+ 
+-static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, 
++static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand,
+ 		    	         pj_ice_sess_cand *rcand)
+ {
+     if (lcand == NULL && rcand == NULL){
+@@ -474,23 +526,23 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand,
+     if (lcand == NULL || rcand == NULL){
+         return PJ_FALSE;
+     }
+-    
++
+     if (lcand->type != rcand->type
+         || lcand->status != rcand->status
+         || lcand->comp_id != rcand->comp_id
          || lcand->transport_id != rcand->transport_id
          || lcand->local_pref != rcand->local_pref
          || lcand->prio != rcand->prio
@@ -1497,7 +1529,10 @@ index 3cb350c2a..1cb6a6d14 100644
          || pj_sockaddr_cmp(&lcand->addr, &rcand->addr) != 0
          || pj_sockaddr_cmp(&lcand->base_addr, &rcand->base_addr) != 0)
      {
-@@ -490,7 +543,6 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand,
+         return PJ_FALSE;
+     }
+-    
++
      return PJ_TRUE;
  }
  
@@ -1539,12 +1574,41 @@ index 3cb350c2a..1cb6a6d14 100644
 -	    pj_bool_t cand_duplicate = PJ_FALSE;
 -	    char addrinfo[PJ_INET6_ADDRSTRLEN+10];
 -	    const pj_sockaddr *addr = &stun_sock_info.aliases[i];
--
++	    status = !PJ_SUCCESS;
++            if (stun_sock_info.conn_type == PJ_STUN_TP_UDP) {
++                status = add_local_candidate(cand, idx, i,
++					     &cand_cnt, &max_cand_cnt,
++                                             stun_sock_info, ice_st, comp,
++                                             PJ_CAND_UDP);
++            } else {
++                status = add_local_candidate(cand, idx, i,
++					     &cand_cnt, &max_cand_cnt,
++                                             stun_sock_info, ice_st, comp,
++                                             PJ_CAND_TCP_PASSIVE);
++                /** RFC 6544, Section 4.1:
++                 * First, agents SHOULD obtain host candidates as described in
++                 * Section 5.1.  Then, each agent SHOULD "obtain" (allocate a
++                 * placeholder for) an active host candidate for each component of
++                 * each TCP-capable media stream on each interface that the host
++                 * has.  The agent does not yet have to actually allocate a port for
++                 * these candidates, but they are used for the creation of the check
++                 * lists.
++                 */
++                status = add_local_candidate(cand, idx, i,
++					     &cand_cnt, &max_cand_cnt,
++                                             stun_sock_info, ice_st, comp,
++                                             PJ_CAND_TCP_ACTIVE);
++            }
++        }
++    }
+ 
 -	    if (max_cand_cnt==0) {
 -		PJ_LOG(4,(ice_st->obj_name, "Too many host candidates"));
 -		break;
 -	    }
--
++    return status;
++}
+ 
 -	    /* Ignore loopback addresses if cfg->stun.loop_addr is unset */
 -	    if (stun_cfg->loop_addr==PJ_FALSE) {
 -		if (stun_cfg->af == pj_AF_INET() && 
@@ -1562,7 +1626,22 @@ index 3cb350c2a..1cb6a6d14 100644
 -		    }
 -		}
 -	    }
--
++static pj_bool_t add_local_candidate(pj_ice_sess_cand *cand,
++                                     unsigned idx,
++                                     unsigned i,
++                                     unsigned *cand_cnt,
++                                     unsigned *max_cand_cnt,
++                                     pj_stun_sock_info stun_sock_info,
++                                     pj_ice_strans *ice_st,
++                                     pj_ice_strans_comp *comp,
++                                     pj_ice_cand_transport transport)
++{
++    unsigned j;
++    pj_bool_t cand_duplicate = PJ_FALSE;
++    char addrinfo[PJ_INET6_ADDRSTRLEN+10];
++    const pj_sockaddr *addr = &stun_sock_info.aliases[i];
++    pj_ice_strans_stun_cfg *stun_cfg = &ice_st->cfg.stun_tp[idx];
+ 
 -	    /* Ignore IPv6 link-local address, unless it is the default
 -	     * address (first alias).
 -	     */
@@ -1571,7 +1650,7 @@ index 3cb350c2a..1cb6a6d14 100644
 -		if (a->s6_addr[0] == 0xFE && (a->s6_addr[1] & 0xC0) == 0x80)
 -		    continue;
 -	    }
--
+ 
 -	    cand = &comp->cand_list[comp->cand_cnt];
 -
 -	    cand->type = PJ_ICE_CAND_TYPE_HOST;
@@ -1590,13 +1669,34 @@ index 3cb350c2a..1cb6a6d14 100644
 -		    break;
 -		}
 -	    }
--
++    if (*max_cand_cnt==0) {
++	PJ_LOG(4,(ice_st->obj_name, "Too many host candidates"));
++	return !PJ_SUCCESS;
++    }
+ 
 -	    if (cand_duplicate) {
 -		PJ_LOG(4, (ice_st->obj_name,
 -		       "Comp %d: host candidate %s (tpid=%d) is a duplicate",
 -		       comp->comp_id, pj_sockaddr_print(&cand->addr, addrinfo,
 -		       sizeof(addrinfo), 3), cand->transport_id));
--
++    /* Ignore loopback addresses if cfg->stun.loop_addr is unset */
++    if (stun_cfg->loop_addr==PJ_FALSE) {
++        if (stun_cfg->af == pj_AF_INET() &&
++            (pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127)
++        {
++            return PJ_SUCCESS;
++        }
++        else if (stun_cfg->af == pj_AF_INET6()) {
++            pj_in6_addr in6addr = {{0}};
++            in6addr.s6_addr[15] = 1;
++	    if (pj_memcmp(&in6addr, &addr->ipv6.sin6_addr,
++			  sizeof(in6addr))==0)
++            {
++                return PJ_SUCCESS;
++            }
++        }
++    }
+ 
 -		pj_bzero(&cand->addr, sizeof(cand->addr));
 -		pj_bzero(&cand->base_addr, sizeof(cand->base_addr));
 -		continue;
@@ -1608,7 +1708,15 @@ index 3cb350c2a..1cb6a6d14 100644
 -            
 -	    pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
 -				   cand->type, &cand->base_addr);
--
++    /* Ignore IPv6 link-local address, unless it is the default
++     * address (first alias).
++     */
++    if (stun_cfg->af == pj_AF_INET6() && i != 0) {
++	const pj_in6_addr *a = &addr->ipv6.sin6_addr;
++	if (a->s6_addr[0] == 0xFE && (a->s6_addr[1] & 0xC0) == 0x80)
++            return PJ_SUCCESS;
++    }
+ 
 -	    /* Set default candidate with the preferred default
 -	     * address family
 -	     */
@@ -1619,7 +1727,8 @@ index 3cb350c2a..1cb6a6d14 100644
 -	    {
 -	        comp->default_cand = (unsigned)(cand - comp->cand_list);
 -	    }
--
++    cand = &comp->cand_list[comp->cand_cnt];
+ 
 -	    PJ_LOG(4,(ice_st->obj_name,
 -		      "Comp %d/%d: host candidate %s (tpid=%d) added",
 -		      comp->comp_id, comp->cand_cnt-1, 
@@ -1627,88 +1736,6 @@ index 3cb350c2a..1cb6a6d14 100644
 -					sizeof(addrinfo), 3),
 -					cand->transport_id));
 -	}
-+	    status = !PJ_SUCCESS;
-+            if (stun_sock_info.conn_type == PJ_STUN_TP_UDP) {
-+                status = add_local_candidate(cand, idx, i,
-+					     &cand_cnt, &max_cand_cnt,
-+                                             stun_sock_info, ice_st, comp,
-+                                             PJ_CAND_UDP);
-+            } else {
-+                status = add_local_candidate(cand, idx, i,
-+					     &cand_cnt, &max_cand_cnt,
-+                                             stun_sock_info, ice_st, comp,
-+                                             PJ_CAND_TCP_PASSIVE);
-+                /** RFC 6544, Section 4.1:
-+                 * First, agents SHOULD obtain host candidates as described in
-+                 * Section 5.1.  Then, each agent SHOULD "obtain" (allocate a
-+                 * placeholder for) an active host candidate for each component of
-+                 * each TCP-capable media stream on each interface that the host
-+                 * has.  The agent does not yet have to actually allocate a port for
-+                 * these candidates, but they are used for the creation of the check
-+                 * lists.
-+                 */
-+                status = add_local_candidate(cand, idx, i,
-+					     &cand_cnt, &max_cand_cnt,
-+                                             stun_sock_info, ice_st, comp,
-+                                             PJ_CAND_TCP_ACTIVE);
-+            }
-+        }
-     }
- 
-     return status;
- }
- 
-+static pj_bool_t add_local_candidate(pj_ice_sess_cand *cand,
-+                                     unsigned idx,
-+                                     unsigned i,
-+                                     unsigned *cand_cnt,
-+                                     unsigned *max_cand_cnt,
-+                                     pj_stun_sock_info stun_sock_info,
-+                                     pj_ice_strans *ice_st,
-+                                     pj_ice_strans_comp *comp,
-+                                     pj_ice_cand_transport transport)
-+{
-+    unsigned j;
-+    pj_bool_t cand_duplicate = PJ_FALSE;
-+    char addrinfo[PJ_INET6_ADDRSTRLEN+10];
-+    const pj_sockaddr *addr = &stun_sock_info.aliases[i];
-+    pj_ice_strans_stun_cfg *stun_cfg = &ice_st->cfg.stun_tp[idx];
-+
-+
-+    if (*max_cand_cnt==0) {
-+	PJ_LOG(4,(ice_st->obj_name, "Too many host candidates"));
-+	return !PJ_SUCCESS;
-+    }
-+
-+    /* Ignore loopback addresses if cfg->stun.loop_addr is unset */
-+    if (stun_cfg->loop_addr==PJ_FALSE) {
-+        if (stun_cfg->af == pj_AF_INET() &&
-+            (pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127)
-+        {
-+            return PJ_SUCCESS;
-+        }
-+        else if (stun_cfg->af == pj_AF_INET6()) {
-+            pj_in6_addr in6addr = {{0}};
-+            in6addr.s6_addr[15] = 1;
-+	    if (pj_memcmp(&in6addr, &addr->ipv6.sin6_addr,
-+			  sizeof(in6addr))==0)
-+            {
-+                return PJ_SUCCESS;
-+            }
-+        }
-+    }
-+
-+    /* Ignore IPv6 link-local address, unless it is the default
-+     * address (first alias).
-+     */
-+    if (stun_cfg->af == pj_AF_INET6() && i != 0) {
-+	const pj_in6_addr *a = &addr->ipv6.sin6_addr;
-+	if (a->s6_addr[0] == 0xFE && (a->s6_addr[1] & 0xC0) == 0x80)
-+            return PJ_SUCCESS;
-+    }
-+
-+    cand = &comp->cand_list[comp->cand_cnt];
-+
 +    cand->type         = PJ_ICE_CAND_TYPE_HOST;
 +    cand->status       = PJ_SUCCESS;
 +    cand->local_pref   = HOST_PREF;
@@ -1726,8 +1753,10 @@ index 3cb350c2a..1cb6a6d14 100644
 +            cand_duplicate = PJ_TRUE;
 +            return !PJ_SUCCESS;
 +        }
-+    }
-+
+     }
+ 
+-    return status;
+-}
 +    if (cand_duplicate) {
 +        PJ_LOG(4, (ice_st->obj_name,
 +                   "Comp %d: host candidate %s (tpid=%d) is a duplicate",
@@ -1744,7 +1773,7 @@ index 3cb350c2a..1cb6a6d14 100644
 +	(*cand_cnt)++;
 +	(*max_cand_cnt)--;
 +    }
-+
+ 
 +    pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
 +                           cand->type, &cand->base_addr);
 +
@@ -1775,6 +1804,51 @@ index 3cb350c2a..1cb6a6d14 100644
  
  /*
   * Create the component.
+@@ -816,7 +921,7 @@ static pj_status_t alloc_send_buf(pj_ice_strans *ice_st, unsigned buf_size)
+ {
+     if (buf_size > ice_st->buf_size) {
+         unsigned i;
+-        
++
+         if (ice_st->is_pending) {
+             /* The current buffer is insufficient, but still currently used.*/
+             return PJ_EBUSY;
+@@ -839,7 +944,7 @@ static pj_status_t alloc_send_buf(pj_ice_strans *ice_st, unsigned buf_size)
+ 	}
+ 	ice_st->buf_idx = ice_st->empty_idx = 0;
+     }
+-    
++
+     return PJ_SUCCESS;
+ }
+ 
+@@ -906,7 +1011,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name,
+     /* To maintain backward compatibility, check if old/deprecated setting is set
+      * and the new setting is not, copy the value to the new setting.
+      */
+-    if (cfg->stun_tp_cnt == 0 && 
++    if (cfg->stun_tp_cnt == 0 &&
+ 	(cfg->stun.server.slen || cfg->stun.max_host_cands))
+     {
+ 	ice_st->cfg.stun_tp_cnt = 1;
+@@ -1105,7 +1210,7 @@ static void sess_init_update(pj_ice_strans *ice_st)
+ 			   pj_ice_get_cand_type_name(cand->type)));
+ 		return;
+ 	    }
+-	    
++
+ 	    if (status == PJ_EUNKNOWN) {
+ 	    	status = cand->status;
+ 	    } else {
+@@ -1114,7 +1219,7 @@ static void sess_init_update(pj_ice_strans *ice_st)
+ 	    	    status = PJ_SUCCESS;
+ 	    }
+ 	}
+-	
++
+ 	if (status != PJ_SUCCESS)
+ 	    break;
+     }
 @@ -1207,6 +1312,12 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
      ice_cb.on_ice_complete = &on_ice_complete;
      ice_cb.on_rx_data = &ice_rx_data;
@@ -1798,7 +1872,52 @@ index 3cb350c2a..1cb6a6d14 100644
  	    if (status != PJ_SUCCESS)
  		goto on_error;
  	}
-@@ -1668,7 +1780,31 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
+@@ -1544,7 +1656,7 @@ pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st,
+ PJ_DEF(pj_status_t) pj_ice_strans_stop_ice(pj_ice_strans *ice_st)
+ {
+     PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
+-    
++
+     /* Protect with group lock, since this may cause race condition with
+      * pj_ice_strans_sendto2().
+      * See ticket #1877.
+@@ -1578,7 +1690,7 @@ static pj_status_t use_buffer( pj_ice_strans *ice_st,
+     status = alloc_send_buf(ice_st, data_len);
+     if (status != PJ_SUCCESS)
+     	return status;
+-    
++
+     if (ice_st->is_pending && ice_st->empty_idx == ice_st->buf_idx) {
+     	/* We don't use buffer or there's no more empty buffer. */
+     	return PJ_EBUSY;
+@@ -1593,12 +1705,12 @@ static pj_status_t use_buffer( pj_ice_strans *ice_st,
+     pj_sockaddr_cp(&ice_st->send_buf[idx].dst_addr, dst_addr);
+     ice_st->send_buf[idx].dst_addr_len = dst_addr_len;
+     *buffer = ice_st->send_buf[idx].buffer;
+-    
++
+     if (ice_st->is_pending) {
+         /* We'll continue later since there's still a pending send. */
+     	return PJ_EPENDING;
+     }
+-    
++
+     ice_st->is_pending = PJ_TRUE;
+     ice_st->buf_idx = idx;
+ 
+@@ -1659,16 +1771,40 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
+      */
+     if (ice_st->ice && ice_st->state == PJ_ICE_STRANS_STATE_RUNNING) {
+ 	status = pj_ice_sess_send_data(ice_st->ice, comp_id, buf, data_len);
+-	
++
+ 	pj_grp_lock_release(ice_st->grp_lock);
+-	
++
+ 	goto on_return;
+-    } 
++    }
+ 
      pj_grp_lock_release(ice_st->grp_lock);
  
      def_cand = &comp->cand_list[comp->default_cand];
@@ -1843,6 +1962,15 @@ index 3cb350c2a..1cb6a6d14 100644
  	    goto on_return;
  	}
  
+@@ -1771,7 +1912,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
+     		       dst_addr_len, PJ_TRUE, PJ_FALSE);
+     if (status == PJ_EPENDING)
+     	status = PJ_SUCCESS;
+-    
++
+     return status;
+ }
+ #endif
 @@ -1842,7 +1983,22 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
  				      sizeof(lip), 3);
  		    pj_sockaddr_print(&check->rcand->addr, rip,
@@ -1897,6 +2025,15 @@ index 3cb350c2a..1cb6a6d14 100644
      if (tp_typ == TP_TURN) {
  	if (comp->turn[tp_idx].sock) {
  	    status = pj_turn_sock_sendto(comp->turn[tp_idx].sock,
+@@ -1958,7 +2137,7 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
+     	    	if (status != PJ_SUCCESS) {
+     	    	    goto on_return;
+     	    	}
+-    	    
++
+     	    	pj_sockaddr_cp(&comp->dst_addr, dst_addr);
+     	    	comp->synth_addr_len = pj_sockaddr_get_len(&comp->synth_addr);
+     	    }
 @@ -1969,9 +2148,13 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
      	    dest_addr_len = dst_addr_len;
      	}
@@ -1914,6 +2051,15 @@ index 3cb350c2a..1cb6a6d14 100644
      } else {
  	pj_assert(!"Invalid transport ID");
  	status = PJ_EINVALIDOP;
+@@ -2017,7 +2200,7 @@ static void check_pending_send(pj_ice_strans *ice_st)
+ 
+     if (ice_st->num_buf > 0)
+         ice_st->buf_idx = (ice_st->buf_idx + 1) % ice_st->num_buf;
+-    
++
+     if (ice_st->num_buf > 0 && ice_st->buf_idx != ice_st->empty_idx) {
+ 	/* There's some pending send. Send it one by one. */
+         pending_send *ps = &ice_st->send_buf[ice_st->buf_idx];
 @@ -2031,6 +2214,237 @@ static void check_pending_send(pj_ice_strans *ice_st)
      }
  }
@@ -2152,6 +2298,47 @@ index 3cb350c2a..1cb6a6d14 100644
  /* Notifification when asynchronous send operation via STUN/TURN
   * has completed.
   */
+@@ -2196,7 +2610,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
+ 		{
+ 		    /* We get an IPv4 mapped address for our IPv6
+ 		     * host address.
+-		     */		     
++		     */
+ 		    comp->ipv4_mapped = PJ_TRUE;
+ 
+ 		    /* Find other host candidates with the same (IPv6)
+@@ -2208,7 +2622,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
+ 
+ 		        if (comp->cand_list[i].type != PJ_ICE_CAND_TYPE_HOST)
+ 		            continue;
+-		        
++
+ 		        a1 = &comp->cand_list[i].addr;
+ 		        a2 = &cand->base_addr;
+ 		        if (pj_memcmp(pj_sockaddr_get_addr(a1),
+@@ -2225,7 +2639,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
+ 		    pj_sockaddr_cp(&cand->base_addr, &info.mapped_addr);
+ 		    pj_sockaddr_cp(&cand->rel_addr, &info.mapped_addr);
+ 		}
+-		
++
+ 		/* Eliminate the srflx candidate if the address is
+ 		 * equal to other (host) candidates.
+ 		 */
+@@ -2268,11 +2682,11 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
+ 					     sizeof(ipaddr), 3)));
+ 
+ 		sess_init_update(ice_st);
+-		
++
+ 		if (op == PJ_STUN_SOCK_MAPPED_ADDR_CHANGE &&
+ 		    ice_st->cb.on_ice_complete)
+ 		{
+-		    (*ice_st->cb.on_ice_complete)(ice_st, 
++		    (*ice_st->cb.on_ice_complete)(ice_st,
+ 		    				  PJ_ICE_STRANS_OP_ADDR_CHANGE,
+ 		    				  status);
+ 		}
 @@ -2318,6 +2732,10 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
  	    }
  	}
@@ -2170,15 +2357,14 @@ index 3cb350c2a..1cb6a6d14 100644
 -	status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
 -				       data->transport_id, pkt, pkt_len,
 -				       peer_addr, addr_len);
--
++	if (comp->ice_st->cfg.turn_tp->conn_type == PJ_TURN_TP_TCP && pkt_len > 0) {
++	    unsigned parsed = 0;
++	    pj_status_t status;
+ 
 -	if (status != PJ_SUCCESS) {
 -	    ice_st_perror(comp->ice_st,
 -			  "Error processing packet from TURN relay",
 -			  status);
-+	if (comp->ice_st->cfg.turn_tp->conn_type == PJ_TURN_TP_TCP && pkt_len > 0) {
-+	    unsigned parsed = 0;
-+	    pj_status_t status;
-+
 +	    do {
 +		pj_uint16_t leftover = pkt_len - parsed;
 +		pj_uint8_t *current_packet = ((pj_uint8_t *)(pkt)) + parsed;
@@ -2688,7 +2874,7 @@ index 5fe825cf5..c4519f82e 100644
  
      stun_sock->ka_interval = cfg->ka_interval;
      if (stun_sock->ka_interval == 0)
-@@ -226,125 +480,6 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
+@@ -226,140 +480,68 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
      pj_grp_lock_add_handler(stun_sock->grp_lock, pool, stun_sock,
  			    &stun_sock_destructor);
  
@@ -2703,7 +2889,10 @@ index 5fe825cf5..c4519f82e 100644
 -				NULL);
 -    if (status != PJ_SUCCESS && !cfg->qos_ignore_error)
 -	goto on_error;
--
++    /* Create STUN session */
++    {
++	pj_stun_session_cb sess_cb;
+ 
 -    /* Apply socket buffer size */
 -    if (cfg->so_rcvbuf_size > 0) {
 -	unsigned sobuf_size = cfg->so_rcvbuf_size;
@@ -2728,7 +2917,16 @@ index 5fe825cf5..c4519f82e 100644
 -	unsigned sobuf_size = cfg->so_sndbuf_size;
 -	status = pj_sock_setsockopt_sobuf(stun_sock->sock_fd, pj_SO_SNDBUF(),
 -					  PJ_TRUE, &sobuf_size);
--	if (status != PJ_SUCCESS) {
++	pj_bzero(&sess_cb, sizeof(sess_cb));
++	sess_cb.on_request_complete = &sess_on_request_complete;
++	sess_cb.on_send_msg = &sess_on_send_msg;
++	status = pj_stun_session_create(&stun_sock->stun_cfg, 
++					stun_sock->obj_name,
++					&sess_cb, PJ_FALSE, 
++					stun_sock->grp_lock,
++					&stun_sock->stun_sess,
++					conn_type);
+ 	if (status != PJ_SUCCESS) {
 -	    PJ_PERROR(3, (stun_sock->obj_name, status,
 -			  "Failed setting SO_SNDBUF"));
 -	} else {
@@ -2741,9 +2939,11 @@ index 5fe825cf5..c4519f82e 100644
 -		PJ_LOG(5, (stun_sock->obj_name, "SO_SNDBUF set to %d",
 -			   sobuf_size));
 -	    }
--	}
--    }
--
++	    pj_stun_sock_destroy(stun_sock);
++	    return status;
+ 	}
+     }
+ 
 -    /* Bind socket */
 -    max_bind_retry = MAX_BIND_RETRY;
 -    if (cfg->port_range && cfg->port_range < max_bind_retry)
@@ -2758,24 +2958,47 @@ index 5fe825cf5..c4519f82e 100644
 -				 cfg->port_range, max_bind_retry);
 -    if (status != PJ_SUCCESS)
 -	goto on_error;
--
++    pj_stun_sock_alloc(stun_sock);
+ 
 -    /* Create more useful information string about this transport */
 -#if 0
 -    {
 -	pj_sockaddr bound_addr;
 -	int addr_len = sizeof(bound_addr);
--
++    /* Done */
++    *p_stun_sock = stun_sock;
++    return PJ_SUCCESS;
++}
+ 
 -	status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr, 
 -				     &addr_len);
 -	if (status != PJ_SUCCESS)
 -	    goto on_error;
--
++/*
++ * Notification when outgoing TCP socket has been connected.
++ */
++static pj_bool_t on_stun_sock_ready(pj_activesock_t *asock, pj_status_t status)
++{
++    pj_stun_sock *stun_sock;
++    stun_sock = (pj_stun_sock *)pj_activesock_get_user_data(asock);
++    if (!stun_sock)
++	return PJ_FALSE;
++
++    pj_grp_lock_acquire(stun_sock->grp_lock);
+ 
 -	stun_sock->info = pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+10);
 -	pj_sockaddr_print(&bound_addr, stun_sock->info, 
 -			  PJ_INET6_ADDRSTRLEN, 3);
--    }
++    /* TURN session may have already been destroyed here.
++     * See ticket #1557 (http://trac.pjsip.org/repos/ticket/1557).
++     */
++    if (!stun_sock->stun_sess) {
++	sess_fail(stun_sock, PJ_STUN_SESS_DESTROYED, status);
++	pj_grp_lock_release(stun_sock->grp_lock);
++	return PJ_FALSE;
+     }
 -#endif
--
+ 
 -    /* Init active socket configuration */
 -    {
 -	pj_activesock_cfg activesock_cfg;
@@ -2809,74 +3032,39 @@ index 5fe825cf5..c4519f82e 100644
 -			       sizeof(stun_sock->send_key));
 -	pj_ioqueue_op_key_init(&stun_sock->int_send_key,
 -			       sizeof(stun_sock->int_send_key));
--    }
--
-     /* Create STUN session */
-     {
- 	pj_stun_session_cb sess_cb;
-@@ -356,11 +491,58 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
- 					stun_sock->obj_name,
- 					&sess_cb, PJ_FALSE, 
- 					stun_sock->grp_lock,
--					&stun_sock->stun_sess);
--	if (status != PJ_SUCCESS)
--	    goto on_error;
-+					&stun_sock->stun_sess,
-+					conn_type);
-+	if (status != PJ_SUCCESS) {
-+	    pj_stun_sock_destroy(stun_sock);
-+	    return status;
-+	}
-     }
- 
-+    pj_stun_sock_alloc(stun_sock);
-+
-+    /* Done */
-+    *p_stun_sock = stun_sock;
-+    return PJ_SUCCESS;
-+}
-+
-+/*
-+ * Notification when outgoing TCP socket has been connected.
-+ */
-+static pj_bool_t on_stun_sock_ready(pj_activesock_t *asock, pj_status_t status)
-+{
-+    pj_stun_sock *stun_sock;
-+    stun_sock = (pj_stun_sock *)pj_activesock_get_user_data(asock);
-+    if (!stun_sock)
-+	return PJ_FALSE;
-+
-+    pj_grp_lock_acquire(stun_sock->grp_lock);
-+
-+    /* TURN session may have already been destroyed here.
-+     * See ticket #1557 (http://trac.pjsip.org/repos/ticket/1557).
-+     */
-+    if (!stun_sock->stun_sess) {
-+	sess_fail(stun_sock, PJ_STUN_SESS_DESTROYED, status);
-+	pj_grp_lock_release(stun_sock->grp_lock);
-+	return PJ_FALSE;
-+    }
-+
 +    if (status != PJ_SUCCESS) {
 +	sess_fail(stun_sock, PJ_STUN_TCP_CONNECT_ERROR, status);
 +	pj_grp_lock_release(stun_sock->grp_lock);
 +	return PJ_FALSE;
-+    }
-+
+     }
+ 
+-    /* Create STUN session */
+-    {
+-	pj_stun_session_cb sess_cb;
 +    if (stun_sock->conn_type != PJ_STUN_TP_UDP)
 +	PJ_LOG(5,(stun_sock->obj_name, "TCP connected"));
-+
+ 
+-	pj_bzero(&sess_cb, sizeof(sess_cb));
+-	sess_cb.on_request_complete = &sess_on_request_complete;
+-	sess_cb.on_send_msg = &sess_on_send_msg;
+-	status = pj_stun_session_create(&stun_sock->stun_cfg, 
+-					stun_sock->obj_name,
+-					&sess_cb, PJ_FALSE, 
+-					stun_sock->grp_lock,
+-					&stun_sock->stun_sess);
+-	if (status != PJ_SUCCESS)
+-	    goto on_error;
+-    }
 +    /* Start asynchronous read operations */
 +    pj_status_t result;
 +    result = pj_activesock_start_recvfrom(asock, stun_sock->pool,
 +					  stun_sock->cfg.max_pkt_size, 0);
 +    if (result != PJ_SUCCESS)
 +	return PJ_FALSE;
-+
+ 
      /* Associate us with the STUN session */
      pj_stun_session_set_user_data(stun_sock->stun_sess, stun_sock);
- 
-@@ -369,24 +551,303 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
+@@ -369,25 +551,304 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
       * STUN messages we sent with STUN messages that the application sends.
       * The last 16bit value in the array is a counter.
       */
@@ -2910,8 +3098,8 @@ index 5fe825cf5..c4519f82e 100644
 +
 +    pj_grp_lock_release(stun_sock->grp_lock);
 +    return PJ_TRUE;
-+}
-+
+ }
+ 
 +static pj_bool_t parse_rx_packet(pj_activesock_t *asock,
 +				 void *data,
 +				 pj_size_t size,
@@ -3182,11 +3370,12 @@ index 5fe825cf5..c4519f82e 100644
 +	return PJ_FALSE;
 +
 +    return PJ_TRUE;
- }
++}
 +#endif
- 
++
  /* Start socket. */
  PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock,
+ 				        const pj_str_t *domain,
 @@ -526,6 +987,26 @@ PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock)
  	stun_sock->sock_fd = PJ_INVALID_SOCKET;
      }
@@ -3630,10 +3819,24 @@ index a378b8672..88985af69 100644
  	do_destroy(sess);
  	return status;
 diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c
-index dc6304d9f..9b69a6a21 100644
+index dc6304d9f..a6e192e9f 100644
 --- a/pjnath/src/pjnath/turn_sock.c
 +++ b/pjnath/src/pjnath/turn_sock.c
-@@ -1766,3 +1766,20 @@ static void turn_on_connection_bind_status(pj_turn_session *sess,
+@@ -894,12 +894,7 @@ static pj_bool_t on_data_sent(pj_turn_sock *turn_sock,
+     }
+ 
+     if (turn_sock->cb.on_data_sent) {
+-	pj_ssize_t header_len, sent_size;
+-
+-        /* Remove the length of packet header from sent size. */
+-	header_len = turn_sock->pkt_len - turn_sock->body_len;
+-	sent_size = (sent > header_len)? (sent - header_len) : 0;
+-	(*turn_sock->cb.on_data_sent)(turn_sock, sent_size);
++	(*turn_sock->cb.on_data_sent)(turn_sock, sent);
+     }
+ 
+     return PJ_TRUE;
+@@ -1766,3 +1761,20 @@ static void turn_on_connection_bind_status(pj_turn_session *sess,
  					      peer_addr, addr_len);
      }
  }
@@ -3924,6 +4127,3 @@ index 474a8d07c..9257f07a4 100644
  				     NULL, sess, &sess->stun_sock);
  	if (status != PJ_SUCCESS) {
  	    char errmsg[PJ_ERR_MSG_SIZE];
--- 
-2.24.1
-