diff --git a/contrib/src/pjproject/0001-rfc6544.patch b/contrib/src/pjproject/0001-rfc6544.patch
index 2ee2626c47371dbc86fd45dc23b04e628f385bfb..fe8e05a1e2277dc1af67004e1e50adce809f72c9 100644
--- a/contrib/src/pjproject/0001-rfc6544.patch
+++ b/contrib/src/pjproject/0001-rfc6544.patch
@@ -1,4 +1,4 @@
-Copyright (C) 2018-2019 Savoir-faire Linux Inc.
+Copyright (C) 2018-2020 Savoir-faire Linux Inc.
 
 ice: rfc6544 support
 
@@ -18,8 +18,9 @@ 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_session.h     |  151 +++-
  pjnath/include/pjnath/ice_strans.h      |   21 +
  pjnath/include/pjnath/stun_session.h    |   75 +-
  pjnath/include/pjnath/stun_sock.h       |   67 +-
@@ -27,8 +28,8 @@ on behalf of Savoir-faire Linux.
  pjnath/src/pjnath-test/concur_test.c    |    5 +-
  pjnath/src/pjnath-test/sess_auth.c      |   14 +-
  pjnath/src/pjnath-test/stun_sock_test.c |    7 +-
- pjnath/src/pjnath/ice_session.c         |  515 ++++++++++-
- pjnath/src/pjnath/ice_strans.c          |  773 +++++++++++++---
+ pjnath/src/pjnath/ice_session.c         |  491 +++++++++--
+ pjnath/src/pjnath/ice_strans.c          |  745 +++++++++++++---
  pjnath/src/pjnath/nat_detect.c          |    7 +-
  pjnath/src/pjnath/stun_session.c        |   15 +-
  pjnath/src/pjnath/stun_sock.c           | 1075 +++++++++++++++++++----
@@ -40,16 +41,16 @@ on behalf of Savoir-faire Linux.
  pjnath/src/pjturn-srv/server.c          |    2 +-
  pjsip-apps/src/samples/icedemo.c        |  116 ++-
  pjsip/src/pjsua-lib/pjsua_core.c        |    2 +-
- 21 files changed, 2510 insertions(+), 403 deletions(-)
+ 21 files changed, 2430 insertions(+), 409 deletions(-)
 
 diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h
-index 8971220f0..39c197c29 100644
+index 8971220f0..4cccd7c64 100644
 --- a/pjnath/include/pjnath/ice_session.h
 +++ b/pjnath/include/pjnath/ice_session.h
 @@ -163,6 +163,52 @@ typedef enum pj_ice_cand_type
-
+ 
  } pj_ice_cand_type;
-
+ 
 +/**
 + * ICE candidates types like described by RFC 6544.
 + */
@@ -96,25 +97,25 @@ index 8971220f0..39c197c29 100644
 +
 +} pj_ice_tp_type;
 +
-
+ 
  /** Forward declaration for pj_ice_sess */
  typedef struct pj_ice_sess pj_ice_sess;
 @@ -309,6 +355,11 @@ typedef struct pj_ice_sess_cand
       */
      pj_sockaddr		 rel_addr;
-
+ 
 +    /**
 +     * Transport used (TCP or UDP)
 +     */
 +    pj_ice_cand_transport transport;
 +
  } pj_ice_sess_cand;
-
-
+ 
+ 
 @@ -324,6 +375,22 @@ typedef enum pj_ice_sess_check_state
       */
      PJ_ICE_SESS_CHECK_STATE_FROZEN,
-
+ 
 +    /**
 +     * The following status is used when a packet sent via TURN got a
 +     * "Connection reset by peer". This mean that the peer didn't allow
@@ -137,7 +138,7 @@ index 8971220f0..39c197c29 100644
 @@ -331,6 +398,12 @@ typedef enum pj_ice_sess_check_state
       */
      PJ_ICE_SESS_CHECK_STATE_WAITING,
-
+ 
 +    /**
 +     * A check has not been performed for this pair, but TCP socket
 +     * is currently connecting to the pair. Wait to finish the connection.
@@ -147,7 +148,7 @@ index 8971220f0..39c197c29 100644
      /**
       * A check has not been performed for this pair, and can be
       * performed as soon as it is the highest priority Waiting pair on
-@@ -520,6 +593,52 @@ typedef struct pj_ice_sess_cb
+@@ -520,6 +593,41 @@ typedef struct pj_ice_sess_cb
  			      void *pkt, pj_size_t size,
  			      const pj_sockaddr_t *src_addr,
  			      unsigned src_addr_len);
@@ -164,17 +165,6 @@ index 8971220f0..39c197c29 100644
 +                                       unsigned check_id);
 +
 +    /**
-+     * Select incoming TURN dataconn
-+     *
-+     * @param ice			The ICE session.
-+     * @param clist			The ICE connection list
-+     * @param check_id		The wanted check.
-+     */
-+    pj_status_t (*select_turn_dataconn)(pj_ice_sess *ice,
-+                                        pj_ice_sess_checklist *clist,
-+                                        unsigned check_id);
-+
-+    /**
 +     * Reconnect a resetted TCP connection and send connectivity check
 +     * cf. PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY
 +     *
@@ -198,17 +188,17 @@ index 8971220f0..39c197c29 100644
 +                                        unsigned check_id);
 +
  } pj_ice_sess_cb;
-
-
-@@ -636,6 +755,7 @@ struct pj_ice_sess
+ 
+ 
+@@ -636,6 +744,7 @@ struct pj_ice_sess
      pj_bool_t            valid_pair_found;          /**< First pair found   */
      pj_status_t		 ice_status;		    /**< Error status.	    */
      pj_timer_entry	 timer;			    /**< ICE timer.	    */
 +    pj_timer_entry	 timer_connect;		    /**< ICE timer tcp timeout*/
      pj_ice_sess_cb	 cb;			    /**< Callback.	    */
-
+ 
      pj_stun_config	 stun_cfg;		    /**< STUN settings.	    */
-@@ -855,6 +975,7 @@ PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
+@@ -855,6 +964,7 @@ PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
   * @param rel_addr	Optional related address.
   * @param addr_len	Length of addresses.
   * @param p_cand_id	Optional pointer to receive the candidate ID.
@@ -216,20 +206,20 @@ index 8971220f0..39c197c29 100644
   *
   * @return		PJ_SUCCESS if candidate is successfully added.
   */
-@@ -868,7 +989,8 @@ PJ_DECL(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
+@@ -868,7 +978,8 @@ PJ_DECL(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
  					  const pj_sockaddr_t *base_addr,
  					  const pj_sockaddr_t *rel_addr,
  					  int addr_len,
 -					  unsigned *p_cand_id);
 +					  unsigned *p_cand_id,
 +					  pj_ice_cand_transport transport);
-
+ 
  /**
   * Find default candidate for the specified component ID, using this
-@@ -980,6 +1102,55 @@ PJ_DECL(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
+@@ -980,6 +1091,44 @@ PJ_DECL(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice,
  					   const pj_sockaddr_t *src_addr,
  					   int src_addr_len);
-
+ 
 +/**
 + * Notification when ICE session get a new incoming connection
 + *
@@ -268,19 +258,8 @@ index 8971220f0..39c197c29 100644
 +PJ_DECL(void) ice_sess_on_peer_packet(pj_ice_sess *ice,
 +				      pj_uint8_t transport_id,
 +				      pj_sockaddr_t* remote_addr);
-+
-+/**
-+ * Select dataconn from TURN
-+ *
-+ * @param ice          The ICE session.
-+ * @param clist        The ice check list
-+ * @param check_id     The wanted check
-+ */
-+PJ_DECL(void) ice_select_incoming_turn(pj_ice_sess *ice,
-+				       pj_ice_sess_checklist *clist,
-+				       unsigned check_id);
-
-
+ 
+ 
  /**
 diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h
 index d0af76679..9eb74b35f 100644
@@ -289,7 +268,7 @@ index d0af76679..9eb74b35f 100644
 @@ -274,6 +274,13 @@ typedef struct pj_ice_strans_stun_cfg
       */
      pj_bool_t		 ignore_stun_error;
-
+ 
 +    /**
 +     * Type of connection to the STUN server.
 +     *
@@ -298,12 +277,12 @@ index d0af76679..9eb74b35f 100644
 +    pj_stun_tp_type conn_type;
 +
  } pj_ice_strans_stun_cfg;
-
-
+ 
+ 
 @@ -289,6 +296,13 @@ typedef struct pj_ice_strans_turn_cfg
       */
      int			 af;
-
+ 
 +    /**
 +     * If we want to use UDP or TCP as described by RFC 6544.
 +     * This will discover candidates via TCP sockets. Then it will
@@ -317,7 +296,7 @@ index d0af76679..9eb74b35f 100644
 @@ -368,6 +382,13 @@ typedef struct pj_ice_strans_cfg
       */
      int			 af;
-
+ 
 +    /**
 +     * If we want to use UDP or TCP as described by RFC 6544.
 +     * This will discover candidates via TCP sockets. Then it will
@@ -335,7 +314,7 @@ index bee630ab4..3f2ecf739 100644
 @@ -174,6 +174,29 @@ typedef struct pj_stun_rx_data pj_stun_rx_data;
  /** Forward declaration for pj_stun_session */
  typedef struct pj_stun_session pj_stun_session;
-
+ 
 +/**
 + * STUN transport types, which will be used both to specify the connection
 + * type for reaching STUN server and the type of allocation transport to be
@@ -359,13 +338,13 @@ index bee630ab4..3f2ecf739 100644
 +    PJ_STUN_TP_TLS = 255
 +
 +} pj_stun_tp_type;
-
+ 
  /**
   * This is the callback to be registered to pj_stun_session, to send
 @@ -307,6 +330,38 @@ typedef struct pj_stun_session_cb
  				    const pj_sockaddr_t *src_addr,
  				    unsigned src_addr_len);
-
+ 
 +    /**
 +     * Notification when STUN session get a ConnectionAttempt indication.
 +     *
@@ -399,8 +378,8 @@ index bee630ab4..3f2ecf739 100644
 +                           pj_sockaddr_t* remote_addr);
 +
  } pj_stun_session_cb;
-
-
+ 
+ 
 @@ -390,6 +445,7 @@ typedef enum pj_stun_sess_msg_log_flag
   * @param grp_lock	Optional group lock to be used by this session.
   * 			If NULL, the session will create one itself.
@@ -416,13 +395,13 @@ index bee630ab4..3f2ecf739 100644
 -					    pj_stun_session **p_sess);
 +					    pj_stun_session **p_sess,
 +					    pj_stun_tp_type conn_type);
-
+ 
  /**
   * Destroy the STUN session and all objects created in the context of
 @@ -752,6 +809,22 @@ PJ_DECL(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
  PJ_DECL(void) pj_stun_msg_destroy_tdata(pj_stun_session *sess,
  					pj_stun_tx_data *tdata);
-
+ 
 +/**
 + *
 + * @param sess     The STUN session.
@@ -439,7 +418,7 @@ index bee630ab4..3f2ecf739 100644
 + */
 +PJ_DECL(pj_stun_tp_type) pj_stun_session_tp_type(pj_stun_session *sess);
 +
-
+ 
  /**
   * @}
 diff --git a/pjnath/include/pjnath/stun_sock.h b/pjnath/include/pjnath/stun_sock.h
@@ -460,7 +439,7 @@ index fff4df885..bfc9c1415 100644
 +#include <pj/pool.h>
  #include <pj/sock.h>
  #include <pj/sock_qos.h>
-
+ 
 @@ -87,7 +91,17 @@ typedef enum pj_stun_sock_op
      /**
       * IP address change notification from the keep-alive operation.
@@ -477,13 +456,13 @@ index fff4df885..bfc9c1415 100644
 +     * TCP fails to connect
 +     */
 +    PJ_STUN_TCP_CONNECT_ERROR
-
-
+ 
+ 
  } pj_stun_sock_op;
 @@ -197,6 +211,11 @@ typedef struct pj_stun_sock_info
       */
      pj_sockaddr	    mapped_addr;
-
+ 
 +    /**
 +     * If connected, the remote address will be stored here.
 +     */
@@ -495,19 +474,19 @@ index fff4df885..bfc9c1415 100644
 @@ -208,6 +227,11 @@ typedef struct pj_stun_sock_info
       */
      pj_sockaddr	    aliases[PJ_ICE_ST_MAX_CAND];
-
+ 
 +    /**
 +     * The tranport type of the socket
 +     */
 +    pj_stun_tp_type conn_type;
 +
  } pj_stun_sock_info;
-
-
+ 
+ 
 @@ -343,6 +367,9 @@ PJ_DECL(void) pj_stun_sock_cfg_default(pj_stun_sock_cfg *cfg);
   *			the operation of this transport.
   * @param af		Address family of socket. Currently pj_AF_INET()
-  *			and pj_AF_INET6() are supported.
+  *			and pj_AF_INET6() are supported. 
 + * @param conn_type     Connection type to the STUN server. Both TCP and UDP are
 + *			supported.
 + *
@@ -525,7 +504,7 @@ index fff4df885..bfc9c1415 100644
 @@ -485,6 +513,43 @@ PJ_DECL(pj_status_t) pj_stun_sock_sendto(pj_stun_sock *stun_sock,
  					 const pj_sockaddr_t *dst_addr,
  					 unsigned addr_len);
-
+ 
 +
 +#if PJ_HAS_TCP
 +/**
@@ -573,7 +552,7 @@ index e4d306174..35388809f 100644
 @@ -623,6 +623,17 @@ PJ_DECL(pj_status_t) pj_turn_sock_bind_channel(pj_turn_sock *turn_sock,
  					       const pj_sockaddr_t *peer,
  					       unsigned addr_len);
-
+ 
 +/**
 + *  Check if peer is a dataconn
 + *
@@ -585,7 +564,7 @@ index e4d306174..35388809f 100644
 +PJ_DECL(pj_bool_t) pj_turn_sock_has_dataconn(pj_turn_sock *turn_sock,
 +					     const pj_sockaddr_t *peer);
 +
-
+ 
  /**
   * @}
 diff --git a/pjnath/src/pjnath-test/concur_test.c b/pjnath/src/pjnath-test/concur_test.c
@@ -630,7 +609,7 @@ index 055eaad61..1d07bf299 100644
  	return -200;
 @@ -575,8 +577,12 @@ static int run_client_test(const char *title,
      }
-
+ 
      /* Send the request */
 -    status = pj_stun_session_send_msg(client->sess, NULL, PJ_FALSE, PJ_TRUE, &server->addr,
 -				      pj_sockaddr_get_len(&server->addr), tdata);
@@ -651,7 +630,7 @@ index fff4fad26..e7f8b84eb 100644
      pj_bzero(&cb, sizeof(cb));
      cb.on_status = &stun_sock_on_status;
      cb.on_rx_data = &stun_sock_on_rx_data;
--    status = pj_stun_sock_create(cfg, NULL, GET_AF(use_ipv6), &cb, &sock_cfg,
+-    status = pj_stun_sock_create(cfg, NULL, GET_AF(use_ipv6), &cb, &sock_cfg, 
 -				 client, &client->sock);
 +    status = pj_stun_sock_create(cfg, NULL, GET_AF(use_ipv6),
 +				 PJ_STUN_TP_UDP,
@@ -663,17 +642,17 @@ index fff4fad26..e7f8b84eb 100644
  	PJ_LOG(3,(THIS_FILE, "     sending to %s", pj_sockaddr_print(&info.srv_addr, txt, sizeof(txt), 3)));
      }
      status = pj_stun_sock_sendto(client->sock, NULL, &ret, sizeof(ret),
--				 0, &info.srv_addr,
+-				 0, &info.srv_addr, 
 +				 0, &info.srv_addr,
  				 pj_sockaddr_get_len(&info.srv_addr));
      if (status != PJ_SUCCESS && status != PJ_EPENDING) {
  	app_perror("    error: server sending data", status);
 diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
-index 2a4125bc5..85d3234c9 100644
+index 2a4125bc5..c3a06fbc4 100644
 --- a/pjnath/src/pjnath/ice_session.c
 +++ b/pjnath/src/pjnath/ice_session.c
 @@ -18,6 +18,7 @@
-  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
   */
  #include <pjnath/ice_session.h>
 +#include <pjnath/stun_session.h>
@@ -681,7 +660,7 @@ index 2a4125bc5..85d3234c9 100644
  #include <pj/array.h>
  #include <pj/assert.h>
 @@ -44,7 +45,10 @@ static const char *cand_type_names[] =
- static const char *check_state_name[] =
+ static const char *check_state_name[] = 
  {
      "Frozen",
 +    "Needs Retry",
@@ -698,9 +677,9 @@ index 2a4125bc5..85d3234c9 100644
 -    TIMER_KEEP_ALIVE		/**< ICE keep-alive timer.		*/
 +    TIMER_KEEP_ALIVE,		/**< ICE keep-alive timer.		*/
 +    TIMER_CONNECTION_TIMEOUT
-
+ 
  };
-
+ 
 @@ -123,6 +128,8 @@ typedef struct timer_data
  {
      pj_ice_sess		    *ice;
@@ -708,10 +687,10 @@ index 2a4125bc5..85d3234c9 100644
 +    /* TODO (remove), for now, needed for the NEEDS_FIRST_PACKET state */
 +    unsigned                first_packet_counter;
  } timer_data;
-
-
+ 
+ 
 @@ -133,6 +140,7 @@ typedef struct timer_data
-
+ 
  /* Forward declarations */
  static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te);
 +static void on_tcp_connect_timeout(pj_ice_sess *ice);
@@ -719,7 +698,7 @@ index 2a4125bc5..85d3234c9 100644
  static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now);
  static void ice_on_destroy(void *obj);
 @@ -291,7 +299,8 @@ static pj_status_t init_comp(pj_ice_sess *ice,
-     status = pj_stun_session_create(&ice->stun_cfg, NULL,
+     status = pj_stun_session_create(&ice->stun_cfg, NULL, 
  			            &sess_cb, PJ_TRUE,
  			            ice->grp_lock,
 -				    &comp->stun_sess);
@@ -727,8 +706,16 @@ index 2a4125bc5..85d3234c9 100644
 +				    PJ_STUN_TP_UDP);
      if (status != PJ_SUCCESS)
  	return status;
-
-@@ -717,7 +726,8 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
+ 
+@@ -359,6 +368,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg,
+     pj_ice_sess_options_default(&ice->opt);
+ 
+     pj_timer_entry_init(&ice->timer, TIMER_NONE, (void*)ice, &on_timer);
++    pj_timer_entry_init(&ice->timer_connect, TIMER_NONE, (void*)ice, &on_timer);
+ 
+     pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
+ 		     name, ice);
+@@ -717,7 +727,8 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
  					 const pj_sockaddr_t *base_addr,
  					 const pj_sockaddr_t *rel_addr,
  					 int addr_len,
@@ -738,7 +725,7 @@ index 2a4125bc5..85d3234c9 100644
  {
      pj_ice_sess_cand *lcand;
      pj_status_t status = PJ_SUCCESS;
-@@ -740,6 +750,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
+@@ -740,6 +751,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
      lcand->comp_id = (pj_uint8_t)comp_id;
      lcand->transport_id = (pj_uint8_t)transport_id;
      lcand->type = type;
@@ -746,7 +733,17 @@ index 2a4125bc5..85d3234c9 100644
      pj_strdup(ice->pool, &lcand->foundation, foundation);
      lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id);
      pj_sockaddr_cp(&lcand->addr, addr);
-@@ -1081,6 +1092,17 @@ static pj_status_t prune_checklist(pj_ice_sess *ice,
+@@ -961,7 +973,8 @@ static void check_set_state(pj_ice_sess *ice, pj_ice_sess_check *check,
+ 			    pj_ice_sess_check_state st, 
+ 			    pj_status_t err_code)
+ {
+-    pj_assert(check->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED);
++    if (check->state >= PJ_ICE_SESS_CHECK_STATE_SUCCEEDED)
++		return;
+ 
+     LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
+ 	 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), &ice->clist, check),
+@@ -1081,6 +1094,17 @@ static pj_status_t prune_checklist(pj_ice_sess *ice,
  		return PJNATH_EICENOHOSTCAND;
  	    }
  	}
@@ -762,9 +759,9 @@ index 2a4125bc5..85d3234c9 100644
 +	    --i;
 +	}
      }
-
+ 
      /* Next remove a pair if its local and remote candidates are identical
-@@ -1183,6 +1205,9 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te)
+@@ -1183,6 +1207,9 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te)
      case TIMER_KEEP_ALIVE:
  	ice_keep_alive(ice, PJ_TRUE);
  	break;
@@ -774,13 +771,13 @@ index 2a4125bc5..85d3234c9 100644
      case TIMER_NONE:
  	/* Nothing to do, just to get rid of gcc warning */
  	break;
-@@ -1619,6 +1644,43 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice,
+@@ -1619,6 +1646,43 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice,
      return PJ_FALSE;
  }
-
+ 
 +static void on_tcp_connect_timeout(pj_ice_sess* ice)
 +{
-+    pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,&ice->timer,
++    pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,&ice->timer_connect,
 +				   TIMER_NONE);
 +
 +    pj_bool_t first_found = PJ_FALSE, set_timer = PJ_FALSE;
@@ -802,7 +799,7 @@ index 2a4125bc5..85d3234c9 100644
 +	}
 +    }
 +
-+    if (set_timer && ice->timer.id == TIMER_NONE) {
++    if (set_timer && ice->timer_connect.id == TIMER_NONE) {
 +	/* Reschedule */
 +	pj_time_val delay = {
 +	    .sec  = 0,
@@ -810,18 +807,18 @@ index 2a4125bc5..85d3234c9 100644
 +	};
 +	pj_time_val_normalize(&delay);
 +	pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
-+				    &ice->timer, &delay,
++				    &ice->timer_connect, &delay,
 +				    TIMER_CONNECTION_TIMEOUT,
 +				    ice->grp_lock);
 +    }
 +}
-
+ 
  /* Create checklist by pairing local candidates with remote candidates */
  PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
-@@ -1705,6 +1767,30 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
+@@ -1705,6 +1769,30 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
  		continue;
  	    }
-
+ 
 +	    /* Section 6.2, RFC 6544 (https://tools.ietf.org/html/rfc6544)
 +	     * As with UDP, check lists are formed only by full ICE implementations.
 +	     * When forming candidate pairs, the following types of TCP candidates
@@ -846,21 +843,21 @@ index 2a4125bc5..85d3234c9 100644
 +		continue;
 +	    }
 +
-
+ 
  	    chk->lcand = lcand;
  	    chk->rcand = rcand;
-@@ -1749,6 +1835,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
+@@ -1749,6 +1837,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
      td = PJ_POOL_ZALLOC_T(ice->pool, timer_data);
      td->ice = ice;
      td->clist = clist;
 +    td->first_packet_counter = 1;
      clist->timer.user_data = (void*)td;
      clist->timer.cb = &periodic_timer;
-
-@@ -1761,6 +1848,36 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
+ 
+@@ -1761,6 +1850,36 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list(
      return PJ_SUCCESS;
  }
-
+ 
 +static pj_status_t send_connectivity_check(pj_ice_sess *ice,
 +					   pj_ice_sess_checklist *clist,
 +					   unsigned check_id,
@@ -892,47 +889,43 @@ index 2a4125bc5..85d3234c9 100644
 +}
 +
  /* Perform check on the specified candidate pair. */
- static pj_status_t perform_check(pj_ice_sess *ice,
+ static pj_status_t perform_check(pj_ice_sess *ice, 
  				 pj_ice_sess_checklist *clist,
-@@ -1771,19 +1888,17 @@ static pj_status_t perform_check(pj_ice_sess *ice,
+@@ -1771,19 +1890,17 @@ static pj_status_t perform_check(pj_ice_sess *ice,
      pj_ice_msg_data *msg_data;
      pj_ice_sess_check *check;
      const pj_ice_sess_cand *lcand;
 -    const pj_ice_sess_cand *rcand;
      pj_uint32_t prio;
      pj_status_t status;
-
+ 
      check = &clist->checks[check_id];
      lcand = check->lcand;
 -    rcand = check->rcand;
      comp = find_comp(ice, lcand->comp_id);
-
+ 
 +    pj_log_push_indent();
-     LOG5((ice->obj_name,
- 	 "Sending connectivity check for check %s",
+     LOG5((ice->obj_name, 
+ 	 "Sending connectivity check for check %s", 
  	 dump_check(ice->tmp.txt, sizeof(ice->tmp.txt), clist, check)));
 -    pj_log_push_indent();
-
+ 
      /* Create request */
-     status = pj_stun_session_create_req(comp->stun_sess,
-@@ -1831,32 +1946,92 @@ static pj_status_t perform_check(pj_ice_sess *ice,
+     status = pj_stun_session_create_req(comp->stun_sess, 
+@@ -1831,32 +1948,71 @@ static pj_status_t perform_check(pj_ice_sess *ice,
  				    &ice->tie_breaker);
-
+ 
      } else {
 +	if (nominate) {
 +	    check->nominated = PJ_TRUE;
 +	}
- 	pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg,
+ 	pj_stun_msg_add_uint64_attr(check->tdata->pool, check->tdata->msg, 
  				    PJ_STUN_ATTR_ICE_CONTROLLED,
  				    &ice->tie_breaker);
      }
-
+ 
 +#if PJ_HAS_TCP
 +    switch (lcand->transport) {
-+    case PJ_CAND_UDP:
-+        status = send_connectivity_check(ice, clist, check_id,
-+                                         nominate, msg_data);
-+        break;
 +    case PJ_CAND_TCP_ACTIVE:
 +        switch (check->state) {
 +        case PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY:
@@ -944,9 +937,9 @@ index 2a4125bc5..85d3234c9 100644
 +            break;
 +        default:
 +            pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,
-+                                           &ice->timer, TIMER_NONE);
++                                           &ice->timer_connect, TIMER_NONE);
 +            status = (*ice->cb.wait_tcp_connection)(ice, clist, check_id);
-+            if (ice->timer.id != TIMER_NONE) {
++            if (ice->timer_connect.id != TIMER_NONE) {
 +                pj_assert(!"Not expected any timer active");
 +            } else {
 +                pj_time_val delay = {
@@ -955,7 +948,7 @@ index 2a4125bc5..85d3234c9 100644
 +                };
 +                pj_time_val_normalize(&delay);
 +                pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
-+                                                  &ice->timer, &delay,
++                                                  &ice->timer_connect, &delay,
 +                                                  TIMER_CONNECTION_TIMEOUT,
 +                                                  ice->grp_lock);
 +            }
@@ -964,39 +957,22 @@ index 2a4125bc5..85d3234c9 100644
 +        break;
 +    case PJ_CAND_TCP_PASSIVE:
 +    case PJ_CAND_TCP_SO:
++    case PJ_CAND_UDP:
 +    default:
-+        if (lcand->type == PJ_ICE_CAND_TYPE_RELAYED) {
-+            status = (*ice->cb.select_turn_dataconn)(ice, clist, check_id);
-+            if (ice->timer.id == TIMER_NONE) {
-+				pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap,
-+											&ice->timer, TIMER_NONE);
-+                pj_time_val delay = {
-+                    .sec  = 0,
-+                    .msec = 1500
-+                };
-+                pj_time_val_normalize(&delay);
-+                pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap,
-+                                                  &ice->timer, &delay,
-+                                                  TIMER_CONNECTION_TIMEOUT,
-+                                                  ice->grp_lock);
-+            }
-+        } else {
-+            status = send_connectivity_check(ice, clist, check_id,
-+                                             nominate, msg_data);
-+	}
++		status = send_connectivity_check(ice, clist, check_id, nominate, msg_data);
 +        break;
 +    }
 +#else
 +    status = send_connectivity_check(ice, clist, check_id, nominate, msg_data);
 +#endif
-
--    /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the
+ 
+-    /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the 
 -     * STUN session.
 -     */
 -
 -    /* Initiate STUN transaction to send the request */
--    status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE,
--				      PJ_TRUE, &rcand->addr,
+-    status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE, 
+-				      PJ_TRUE, &rcand->addr, 
 -				      pj_sockaddr_get_len(&rcand->addr),
 -				      check->tdata);
 -    if (status != PJ_SUCCESS) {
@@ -1016,24 +992,24 @@ index 2a4125bc5..85d3234c9 100644
 -	return status;
      }
 -
--    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS,
+-    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, 
 -	            PJ_SUCCESS);
      pj_log_pop_indent();
 -    return PJ_SUCCESS;
 +    return status;
  }
-
-
-@@ -1893,39 +2068,95 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th,
+ 
+ 
+@@ -1893,39 +2049,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
 -     * 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) {
@@ -1056,7 +1032,7 @@ index 2a4125bc5..85d3234c9 100644
  	    }
 +	}
 +    }
-
+ 
 -	    ++start_count;
 -	    break;
 +    if (start_count == 0) {
@@ -1103,7 +1079,7 @@ index 2a4125bc5..85d3234c9 100644
 +	    }
  	}
      }
-
+ 
      /* If we don't have anything in Waiting state, perform check to
       * highest priority pair that is in Frozen state.
       */
@@ -1112,7 +1088,7 @@ index 2a4125bc5..85d3234c9 100644
 +    if (start_count == 0) {
 +	for (i = 0; i < clist->count; ++i) {
  	    pj_ice_sess_check *check = &clist->checks[i];
-
+ 
  	    if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) {
  		status = perform_check(ice, clist, i, ice->is_nominating);
 -		if (status != PJ_SUCCESS) {
@@ -1127,7 +1103,7 @@ index 2a4125bc5..85d3234c9 100644
 +	    }
 +	}
 +    }
-
+ 
 +    if (start_count == 0) {
 +	// If all sockets are pending, do nothing
 +	for (i = 0; i < clist->count; ++i) {
@@ -1136,27 +1112,27 @@ index 2a4125bc5..85d3234c9 100644
  		++start_count;
  		break;
  	    }
-@@ -1933,14 +2164,14 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th,
+@@ -1933,14 +2145,14 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th,
      }
-
+ 
      /* Cannot start check because there's no suitable candidate pair.
 -     */
 +    */
      if (start_count!=0) {
  	/* Schedule for next timer */
  	pj_time_val timeout = {0, PJ_ICE_TA_VAL};
-
+ 
  	pj_time_val_normalize(&timeout);
  	pj_timer_heap_schedule_w_grp_lock(th, te, &timeout, PJ_TRUE,
 -	                                  ice->grp_lock);
 +					  ice->grp_lock);
      }
-
+ 
      pj_grp_lock_release(ice->grp_lock);
-@@ -2181,6 +2412,192 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess,
+@@ -2181,6 +2393,179 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess,
      return status;
  }
-
+ 
 +static pj_ice_sess_check* get_current_check_at_state(pj_ice_sess *ice,
 +                                                     pj_sockaddr_t *remote_addr,
 +                                                     pj_ice_sess_check_state state,
@@ -1326,28 +1302,15 @@ index 2a4125bc5..85d3234c9 100644
 +
 +    const pj_ice_sess_cand *rcand = check->rcand;
 +    if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED) {
-+	check->state = PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS;
 +	check_set_state(ice, check,
 +			PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, PJ_SUCCESS);
 +    }
 +}
-+
-+
-+void ice_select_incoming_turn(pj_ice_sess *ice,
-+			      pj_ice_sess_checklist *clist,
-+			      unsigned check_id)
-+{
-+    check_set_state(ice, &clist->checks[check_id],
-+		    PJ_ICE_SESS_CHECK_STATE_SUCCEEDED, PJ_SUCCESS);
-+    update_comp_check(ice, clist->checks[check_id].lcand->comp_id,
-+		      &clist->checks[check_id]);
-+    on_check_complete(ice, &clist->checks[check_id]);
-+}
-
+ 
  /* This callback is called when outgoing STUN request completed */
  static void on_stun_request_complete(pj_stun_session *stun_sess,
-@@ -2411,7 +2828,9 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
- 				      &check->lcand->base_addr,
+@@ -2411,7 +2796,9 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
+ 				      &check->lcand->base_addr, 
  				      &check->lcand->base_addr,
  				      pj_sockaddr_get_len(&xaddr->sockaddr),
 -				      &cand_id);
@@ -1355,27 +1318,40 @@ index 2a4125bc5..85d3234c9 100644
 +				      check->rcand->transport == PJ_CAND_UDP ?
 +				      PJ_CAND_UDP : PJ_CAND_TCP_PASSIVE);
  	if (status != PJ_SUCCESS) {
- 	    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED,
+ 	    check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, 
  			    status);
-@@ -2673,7 +3092,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
+@@ -2474,11 +2861,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
+     /* Perform 7.1.2.2.2.  Updating Pair States.
+      * This may terminate ICE processing.
+      */
+-    if (on_check_complete(ice, check)) {
+-	/* ICE complete! */
+-	pj_grp_lock_release(ice->grp_lock);
+-	return;
+-    }
++	on_check_complete(ice, check);
+ 
+     pj_grp_lock_release(ice->grp_lock);
+ }
+@@ -2673,7 +3056,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
      msg_data->has_req_data = PJ_FALSE;
-
+ 
      /* Send the response */
 -    status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE, PJ_TRUE,
 +    status = pj_stun_session_send_msg(sess, msg_data, PJ_TRUE,
 +                                      pj_stun_session_tp_type(sess) ==
 +                                      PJ_STUN_TP_UDP,
  				      src_addr, src_addr_len, tdata);
-
-
-@@ -2794,12 +3215,12 @@ static void handle_incoming_check(pj_ice_sess *ice,
+ 
+ 
+@@ -2794,12 +3179,12 @@ static void handle_incoming_check(pj_ice_sess *ice,
      /* Just get candidate with the highest priority and same transport ID
       * for the specified  component ID in the checklist.
       */
 -    for (i=0; i<ice->clist.count; ++i) {
 -	pj_ice_sess_check *c = &ice->clist.checks[i];
 -	if (c->lcand->comp_id == rcheck->comp_id &&
--	    c->lcand->transport_id == rcheck->transport_id)
+-	    c->lcand->transport_id == rcheck->transport_id) 
 +    for (i=0; i<ice->lcand_cnt; ++i) {
 +	pj_ice_sess_cand* lcand_tmp = &ice->lcand[i];
 +	if (lcand_tmp->comp_id == rcheck->comp_id &&
@@ -1387,21 +1363,21 @@ index 2a4125bc5..85d3234c9 100644
  	}
      }
 diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c
-index 3cb350c2a..bf7f98096 100644
+index 3cb350c2a..d29c1f0db 100644
 --- a/pjnath/src/pjnath/ice_strans.c
 +++ b/pjnath/src/pjnath/ice_strans.c
 @@ -69,6 +69,7 @@ enum tp_type
  #   define RELAY_PREF  0
  #endif
-
+ 
 +#define MAX_RTP_SIZE 65536
-
+ 
  /* The candidate type preference when STUN candidate is used */
  static pj_uint8_t srflx_pref_table[PJ_ICE_CAND_TYPE_MAX] =
 @@ -87,6 +88,14 @@ static pj_uint8_t srflx_pref_table[PJ_ICE_CAND_TYPE_MAX] =
  #endif
  };
-
+ 
 +//////////////////////////////////////////////////////////////////////////////
 +
 +static pj_uint16_t GETVAL16H(const pj_uint8_t *buf1, const pj_uint8_t *buf2)
@@ -1410,22 +1386,18 @@ index 3cb350c2a..bf7f98096 100644
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////
-
+ 
  /* ICE callbacks */
  static void	   on_ice_complete(pj_ice_sess *ice, pj_status_t status);
-@@ -103,6 +112,24 @@ static void	   ice_rx_data(pj_ice_sess *ice,
+@@ -103,6 +112,20 @@ static void	   ice_rx_data(pj_ice_sess *ice,
  			       const pj_sockaddr_t *src_addr,
  			       unsigned src_addr_len);
-
+ 
 +#if PJ_HAS_TCP
 +static pj_status_t ice_wait_tcp_connection(pj_ice_sess *ice,
 +					   pj_ice_sess_checklist *clist,
 +					   unsigned check_id);
 +
-+static pj_status_t ice_select_turn_dataconn(pj_ice_sess *ice,
-+					    pj_ice_sess_checklist *clist,
-+					    unsigned check_id);
-+
 +static pj_status_t ice_reconnect_tcp_connection(pj_ice_sess *ice,
 +						pj_ice_sess_checklist *clist,
 +						unsigned check_id);
@@ -1435,13 +1407,13 @@ index 3cb350c2a..bf7f98096 100644
 +					    unsigned check_id);
 +#endif
 +
-
+ 
  /* STUN socket callbacks */
  /* Notification when incoming packet has been received. */
-@@ -182,6 +209,16 @@ typedef struct pj_ice_strans_comp
+@@ -182,6 +205,16 @@ typedef struct pj_ice_strans_comp
  } pj_ice_strans_comp;
-
-
+ 
+ 
 +static pj_bool_t add_local_candidate(pj_ice_sess_cand *cand,
 +				     unsigned idx,
 +				     unsigned i,
@@ -1455,7 +1427,7 @@ index 3cb350c2a..bf7f98096 100644
  /* Pending send buffer */
  typedef struct pending_send
  {
-@@ -225,6 +262,13 @@ struct pj_ice_strans
+@@ -225,6 +258,13 @@ struct pj_ice_strans
      pj_bool_t		     destroy_req;/**< Destroy has been called?	*/
      pj_bool_t		     cb_called;	/**< Init error callback called?*/
      pj_bool_t		     call_send_cb;/**< Need to call send cb?	*/
@@ -1467,25 +1439,25 @@ index 3cb350c2a..bf7f98096 100644
 +
 +    pj_ssize_t          last_data_len; /**< What the application is waiting. */
  };
-
-
-@@ -261,6 +305,7 @@ PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg)
+ 
+ 
+@@ -261,6 +301,7 @@ PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg)
      pj_bzero(cfg, sizeof(*cfg));
-
+ 
      cfg->af = pj_AF_INET();
 +    cfg->protocol = PJ_ICE_TP_UDP;
      pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL);
      pj_ice_strans_stun_cfg_default(&cfg->stun);
      pj_ice_strans_turn_cfg_default(&cfg->turn);
-@@ -278,6 +323,7 @@ PJ_DEF(void) pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg *cfg)
+@@ -278,6 +319,7 @@ PJ_DEF(void) pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg *cfg)
      pj_bzero(cfg, sizeof(*cfg));
-
+ 
      cfg->af = pj_AF_INET();
 +    cfg->conn_type = PJ_STUN_TP_UDP;
      cfg->port = PJ_STUN_PORT;
      cfg->max_host_cands = 64;
      cfg->ignore_stun_error = PJ_FALSE;
-@@ -421,6 +467,9 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st,
+@@ -421,6 +463,9 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st,
  	cand->transport_id = tp_id;
  	cand->comp_id = (pj_uint8_t) comp->comp_id;
  	new_cand = PJ_TRUE;
@@ -1493,12 +1465,12 @@ index 3cb350c2a..bf7f98096 100644
 +						    PJ_CAND_UDP :
 +						    PJ_CAND_TCP_PASSIVE;
      }
-
+ 
      /* Allocate and initialize TURN socket data */
-@@ -428,6 +477,10 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st,
+@@ -428,6 +473,10 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st,
      data->comp = comp;
      data->transport_id = cand->transport_id;
-
+ 
 +    if (turn_cfg->conn_type == PJ_TURN_TP_TCP) {
 +	turn_cfg->alloc_param.peer_conn_type = PJ_TURN_TP_TCP;
 +    }
@@ -1506,20 +1478,20 @@ index 3cb350c2a..bf7f98096 100644
      /* Create the TURN transport */
      status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, turn_cfg->af,
  				 turn_cfg->conn_type,
-@@ -465,7 +518,7 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st,
+@@ -465,7 +514,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, 
 +static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand,
  		    	         pj_ice_sess_cand *rcand)
  {
      if (lcand == NULL && rcand == NULL){
-@@ -474,23 +527,23 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand,
+@@ -474,23 +523,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
@@ -1533,27 +1505,27 @@ index 3cb350c2a..bf7f98096 100644
      {
          return PJ_FALSE;
      }
--
+-    
 +
      return PJ_TRUE;
  }
-
+ 
 -
  static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
  				     pj_ice_strans_comp *comp,
  				     unsigned idx,
-@@ -541,6 +594,9 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
+@@ -541,6 +590,9 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
      cand->local_pref = SRFLX_PREF;
      cand->transport_id = CREATE_TP_ID(TP_STUN, idx);
      cand->comp_id = (pj_uint8_t) comp->comp_id;
 +    cand->transport = stun_cfg->conn_type == PJ_STUN_TP_UDP ?
 +                                                PJ_CAND_UDP :
 +                                                PJ_CAND_TCP_PASSIVE;
-
+ 
      /* Allocate and initialize STUN socket data */
      data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data);
-@@ -549,8 +605,9 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
-
+@@ -549,8 +601,9 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
+ 
      /* Create the STUN transport */
      status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL,
 -				 stun_cfg->af, &stun_sock_cb,
@@ -1563,10 +1535,10 @@ index 3cb350c2a..bf7f98096 100644
 +				 &comp->stun[idx].sock);
      if (status != PJ_SUCCESS)
  	return status;
-
-@@ -635,105 +692,154 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
+ 
+@@ -635,105 +688,154 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
  	}
-
+ 
  	for (i = 0; i < stun_sock_info.alias_cnt &&
 -		    cand_cnt < stun_cfg->max_host_cands; ++i)
 +		    cand_cnt < stun_cfg->max_host_cands &&
@@ -1603,17 +1575,17 @@ index 3cb350c2a..bf7f98096 100644
 +            }
 +        }
 +    }
-
+ 
 -	    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() &&
+-		if (stun_cfg->af == pj_AF_INET() && 
 -		    (pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127)
 -		{
 -		    continue;
@@ -1643,7 +1615,7 @@ index 3cb350c2a..bf7f98096 100644
 +    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).
 -	     */
@@ -1652,7 +1624,7 @@ index 3cb350c2a..bf7f98096 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;
@@ -1663,7 +1635,7 @@ index 3cb350c2a..bf7f98096 100644
 -	    pj_sockaddr_cp(&cand->addr, addr);
 -	    pj_sockaddr_cp(&cand->base_addr, addr);
 -	    pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr));
--
+-            
 -	    /* Check if not already in list */
 -	    for (j=0; j<comp->cand_cnt; j++) {
 -		if (ice_cand_equals(cand, &comp->cand_list[j])) {
@@ -1675,7 +1647,7 @@ index 3cb350c2a..bf7f98096 100644
 +	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",
@@ -1698,7 +1670,7 @@ index 3cb350c2a..bf7f98096 100644
 +            }
 +        }
 +    }
-
+ 
 -		pj_bzero(&cand->addr, sizeof(cand->addr));
 -		pj_bzero(&cand->base_addr, sizeof(cand->base_addr));
 -		continue;
@@ -1707,7 +1679,7 @@ index 3cb350c2a..bf7f98096 100644
 -		cand_cnt++;
 -		max_cand_cnt--;
 -	    }
--
+-            
 -	    pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
 -				   cand->type, &cand->base_addr);
 +    /* Ignore IPv6 link-local address, unless it is the default
@@ -1718,7 +1690,7 @@ index 3cb350c2a..bf7f98096 100644
 +	if (a->s6_addr[0] == 0xFE && (a->s6_addr[1] & 0xC0) == 0x80)
 +            return PJ_SUCCESS;
 +    }
-
+ 
 -	    /* Set default candidate with the preferred default
 -	     * address family
 -	     */
@@ -1730,10 +1702,10 @@ index 3cb350c2a..bf7f98096 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,
+-		      comp->comp_id, comp->cand_cnt-1, 
 -		      pj_sockaddr_print(&cand->addr, addrinfo,
 -					sizeof(addrinfo), 3),
 -					cand->transport_id));
@@ -1756,7 +1728,7 @@ index 3cb350c2a..bf7f98096 100644
 +            return !PJ_SUCCESS;
 +        }
      }
-
+ 
 -    return status;
 -}
 +    if (cand_duplicate) {
@@ -1778,7 +1750,7 @@ index 3cb350c2a..bf7f98096 100644
 +
 +    pj_ice_calc_foundation(ice_st->pool, &cand->foundation,
 +                           cand->type, &cand->base_addr);
-+
+ 
 +    /* Set default candidate with the preferred default
 +     * address family
 +     */
@@ -1789,7 +1761,7 @@ index 3cb350c2a..bf7f98096 100644
 +    {
 +        comp->default_cand = (unsigned)(cand - comp->cand_list);
 +    }
-
++
 +    if (transport == PJ_CAND_TCP_ACTIVE) {
 +        // Use the port 9 (DISCARD Protocol) for TCP active candidates.
 +        pj_sockaddr_set_port(&cand->addr, 9);
@@ -1803,68 +1775,67 @@ index 3cb350c2a..bf7f98096 100644
 +              cand->transport_id));
 +    return PJ_SUCCESS;
 +}
-
+ 
  /*
   * Create the component.
-@@ -816,7 +922,7 @@ static pj_status_t alloc_send_buf(pj_ice_strans *ice_st, unsigned buf_size)
+@@ -816,7 +918,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 +945,7 @@ static pj_status_t alloc_send_buf(pj_ice_strans *ice_st, unsigned buf_size)
+@@ -839,7 +941,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 +1012,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name,
+ 
+@@ -906,7 +1008,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 && 
 +    if (cfg->stun_tp_cnt == 0 &&
  	(cfg->stun.server.slen || cfg->stun.max_host_cands))
      {
  	ice_st->cfg.stun_tp_cnt = 1;
-@@ -1105,7 +1211,7 @@ static void sess_init_update(pj_ice_strans *ice_st)
+@@ -1105,7 +1207,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 +1220,7 @@ static void sess_init_update(pj_ice_strans *ice_st)
+@@ -1114,7 +1216,7 @@ static void sess_init_update(pj_ice_strans *ice_st)
  	    	    status = PJ_SUCCESS;
  	    }
  	}
--
+-	
 +
  	if (status != PJ_SUCCESS)
  	    break;
      }
-@@ -1207,6 +1313,12 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
+@@ -1207,6 +1309,11 @@ 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;
      ice_cb.on_tx_pkt = &ice_tx_pkt;
 +#if PJ_HAS_TCP
 +    ice_cb.wait_tcp_connection      = &ice_wait_tcp_connection;
-+    ice_cb.select_turn_dataconn     = &ice_select_turn_dataconn;
 +    ice_cb.reconnect_tcp_connection = &ice_reconnect_tcp_connection;
 +    ice_cb.close_tcp_connection     = &ice_close_tcp_connection;
 +#endif
-
+ 
      /* Create! */
      status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role,
-@@ -1282,7 +1394,8 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
+@@ -1282,7 +1389,8 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
  					  &cand->foundation, &cand->addr,
  					  &cand->base_addr,  &cand->rel_addr,
  					  pj_sockaddr_get_len(&cand->addr),
@@ -1874,66 +1845,66 @@ index 3cb350c2a..bf7f98096 100644
  	    if (status != PJ_SUCCESS)
  		goto on_error;
  	}
-@@ -1544,7 +1657,7 @@ pj_ice_strans_get_valid_pair(const pj_ice_strans *ice_st,
+@@ -1544,7 +1652,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 +1691,7 @@ static pj_status_t use_buffer( pj_ice_strans *ice_st,
+@@ -1578,7 +1686,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 +1706,12 @@ static pj_status_t use_buffer( pj_ice_strans *ice_st,
+@@ -1593,12 +1701,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;
-
-@@ -1651,6 +1764,9 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
+ 
+@@ -1651,6 +1759,9 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
      	}
      }
-
+ 
 +    def_cand = &comp->cand_list[comp->default_cand];
 +    pj_bool_t add_header = def_cand->transport != PJ_CAND_UDP;
 +
      /* If ICE is available, send data with ICE, otherwise send with the
       * default candidate selected during initialization.
       *
-@@ -1659,16 +1775,37 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
+@@ -1659,16 +1770,37 @@ 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];
--
+-    
 +    /* TCP, add header */
 +    if (add_header) {
 +	/*
@@ -1959,8 +1930,8 @@ index 3cb350c2a..bf7f98096 100644
 +
      if (def_cand->status == PJ_SUCCESS) {
  	unsigned tp_idx = GET_TP_IDX(def_cand->transport_id);
-
-@@ -1730,6 +1867,11 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
+ 
+@@ -1730,6 +1862,11 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
  	    status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, buf,
  					 (unsigned)data_len, 0, dest_addr,
  					 dest_addr_len);
@@ -1971,9 +1942,9 @@ index 3cb350c2a..bf7f98096 100644
 +
  	    goto on_return;
  	}
-
-@@ -1738,8 +1880,14 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
-
+ 
+@@ -1738,8 +1875,14 @@ static pj_status_t send_data(pj_ice_strans *ice_st,
+ 
  on_return:
      /* We continue later in on_data_sent() callback. */
 -    if (status == PJ_EPENDING)
@@ -1985,19 +1956,19 @@ index 3cb350c2a..bf7f98096 100644
 +		}
      	return status;
 +	}
-
+ 
      if (call_cb) {
      	on_data_sent(ice_st, (status == PJ_SUCCESS? data_len: -status));
-@@ -1771,7 +1919,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
+@@ -1771,7 +1914,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 +1990,22 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
+@@ -1842,7 +1985,22 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
  				      sizeof(lip), 3);
  		    pj_sockaddr_print(&check->rcand->addr, rip,
  				      sizeof(rip), 3);
@@ -2021,10 +1992,10 @@ index 3cb350c2a..bf7f98096 100644
  		    if (tp_typ == TP_TURN) {
  			/* Activate channel binding for the remote address
  			 * for more efficient data transfer using TURN.
-@@ -1936,6 +2099,29 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
+@@ -1936,6 +2094,29 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
  	       pj_sockaddr_get_port(dst_addr),
  	       tp_typ));
-
+ 
 +    /* TCP, add header */
 +    if (comp->ice_st->cfg.stun_tp->conn_type == PJ_STUN_TP_TCP) {
 +	/*
@@ -2051,19 +2022,19 @@ index 3cb350c2a..bf7f98096 100644
      if (tp_typ == TP_TURN) {
  	if (comp->turn[tp_idx].sock) {
  	    status = pj_turn_sock_sendto(comp->turn[tp_idx].sock,
-@@ -1958,7 +2144,7 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
+@@ -1958,7 +2139,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 +2155,13 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
+@@ -1969,9 +2150,13 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
      	    dest_addr_len = dst_addr_len;
      	}
-
+ 
 -	status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL,
 -				     buf, (unsigned)size, 0,
 -				     dest_addr, dest_addr_len);
@@ -2077,19 +2048,19 @@ index 3cb350c2a..bf7f98096 100644
      } else {
  	pj_assert(!"Invalid transport ID");
  	status = PJ_EINVALIDOP;
-@@ -2017,7 +2207,7 @@ static void check_pending_send(pj_ice_strans *ice_st)
-
+@@ -2017,7 +2202,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 +2221,237 @@ static void check_pending_send(pj_ice_strans *ice_st)
+@@ -2031,6 +2216,214 @@ static void check_pending_send(pj_ice_strans *ice_st)
      }
  }
-
+ 
 +static void on_peer_connection(pj_stun_session* sess,
 +                               pj_status_t status,
 +                               pj_sockaddr_t* remote_addr)
@@ -2228,29 +2199,6 @@ index 3cb350c2a..bf7f98096 100644
 +    return PJ_EINVAL;
 +}
 +
-+static pj_status_t ice_select_turn_dataconn(pj_ice_sess *ice,
-+                                            pj_ice_sess_checklist *clist,
-+                                            unsigned check_id)
-+{
-+    pj_ice_sess_check      *check   = &clist->checks[check_id];
-+    const pj_ice_sess_cand *lcand   = check->lcand;
-+    const pj_ice_sess_cand *rcand   = check->rcand;
-+    pj_ice_strans          *ice_st  = (pj_ice_strans *)ice->user_data;
-+    pj_ice_strans_comp     *st_comp = ice_st->comp[lcand->comp_id - 1];
-+
-+    for (int i=0; i<ice_st->cfg.turn_tp_cnt; ++i) {
-+        pj_turn_session_info info;
-+        pj_turn_sock_get_info(st_comp->turn[i].sock, &info);
-+        if (st_comp->turn[i].sock
-+            && pj_turn_sock_has_dataconn(st_comp->turn[i].sock, &rcand->addr)) {
-+            ice_select_incoming_turn(ice, clist, check_id);
-+            return PJ_SUCCESS; // Already connected via TURN
-+        }
-+    }
-+
-+    return PJ_EINVAL;
-+}
-+
 +static pj_status_t ice_reconnect_tcp_connection(pj_ice_sess *ice,
 +                                                pj_ice_sess_checklist *clist,
 +                                                unsigned check_id)
@@ -2324,58 +2272,58 @@ index 3cb350c2a..bf7f98096 100644
  /* Notifification when asynchronous send operation via STUN/TURN
   * has completed.
   */
-@@ -2039,7 +2460,8 @@ static pj_bool_t on_data_sent(pj_ice_strans *ice_st, pj_ssize_t sent)
+@@ -2039,7 +2432,8 @@ static pj_bool_t on_data_sent(pj_ice_strans *ice_st, pj_ssize_t sent)
      if (ice_st->destroy_req || !ice_st->is_pending)
  	return PJ_TRUE;
-
+ 
 -    if (ice_st->call_send_cb && ice_st->cb.on_data_sent) {
 +    if (ice_st->call_send_cb && ice_st->cb.on_data_sent
 +		&& sent == ice_st->last_data_len /* Only app data should be announced */) {
  	(*ice_st->cb.on_data_sent)(ice_st, sent);
      }
-
-@@ -2196,7 +2618,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
+ 
+@@ -2196,7 +2590,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 +2630,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
-
+@@ -2208,7 +2602,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 +2647,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
+@@ -2225,7 +2619,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 +2690,11 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
+@@ -2268,11 +2662,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, 
 +		    (*ice_st->cb.on_ice_complete)(ice_st,
  		    				  PJ_ICE_STRANS_OP_ADDR_CHANGE,
  		    				  status);
  		}
-@@ -2318,6 +2740,10 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
+@@ -2318,6 +2712,10 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
  	    }
  	}
  	break;
@@ -2384,11 +2332,11 @@ index 3cb350c2a..bf7f98096 100644
 +    default:
 +	break;
      }
-
+ 
      return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE;
-@@ -2358,14 +2784,103 @@ static void turn_on_rx_data(pj_turn_sock *turn_sock,
+@@ -2358,14 +2756,103 @@ static void turn_on_rx_data(pj_turn_sock *turn_sock,
      } else {
-
+ 
  	/* Hand over the packet to ICE */
 -	status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id,
 -				       data->transport_id, pkt, pkt_len,
@@ -2396,7 +2344,7 @@ index 3cb350c2a..bf7f98096 100644
 +	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",
@@ -2496,7 +2444,7 @@ index 3cb350c2a..bf7f98096 100644
 +			      status);
  	}
      }
-
+ 
 diff --git a/pjnath/src/pjnath/nat_detect.c b/pjnath/src/pjnath/nat_detect.c
 index db0de10bc..808342bec 100644
 --- a/pjnath/src/pjnath/nat_detect.c
@@ -2510,12 +2458,12 @@ index db0de10bc..808342bec 100644
 +				    PJ_STUN_TP_UDP);
      if (status != PJ_SUCCESS)
  	goto on_error;
-
+ 
 @@ -875,7 +876,9 @@ static pj_status_t send_test(nat_detect_session *sess,
-
+ 
      /* Send the request */
      status = pj_stun_session_send_msg(sess->stun_sess, NULL, PJ_TRUE,
--				      PJ_TRUE, sess->cur_server,
+-				      PJ_TRUE, sess->cur_server, 
 +				      (pj_stun_session_tp_type(sess->stun_sess) ==
 +				       PJ_STUN_TP_UDP),
 +				      sess->cur_server,
@@ -2527,13 +2475,13 @@ index f2b4f7058..ed17b904f 100644
 --- a/pjnath/src/pjnath/stun_session.c
 +++ b/pjnath/src/pjnath/stun_session.c
 @@ -49,6 +49,8 @@ struct pj_stun_session
-
+ 
      pj_stun_tx_data	 pending_request_list;
      pj_stun_tx_data	 cached_response_list;
 +
 +    pj_stun_tp_type	 conn_type;
  };
-
+ 
  #define SNAME(s_)		    ((s_)->pool->obj_name)
 @@ -524,7 +526,8 @@ PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg,
  					    const pj_stun_session_cb *cb,
@@ -2550,13 +2498,13 @@ index f2b4f7058..ed17b904f 100644
      sess->use_fingerprint = fingerprint;
      sess->log_flag = 0xFFFF;
 +    sess->conn_type = conn_type;
-
+ 
      if (grp_lock) {
  	sess->grp_lock = grp_lock;
 @@ -1538,3 +1542,12 @@ on_return:
      return status;
  }
-
+ 
 +PJ_DECL(pj_stun_session_cb *) pj_stun_session_callback(pj_stun_session *sess)
 +{
 +    return sess ? &sess->cb : NULL;
@@ -2567,13 +2515,13 @@ index f2b4f7058..ed17b904f 100644
 +    return sess ? sess->conn_type : PJ_STUN_TP_UDP;
 +}
 diff --git a/pjnath/src/pjnath/stun_sock.c b/pjnath/src/pjnath/stun_sock.c
-index 5fe825cf5..c4cd9b224 100644
+index 5fe825cf5..05461676e 100644
 --- a/pjnath/src/pjnath/stun_sock.c
 +++ b/pjnath/src/pjnath/stun_sock.c
 @@ -40,6 +40,36 @@
-
+ 
  enum { MAX_BIND_RETRY = 100 };
-
+ 
 +#if PJ_HAS_TCP
 +// The head of a RTP packet is stored in a 16 bits header, so the max size of a
 +// packet is 65536
@@ -2615,7 +2563,7 @@ index 5fe825cf5..c4cd9b224 100644
 +    pj_stun_sock_cfg	 cfg;
      pj_stun_config	 stun_cfg;	/* STUN config (ioqueue etc)*/
      pj_stun_sock_cb	 cb;		/* Application callbacks    */
-
+ 
 @@ -59,6 +91,13 @@ struct pj_stun_sock
      pj_dns_srv_async_query *q;		/* Pending DNS query	    */
      pj_sock_t		 sock_fd;	/* Socket descriptor	    */
@@ -2633,7 +2581,7 @@ index 5fe825cf5..c4cd9b224 100644
 @@ -68,6 +107,15 @@ struct pj_stun_sock
      pj_grp_lock_t	*grp_lock;	/* Session group lock	    */
  };
-
+ 
 +//////////////////////////////////////////////////////////////////////////////
 +
 +static pj_uint16_t GETVAL16H(const pj_uint8_t *buf1, const pj_uint8_t *buf2)
@@ -2643,13 +2591,13 @@ index 5fe825cf5..c4cd9b224 100644
 +
 +//////////////////////////////////////////////////////////////////////////////
 +
- /*
-  * Prototypes for static functions
+ /* 
+  * Prototypes for static functions 
   */
 @@ -120,6 +168,24 @@ static void start_ka_timer(pj_stun_sock *stun_sock);
  /* Keep-alive timer callback */
  static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te);
-
+ 
 +
 +static pj_bool_t on_stun_sock_ready(pj_activesock_t *asock,
 +				    pj_status_t status);
@@ -2669,12 +2617,12 @@ index 5fe825cf5..c4cd9b224 100644
 +
 +
  #define INTERNAL_MSG_TOKEN  (void*)(pj_ssize_t)1
-
-
+ 
+ 
 @@ -160,12 +226,183 @@ static pj_bool_t pj_stun_sock_cfg_is_valid(const pj_stun_sock_cfg *cfg)
      return cfg->max_pkt_size > 1 && cfg->async_cnt >= 1;
  }
-
+ 
 +/*
 + * Initialize.
 + */
@@ -2863,17 +2811,17 @@ index 5fe825cf5..c4cd9b224 100644
 -    unsigned i;
 -    pj_uint16_t max_bind_retry;
      pj_status_t status;
-
+ 
      PJ_ASSERT_RETURN(stun_cfg && cb && p_stun_sock, PJ_EINVAL);
      PJ_ASSERT_RETURN(af==pj_AF_INET()||af==pj_AF_INET6(), PJ_EAFNOTSUP);
      PJ_ASSERT_RETURN(!cfg || pj_stun_sock_cfg_is_valid(cfg), PJ_EINVAL);
      PJ_ASSERT_RETURN(cb->on_status, PJ_EINVAL);
 +    PJ_ASSERT_RETURN(conn_type != PJ_STUN_TP_TCP || PJ_HAS_TCP, PJ_EINVAL);
-
+ 
      status = pj_stun_config_check_valid(stun_cfg);
      if (status != PJ_SUCCESS)
  	return status;
-
+ 
 -    if (name == NULL)
 -	name = "stuntp%p";
 +    if (name == NULL) {
@@ -2890,7 +2838,7 @@ index 5fe825cf5..c4cd9b224 100644
 +	    break;
 +	}
 +    }
-
+ 
      if (cfg == NULL) {
  	pj_stun_sock_cfg_default(&default_cfg);
 @@ -204,9 +451,16 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
@@ -2907,13 +2855,13 @@ index 5fe825cf5..c4cd9b224 100644
      pj_memcpy(&stun_sock->cb, cb, sizeof(*cb));
 +    /* Copy socket settings; QoS parameters etc */
 +    pj_memcpy(&stun_sock->cfg, cfg, sizeof(*cfg));
-
+ 
      stun_sock->ka_interval = cfg->ka_interval;
      if (stun_sock->ka_interval == 0)
 @@ -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);
-
+ 
 -    /* Create socket and bind socket */
 -    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd);
 -    if (status != PJ_SUCCESS)
@@ -2928,7 +2876,7 @@ index 5fe825cf5..c4cd9b224 100644
 +    /* 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;
@@ -2939,7 +2887,7 @@ index 5fe825cf5..c4cd9b224 100644
 -			  "Failed setting SO_RCVBUF"));
 -	} else {
 -	    if (sobuf_size < cfg->so_rcvbuf_size) {
--		PJ_LOG(4, (stun_sock->obj_name,
+-		PJ_LOG(4, (stun_sock->obj_name, 
 -			   "Warning! Cannot set SO_RCVBUF as configured, "
 -			   "now=%d, configured=%d",
 -			   sobuf_size, cfg->so_rcvbuf_size));
@@ -2967,7 +2915,7 @@ index 5fe825cf5..c4cd9b224 100644
 -			  "Failed setting SO_SNDBUF"));
 -	} else {
 -	    if (sobuf_size < cfg->so_sndbuf_size) {
--		PJ_LOG(4, (stun_sock->obj_name,
+-		PJ_LOG(4, (stun_sock->obj_name, 
 -			   "Warning! Cannot set SO_SNDBUF as configured, "
 -			   "now=%d, configured=%d",
 -			   sobuf_size, cfg->so_sndbuf_size));
@@ -2979,13 +2927,13 @@ index 5fe825cf5..c4cd9b224 100644
 +	    return status;
  	}
      }
-
+ 
 -    /* Bind socket */
 -    max_bind_retry = MAX_BIND_RETRY;
 -    if (cfg->port_range && cfg->port_range < max_bind_retry)
 -	max_bind_retry = cfg->port_range;
 -    pj_sockaddr_init(af, &bound_addr, NULL, 0);
--    if (cfg->bound_addr.addr.sa_family == pj_AF_INET() ||
+-    if (cfg->bound_addr.addr.sa_family == pj_AF_INET() || 
 -	cfg->bound_addr.addr.sa_family == pj_AF_INET6())
 -    {
 -	pj_sockaddr_cp(&bound_addr, &cfg->bound_addr);
@@ -2995,7 +2943,7 @@ index 5fe825cf5..c4cd9b224 100644
 -    if (status != PJ_SUCCESS)
 -	goto on_error;
 +    pj_stun_sock_alloc(stun_sock);
-
+ 
 -    /* Create more useful information string about this transport */
 -#if 0
 -    {
@@ -3005,8 +2953,8 @@ index 5fe825cf5..c4cd9b224 100644
 +    *p_stun_sock = stun_sock;
 +    return PJ_SUCCESS;
 +}
-
--	status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr,
+ 
+-	status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr, 
 -				     &addr_len);
 -	if (status != PJ_SUCCESS)
 -	    goto on_error;
@@ -3021,9 +2969,9 @@ index 5fe825cf5..c4cd9b224 100644
 +	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_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).
@@ -3034,7 +2982,7 @@ index 5fe825cf5..c4cd9b224 100644
 +	return PJ_FALSE;
      }
 -#endif
-
+ 
 -    /* Init active socket configuration */
 -    {
 -	pj_activesock_cfg activesock_cfg;
@@ -3049,8 +2997,8 @@ index 5fe825cf5..c4cd9b224 100644
 -	pj_bzero(&activesock_cb, sizeof(activesock_cb));
 -	activesock_cb.on_data_recvfrom = &on_data_recvfrom;
 -	activesock_cb.on_data_sent = &on_data_sent;
--	status = pj_activesock_create(pool, stun_sock->sock_fd,
--				      pj_SOCK_DGRAM(),
+-	status = pj_activesock_create(pool, stun_sock->sock_fd, 
+-				      pj_SOCK_DGRAM(), 
 -				      &activesock_cfg, stun_cfg->ioqueue,
 -				      &activesock_cb, stun_sock,
 -				      &stun_sock->active_sock);
@@ -3064,7 +3012,7 @@ index 5fe825cf5..c4cd9b224 100644
 -	    goto on_error;
 -
 -	/* Init send keys */
--	pj_ioqueue_op_key_init(&stun_sock->send_key,
+-	pj_ioqueue_op_key_init(&stun_sock->send_key, 
 -			       sizeof(stun_sock->send_key));
 -	pj_ioqueue_op_key_init(&stun_sock->int_send_key,
 -			       sizeof(stun_sock->int_send_key));
@@ -3073,19 +3021,19 @@ index 5fe825cf5..c4cd9b224 100644
 +	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,
+-	status = pj_stun_session_create(&stun_sock->stun_cfg, 
 -					stun_sock->obj_name,
--					&sess_cb, PJ_FALSE,
+-					&sess_cb, PJ_FALSE, 
 -					stun_sock->grp_lock,
 -					&stun_sock->stun_sess);
 -	if (status != PJ_SUCCESS)
@@ -3097,7 +3045,7 @@ index 5fe825cf5..c4cd9b224 100644
 +					  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,25 +551,305 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
@@ -3109,12 +3057,12 @@ index 5fe825cf5..c4cd9b224 100644
  	stun_sock->tsx_id[i] = (pj_uint16_t) pj_rand();
      }
      stun_sock->tsx_id[5] = 0;
-
+ 
 -
      /* Init timer entry */
      stun_sock->ka_timer.cb = &ka_timer_cb;
      stun_sock->ka_timer.user_data = stun_sock;
-
+ 
 -    /* Done */
 -    *p_stun_sock = stun_sock;
 -    return PJ_SUCCESS;
@@ -3123,7 +3071,7 @@ index 5fe825cf5..c4cd9b224 100644
 +	pj_grp_lock_release(stun_sock->grp_lock);
 +	return status;
 +    }
-
+ 
 -on_error:
 -    pj_stun_sock_destroy(stun_sock);
 -    return status;
@@ -3135,7 +3083,7 @@ index 5fe825cf5..c4cd9b224 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,
@@ -3416,7 +3364,7 @@ index 5fe825cf5..c4cd9b224 100644
 @@ -526,6 +988,26 @@ PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock)
  	stun_sock->sock_fd = PJ_INVALID_SOCKET;
      }
-
+ 
 +    for (int i = 0; i < stun_sock->incoming_nb ; ++i) {
 +	if (stun_sock->incoming_socks[i].sock != NULL) {
 +	    stun_sock->incoming_socks[i].fd = PJ_INVALID_SOCKET;
@@ -3441,7 +3389,7 @@ index 5fe825cf5..c4cd9b224 100644
  	pj_stun_session_destroy(stun_sock->stun_sess);
      }
 @@ -634,10 +1116,12 @@ static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock)
-
+     
      /* Send request */
      status=pj_stun_session_send_msg(stun_sock->stun_sess, INTERNAL_MSG_TOKEN,
 -				    PJ_FALSE, PJ_TRUE, &stun_sock->srv_addr,
@@ -3453,12 +3401,12 @@ index 5fe825cf5..c4cd9b224 100644
 -    if (status != PJ_SUCCESS)
 +    if (status != PJ_SUCCESS && status != PJ_EPENDING)
  	goto on_error;
-
+ 
      return PJ_SUCCESS;
 @@ -658,6 +1142,8 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock,
-
+ 
      pj_grp_lock_acquire(stun_sock->grp_lock);
-
+ 
 +    info->conn_type = stun_sock->conn_type;
 +
      /* Copy STUN server address and mapped address */
@@ -3466,7 +3414,7 @@ index 5fe825cf5..c4cd9b224 100644
  	      sizeof(pj_sockaddr));
 @@ -770,13 +1256,241 @@ PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock,
  	send_key = &stun_sock->send_key;
-
+ 
      size = pkt_len;
 -    status = pj_activesock_sendto(stun_sock->active_sock, send_key,
 -                                  pkt, &size, flag, dst_addr, addr_len);
@@ -3615,11 +3563,11 @@ index 5fe825cf5..c4cd9b224 100644
 +            return status;
 +        }
 +    }
-
+ 
      pj_grp_lock_release(stun_sock->grp_lock);
      return status;
  }
-
+ 
 +PJ_DECL(pj_status_t) pj_stun_sock_connect_active(pj_stun_sock *stun_sock,
 +						 const pj_sockaddr_t *remote_addr,
 +						 int af)
@@ -3713,12 +3661,12 @@ index 5fe825cf5..c4cd9b224 100644
      pj_stun_sock *stun_sock;
      pj_ssize_t size;
 +    pj_status_t status;
-
+ 
      stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess);
      if (!stun_sock || !stun_sock->active_sock) {
 @@ -800,9 +1515,29 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess,
      PJ_UNUSED_ARG(token);
-
+ 
      size = pkt_size;
 -    return pj_activesock_sendto(stun_sock->active_sock,
 -				&stun_sock->int_send_key,
@@ -3747,25 +3695,25 @@ index 5fe825cf5..c4cd9b224 100644
 +#endif
 +    return status;
  }
-
- /* This callback is called by the STUN session when outgoing transaction
+ 
+ /* This callback is called by the STUN session when outgoing transaction 
 @@ -942,8 +1677,6 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
  				  pj_status_t status)
  {
      pj_stun_sock *stun_sock;
 -    pj_stun_msg_hdr *hdr;
 -    pj_uint16_t type;
-
+ 
      stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock);
      if (!stun_sock)
 @@ -955,58 +1688,7 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
  	return PJ_TRUE;
      }
-
+ 
 -    pj_grp_lock_acquire(stun_sock->grp_lock);
 -
 -    /* Check that this is STUN message */
--    status = pj_stun_msg_check((const pj_uint8_t*)data, size,
+-    status = pj_stun_msg_check((const pj_uint8_t*)data, size, 
 -    			       PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET);
 -    if (status != PJ_SUCCESS) {
 -	/* Not STUN -- give it to application */
@@ -3787,7 +3735,7 @@ index 5fe825cf5..c4cd9b224 100644
 -     */
 -    if (!PJ_STUN_IS_RESPONSE(type) ||
 -	PJ_STUN_GET_METHOD(type) != PJ_STUN_BINDING_METHOD ||
--	pj_memcmp(hdr->tsx_id, stun_sock->tsx_id, 10) != 0)
+-	pj_memcmp(hdr->tsx_id, stun_sock->tsx_id, 10) != 0) 
 -    {
 -	/* Not STUN Binding response, or STUN transaction ID mismatch.
 -	 * This is not our message too -- give it to application.
@@ -3816,12 +3764,12 @@ index 5fe825cf5..c4cd9b224 100644
 -    return status!=PJ_EGONE ? PJ_TRUE : PJ_FALSE;
 +    return parse_rx_packet(asock, data, size, src_addr, addr_len);
  }
-
+ 
  /* Callback from active socket about send status */
 @@ -1047,3 +1729,8 @@ static pj_bool_t on_data_sent(pj_activesock_t *asock,
      return PJ_TRUE;
  }
-
+ 
 +pj_stun_session* pj_stun_sock_get_session(pj_stun_sock *stun_sock)
 +{
 +    return stun_sock ? stun_sock->stun_sess : NULL;
@@ -3861,7 +3809,7 @@ index dc6304d9f..a6e192e9f 100644
 +++ b/pjnath/src/pjnath/turn_sock.c
 @@ -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;
 -
@@ -3871,7 +3819,7 @@ index dc6304d9f..a6e192e9f 100644
 -	(*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);
@@ -3899,9 +3847,9 @@ index 6f9f1ff1a..e56c510c8 100644
 --- a/pjnath/src/pjturn-client/client_main.c
 +++ b/pjnath/src/pjturn-client/client_main.c
 @@ -155,7 +155,7 @@ static int init()
-
+ 
  	name[strlen(name)-1] = '0'+i;
- 	status = pj_stun_sock_create(&g.stun_config, name, pj_AF_INET(),
+ 	status = pj_stun_sock_create(&g.stun_config, name, pj_AF_INET(), 
 -				     &stun_sock_cb, &ss_cfg,
 +				     PJ_STUN_TP_UDP, &stun_sock_cb, &ss_cfg,
  				     &g.peer[i], &g.peer[i].stun_sock);
@@ -3926,7 +3874,7 @@ index 94dda29a3..95ad1793d 100644
 --- a/pjnath/src/pjturn-srv/server.c
 +++ b/pjnath/src/pjturn-srv/server.c
 @@ -156,7 +156,7 @@ PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf,
-
+ 
      status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name,
  				    &sess_cb, PJ_FALSE, NULL,
 -				    &srv->core.stun_sess);
@@ -3949,7 +3897,7 @@ index 07ccc31f0..3b93b9417 100644
 @@ -341,6 +342,12 @@ static pj_status_t icedemo_init(void)
      else
  	icedemo.ice_cfg.opt.aggressive = PJ_TRUE;
-
+ 
 +    /* Connection type to STUN server */
 +    if (icedemo.opt.ice_tcp)
 +	icedemo.ice_cfg.stun.conn_type = PJ_STUN_TP_TCP;
@@ -3961,7 +3909,7 @@ index 07ccc31f0..3b93b9417 100644
  	char *pos;
 @@ -384,7 +391,7 @@ static pj_status_t icedemo_init(void)
  	icedemo.ice_cfg.turn.auth_cred.data.static_cred.data = icedemo.opt.turn_password;
-
+ 
  	/* Connection type to TURN server */
 -	if (icedemo.opt.turn_tcp)
 +	if (icedemo.opt.ice_tcp)
@@ -3971,7 +3919,7 @@ index 07ccc31f0..3b93b9417 100644
 @@ -395,6 +402,10 @@ static pj_status_t icedemo_init(void)
  	icedemo.ice_cfg.turn.alloc_param.ka_interval = KA_INTERVAL;
      }
-
+ 
 +    if (icedemo.opt.ice_tcp) {
 +	icedemo.ice_cfg.protocol = PJ_ICE_TP_TCP;
 +    }
@@ -3982,7 +3930,7 @@ index 07ccc31f0..3b93b9417 100644
 @@ -530,10 +541,27 @@ static int print_cand(char buffer[], unsigned maxlen,
      char *p = buffer;
      int printed;
-
+ 
 -    PRINT("a=candidate:%.*s %u UDP %u %s %u typ ",
 +    /**   Section 4.5, RFC 6544 (https://tools.ietf.org/html/rfc6544)
 +     *    candidate-attribute   = "candidate" ":" foundation SP component-id SP
@@ -4006,12 +3954,12 @@ index 07ccc31f0..3b93b9417 100644
  	  (unsigned)cand->comp_id,
 +	  cand->transport == PJ_CAND_UDP? "UDP" : "TCP",
  	  cand->prio,
- 	  pj_sockaddr_print(&cand->addr, ipaddr,
+ 	  pj_sockaddr_print(&cand->addr, ipaddr, 
  			    sizeof(ipaddr), 0),
 @@ -542,6 +570,23 @@ static int print_cand(char buffer[], unsigned maxlen,
      PRINT("%s\n",
  	  pj_ice_get_cand_type_name(cand->type));
-
+ 
 +    if (cand->transport != PJ_CAND_UDP) {
 +	PRINT(" tcptype");
 +	switch (cand->transport) {
@@ -4031,11 +3979,11 @@ index 07ccc31f0..3b93b9417 100644
 +
      if (p == buffer+maxlen)
  	return -PJ_ETOOSMALL;
-
+ 
 @@ -608,6 +653,26 @@ static int encode_session(char buffer[], unsigned maxlen)
  				    sizeof(ipaddr), 0));
  	}
-
+ 
 +	if (cand[0].transport != PJ_CAND_UDP) {
 +	    /** RFC 6544, Section 4.5:
 +	     * If the default candidate is TCP-based, the agent MUST include the
@@ -4070,7 +4018,7 @@ index 07ccc31f0..3b93b9417 100644
      char     comp0_addr[80];
 @@ -819,27 +884,43 @@ static void icedemo_input_remote(void)
  		    pj_sockaddr_set_port(&icedemo.rem.def_addr[1], (pj_uint16_t)port);
-
+ 
  		} else if (strcmp(attr, "candidate")==0) {
 +		    /**   Section 4.5, RFC 6544 (https://tools.ietf.org/html/rfc6544)
 +		     *    candidate-attribute   = "candidate" ":" foundation SP component-id
@@ -4091,7 +4039,7 @@ index 07ccc31f0..3b93b9417 100644
  		    pj_ice_sess_cand *cand;
  		    pj_status_t status;
 +		    pj_bool_t is_tcp = PJ_FALSE;
-
+ 
 -		    cnt = sscanf(sdpcand, "%s %d %s %d %s %d typ %s",
 +		    cnt = sscanf(sdpcand, "%s %d %s %d %s %d typ %s tcptype %s\n",
  				 foundation,
@@ -4108,18 +4056,18 @@ index 07ccc31f0..3b93b9417 100644
  			PJ_LOG(1, (THIS_FILE, "error: Invalid ICE candidate line"));
  			goto on_error;
  		    }
-
+ 
 +		    if (strcmp(transport, "TCP") == 0) {
 +			is_tcp = PJ_TRUE;
 +		    }
 +
  		    cand = &icedemo.rem.cand[icedemo.rem.cand_cnt];
  		    pj_bzero(cand, sizeof(*cand));
-
+ 		    
 @@ -855,6 +936,23 @@ static void icedemo_input_remote(void)
  			goto on_error;
  		    }
-
+ 
 +		    if (is_tcp) {
 +			if (strcmp(tcp_type, "active") == 0)
 +			    cand->transport = PJ_CAND_TCP_ACTIVE;
@@ -4141,7 +4089,7 @@ index 07ccc31f0..3b93b9417 100644
  		    pj_strdup2(icedemo.pool, &cand->foundation, foundation);
  		    cand->prio = prio;
 @@ -879,6 +977,10 @@ static void icedemo_input_remote(void)
-
+ 
  		    if (cand->comp_id > icedemo.rem.comp_cnt)
  			icedemo.rem.comp_cnt = cand->comp_id;
 +		} else if (strcmp(attr, "setup") == 0) {
@@ -4164,5 +4112,6 @@ index 474a8d07c..9257f07a4 100644
  				     NULL, sess, &sess->stun_sock);
  	if (status != PJ_SUCCESS) {
  	    char errmsg[PJ_ERR_MSG_SIZE];
---
-2.26.2
+-- 
+2.25.4
+
diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp
index 732df49978e24a8deb0ad580ba865b22265c6a96..d12c3cb53e4d265c77f90728d95cfb8d176061fd 100644
--- a/src/ice_transport.cpp
+++ b/src/ice_transport.cpp
@@ -530,6 +530,7 @@ IceTransport::Impl::onComplete(pj_ice_strans* ice_st, pj_ice_strans_op op, pj_st
         JAMI_ERR("[ice:%p] %s %s failed: %s", this, (config_.protocol == PJ_ICE_TP_TCP? "TCP" : "UDP"), opname, last_errmsg_.c_str());
     }
 
+
     {
         std::lock_guard<std::mutex> lk(iceMutex_);
         if (!icest_.get())