diff --git a/contrib/src/pjproject/fetch_and_patch.bat b/contrib/src/pjproject/fetch_and_patch.bat index 5cb61f566533a237f3befcb7a531d02eb8130260..febc0ce91c5ddb11e200453655903bff8dadf88a 100644 --- a/contrib/src/pjproject/fetch_and_patch.bat +++ b/contrib/src/pjproject/fetch_and_patch.bat @@ -35,6 +35,7 @@ bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_ioqueue_ipv6_sendto.patch" bash -c "%PATCH_CMD% %UNIXPATH%pjproject/add_dtls_transport.patch" bash -c "%PATCH_CMD% %UNIXPATH%pjproject/rfc6544.patch" bash -c "%PATCH_CMD% %UNIXPATH%pjproject/ice_config.patch" +bash -c "%PATCH_CMD% %UNIXPATH%pjproject/win32_ice_tcp_temp_fix.patch" %APPLY_CMD% %SRC%\pjproject\win32_vs_gnutls.patch %APPLY_CMD% %SRC%\pjproject\win_config.patch diff --git a/contrib/src/pjproject/rfc6544.patch b/contrib/src/pjproject/rfc6544.patch index cad0f947a7dc10012ea9c85b4a1c18626df27e94..d12dfb8921acaa91a9b8ed4d64514f5729ad58dc 100644 --- a/contrib/src/pjproject/rfc6544.patch +++ b/contrib/src/pjproject/rfc6544.patch @@ -17,29 +17,28 @@ on behalf of Savoir-faire Linux. --- pjnath/include/pjnath/config.h | 13 +- - pjnath/include/pjnath/ice_session.h | 166 ++- - pjnath/include/pjnath/ice_strans.h | 61 +- - pjnath/include/pjnath/stun_session.h | 82 +- - pjnath/include/pjnath/stun_sock.h | 93 +- + pjnath/include/pjnath/ice_session.h | 118 ++++++++++++++--- + pjnath/include/pjnath/ice_strans.h | 61 ++++++++- + pjnath/include/pjnath/stun_session.h | 66 ++++++++- + pjnath/include/pjnath/stun_sock.h | 84 +++++++++--- pjnath/src/pjnath-test/concur_test.c | 8 +- pjnath/src/pjnath-test/sess_auth.c | 12 +- pjnath/src/pjnath-test/stun_sock_test.c | 7 +- - pjnath/src/pjnath/ice_session.c | 535 +++++++-- - pjnath/src/pjnath/ice_strans.c | 958 ++++++++++++----- + pjnath/src/pjnath/ice_session.c | 388 +++++++++++++++++++++++++++++++++++++---------------- + pjnath/src/pjnath/ice_strans.c | 741 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- pjnath/src/pjnath/nat_detect.c | 12 +- pjnath/src/pjnath/stun_session.c | 12 +- - pjnath/src/pjnath/stun_sock.c | 1313 ++++++++++++++++------- - pjnath/src/pjnath/stun_transaction.c | 1 + + pjnath/src/pjnath/stun_sock.c | 1285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------- pjnath/src/pjnath/turn_session.c | 3 +- pjnath/src/pjturn-client/client_main.c | 11 +- pjnath/src/pjturn-srv/allocation.c | 2 +- pjnath/src/pjturn-srv/server.c | 2 +- - pjsip-apps/src/samples/icedemo.c | 671 +++++++----- + pjsip-apps/src/samples/icedemo.c | 671 +++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------- pjsip/src/pjsua-lib/pjsua_core.c | 8 +- - 20 files changed, 2877 insertions(+), 1093 deletions(-) + 19 files changed, 2424 insertions(+), 1080 deletions(-) diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h -index fc1e27550..6f17a663b 100644 +index fc1e2755..6f17a663 100644 --- a/pjnath/include/pjnath/config.h +++ b/pjnath/include/pjnath/config.h @@ -1,5 +1,5 @@ @@ -85,7 +84,7 @@ index fc1e27550..6f17a663b 100644 diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h -index fa13a3b7c..9644836d0 100644 +index fa13a3b7..2e686ea1 100644 --- a/pjnath/include/pjnath/ice_session.h +++ b/pjnath/include/pjnath/ice_session.h @@ -163,6 +163,51 @@ typedef enum pj_ice_cand_type @@ -152,30 +151,7 @@ index fa13a3b7c..9644836d0 100644 } pj_ice_sess_cand; -@@ -324,6 +374,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 -+ * us to connect yet. The socket will be reconnected during the next -+ * loop. -+ */ -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY, -+ -+ /** -+ * TODO (sblin): REMOVE THIS! - https://github.com/coturn/coturn/issues/408 -+ * For now, this status is only used because sometimes, the first packet -+ * doesn't receive any response. So, we retry to send the packet every -+ * 50 loops. -+ */ -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, -+ - /** - * A check has not been performed for this pair, and can be - * performed as soon as it is the highest priority Waiting pair on -@@ -331,6 +397,13 @@ typedef enum pj_ice_sess_check_state +@@ -331,6 +381,13 @@ typedef enum pj_ice_sess_check_state */ PJ_ICE_SESS_CHECK_STATE_WAITING, @@ -189,7 +165,7 @@ index fa13a3b7c..9644836d0 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 -@@ -512,6 +585,41 @@ typedef struct pj_ice_sess_cb +@@ -512,6 +569,29 @@ typedef struct pj_ice_sess_cb void *pkt, pj_size_t size, const pj_sockaddr_t *src_addr, unsigned src_addr_len); @@ -206,18 +182,6 @@ index fa13a3b7c..9644836d0 100644 + unsigned check_id); + + /** -+ * Reconnect a resetted TCP connection and send connectivity check -+ * cf. PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY -+ * -+ * @param ice The ICE session. -+ * @param clist The ICE connection list -+ * @param check_id The wanted check. -+ */ -+ pj_status_t (*reconnect_tcp_connection)(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id); -+ -+ /** + * Close TCP socket + * + * @param ice The ICE session. @@ -231,7 +195,7 @@ index fa13a3b7c..9644836d0 100644 } pj_ice_sess_cb; -@@ -627,6 +735,7 @@ struct pj_ice_sess +@@ -627,6 +707,7 @@ struct pj_ice_sess pj_bool_t is_destroying; /**< Destroy is called */ pj_status_t ice_status; /**< Error status. */ pj_timer_entry timer; /**< ICE timer. */ @@ -239,7 +203,7 @@ index fa13a3b7c..9644836d0 100644 pj_ice_sess_cb cb; /**< Callback. */ pj_stun_config stun_cfg; /**< STUN settings. */ -@@ -669,6 +778,7 @@ struct pj_ice_sess +@@ -669,6 +750,7 @@ struct pj_ice_sess char txt[128]; char errmsg[PJ_ERR_MSG_SIZE]; } tmp; @@ -247,7 +211,7 @@ index fa13a3b7c..9644836d0 100644 }; -@@ -826,8 +936,6 @@ PJ_DECL(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice, +@@ -826,8 +908,6 @@ PJ_DECL(pj_status_t) pj_ice_sess_change_role(pj_ice_sess *ice, PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice, const pj_uint8_t prefs[4]); @@ -256,7 +220,7 @@ index fa13a3b7c..9644836d0 100644 /** * Add a candidate to this ICE session. Application must add candidates for * each components ID before it can start pairing the candidates and -@@ -846,20 +954,17 @@ PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice, +@@ -846,20 +926,17 @@ 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. @@ -285,10 +249,12 @@ index fa13a3b7c..9644836d0 100644 /** * Find default candidate for the specified component ID, using this -@@ -968,7 +1073,42 @@ PJ_DECL(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice, +@@ -968,8 +1045,19 @@ 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 + * @@ -302,34 +268,11 @@ index fa13a3b7c..9644836d0 100644 +PJ_DECL(void) +ice_sess_on_peer_connection(pj_ice_sess *ice, + pj_uint8_t transport_id, pj_status_t status, pj_sockaddr_t* remote_addr); - -+/** -+ * Notification when ICE session get a new resetted connection -+ * cf PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY -+ * -+ * @param ice The ICE session. -+ * @param transport_id Related transport -+ * @param remote_addr Connected remove address -+ */ -+PJ_DECL(void) -+ice_sess_on_peer_reset_connection(pj_ice_sess *ice, -+ pj_uint8_t transport_id, pj_sockaddr_t* remote_addr); -+ -+/** -+ * Notification when ICE session get a new packet -+ * Used to remove the PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET status -+ * -+ * @param ice The ICE session. -+ * @param transport_id Related transport -+ * @param remote_addr Connected remove address -+ */ -+PJ_DECL(void) -+ice_sess_on_peer_packet(pj_ice_sess *ice, pj_uint8_t transport_id, pj_sockaddr_t* remote_addr); - /** * @} + */ diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h -index b4a83067f..2b491e0d0 100644 +index b4a83067..2b491e0d 100644 --- a/pjnath/include/pjnath/ice_strans.h +++ b/pjnath/include/pjnath/ice_strans.h @@ -1,5 +1,5 @@ @@ -434,7 +377,7 @@ index b4a83067f..2b491e0d0 100644 /** * @} diff --git a/pjnath/include/pjnath/stun_session.h b/pjnath/include/pjnath/stun_session.h -index f8ea4d1dc..3d42af5a2 100644 +index f8ea4d1d..1e95a297 100644 --- a/pjnath/include/pjnath/stun_session.h +++ b/pjnath/include/pjnath/stun_session.h @@ -1,5 +1,5 @@ @@ -474,7 +417,7 @@ index f8ea4d1dc..3d42af5a2 100644 /** * This is the callback to be registered to pj_stun_session, to send -@@ -307,6 +330,33 @@ typedef struct pj_stun_session_cb +@@ -307,6 +330,17 @@ typedef struct pj_stun_session_cb const pj_sockaddr_t *src_addr, unsigned src_addr_len); @@ -488,27 +431,11 @@ index f8ea4d1dc..3d42af5a2 100644 + * @param remote_addr The remote connected + */ + void (*on_peer_connection)(pj_stun_session *sess, pj_status_t status, pj_sockaddr_t* remote_addr); -+ -+ /** -+ * Notification when STUN connection is resetted (TCP only). -+ * -+ * @param stun_session The STUN session. -+ * @param remote_addr The remote resetted -+ */ -+ void (*on_peer_reset_connection)(pj_stun_session *sess, pj_sockaddr_t* remote_addr); -+ -+ /** -+ * Notification when STUN connection is resetted (TCP only). -+ * -+ * @param stun_session The STUN session. -+ * @param remote_addr The remote resetted -+ */ -+ void (*on_peer_packet)(pj_stun_session *sess, pj_sockaddr_t* remote_addr); + } pj_stun_session_cb; -@@ -388,15 +438,15 @@ typedef enum pj_stun_sess_msg_log_flag +@@ -388,15 +422,15 @@ 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. * @param p_sess Pointer to receive STUN session instance. @@ -530,7 +457,7 @@ index f8ea4d1dc..3d42af5a2 100644 /** * Destroy the STUN session and all objects created in the context of -@@ -751,6 +801,24 @@ PJ_DECL(void) pj_stun_msg_destroy_tdata(pj_stun_session *sess, +@@ -751,6 +785,24 @@ PJ_DECL(void) pj_stun_msg_destroy_tdata(pj_stun_session *sess, pj_stun_tx_data *tdata); @@ -556,7 +483,7 @@ index f8ea4d1dc..3d42af5a2 100644 * @} */ diff --git a/pjnath/include/pjnath/stun_sock.h b/pjnath/include/pjnath/stun_sock.h -index fff4df885..05a61bb11 100644 +index fff4df88..d70300bb 100644 --- a/pjnath/include/pjnath/stun_sock.h +++ b/pjnath/include/pjnath/stun_sock.h @@ -1,5 +1,5 @@ @@ -682,7 +609,7 @@ index fff4df885..05a61bb11 100644 * * @return PJ_SUCCESS if data has been sent immediately, or * PJ_EPENDING if data cannot be sent immediately. In -@@ -483,7 +502,45 @@ PJ_DECL(pj_status_t) pj_stun_sock_sendto(pj_stun_sock *stun_sock, +@@ -483,7 +502,36 @@ PJ_DECL(pj_status_t) pj_stun_sock_sendto(pj_stun_sock *stun_sock, unsigned pkt_len, unsigned flag, const pj_sockaddr_t *dst_addr, @@ -702,15 +629,6 @@ index fff4df885..05a61bb11 100644 +pj_stun_sock_connect_active(pj_stun_sock *stun_sock, const pj_sockaddr_t *remote_addr, int af); + +/** -+ * Connect active socket to remote address -+ * @param stun_sock -+ * @param remote_addr the destination -+ * @param af address family -+ */ -+PJ_DECL(pj_status_t) -+pj_stun_sock_reconnect_active(pj_stun_sock *stun_sock, const pj_sockaddr_t *remote_addr, int af); -+ -+/** + * Close active socket + * @param stun_sock + * @param remote_addr The remote address linked @@ -730,7 +648,7 @@ index fff4df885..05a61bb11 100644 /** * @} diff --git a/pjnath/src/pjnath-test/concur_test.c b/pjnath/src/pjnath-test/concur_test.c -index c3013d2ab..ebe173922 100644 +index c3013d2a..ebe17392 100644 --- a/pjnath/src/pjnath-test/concur_test.c +++ b/pjnath/src/pjnath-test/concur_test.c @@ -183,10 +183,10 @@ static int stun_destroy_test_session(struct stun_test_session *test_sess) @@ -749,7 +667,7 @@ index c3013d2ab..ebe173922 100644 return -10; } diff --git a/pjnath/src/pjnath-test/sess_auth.c b/pjnath/src/pjnath-test/sess_auth.c -index 055eaad61..d1ad137a3 100644 +index 055eaad6..d1ad137a 100644 --- a/pjnath/src/pjnath-test/sess_auth.c +++ b/pjnath/src/pjnath-test/sess_auth.c @@ -248,7 +248,8 @@ static int create_std_server(pj_stun_auth_type auth_type, @@ -786,7 +704,7 @@ index 055eaad61..d1ad137a3 100644 destroy_client_server(); return -270; diff --git a/pjnath/src/pjnath-test/stun_sock_test.c b/pjnath/src/pjnath-test/stun_sock_test.c -index fff4fad26..a54df74dc 100644 +index fff4fad2..a54df74d 100644 --- a/pjnath/src/pjnath-test/stun_sock_test.c +++ b/pjnath/src/pjnath-test/stun_sock_test.c @@ -255,8 +255,8 @@ static pj_status_t create_client(pj_stun_config *cfg, @@ -813,7 +731,7 @@ index fff4fad26..a54df74dc 100644 app_perror(" error: server sending data", status); ret = -390; diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c -index c51dba771..52fa05e3e 100644 +index c51dba77..b9639061 100644 --- a/pjnath/src/pjnath/ice_session.c +++ b/pjnath/src/pjnath/ice_session.c @@ -1,5 +1,5 @@ @@ -823,18 +741,15 @@ index c51dba771..52fa05e3e 100644 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> * -@@ -44,7 +44,10 @@ static const char *cand_type_names[] = - static const char *check_state_name[] = +@@ -45,6 +45,7 @@ static const char *check_state_name[] = { "Frozen", -+ "Needs Retry", -+ "Needs First Packet", "Waiting", + "Pending", "In Progress", "Succeeded", "Failed" -@@ -75,8 +78,8 @@ enum timer_type +@@ -75,8 +76,8 @@ enum timer_type valid check for every components. */ TIMER_START_NOMINATED_CHECK,/**< Controlling agent start connectivity checks with USE-CANDIDATE flag. */ @@ -845,15 +760,7 @@ index c51dba771..52fa05e3e 100644 }; /* Candidate type preference */ -@@ -123,6 +126,7 @@ typedef struct timer_data - { - pj_ice_sess *ice; - pj_ice_sess_checklist *clist; -+ unsigned first_packet_counter; // TODO (remove), for now, needed for the NEEDS_FIRST_PACKET state - } timer_data; - - -@@ -133,6 +137,7 @@ typedef struct timer_data +@@ -133,6 +134,7 @@ typedef struct timer_data /* Forward declarations */ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te); @@ -861,7 +768,7 @@ index c51dba771..52fa05e3e 100644 static void on_ice_complete(pj_ice_sess *ice, pj_status_t status); static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now); static void ice_on_destroy(void *obj); -@@ -288,10 +293,9 @@ static pj_status_t init_comp(pj_ice_sess *ice, +@@ -288,10 +290,9 @@ static pj_status_t init_comp(pj_ice_sess *ice, sess_cb.on_send_msg = &on_stun_send_msg; /* Create STUN session for this candidate */ @@ -875,7 +782,7 @@ index c51dba771..52fa05e3e 100644 if (status != PJ_SUCCESS) return status; -@@ -715,7 +719,8 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, +@@ -715,7 +716,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, @@ -885,7 +792,7 @@ index c51dba771..52fa05e3e 100644 { pj_ice_sess_cand *lcand; pj_status_t status = PJ_SUCCESS; -@@ -738,6 +743,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, +@@ -738,6 +740,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; @@ -893,16 +800,15 @@ index c51dba771..52fa05e3e 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); -@@ -959,6 +965,8 @@ static void check_set_state(pj_ice_sess *ice, pj_ice_sess_check *check, +@@ -959,6 +962,7 @@ 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) { + if (check->state == st) return; // nothing to do -+ if (st == PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET && check->state == PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS) return; pj_assert(check->state < PJ_ICE_SESS_CHECK_STATE_SUCCEEDED); LOG5((ice->obj_name, "Check %s: state changed from %s to %s", -@@ -1079,6 +1087,17 @@ static pj_status_t prune_checklist(pj_ice_sess *ice, +@@ -1079,6 +1083,17 @@ static pj_status_t prune_checklist(pj_ice_sess *ice, return PJNATH_EICENOHOSTCAND; } } @@ -920,7 +826,7 @@ index c51dba771..52fa05e3e 100644 } /* Next remove a pair if its local and remote candidates are identical -@@ -1181,6 +1200,8 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) +@@ -1181,6 +1196,8 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) case TIMER_KEEP_ALIVE: ice_keep_alive(ice, PJ_TRUE); break; @@ -929,7 +835,29 @@ index c51dba771..52fa05e3e 100644 case TIMER_NONE: /* Nothing to do, just to get rid of gcc warning */ break; -@@ -1202,9 +1223,9 @@ static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now) +@@ -1189,6 +1206,21 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) + pj_grp_lock_release(ice->grp_lock); + } + ++static void on_tcp_connect_timeout(pj_ice_sess* ice) { ++ pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, TIMER_NONE); ++ ++ for (int i = 0; i < ice->clist.count; ++i) { ++ pj_ice_sess_check *check = &ice->clist.checks[i]; ++ if (check->state == PJ_ICE_SESS_CHECK_STATE_PENDING) { ++ if (*ice->cb.wait_tcp_connection) { ++ (*ice->cb.close_tcp_connection)(ice, &ice->clist, i); ++ } ++ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, PJ_ECANCELLED); ++ break; ++ } ++ } ++} ++ + /* Send keep-alive */ + static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now) + { +@@ -1202,9 +1234,9 @@ static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now) pj_bool_t saved; pj_status_t status; @@ -942,7 +870,7 @@ index c51dba771..52fa05e3e 100644 /* Create the Binding Indication */ status = pj_stun_session_create_ind(comp->stun_sess, -@@ -1343,7 +1364,6 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice, +@@ -1343,7 +1375,6 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice, check_set_state(ice, c, PJ_ICE_SESS_CHECK_STATE_WAITING, 0); } } @@ -950,43 +878,7 @@ index c51dba771..52fa05e3e 100644 LOG5((ice->obj_name, "Check %d is successful%s", GET_CHECK_ID(&ice->clist, check), (check->nominated ? " and nominated" : ""))); -@@ -1609,6 +1629,35 @@ 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, TIMER_NONE); -+ -+ pj_bool_t first_found = PJ_FALSE, set_timer = PJ_FALSE; -+ -+ for (int i = 0; i < ice->clist.count; ++i) { -+ pj_ice_sess_check *check = &ice->clist.checks[i]; -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_PENDING && !first_found) { -+ if (*ice->cb.wait_tcp_connection) (*ice->cb.close_tcp_connection)(ice, &ice->clist, i); -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, PJ_ECANCELLED); -+ on_check_complete(ice, check); -+ first_found = PJ_TRUE; -+ } else if(check->state == PJ_ICE_SESS_CHECK_STATE_PENDING) { -+ set_timer = PJ_TRUE; -+ break; -+ } -+ } -+ -+ if (set_timer && ice->timer.id == TIMER_NONE) { -+ // Reschedule -+ pj_time_val delay = {0, 0}; -+ delay.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); -+ } -+} -+ - - /* Create checklist by pairing local candidates with remote candidates */ - PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( -@@ -1695,6 +1744,25 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( +@@ -1695,6 +1726,25 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( continue; } @@ -1012,15 +904,7 @@ index c51dba771..52fa05e3e 100644 chk->lcand = lcand; chk->rcand = rcand; -@@ -1739,6 +1807,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; - -@@ -1751,40 +1820,73 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( +@@ -1751,40 +1801,71 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( return PJ_SUCCESS; } @@ -1058,8 +942,6 @@ index c51dba771..52fa05e3e 100644 + &rcand->addr, pj_sockaddr_get_len(&rcand->addr), check->tdata); + if (status != PJ_SUCCESS) { + check->tdata = NULL; -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); -+ on_check_complete(ice, check); + pjnath_perror(ice->obj_name, "Error sending STUN request", status); + pj_log_pop_indent(); + return status; @@ -1112,7 +994,7 @@ index c51dba771..52fa05e3e 100644 /* Attach data to be retrieved later when STUN request transaction * completes and on_stun_request_complete() callback is called. */ -@@ -1796,57 +1898,84 @@ static pj_status_t perform_check(pj_ice_sess *ice, +@@ -1796,57 +1877,72 @@ static pj_status_t perform_check(pj_ice_sess *ice, msg_data->data.req.ckid = check_id; /* Add PRIORITY */ @@ -1170,24 +1052,17 @@ index c51dba771..52fa05e3e 100644 + if (lcand->transport == PJ_CAND_UDP) { + status = send_connectivity_check(ice, clist, check_id, nominate, msg_data); + } else if (lcand->transport == PJ_CAND_TCP_ACTIVE) { -+ -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY) { -+ status = (*ice->cb.reconnect_tcp_connection)(ice, clist, check_id); -+ } else if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET) { -+ status = send_connectivity_check(ice, clist, check_id, nominate, msg_data); ++ pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, TIMER_NONE); ++ status = (*ice->cb.wait_tcp_connection)(ice, clist, check_id); ++ if (ice->timer.id == TIMER_NONE) { ++ pj_time_val delay = {0, 0}; ++ delay.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 { -+ pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, TIMER_NONE); -+ status = (*ice->cb.wait_tcp_connection)(ice, clist, check_id); -+ if (ice->timer.id == TIMER_NONE) { -+ pj_time_val delay = {0, 0}; -+ delay.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 if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY) { -+ pj_assert(!"Not expected any timer active"); -+ } ++ pj_assert(!"Not expected any timer active"); + } } +#else @@ -1213,13 +1088,8 @@ index c51dba771..52fa05e3e 100644 + check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_PENDING, + status); + } else { -+ if (check->rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ // TODO (sblin) remove this - https://github.com/coturn/coturn/issues/408 -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, status); -+ } else { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, -+ PJ_SUCCESS); -+ } ++ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, ++ PJ_SUCCESS); } - check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, @@ -1231,55 +1101,16 @@ index c51dba771..52fa05e3e 100644 } -@@ -1882,44 +2011,101 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, - LOG5((ice->obj_name, "Starting checklist periodic check")); - pj_log_push_indent(); +@@ -1859,7 +1955,7 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, + timer_data *td; + pj_ice_sess *ice; + pj_ice_sess_checklist *clist; +- unsigned i, start_count=0; ++ unsigned i, start_count=0, pending_count=0; + pj_status_t status; -+ /* Send STUN Binding request for check with highest priority on -+ * retry state. -+ */ -+ -+ if (start_count == 0) { -+ for (i = 0; i < clist->count; ++i) { -+ pj_ice_sess_check *check = &clist->checks[i]; -+ // Reconnect closed TURN sockets -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY) { -+ status = perform_check(ice, clist, i, ice->is_nominating); -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -+ status); -+ on_check_complete(ice, check); -+ } -+ ++start_count; -+ break; -+ } -+ } -+ } -+ -+ if (start_count == 0) { -+ // TODO (sblin) remove - https://github.com/coturn/coturn/issues/408 -+ pj_bool_t inc_counter = PJ_TRUE; -+ for (i = 0; i < clist->count; ++i) { -+ pj_ice_sess_check *check = &clist->checks[i]; -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET) { -+ if (inc_counter) { -+ td->first_packet_counter += 1; -+ inc_counter = PJ_FALSE; -+ } -+ if (td->first_packet_counter % 50 == 0) { -+ status = perform_check(ice, clist, i, ice->is_nominating); -+ if (status != PJ_SUCCESS && status != PJ_EPENDING) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, -+ status); -+ on_check_complete(ice, check); -+ } -+ } -+ ++start_count; -+ break; -+ } -+ } -+ } -+ + td = (struct timer_data*) te->user_data; +@@ -1885,41 +1981,41 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, /* Send STUN Binding request for check with highest priority on * Waiting state. */ @@ -1323,7 +1154,12 @@ index c51dba771..52fa05e3e 100644 - PJ_ICE_SESS_CHECK_STATE_FAILED, status); - on_check_complete(ice, check); - } -+ if (start_count == 0) { +- +- ++start_count; +- break; +- } +- } ++ if (start_count == 0 && pending_count == 0) { + for (i = 0; i < clist->count; ++i) { + pj_ice_sess_check *check = &clist->checks[i]; + @@ -1337,26 +1173,10 @@ index c51dba771..52fa05e3e 100644 + break; + } + } -+ } - -- ++start_count; -- break; -- } -- } -+ if (start_count == 0) { -+ // If all sockets are pending, do nothing -+ pj_bool_t inc_counter = PJ_TRUE; -+ for (i = 0; i < clist->count; ++i) { -+ pj_ice_sess_check *check = &clist->checks[i]; -+ if (check->state == PJ_ICE_SESS_CHECK_STATE_PENDING) { -+ ++start_count; -+ break; -+ } -+ } } /* Cannot start check because there's no suitable candidate pair. -@@ -1936,8 +2122,7 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, +@@ -1936,8 +2032,7 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, pj_grp_lock_release(ice->grp_lock); pj_log_pop_indent(); return PJ_SUCCESS; @@ -1366,7 +1186,7 @@ index c51dba771..52fa05e3e 100644 /* Start sending connectivity check with USE-CANDIDATE */ static void start_nominated_check(pj_ice_sess *ice) -@@ -2109,13 +2294,13 @@ PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice) +@@ -2109,13 +2204,13 @@ PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice) /* First, perform all pending triggered checks, simultaneously. */ rcheck = ice->early_check.next; while (rcheck != &ice->early_check) { @@ -1387,7 +1207,7 @@ index c51dba771..52fa05e3e 100644 } pj_list_init(&ice->early_check); -@@ -2161,7 +2346,7 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess, +@@ -2161,7 +2256,7 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess, /* Stray retransmit timer that could happen while * we're being destroyed */ pj_grp_lock_release(ice->grp_lock); @@ -1396,33 +1216,10 @@ index c51dba771..52fa05e3e 100644 } status = (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id, -@@ -2171,6 +2356,136 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess, +@@ -2171,6 +2266,75 @@ 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, int* current_check) -+{ -+ if (!ice || !remote_addr) return NULL; -+ // NOTE: Multiple checks can have the same remote, we only take care of the first -+ // First, check if the TCP is really connected. If not, abort -+ pj_ice_sess_check *check = NULL; -+ for (int i = 0; i < ice->clist.count; ++i) { -+ // Find related check -+ pj_ice_sess_check *c = &ice->clist.checks[i]; -+ /* Host candidate not found this this srflx! */ -+ if (pj_sockaddr_cmp(remote_addr, &c->rcand->addr) == 0) { -+ if (c->tdata == NULL || c->state != state) -+ continue; -+ /* Match */ -+ check = c; -+ if (current_check) *current_check = i; -+ break; -+ } -+ } -+ return check; -+} -+ +void ice_sess_on_peer_connection(pj_ice_sess *ice, pj_uint8_t transport_id, + pj_status_t status, + pj_sockaddr_t* remote_addr) { @@ -1431,15 +1228,27 @@ index c51dba771..52fa05e3e 100644 + // finished + if (!remote_addr) return; + ++ // First, check if the TCP is really connected. If not, abort ++ pj_ice_sess_check *check = NULL; + int current_check = -1; -+ pj_ice_sess_check *check = get_current_check_at_state(ice, remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_PENDING, ¤t_check); -+ if (!check) { -+ // Handle peer reflexive candidates (incoming are still waiting here) -+ check = get_current_check_at_state(ice, remote_addr, PJ_ICE_SESS_CHECK_STATE_WAITING, ¤t_check); -+ if (!check) { -+ return; ++ for (int i = 0; i < ice->clist.count; ++i) { ++ // Find related check ++ pj_ice_sess_check *c = &ice->clist.checks[i]; ++ /* Host candidate not found this this srflx! */ ++ if (pj_sockaddr_cmp(remote_addr, &c->rcand->addr) == 0) { ++ if (c->tdata == NULL) { ++ continue; + } ++ /* Match */ ++ check = c; ++ current_check = i; ++ break; ++ } ++ } ++ ++ // NOTE: Multiple checks can have the same remote, we only take care of the first ++ if (!check) { ++ return; + } + + if (status != PJ_SUCCESS) { @@ -1469,71 +1278,21 @@ index c51dba771..52fa05e3e 100644 + // Note that USERNAME and MESSAGE-INTEGRITY will be added by the + // STUN session. + -+ // Initiate STUN transaction to send the request -+ status_send_msg = pj_stun_session_send_msg( -+ comp->stun_sess, msg_data, PJ_FALSE, PJ_FALSE, &rcand->addr, -+ pj_sockaddr_get_len(&rcand->addr), check->tdata); -+ if (status_send_msg == 120104 /* CONNECTION RESET BY PEER */ -+ && rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ /** -+ * This part of the code is triggered when using ICE over TCP via TURN -+ * In fact, the other peer has to authorize this peer to connect to -+ * the relayed candidate. This is done by set_perm from the other case. -+ * But from this side, we can't know if the peer has authorized us. If it's -+ * not the case, the connection will got a CONNECTION RESET BY PEER status. -+ * In this case, we can try to reconnect a bit after and this until the check -+ * reached its timeout. -+ */ -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY, status); -+ } else if (status_send_msg != PJ_SUCCESS) { -+ check->tdata = NULL; -+ pjnath_perror(ice->obj_name, "Error sending STUN request", status_send_msg); -+ pj_log_pop_indent(); -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); -+ on_check_complete(ice, check); -+ } else if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, status); -+ } else { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, status); -+ } -+} -+ -+void ice_sess_on_peer_reset_connection(pj_ice_sess *ice, pj_uint8_t transport_id, -+ pj_sockaddr_t* remote_addr) { -+ // The TCP link is reseted -+ if (!remote_addr) return; -+ pj_ice_sess_check *check = get_current_check_at_state(ice, remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_PENDING, NULL); -+ if (!check) { -+ // Just check if it's not the first packet failing -+ check = get_current_check_at_state(ice, remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, NULL); -+ if (!check) return; -+ } -+ -+ const pj_ice_sess_cand *rcand = check->rcand; -+ if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_NEEDS_RETRY, 120104); -+ } -+} -+ -+void ice_sess_on_peer_packet(pj_ice_sess *ice, pj_uint8_t transport_id, -+ pj_sockaddr_t* remote_addr) { -+ // The TCP link received its bind request response -+ if (!ice || !remote_addr) return; -+ pj_ice_sess_check *check = get_current_check_at_state(ice, remote_addr, -+ PJ_ICE_SESS_CHECK_STATE_NEEDS_FIRST_PACKET, NULL); -+ if (!check) return; -+ -+ const pj_ice_sess_cand *rcand = check->rcand; -+ if (rcand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, PJ_SUCCESS); -+ } ++ // Initiate STUN transaction to send the request ++ status_send_msg = pj_stun_session_send_msg( ++ comp->stun_sess, msg_data, PJ_FALSE, PJ_FALSE, &rcand->addr, ++ pj_sockaddr_get_len(&rcand->addr), check->tdata); ++ if (status_send_msg != PJ_SUCCESS) { ++ check->tdata = NULL; ++ pjnath_perror(ice->obj_name, "Error sending STUN request", status_send_msg); ++ pj_log_pop_indent(); ++ } ++ check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_IN_PROGRESS, status); +} /* This callback is called when outgoing STUN request completed */ static void on_stun_request_complete(pj_stun_session *stun_sess, -@@ -2401,7 +2716,8 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, +@@ -2401,7 +2565,8 @@ 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), @@ -1543,7 +1302,7 @@ index c51dba771..52fa05e3e 100644 if (status != PJ_SUCCESS) { check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); -@@ -2516,8 +2832,8 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, +@@ -2516,8 +2681,8 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, pj_grp_lock_acquire(ice->grp_lock); if (ice->is_destroying) { @@ -1554,7 +1313,7 @@ index c51dba771..52fa05e3e 100644 } /* -@@ -2532,9 +2848,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, +@@ -2532,9 +2697,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, prio_attr = (pj_stun_priority_attr*) pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0); if (prio_attr == NULL) { @@ -1567,7 +1326,7 @@ index c51dba771..52fa05e3e 100644 } /* Get USE-CANDIDATE attribute */ -@@ -2579,7 +2895,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, +@@ -2579,7 +2744,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, NULL, token, PJ_TRUE, src_addr, src_addr_len); pj_grp_lock_release(ice->grp_lock); @@ -1576,7 +1335,7 @@ index c51dba771..52fa05e3e 100644 } } else if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLED && -@@ -2591,7 +2907,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, +@@ -2591,7 +2756,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, NULL, token, PJ_TRUE, src_addr, src_addr_len); pj_grp_lock_release(ice->grp_lock); @@ -1585,7 +1344,7 @@ index c51dba771..52fa05e3e 100644 } else { /* Switch role to controlled */ LOG4((ice->obj_name, -@@ -2606,7 +2922,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, +@@ -2606,7 +2771,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, status = pj_stun_session_create_res(sess, rdata, 0, NULL, &tdata); if (status != PJ_SUCCESS) { pj_grp_lock_release(ice->grp_lock); @@ -1594,7 +1353,7 @@ index c51dba771..52fa05e3e 100644 } if (((pj_sockaddr *)src_addr)->addr.sa_family == pj_AF_INET6()) { -@@ -2663,9 +2979,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, +@@ -2663,9 +2828,9 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, msg_data->has_req_data = PJ_FALSE; /* Send the response */ @@ -1607,7 +1366,7 @@ index c51dba771..52fa05e3e 100644 /* * Handling early check. -@@ -2839,7 +3155,6 @@ static void handle_incoming_check(pj_ice_sess *ice, +@@ -2839,7 +3004,6 @@ static void handle_incoming_check(pj_ice_sess *ice, * Note: DO NOT overwrite nominated flag if one is already set. */ c->nominated = ((rcheck->use_candidate) || c->nominated); @@ -1616,7 +1375,7 @@ index c51dba771..52fa05e3e 100644 c->state == PJ_ICE_SESS_CHECK_STATE_WAITING) { diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c -index ca15a74e8..ca4cbae56 100644 +index ca15a74e..d5877e31 100644 --- a/pjnath/src/pjnath/ice_strans.c +++ b/pjnath/src/pjnath/ice_strans.c @@ -69,6 +69,7 @@ enum tp_type @@ -1627,7 +1386,7 @@ index ca15a74e8..ca4cbae56 100644 /* The candidate type preference when STUN candidate is used */ static pj_uint8_t srflx_pref_table[PJ_ICE_CAND_TYPE_MAX] = -@@ -102,8 +103,19 @@ static void ice_rx_data(pj_ice_sess *ice, +@@ -102,8 +103,15 @@ static void ice_rx_data(pj_ice_sess *ice, void *pkt, pj_size_t size, const pj_sockaddr_t *src_addr, unsigned src_addr_len); @@ -1638,10 +1397,6 @@ index ca15a74e8..ca4cbae56 100644 + 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); -+ +static pj_status_t ice_close_tcp_connection(pj_ice_sess *ice, + pj_ice_sess_checklist *clist, + unsigned check_id); @@ -1649,24 +1404,7 @@ index ca15a74e8..ca4cbae56 100644 /* STUN socket callbacks */ /* Notification when incoming packet has been received. */ static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock, -@@ -115,6 +127,7 @@ static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock, - static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock, - pj_ioqueue_op_key_t *send_key, - pj_ssize_t sent); -+static pj_bool_t turn_on_data_sent(pj_turn_sock *turn_sock, pj_ssize_t sent); - /* Notification when the status of the STUN transport has changed. */ - static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, - pj_stun_sock_op op, -@@ -130,8 +143,6 @@ static void turn_on_rx_data(pj_turn_sock *turn_sock, - static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, - pj_turn_state_t new_state); - -- -- - /* Forward decls */ - static void ice_st_on_destroy(void *obj); - static void destroy_ice_st(pj_ice_strans *ice_st); -@@ -201,6 +212,14 @@ struct pj_ice_strans +@@ -201,6 +209,10 @@ struct pj_ice_strans pj_bool_t destroy_req;/**< Destroy has been called? */ pj_bool_t cb_called; /**< Init error callback called?*/ @@ -1674,14 +1412,10 @@ index ca15a74e8..ca4cbae56 100644 + pj_bool_t is_pending; + + pj_uint8_t rtp_pkt[MAX_RTP_SIZE]; -+ -+ pj_uint8_t rx_buffer[MAX_RTP_SIZE]; -+ pj_uint16_t rx_buffer_size; -+ pj_uint16_t rx_wanted_size; }; -@@ -237,6 +256,7 @@ PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg) +@@ -237,6 +249,7 @@ PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg) pj_bzero(cfg, sizeof(*cfg)); cfg->af = pj_AF_INET(); @@ -1689,7 +1423,7 @@ index ca15a74e8..ca4cbae56 100644 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); -@@ -252,6 +272,7 @@ PJ_DEF(void) pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg *cfg) +@@ -252,6 +265,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(); @@ -1697,7 +1431,7 @@ index ca15a74e8..ca4cbae56 100644 cfg->port = PJ_STUN_PORT; cfg->max_host_cands = 64; cfg->ignore_stun_error = PJ_FALSE; -@@ -389,6 +410,7 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st, +@@ -389,6 +403,7 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st, cand->local_pref = RELAY_PREF; cand->transport_id = tp_id; cand->comp_id = (pj_uint8_t) comp->comp_id; @@ -1705,18 +1439,7 @@ index ca15a74e8..ca4cbae56 100644 } /* Allocate and initialize TURN socket data */ -@@ -396,6 +418,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; -+ } -+ - /* Create the TURN transport */ - status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, turn_cfg->af, - turn_cfg->conn_type, -@@ -447,6 +473,7 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, +@@ -447,6 +462,7 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, || lcand->transport_id != rcand->transport_id || lcand->local_pref != rcand->local_pref || lcand->prio != rcand->prio @@ -1724,7 +1447,7 @@ index ca15a74e8..ca4cbae56 100644 || pj_sockaddr_cmp(&lcand->addr, &rcand->addr) != 0 || pj_sockaddr_cmp(&lcand->base_addr, &rcand->base_addr) != 0) { -@@ -456,6 +483,115 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, +@@ -456,6 +472,115 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, return PJ_TRUE; } @@ -1840,7 +1563,7 @@ index ca15a74e8..ca4cbae56 100644 static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, pj_ice_strans_comp *comp, -@@ -504,6 +640,7 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, +@@ -504,6 +629,7 @@ 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; @@ -1848,7 +1571,7 @@ index ca15a74e8..ca4cbae56 100644 /* Allocate and initialize STUN socket data */ data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data); -@@ -511,11 +648,12 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, +@@ -511,11 +637,12 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, data->transport_id = cand->transport_id; /* Create the STUN transport */ @@ -1866,7 +1589,7 @@ index ca15a74e8..ca4cbae56 100644 /* Start STUN Binding resolution and add srflx candidate only if server * is set. When any error occur during STUN Binding resolution, let's -@@ -581,116 +719,43 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, +@@ -581,116 +708,43 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, break; } @@ -2016,7 +1739,7 @@ index ca15a74e8..ca4cbae56 100644 } return status; -@@ -803,6 +868,13 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name, +@@ -803,6 +857,13 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name, return status; } @@ -2030,19 +1753,18 @@ index ca15a74e8..ca4cbae56 100644 pj_grp_lock_add_ref(ice_st->grp_lock); pj_grp_lock_add_handler(ice_st->grp_lock, pool, ice_st, &ice_st_on_destroy); -@@ -1097,6 +1169,11 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st, +@@ -1097,6 +1158,10 @@ 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.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, -@@ -1172,7 +1249,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st, +@@ -1172,7 +1237,7 @@ 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), @@ -2051,7 +1773,7 @@ index ca15a74e8..ca4cbae56 100644 if (status != PJ_SUCCESS) goto on_error; } -@@ -1460,110 +1537,154 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, +@@ -1460,110 +1525,162 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, const pj_sockaddr_t *dst_addr, int dst_addr_len) { @@ -2138,27 +1860,23 @@ index ca15a74e8..ca4cbae56 100644 - - if (def_cand->status == PJ_SUCCESS) { - unsigned tp_idx = GET_TP_IDX(def_cand->transport_id); -+ if (ice_st->is_pending) { -+ return PJ_EPENDING; -+ } - +- - if (def_cand->type == PJ_ICE_CAND_TYPE_RELAYED) { -+ return status; -+ } - +- - enum { - msg_disable_ind = 0xFFFF & - ~(PJ_STUN_SESS_LOG_TX_IND| - PJ_STUN_SESS_LOG_RX_IND) - }; -+ pj_grp_lock_release(ice_st->grp_lock); - +- - /* https://trac.pjsip.org/repos/ticket/1316 */ - if (comp->turn[tp_idx].sock == NULL) { - /* TURN socket error */ - return PJ_EINVALIDOP; - } -+ def_cand = &comp->cand_list[comp->default_cand]; ++ if (ice_st->is_pending) { ++ return PJ_EPENDING; ++ } - if (!comp->turn[tp_idx].log_off) { - /* Disable logging for Send/Data indications */ @@ -2169,63 +1887,13 @@ index ca15a74e8..ca4cbae56 100644 - msg_disable_ind); - comp->turn[tp_idx].log_off = PJ_TRUE; - } -+ pj_bool_t add_header = def_cand->transport != PJ_CAND_UDP; -+ pj_uint8_t* final_pkt = data; -+ unsigned final_len = data_len; -+ -+ if (add_header) { -+ // TCP -+ /* -+ * RFC6544 ICE requires an agent to demultiplex STUN and -+ * application-layer traffic, since they appear on the same port. This -+ * demultiplexing is described in [RFC5245] and is done using the magic -+ * cookie and other fields of the message. Stream-oriented transports -+ * introduce another wrinkle, since they require a way to frame the -+ * connection so that the application and STUN packets can be extracted -+ * in order to differentiate STUN packets from application-layer -+ * traffic. For this reason, TCP media streams utilizing ICE use the -+ * basic framing provided in RFC 4571 [RFC4571], even if the application -+ * layer protocol is not RTP. -+ */ -+ pj_uint8_t header_1 = data_len % 256; -+ pj_uint8_t header_0 = data_len >> 8; -+ final_len = 2 + data_len; -+ memcpy(&ice_st->rtp_pkt, &(header_0), sizeof(pj_uint8_t)); -+ memcpy(&ice_st->rtp_pkt[1], &(header_1), sizeof(pj_uint8_t)); -+ memcpy(&ice_st->rtp_pkt[2], (unsigned char *)data, data_len); -+ final_pkt = &ice_st->rtp_pkt; -+ } - -- status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, -- (const pj_uint8_t*)data, -- (unsigned)data_len, -- dst_addr, dst_addr_len); -- return (status==PJ_SUCCESS||status==PJ_EPENDING) ? -- PJ_SUCCESS : status; -- } else { -- const pj_sockaddr_t *dest_addr; -- unsigned dest_addr_len; -- -- if (comp->ipv4_mapped) { -- if (comp->synth_addr_len == 0 || -- pj_sockaddr_cmp(&comp->dst_addr, dst_addr) != 0) -- { -- status = pj_sockaddr_synthesize(pj_AF_INET6(), -- &comp->synth_addr, -- dst_addr); -- if (status != PJ_SUCCESS) -- return status; -- -- pj_sockaddr_cp(&comp->dst_addr, dst_addr); -- comp->synth_addr_len = pj_sockaddr_get_len( -- &comp->synth_addr); -- } -- dest_addr = &comp->synth_addr; -- dest_addr_len = comp->synth_addr_len; -- } else { -- dest_addr = dst_addr; -- dest_addr_len = dst_addr_len; -- } ++ return status; ++ } ++ ++ pj_grp_lock_release(ice_st->grp_lock); ++ ++ def_cand = &comp->cand_list[comp->default_cand]; ++ + if (def_cand->status == PJ_SUCCESS) { + unsigned tp_idx = GET_TP_IDX(def_cand->transport_id); + @@ -2252,9 +1920,11 @@ index ca15a74e8..ca4cbae56 100644 + comp->turn[tp_idx].log_off = PJ_TRUE; + } + -+ status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, final_pkt, -+ final_len, dst_addr, dst_addr_len); -+ ice_st->is_pending = ((status == PJ_EPENDING) && ice_st); ++ status = ++ pj_turn_sock_sendto(comp->turn[tp_idx].sock, (const pj_uint8_t *)data, ++ (unsigned)data_len, dst_addr, dst_addr_len); ++ return (status == PJ_SUCCESS || status == PJ_EPENDING) ? PJ_SUCCESS ++ : status; + } else { + const pj_sockaddr_t *dest_addr; + unsigned dest_addr_len; @@ -2277,20 +1947,83 @@ index ca15a74e8..ca4cbae56 100644 + dest_addr_len = dst_addr_len; + } +- status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, +- (const pj_uint8_t*)data, +- (unsigned)data_len, +- dst_addr, dst_addr_len); +- return (status==PJ_SUCCESS||status==PJ_EPENDING) ? +- PJ_SUCCESS : status; +- } else { +- const pj_sockaddr_t *dest_addr; +- unsigned dest_addr_len; +- +- if (comp->ipv4_mapped) { +- if (comp->synth_addr_len == 0 || +- pj_sockaddr_cmp(&comp->dst_addr, dst_addr) != 0) +- { +- status = pj_sockaddr_synthesize(pj_AF_INET6(), +- &comp->synth_addr, +- dst_addr); +- if (status != PJ_SUCCESS) +- return status; +- +- pj_sockaddr_cp(&comp->dst_addr, dst_addr); +- comp->synth_addr_len = pj_sockaddr_get_len( +- &comp->synth_addr); +- } +- dest_addr = &comp->synth_addr; +- dest_addr_len = comp->synth_addr_len; +- } else { +- dest_addr = dst_addr; +- dest_addr_len = dst_addr_len; +- } ++ pj_stun_sock_info stun_sock_info; ++ pj_stun_sock_get_info(comp->stun[tp_idx].sock, &stun_sock_info); ++ pj_bool_t add_header = stun_sock_info.conn_type != PJ_STUN_TP_UDP; ++ if (add_header) { ++ //TCP ++ /* ++ * RFC6544 ICE requires an agent to demultiplex STUN and ++ * application-layer traffic, since they appear on the same port. This ++ * demultiplexing is described in [RFC5245] and is done using the magic ++ * cookie and other fields of the message. Stream-oriented transports ++ * introduce another wrinkle, since they require a way to frame the ++ * connection so that the application and STUN packets can be extracted ++ * in order to differentiate STUN packets from application-layer ++ * traffic. For this reason, TCP media streams utilizing ICE use the ++ * basic framing provided in RFC 4571 [RFC4571], even if the application ++ * layer protocol is not RTP. ++ */ ++ pj_uint8_t header_1 = data_len % 256; ++ pj_uint8_t header_0 = data_len >> 8; ++ pj_size_t final_size = 2 + data_len; ++ memcpy(&ice_st->rtp_pkt, &(header_0), sizeof(pj_uint8_t)); ++ memcpy(&ice_st->rtp_pkt[1], &(header_1), sizeof(pj_uint8_t)); ++ memcpy(&ice_st->rtp_pkt[2], (unsigned char *)data, data_len); ++ status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, &ice_st->rtp_pkt, ++ (unsigned)final_size, 0, dest_addr, dest_addr_len, size); ++ if ((status == PJ_EPENDING || *size != final_size) && ice_st) { ++ ice_st->is_pending = PJ_TRUE; ++ } ++ *size -= sizeof(pj_uint16_t); ++ } else { ++ // UDP ++ status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, data, ++ (unsigned)data_len, 0, dest_addr, ++ dest_addr_len, size); ++ if ((status == PJ_EPENDING || *size != data_len) && ice_st) { ++ ice_st->is_pending = PJ_TRUE; ++ } ++ } + - status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, data, - (unsigned)data_len, 0, dest_addr, - dest_addr_len); - return (status==PJ_SUCCESS||status==PJ_EPENDING) ? - PJ_SUCCESS : status; - } -+ status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, final_pkt, -+ final_len, 0, dest_addr, dest_addr_len, size); -+ -+ if (add_header) *size -= sizeof(pj_uint16_t); // Do not count the header -+ ice_st->is_pending = ((status == PJ_EPENDING || *size != data_len) && ice_st); ++ return status; + } -+ -+ return status; - } else - return PJ_EINVALIDOP; @@ -2299,7 +2032,7 @@ index ca15a74e8..ca4cbae56 100644 } /* -@@ -1615,7 +1736,15 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status) +@@ -1615,7 +1732,15 @@ 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); @@ -2316,7 +2049,7 @@ index ca15a74e8..ca4cbae56 100644 if (tp_typ == TP_TURN) { /* Activate channel binding for the remote address * for more efficient data transfer using TURN. -@@ -1683,24 +1812,55 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, +@@ -1683,12 +1808,16 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL); @@ -2334,54 +2067,7 @@ index ca15a74e8..ca4cbae56 100644 pj_sockaddr_get_port(dst_addr), tp_typ)); -- if (tp_typ == TP_TURN) { -- if (comp->turn[tp_idx].sock) { -- status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, -- (const pj_uint8_t*)pkt, -- (unsigned)size, -- dst_addr, dst_addr_len); -- } else { -- status = PJ_EINVALIDOP; -+ pj_bool_t add_header = comp->ice_st->cfg.stun_tp->conn_type == PJ_STUN_TP_TCP; -+ pj_uint8_t* final_pkt = pkt; -+ unsigned final_len = size; -+ pj_ssize_t sent_size; -+ -+ if (add_header) { -+ // TCP -+ /* -+ * RFC6544 ICE requires an agent to demultiplex STUN and -+ * application-layer traffic, since they appear on the same port. This -+ * demultiplexing is described in [RFC5245] and is done using the magic -+ * cookie and other fields of the message. Stream-oriented transports -+ * introduce another wrinkle, since they require a way to frame the -+ * connection so that the application and STUN packets can be extracted -+ * in order to differentiate STUN packets from application-layer -+ * traffic. For this reason, TCP media streams utilizing ICE use the -+ * basic framing provided in RFC 4571 [RFC4571], even if the application -+ * layer protocol is not RTP. -+ */ -+ pj_uint8_t header_1 = size % 256; -+ pj_uint8_t header_0 = size >> 8; -+ final_len = 2 + size; -+ memcpy(&ice_st->rtp_pkt, &(header_0), sizeof(pj_uint8_t)); -+ memcpy(&ice_st->rtp_pkt[1], &(header_1), sizeof(pj_uint8_t)); -+ memcpy(&ice_st->rtp_pkt[2], (unsigned char *)pkt, size); -+ final_pkt = &ice_st->rtp_pkt; - } -+ -+ if (tp_typ == TP_TURN) { -+ if (comp->turn[tp_idx].sock) { -+ status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, -+ final_pkt, final_len, dst_addr, dst_addr_len); -+ ice_st->is_pending = status == PJ_EPENDING; -+ } else { -+ status = PJ_EINVALIDOP; -+ } - } else if (tp_typ == TP_STUN) { - const pj_sockaddr_t *dest_addr; - unsigned dest_addr_len; -@@ -1724,12 +1884,16 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, +@@ -1724,12 +1853,52 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, dest_addr_len = dst_addr_len; } @@ -2389,9 +2075,45 @@ index ca15a74e8..ca4cbae56 100644 - pkt, (unsigned)size, 0, - dest_addr, dest_addr_len); + if (comp->stun[tp_idx].sock) { -+ status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, final_pkt, -+ final_len, 0, dest_addr, dest_addr_len, &sent_size); -+ ice_st->is_pending = (status == PJ_EPENDING || sent_size != final_len); ++ pj_ssize_t sent_size; ++ ++ pj_stun_sock_info stun_sock_info; ++ pj_stun_sock_get_info(comp->stun[tp_idx].sock, &stun_sock_info); ++ pj_bool_t add_header = stun_sock_info.conn_type != PJ_STUN_TP_UDP; ++ if (add_header) { ++ //TCP ++ /* ++ * RFC6544 ICE requires an agent to demultiplex STUN and ++ * application-layer traffic, since they appear on the same port. This ++ * demultiplexing is described in [RFC5245] and is done using the magic ++ * cookie and other fields of the message. Stream-oriented transports ++ * introduce another wrinkle, since they require a way to frame the ++ * connection so that the application and STUN packets can be extracted ++ * in order to differentiate STUN packets from application-layer ++ * traffic. For this reason, TCP media streams utilizing ICE use the ++ * basic framing provided in RFC 4571 [RFC4571], even if the application ++ * layer protocol is not RTP. ++ */ ++ pj_uint8_t header_1 = size % 256; ++ pj_uint8_t header_0 = size >> 8; ++ const pj_size_t final_size = 2 + size; ++ memcpy(&ice_st->rtp_pkt, &(header_0), sizeof(pj_uint8_t)); ++ memcpy(&ice_st->rtp_pkt[1], &(header_1), sizeof(pj_uint8_t)); ++ memcpy(&ice_st->rtp_pkt[2], (unsigned char *)pkt, size); ++ status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, &ice_st->rtp_pkt, ++ (unsigned)final_size, 0, dest_addr, dest_addr_len, &sent_size); ++ if (status == PJ_EPENDING || sent_size != final_size) { ++ ice_st->is_pending = PJ_TRUE; ++ } ++ } else { ++ // UDP ++ status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, pkt, ++ (unsigned)size, 0, dest_addr, dest_addr_len, &sent_size); ++ if (status == PJ_EPENDING || sent_size != size) { ++ ice_st->is_pending = PJ_TRUE; ++ } ++ } ++ + } else { + status = PJ_EINVALIDOP; + } @@ -2402,7 +2124,7 @@ index ca15a74e8..ca4cbae56 100644 } return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; -@@ -1755,22 +1919,213 @@ static void ice_rx_data(pj_ice_sess *ice, +@@ -1755,22 +1924,115 @@ static void ice_rx_data(pj_ice_sess *ice, } } @@ -2432,61 +2154,6 @@ index ca15a74e8..ca4cbae56 100644 + ice_sess_on_peer_connection(ice_st->ice, data->transport_id, status, remote_addr); +} + -+static void on_peer_reset_connection(pj_stun_session* sess, pj_sockaddr_t* remote_addr) { -+ -+ sock_user_data *data; -+ pj_ice_strans_comp *comp; -+ pj_ice_strans *ice_st; -+ pj_stun_sock* stun_sock = (pj_stun_sock *)pj_stun_session_get_user_data(sess); -+ if (!stun_sock) { -+ /* We have disassociated ourselves from the STUN session */ -+ return; -+ } -+ data = (sock_user_data *)pj_stun_sock_get_user_data(stun_sock); -+ if (!data) { -+ /* We have disassociated ourselves from the STUN socket */ -+ return; -+ } -+ -+ comp = data->comp; -+ ice_st = comp->ice_st; -+ if (!ice_st || !ice_st->ice) { -+ // Incorrect ICE -+ return; -+ } -+ -+ ice_sess_on_peer_reset_connection(ice_st->ice, data->transport_id, remote_addr); -+} -+ -+static void on_peer_packet(pj_stun_session* sess, pj_sockaddr_t* remote_addr) { -+ -+ if (!sess || !remote_addr) return; -+ sock_user_data *data; -+ pj_ice_strans_comp *comp; -+ pj_ice_strans *ice_st; -+ pj_stun_sock* stun_sock = (pj_stun_sock *)pj_stun_session_get_user_data(sess); -+ if (!stun_sock) { -+ /* We have disassociated ourselves from the STUN session */ -+ return; -+ } -+ data = (sock_user_data *)pj_stun_sock_get_user_data(stun_sock); -+ if (!data) { -+ /* We have disassociated ourselves from the STUN socket */ -+ return; -+ } -+ -+ comp = data->comp; -+ if (!comp) return; -+ ice_st = comp->ice_st; -+ if (!ice_st || !ice_st->ice) { -+ // Incorrect ICE -+ return; -+ } -+ -+ ice_sess_on_peer_packet(ice_st->ice, data->transport_id, remote_addr); -+} -+ -+#if PJ_HAS_TCP +static pj_status_t ice_wait_tcp_connection(pj_ice_sess *ice, + pj_ice_sess_checklist *clist, + unsigned check_id) { @@ -2520,8 +2187,6 @@ index ca15a74e8..ca4cbae56 100644 + return PJ_EINVAL; + } + pj_stun_session_callback(sess)->on_peer_connection = &on_peer_connection; -+ pj_stun_session_callback(sess)->on_peer_reset_connection = &on_peer_reset_connection; -+ pj_stun_session_callback(sess)->on_peer_packet = &on_peer_packet; + return pj_stun_sock_connect_active(st_comp->stun[idx].sock, &rcand->addr, + rcand->addr.addr.sa_family); + } @@ -2529,48 +2194,7 @@ index ca15a74e8..ca4cbae56 100644 + return PJ_EINVAL; +} + -+static pj_status_t ice_reconnect_tcp_connection(pj_ice_sess *ice, -+ pj_ice_sess_checklist *clist, -+ unsigned check_id) { -+ pj_ice_sess_check *check; -+ check = &clist->checks[check_id]; -+ const pj_ice_sess_cand *lcand; -+ lcand = check->lcand; -+ const pj_ice_sess_cand *rcand; -+ 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]; -+ -+ int idx = -1; -+ for (int i=0; i<ice_st->cfg.stun_tp_cnt; ++i) { -+ if (ice_st->cfg.stun_tp[i].af == rcand->addr.addr.sa_family) { -+ idx = i; -+ break; -+ } -+ } -+ if (idx == -1) { -+ PJ_LOG(4, (ice_st->obj_name, "Comp %d: No STUN sock found.", -+ st_comp->comp_id)); -+ return PJ_EINVAL; -+ } -+ if (st_comp->stun[idx].sock) { -+ pj_stun_session *sess = pj_stun_sock_get_session(st_comp->stun[idx].sock); -+ if (!sess) { -+ PJ_LOG(4, (ice_st->obj_name, "Comp %d: No STUN session.", -+ st_comp->comp_id)); -+ return PJ_EINVAL; -+ } -+ pj_stun_session_callback(sess)->on_peer_connection = &on_peer_connection; -+ pj_stun_session_callback(sess)->on_peer_reset_connection = &on_peer_reset_connection; -+ pj_stun_session_callback(sess)->on_peer_packet = &on_peer_packet; -+ return pj_stun_sock_reconnect_active(st_comp->stun[idx].sock, &rcand->addr, -+ rcand->addr.addr.sa_family); -+ } -+ -+ return PJ_EINVAL; -+} -+ ++#if PJ_HAS_TCP +static pj_status_t ice_close_tcp_connection(pj_ice_sess *ice, + pj_ice_sess_checklist *clist, + unsigned check_id) { @@ -2629,7 +2253,7 @@ index ca15a74e8..ca4cbae56 100644 /* We have disassociated ourselves from the STUN socket */ return PJ_FALSE; } -@@ -1814,9 +2169,34 @@ static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock, +@@ -1814,9 +2076,17 @@ static pj_bool_t stun_on_data_sent(pj_stun_sock *stun_sock, pj_ioqueue_op_key_t *send_key, pj_ssize_t sent) { @@ -2646,28 +2270,11 @@ index ca15a74e8..ca4cbae56 100644 + ice_st->is_pending = PJ_FALSE; + if (ice_st->cb.on_data_sent) { + (*ice_st->cb.on_data_sent)(ice_st, comp->comp_id, sent); -+ } -+ return PJ_TRUE; -+} -+ -+static pj_bool_t turn_on_data_sent(pj_turn_sock *turn_sock, pj_ssize_t sent) -+{ -+ sock_user_data *data; -+ pj_ice_strans_comp *comp; -+ pj_ice_strans *ice_st; -+ -+ data = (sock_user_data*) pj_turn_sock_get_user_data(turn_sock); -+ comp = data->comp; -+ ice_st = comp->ice_st; -+ ice_st->is_pending = PJ_FALSE; -+ -+ if (ice_st->cb.on_data_sent) { -+ (*ice_st->cb.on_data_sent)(ice_st, comp->comp_id, sent); + } return PJ_TRUE; } -@@ -2021,6 +2401,10 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, +@@ -2021,6 +2291,10 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, } } break; @@ -2678,119 +2285,7 @@ index ca15a74e8..ca4cbae56 100644 } return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE; -@@ -2029,7 +2413,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, - /* Callback when TURN socket has received a packet */ - static void turn_on_rx_data(pj_turn_sock *turn_sock, - void *pkt, -- unsigned pkt_len, -+ unsigned size, - const pj_sockaddr_t *peer_addr, - unsigned addr_len) - { -@@ -2055,20 +2439,93 @@ static void turn_on_rx_data(pj_turn_sock *turn_sock, - */ - if (comp->ice_st->cb.on_rx_data) { - (*comp->ice_st->cb.on_rx_data)(comp->ice_st, comp->comp_id, pkt, -- pkt_len, peer_addr, addr_len); -+ size, peer_addr, addr_len); - } - - } 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, -- peer_addr, addr_len); -- -- 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 && size > 0) { -+ pj_uint16_t parsed = 0; -+ pj_status_t result = PJ_TRUE; -+ pj_status_t status; -+ -+ do { -+ pj_uint16_t pkt_len = size - parsed; -+ pj_uint8_t *current_packet = ((pj_uint8_t *)(pkt)) + parsed; -+ -+ /* RFC6544, the packet is wrapped into a packet following the RFC4571 */ -+ // cf stun_sock.c:parse_rx_packet -+ pj_bool_t store_remaining = PJ_TRUE; -+ if (comp->ice_st->rx_buffer_size != 0 || comp->ice_st->rx_wanted_size != 0) { -+ // We currently have a packet to complete -+ if (comp->ice_st->rx_buffer_size == 1) { -+ // We do not know the current size, parse it. -+ pkt_len = (((pj_uint8_t *)comp->ice_st->rx_buffer)[0] << 8) + -+ ((pj_uint8_t *)current_packet)[0]; -+ comp->ice_st->rx_buffer_size = 0; // We have eaten the temp packet. -+ current_packet = current_packet + 1; -+ parsed += 1; -+ if (pkt_len + parsed <= size) { -+ store_remaining = PJ_FALSE; -+ parsed += pkt_len; -+ } else { -+ comp->ice_st->rx_wanted_size = pkt_len; -+ } -+ } else if (pkt_len + comp->ice_st->rx_buffer_size >= comp->ice_st->rx_wanted_size) { -+ // We have enough pkt Build new packet to parse -+ store_remaining = PJ_FALSE; -+ pj_uint16_t eaten_bytes = comp->ice_st->rx_wanted_size - comp->ice_st->rx_buffer_size; -+ memcpy(comp->ice_st->rx_buffer + comp->ice_st->rx_buffer_size, -+ current_packet, eaten_bytes); -+ pkt_len = comp->ice_st->rx_wanted_size; -+ current_packet = comp->ice_st->rx_buffer; -+ parsed += eaten_bytes; -+ comp->ice_st->rx_buffer_size = 0; -+ comp->ice_st->rx_wanted_size = 0; -+ } -+ } else if (pkt_len > 1) { -+ pkt_len = (((pj_uint8_t *)current_packet)[0] << 8) + ((pj_uint8_t *)current_packet)[1]; -+ current_packet = current_packet + 2; -+ parsed += 2; -+ if (pkt_len + parsed <= size) { -+ store_remaining = PJ_FALSE; -+ parsed += pkt_len; -+ } else { -+ comp->ice_st->rx_wanted_size = pkt_len; -+ -+ } -+ } -+ if (store_remaining) { -+ pj_uint16_t stored_size = size - parsed; -+ memcpy(comp->ice_st->rx_buffer + comp->ice_st->rx_buffer_size, -+ current_packet, stored_size); -+ comp->ice_st->rx_buffer_size += stored_size; -+ status = pj_grp_lock_release(comp->ice_st->grp_lock); -+ result &= status != PJ_EGONE ? PJ_TRUE : PJ_FALSE; -+ status = PJ_SUCCESS; -+ break; -+ } -+ -+ status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, -+ data->transport_id, current_packet, pkt_len, -+ peer_addr, addr_len); -+ -+ if (status != PJ_SUCCESS) { -+ ice_st_perror(comp->ice_st, -+ "Error processing packet from TURN relay", -+ status); -+ } -+ } while (parsed < size && result); -+ } else { -+ status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, -+ data->transport_id, pkt, size, -+ peer_addr, addr_len); -+ if (status != PJ_SUCCESS) { -+ ice_st_perror(comp->ice_st, -+ "Error processing packet from TURN relay", -+ status); -+ } - } - } - -@@ -2252,5 +2709,4 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, +@@ -2252,5 +2526,4 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, pj_grp_lock_dec_ref(comp->ice_st->grp_lock); pj_log_pop_indent(); @@ -2799,7 +2294,7 @@ index ca15a74e8..ca4cbae56 100644 +} \ No newline at end of file diff --git a/pjnath/src/pjnath/nat_detect.c b/pjnath/src/pjnath/nat_detect.c -index db0de10bc..3013eeed2 100644 +index db0de10b..3013eeed 100644 --- a/pjnath/src/pjnath/nat_detect.c +++ b/pjnath/src/pjnath/nat_detect.c @@ -329,7 +329,8 @@ PJ_DEF(pj_status_t) pj_stun_detect_nat_type2(const pj_sockaddr *server, @@ -2829,7 +2324,7 @@ index db0de10bc..3013eeed2 100644 goto on_error; diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c -index 7b53aba74..2b006d918 100644 +index 7b53aba7..2b006d91 100644 --- a/pjnath/src/pjnath/stun_session.c +++ b/pjnath/src/pjnath/stun_session.c @@ -49,6 +49,8 @@ struct pj_stun_session @@ -2859,7 +2354,7 @@ index 7b53aba74..2b006d918 100644 if (grp_lock) { sess->grp_lock = grp_lock; -@@ -1511,3 +1515,9 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess, +@@ -1511,3 +1515,9 @@ on_return: return status; } @@ -2870,7 +2365,7 @@ index 7b53aba74..2b006d918 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 7692e6c14..3b8d509ab 100644 +index 7692e6c1..7624cf25 100644 --- a/pjnath/src/pjnath/stun_sock.c +++ b/pjnath/src/pjnath/stun_sock.c @@ -1,5 +1,5 @@ @@ -3540,7 +3035,7 @@ index 7692e6c14..3b8d509ab 100644 } stun_sock->tsx_id[5] = 0; -@@ -378,15 +530,248 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, +@@ -378,15 +530,238 @@ PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg, stun_sock->ka_timer.cb = &ka_timer_cb; stun_sock->ka_timer.user_data = stun_sock; @@ -3635,6 +3130,7 @@ index 7692e6c14..3b8d509ab 100644 +#if PJ_HAS_TCP + } +#endif ++ + /* Check that this is STUN message */ + status = pj_stun_msg_check((const pj_uint8_t *)current_packet, pkt_len, + PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET); @@ -3688,29 +3184,21 @@ index 7692e6c14..3b8d509ab 100644 + result &= status != PJ_EGONE ? PJ_TRUE : PJ_FALSE; + } while (parsed < size && result); + return result; - } - ++} ++ +pj_bool_t on_data_read(pj_activesock_t *asock, void *data, pj_size_t size, + pj_status_t status, pj_size_t *remainder) { + + pj_stun_sock *stun_sock; + + stun_sock = (pj_stun_sock *)pj_activesock_get_user_data(asock); -+ if (!stun_sock) return PJ_FALSE; ++ if (!stun_sock) ++ return PJ_FALSE; + -+ pj_stun_session_cb *cb = pj_stun_session_callback(stun_sock->stun_sess); + /* Log socket error or disconnection */ + if (status != PJ_SUCCESS) { -+ if (stun_sock->conn_type == PJ_STUN_TP_UDP || (status != PJ_EEOF && status != 120104)) { ++ if (stun_sock->conn_type == PJ_STUN_TP_UDP || status != PJ_EEOF) { + PJ_PERROR(2, (stun_sock->obj_name, status, "read() error")); -+ } else if (status == 120104 /* RESET BY PEER */) { -+ for (int i = 0; i <= stun_sock->outgoing_nb; ++i) { -+ if (stun_sock->outgoing_socks[i].sock == asock) { -+ if (cb && (cb->on_peer_reset_connection)) { -+ (cb->on_peer_reset_connection)(stun_sock->stun_sess, stun_sock->outgoing_socks[i].addr); -+ } -+ } -+ } + } + return PJ_FALSE; + } @@ -3721,8 +3209,6 @@ index 7692e6c14..3b8d509ab 100644 + if (stun_sock->outgoing_socks[i].sock == asock) { + rx_addr = stun_sock->outgoing_socks[i].addr; + sock_addr_len = pj_sockaddr_get_len(rx_addr); -+ if (cb && (cb->on_peer_packet)) -+ (cb->on_peer_packet)(stun_sock->stun_sess, stun_sock->outgoing_socks[i].addr); + } + } + if (rx_addr == NULL && stun_sock->incoming_nb != -1) { @@ -3732,11 +3218,10 @@ index 7692e6c14..3b8d509ab 100644 + } + return parse_rx_packet(stun_sock, data, size, rx_addr, sock_addr_len); +#else -+ pj_grp_lock_release(stun_sock->grp_lock); + return PJ_FALSE; +#endif -+} -+ + } + +#if PJ_HAS_TCP +/* + * Notification when incoming TCP socket has been connected. @@ -3795,7 +3280,7 @@ index 7692e6c14..3b8d509ab 100644 /* Start socket. */ PJ_DEF(pj_status_t) pj_stun_sock_start( pj_stun_sock *stun_sock, const pj_str_t *domain, -@@ -504,15 +889,35 @@ PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock) +@@ -504,15 +879,35 @@ PJ_DEF(pj_status_t) pj_stun_sock_destroy(pj_stun_sock *stun_sock) } stun_sock->is_destroying = PJ_TRUE; @@ -3838,7 +3323,7 @@ index 7692e6c14..3b8d509ab 100644 } if (stun_sock->stun_sess) { -@@ -619,12 +1024,12 @@ static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock) +@@ -619,12 +1014,12 @@ static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock) &tdata); if (status != PJ_SUCCESS) goto on_error; @@ -3856,7 +3341,7 @@ index 7692e6c14..3b8d509ab 100644 if (status != PJ_SUCCESS && status != PJ_EPENDING) goto on_error; -@@ -637,7 +1042,7 @@ static pj_status_t get_mapped_addr(pj_stun_sock *stun_sock) +@@ -637,7 +1032,7 @@ on_error: /* Get info */ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock, @@ -3865,7 +3350,7 @@ index 7692e6c14..3b8d509ab 100644 { int addr_len; pj_status_t status; -@@ -646,73 +1051,73 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock, +@@ -646,73 +1041,73 @@ PJ_DEF(pj_status_t) pj_stun_sock_get_info( pj_stun_sock *stun_sock, pj_grp_lock_acquire(stun_sock->grp_lock); @@ -3995,7 +3480,7 @@ index 7692e6c14..3b8d509ab 100644 } pj_grp_lock_release(stun_sock->grp_lock); -@@ -726,36 +1131,253 @@ PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock, +@@ -726,36 +1121,235 @@ PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock, unsigned pkt_len, unsigned flag, const pj_sockaddr_t *dst_addr, @@ -4028,10 +3513,7 @@ index 7692e6c14..3b8d509ab 100644 if (send_key==NULL) - send_key = &stun_sock->send_key; + 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); ++ + *size = pkt_len; + if (stun_sock->conn_type == PJ_STUN_TP_UDP) { + status = pj_activesock_sendto(stun_sock->main_sock, send_key, @@ -4066,7 +3548,7 @@ index 7692e6c14..3b8d509ab 100644 + +#endif + } - ++ + pj_grp_lock_release(stun_sock->grp_lock); + return status; +} @@ -4074,22 +3556,39 @@ index 7692e6c14..3b8d509ab 100644 +#if PJ_HAS_TCP + +PJ_DECL(pj_status_t) -+pj_stun_sock_connect(pj_stun_sock *stun_sock, const pj_sockaddr_t *remote_addr, int af, int nb_check) { ++pj_stun_sock_connect_active(pj_stun_sock *stun_sock, const pj_sockaddr_t *remote_addr, int af) { + +- size = pkt_len; +- status = pj_activesock_sendto(stun_sock->active_sock, send_key, +- pkt, &size, flag, dst_addr, addr_len); ++ if (stun_sock->incoming_nb != -1) { ++ // Check if not incoming, if so, already connected (mainly for PRFLX candidates) ++ for (int i = 0 ; i <= stun_sock->incoming_nb; ++i) { ++ if (pj_sockaddr_cmp(&stun_sock->incoming_socks[i].addr, remote_addr) == 0) { ++ pj_stun_session_cb *cb = pj_stun_session_callback(stun_sock->stun_sess); ++ (cb->on_peer_connection)(stun_sock->stun_sess, PJ_SUCCESS, remote_addr); ++ return PJ_SUCCESS; ++ } ++ } ++ } ++ pj_status_t status; + + pj_grp_lock_acquire(stun_sock->grp_lock); + int sock_type = pj_SOCK_STREAM(); + ++ /* Create socket and bind socket */ ++ stun_sock->outgoing_nb += 1; ++ int nb_check = stun_sock->outgoing_nb; + pj_sock_t *fd = &stun_sock->outgoing_socks[nb_check].fd; + pj_activesock_t **asock = &stun_sock->outgoing_socks[nb_check].sock; + pj_sockaddr_t **addr = &stun_sock->outgoing_socks[nb_check].addr; -+ -+ pj_status_t status = pj_sock_socket(af, sock_type, 0, fd); ++ status = pj_sock_socket(af, sock_type, 0, fd); + if (status != PJ_SUCCESS) { + pj_stun_sock_destroy(stun_sock); + pj_grp_lock_release(stun_sock->grp_lock); + return status; + } -+ + + /* Apply QoS, if specified */ + status = pj_sock_apply_qos2(*fd, stun_sock->setting.qos_type, + &stun_sock->setting.qos_params, 2, stun_sock->obj_name, NULL); @@ -4178,40 +3677,8 @@ index 7692e6c14..3b8d509ab 100644 + + 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) { -+ -+ if (stun_sock->incoming_nb != -1) { -+ // Check if not incoming, if so, already connected (mainly for PRFLX candidates) -+ for (int i = 0 ; i <= stun_sock->incoming_nb; ++i) { -+ if (pj_sockaddr_cmp(&stun_sock->incoming_socks[i].addr, remote_addr) == 0) { -+ pj_stun_session_cb *cb = pj_stun_session_callback(stun_sock->stun_sess); -+ (cb->on_peer_connection)(stun_sock->stun_sess, PJ_SUCCESS, remote_addr); -+ return PJ_SUCCESS; -+ } -+ } -+ } -+ -+ /* Create socket and bind socket */ -+ stun_sock->outgoing_nb += 1; -+ int nb_check = stun_sock->outgoing_nb; -+ return pj_stun_sock_connect(stun_sock, remote_addr, af, nb_check); -+ -+} -+ -+PJ_DECL(pj_status_t) -+pj_stun_sock_reconnect_active(pj_stun_sock *stun_sock, const pj_sockaddr_t *remote_addr, int af) { -+ for (int i = 0; i <= stun_sock->outgoing_nb; ++i) { -+ if (pj_sockaddr_cmp(stun_sock->outgoing_socks[i].addr, remote_addr) == 0) { -+ pj_activesock_close(stun_sock->outgoing_socks[i].sock); -+ return pj_stun_sock_connect(stun_sock, remote_addr, af, i); -+ } -+ } -+ return PJ_EINVAL; -+} -+ + } + +PJ_DECL(pj_status_t) +pj_stun_sock_close(pj_stun_sock *stun_sock, const pj_sockaddr_t *remote_addr) { + for (int i = 0; i <= stun_sock->outgoing_nb; ++i) { @@ -4253,8 +3720,8 @@ index 7692e6c14..3b8d509ab 100644 + if (!remote_addr) return PJ_FALSE; + (cb->on_peer_connection)(stun_sock->stun_sess, status, remote_addr); + return PJ_TRUE; - } - ++} ++ +#endif + /* This callback is called by the STUN session to send packet */ @@ -4263,7 +3730,7 @@ index 7692e6c14..3b8d509ab 100644 void *token, const void *pkt, pj_size_t pkt_size, -@@ -766,7 +1388,7 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess, +@@ -766,7 +1360,7 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess, pj_ssize_t size; stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess); @@ -4272,7 +3739,7 @@ index 7692e6c14..3b8d509ab 100644 /* We have been shutdown, but this callback may still get called * by retransmit timer. */ -@@ -777,15 +1399,31 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess, +@@ -777,15 +1371,31 @@ static pj_status_t sess_on_send_msg(pj_stun_session *sess, PJ_UNUSED_ARG(token); size = pkt_size; @@ -4308,7 +3775,7 @@ index 7692e6c14..3b8d509ab 100644 pj_status_t status, void *token, pj_stun_tx_data *tdata, -@@ -869,9 +1507,9 @@ static void sess_on_request_complete(pj_stun_session *sess, +@@ -869,9 +1479,9 @@ on_return: } /* Schedule keep-alive timer */ @@ -4320,7 +3787,7 @@ index 7692e6c14..3b8d509ab 100644 &stun_sock->ka_timer, 0); pj_assert(stun_sock->ka_interval != 0); -@@ -881,7 +1519,7 @@ static void start_ka_timer(pj_stun_sock *stun_sock) +@@ -881,7 +1491,7 @@ static void start_ka_timer(pj_stun_sock *stun_sock) delay.sec = stun_sock->ka_interval; delay.msec = 0; @@ -4329,7 +3796,7 @@ index 7692e6c14..3b8d509ab 100644 &stun_sock->ka_timer, &delay, PJ_TRUE, stun_sock->grp_lock); -@@ -889,7 +1527,7 @@ static void start_ka_timer(pj_stun_sock *stun_sock) +@@ -889,7 +1499,7 @@ static void start_ka_timer(pj_stun_sock *stun_sock) } /* Keep-alive timer callback */ @@ -4338,7 +3805,7 @@ index 7692e6c14..3b8d509ab 100644 { pj_stun_sock *stun_sock; -@@ -911,7 +1549,7 @@ static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te) +@@ -911,7 +1521,7 @@ static void ka_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te) } /* Callback from active socket when incoming packet is received */ @@ -4347,7 +3814,7 @@ index 7692e6c14..3b8d509ab 100644 void *data, pj_size_t size, const pj_sockaddr_t *src_addr, -@@ -919,8 +1557,6 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock, +@@ -919,8 +1529,6 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock, pj_status_t status) { pj_stun_sock *stun_sock; @@ -4356,7 +3823,7 @@ index 7692e6c14..3b8d509ab 100644 stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock); if (!stun_sock) -@@ -932,62 +1568,11 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock, +@@ -932,62 +1540,11 @@ static pj_bool_t on_data_recvfrom(pj_activesock_t *asock, return PJ_TRUE; } @@ -4421,7 +3888,7 @@ index 7692e6c14..3b8d509ab 100644 pj_ioqueue_op_key_t *send_key, pj_ssize_t sent) { -@@ -1024,3 +1609,7 @@ static pj_bool_t on_data_sent(pj_activesock_t *asock, +@@ -1024,3 +1581,7 @@ static pj_bool_t on_data_sent(pj_activesock_t *asock, return PJ_TRUE; } @@ -4429,20 +3896,8 @@ index 7692e6c14..3b8d509ab 100644 +{ + return stun_sock ? stun_sock->stun_sess : NULL; +} -diff --git a/pjnath/src/pjnath/stun_transaction.c b/pjnath/src/pjnath/stun_transaction.c -index 28f623005..0c15763c2 100644 ---- a/pjnath/src/pjnath/stun_transaction.c -+++ b/pjnath/src/pjnath/stun_transaction.c -@@ -394,6 +394,7 @@ static void retransmit_timer_callback(pj_timer_heap_t *timer_heap, - PJ_DEF(pj_status_t) pj_stun_client_tsx_retransmit(pj_stun_client_tsx *tsx, - pj_bool_t mod_count) - { -+ if (!tsx) return PJ_EINVAL; - if (tsx->destroy_timer.id != 0) { - return PJ_SUCCESS; - } diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c -index fcbe703e8..1c0430bc7 100644 +index fcbe703e..1c0430bc 100644 --- a/pjnath/src/pjnath/turn_session.c +++ b/pjnath/src/pjnath/turn_session.c @@ -311,7 +311,8 @@ PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg, @@ -4456,7 +3911,7 @@ index fcbe703e8..1c0430bc7 100644 do_destroy(sess); return status; diff --git a/pjnath/src/pjturn-client/client_main.c b/pjnath/src/pjturn-client/client_main.c -index 1a8667220..5f013631a 100644 +index 1a866722..5f013631 100644 --- a/pjnath/src/pjturn-client/client_main.c +++ b/pjnath/src/pjturn-client/client_main.c @@ -154,10 +154,10 @@ static int init() @@ -4486,7 +3941,7 @@ index 1a8667220..5f013631a 100644 case 'q': g.quit = PJ_TRUE; diff --git a/pjnath/src/pjturn-srv/allocation.c b/pjnath/src/pjturn-srv/allocation.c -index 6c9c9ce11..eea91f01b 100644 +index 6c9c9ce1..eea91f01 100644 --- a/pjnath/src/pjturn-srv/allocation.c +++ b/pjnath/src/pjturn-srv/allocation.c @@ -338,7 +338,7 @@ PJ_DEF(pj_status_t) pj_turn_allocation_create(pj_turn_transport *transport, @@ -4499,7 +3954,7 @@ index 6c9c9ce11..eea91f01b 100644 goto on_error; } diff --git a/pjnath/src/pjturn-srv/server.c b/pjnath/src/pjturn-srv/server.c -index 94dda29a3..95ad1793d 100644 +index 94dda29a..95ad1793 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, @@ -4512,7 +3967,7 @@ index 94dda29a3..95ad1793d 100644 goto on_error; } diff --git a/pjsip-apps/src/samples/icedemo.c b/pjsip-apps/src/samples/icedemo.c -index 9d811374a..92826fd8d 100644 +index 9d811374..92826fd8 100644 --- a/pjsip-apps/src/samples/icedemo.c +++ b/pjsip-apps/src/samples/icedemo.c @@ -43,7 +43,7 @@ static struct app_t @@ -5262,7 +4717,7 @@ index 9d811374a..92826fd8d 100644 status = icedemo_init(); diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c -index ea1e72b85..39d05d1ed 100644 +index ea1e72b8..39d05d1e 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -1529,10 +1529,10 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess) diff --git a/contrib/src/pjproject/win32_ice_tcp_temp_fix.patch b/contrib/src/pjproject/win32_ice_tcp_temp_fix.patch new file mode 100644 index 0000000000000000000000000000000000000000..069664d7597b344dbe26e5be725fe82f7e232e81 --- /dev/null +++ b/contrib/src/pjproject/win32_ice_tcp_temp_fix.patch @@ -0,0 +1,38 @@ +From 5f288fe0067f995b91ea87ba4ed19fd65b75ff31 Mon Sep 17 00:00:00 2001 +From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> +Date: Tue, 11 Jun 2019 16:47:06 -0400 +Subject: [PATCH] fix for windows GetAdaptersAddresses + +--- + pjnath/src/pjnath/ice_strans.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c +index 6172172..33ac521 100644 +--- a/pjnath/src/pjnath/ice_strans.c ++++ b/pjnath/src/pjnath/ice_strans.c +@@ -1645,9 +1645,7 @@ pj_ice_strans_sendto2(pj_ice_strans *ice_st, unsigned comp_id, const void *data, + dest_addr_len = dst_addr_len; + } + +- pj_stun_sock_info stun_sock_info; +- pj_stun_sock_get_info(comp->stun[tp_idx].sock, &stun_sock_info); +- pj_bool_t add_header = stun_sock_info.conn_type != PJ_STUN_TP_UDP; ++ pj_bool_t add_header = comp->ice_st->cfg.stun_tp->conn_type == PJ_STUN_TP_TCP; + if (add_header) { + //TCP + /* +@@ -1864,9 +1862,7 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, + if (comp->stun[tp_idx].sock) { + pj_ssize_t sent_size; + +- pj_stun_sock_info stun_sock_info; +- pj_stun_sock_get_info(comp->stun[tp_idx].sock, &stun_sock_info); +- pj_bool_t add_header = stun_sock_info.conn_type != PJ_STUN_TP_UDP; ++ pj_bool_t add_header = comp->ice_st->cfg.stun_tp->conn_type == PJ_STUN_TP_TCP; + if (add_header) { + //TCP + /* +-- +2.7.4 + diff --git a/src/ice_socket.h b/src/ice_socket.h index cdccafcdd4c029e436a2338bdb732176522b1687..4810bc5471b2bf28bd14ab561ec23cb601c1628f 100644 --- a/src/ice_socket.h +++ b/src/ice_socket.h @@ -67,13 +67,12 @@ public: static constexpr uint16_t IPV4_HEADER_SIZE = 20; // Size in bytes of IPv4 packet header static constexpr uint16_t UDP_HEADER_SIZE = 8; // Size in bytes of UDP header - IceSocketTransport(std::shared_ptr<IceTransport>& ice, int comp_id, bool reliable = false) + IceSocketTransport(std::shared_ptr<IceTransport>& ice, int comp_id) : compId_ {comp_id} - , ice_ {ice} - , reliable_ {reliable} {} + , ice_ {ice} {} bool isReliable() const override { - return reliable_; + return false; // we consider that a ICE transport is never reliable (UDP support only) } bool isInitiator() const override; @@ -95,7 +94,6 @@ public: private: const int compId_; std::shared_ptr<IceTransport> ice_; - bool reliable_; }; }; diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp index 1bda97e7afeb15c48f72a18afe2f29e7604317ca..0a7478751fa170f022fbc80d400bab4144452bc7 100644 --- a/src/ice_transport.cpp +++ b/src/ice_transport.cpp @@ -26,6 +26,7 @@ #include "upnp/upnp_control.h" #include <pjlib.h> +#include <msgpack.hpp> #include <map> #include <atomic> @@ -91,6 +92,8 @@ public: MutexGuard lk{mutex_}; stream_.clear(); stream_ << data; + + notified_ = true; cv_.notify_one(); } @@ -108,14 +111,14 @@ public: MutexGuard lk_api{apiMutex_, std::adopt_lock}; MutexLock lk{mutex_, std::adopt_lock}; auto a = cv_.wait_for(lk, timeout, - [this] { return stop_ or !stream_.eof(); }); + [this] { return stop_ or /*(data.size() != 0)*/ !stream_.eof(); }); return a; } std::size_t read(char *output, std::size_t size) { - MutexLock lk{mutex_, std::adopt_lock}; - if (stream_.eof()) return 0; + std::lock(apiMutex_, mutex_); MutexGuard lk_api{apiMutex_, std::adopt_lock}; + MutexLock lk{mutex_, std::adopt_lock}; cv_.wait(lk, [&, this] { if (stop_) return true; @@ -133,6 +136,9 @@ public: stop_ = true; } cv_.notify_all(); + + // Make sure that no thread is blocked into read() or wait() methods + MutexGuard lk_api{apiMutex_}; } private: @@ -143,6 +149,9 @@ private: std::condition_variable cv_{}; std::stringstream stream_{}; bool stop_{false}; + bool notified_{false}; + + std::vector<char> data; friend void operator<<(std::vector<char> &, PeerChannel &); }; @@ -204,8 +213,6 @@ public: pj_ice_strans_cfg config_; std::string last_errmsg_; - std::atomic_bool is_stopped_ {false}; - struct Packet { Packet(void *pkt, pj_size_t size) : data{reinterpret_cast<char *>(pkt), reinterpret_cast<char *>(pkt) + size} { } @@ -862,12 +869,11 @@ IceTransport::Impl::onReceiveData(unsigned comp_id, void *pkt, pj_size_t size) if (on_recv_cb_) { on_recv_cb_(); } - if (io.cb) { io.cb((uint8_t*)pkt, size); } else { MutexLock lk{apiMutex_}; - auto &channel = peerChannels_.at(comp_id-1); + auto &channel = peerChannels_.at(comp_id); lk.unlock(); channel << std::string(reinterpret_cast<const char *>(pkt), size); } @@ -901,13 +907,6 @@ IceTransport::isRunning() const return pimpl_->_isRunning(); } -bool -IceTransport::isStopped() const -{ - std::lock_guard<std::mutex> lk {pimpl_->iceMutex_}; - return pimpl_->is_stopped_; -} - bool IceTransport::isFailed() const { @@ -951,14 +950,12 @@ IceTransport::start(const Attribute& rem_attrs, const std::vector<IceCandidate>& { if (not isInitialized()) { JAMI_ERR("[ice:%p] not initialized transport", this); - pimpl_->is_stopped_ = true; return false; } // pj_ice_strans_start_ice crashes if remote candidates array is empty if (rem_candidates.empty()) { JAMI_ERR("[ice:%p] start failed: no remote candidates", this); - pimpl_->is_stopped_ = true; return false; } @@ -972,49 +969,62 @@ IceTransport::start(const Attribute& rem_attrs, const std::vector<IceCandidate>& if (status != PJ_SUCCESS) { pimpl_->last_errmsg_ = sip_utils::sip_strerror(status); JAMI_ERR("[ice:%p] start failed: %s", this, pimpl_->last_errmsg_.c_str()); - pimpl_->is_stopped_ = true; return false; } return true; } bool -IceTransport::start(const SDP& sdp) +IceTransport::start(const std::vector<uint8_t>& rem_data) { - if (not isInitialized()) { - JAMI_ERR("[ice:%p] not initialized transport", this); - pimpl_->is_stopped_ = true; - return false; - } + std::string rem_ufrag; + std::string rem_pwd; + std::vector<IceCandidate> rem_candidates; - JAMI_DBG("[ice:%p] negotiation starting (%zu remote candidates)", this, sdp.candidates.size()); - pj_str_t ufrag, pwd; + auto data = reinterpret_cast<const char*>(rem_data.data()); + auto size = rem_data.size(); - std::vector<IceCandidate> rem_candidates; - rem_candidates.reserve(sdp.candidates.size()); - IceCandidate cand; - for (const auto &line : sdp.candidates) { - if (getCandidateFromSDP(line, cand)) - rem_candidates.emplace_back(cand); + try { + std::size_t offset = 0; + auto result = msgpack::unpack(data, size, offset); + auto version = result.get().as<uint8_t>(); + JAMI_DBG("[ice:%p] rx msg v%u", this, version); + if (version == 1) { + result = msgpack::unpack(data, size, offset); + std::tie(rem_ufrag, rem_pwd) = result.get().as<std::pair<std::string, std::string>>(); + result = msgpack::unpack(data, size, offset); + auto comp_cnt = result.get().as<uint8_t>(); + while (comp_cnt-- > 0) { + result = msgpack::unpack(data, size, offset); + IceCandidate cand; + for (const auto& line : result.get().as<std::vector<std::string>>()) { + if (getCandidateFromSDP(line, cand)) + rem_candidates.emplace_back(cand); + } + } + } else { + JAMI_ERR("[ice:%p] invalid msg version", this); + return false; + } + } catch (const msgpack::unpack_error& e) { + JAMI_ERR("[ice:%p] remote msg unpack error: %s", this, e.what()); + return false; } - auto status = pj_ice_strans_start_ice(pimpl_->icest_.get(), - pj_strset(&ufrag, (char*)sdp.ufrag.c_str(), sdp.ufrag.size()), - pj_strset(&pwd, (char*)sdp.pwd.c_str(), sdp.pwd.size()), - rem_candidates.size(), - rem_candidates.data()); - if (status != PJ_SUCCESS) { - pimpl_->last_errmsg_ = sip_utils::sip_strerror(status); - JAMI_ERR("[ice:%p] start failed: %s", this, pimpl_->last_errmsg_.c_str()); - pimpl_->is_stopped_ = true; + + if (rem_ufrag.empty() or rem_pwd.empty() or rem_candidates.empty()) { + JAMI_ERR("[ice:%p] invalid remote attributes", this); return false; } - return true; + + if (pimpl_->onlyIPv4Private_) + JAMI_WARN("[ice:%p] no public IPv4 found, your connection may fail!", this); + + return start({rem_ufrag, rem_pwd}, rem_candidates); } bool IceTransport::stop() { - pimpl_->is_stopped_ = true; if (isStarted()) { auto status = pj_ice_strans_stop_ice(pimpl_->icest_.get()); if (status != PJ_SUCCESS) { @@ -1129,29 +1139,20 @@ IceTransport::registerPublicIP(unsigned compId, const IpAddr& publicIP) } std::vector<uint8_t> -IceTransport::packIceMsg(uint8_t version) const +IceTransport::packIceMsg() const { + static constexpr uint8_t ICE_MSG_VERSION = 1; + if (not isInitialized()) return {}; std::stringstream ss; - if (version == 1) { - msgpack::pack(ss, version); - msgpack::pack(ss, std::make_pair(pimpl_->local_ufrag_, pimpl_->local_pwd_)); - msgpack::pack(ss, static_cast<uint8_t>(pimpl_->component_count_)); - for (unsigned i=0; i<pimpl_->component_count_; i++) - msgpack::pack(ss, getLocalCandidates(i)); - } else { - SDP sdp; - sdp.ufrag = pimpl_->local_ufrag_; - sdp.pwd = pimpl_->local_pwd_; - for (unsigned i = 0; i < pimpl_->component_count_; i++) { - auto candidates = getLocalCandidates(i); - sdp.candidates.reserve(sdp.candidates.size() + candidates.size()); - sdp.candidates.insert(sdp.candidates.end(), candidates.begin(), candidates.end()); - } - msgpack::pack(ss, sdp); - } + msgpack::pack(ss, ICE_MSG_VERSION); + msgpack::pack(ss, std::make_pair(pimpl_->local_ufrag_, pimpl_->local_pwd_)); + msgpack::pack(ss, static_cast<uint8_t>(pimpl_->component_count_)); + for (unsigned i=0; i<pimpl_->component_count_; i++) + msgpack::pack(ss, getLocalCandidates(i)); + auto str(ss.str()); return std::vector<uint8_t>(str.begin(), str.end()); } @@ -1371,53 +1372,6 @@ IceTransport::waitForData(int comp_id, unsigned int timeout, std::error_code& ec return channel.wait(std::chrono::milliseconds(timeout)); } -std::vector<SDP> -IceTransport::parseSDPList(const std::vector<uint8_t>& msg) -{ - std::vector<SDP> sdp_list; - - msgpack::unpacker pac; - pac.reserve_buffer(msg.size()); - memcpy(pac.buffer(), msg.data(), msg.size()); - pac.buffer_consumed(msg.size()); - msgpack::object_handle oh; - - while (auto result = pac.next(oh)) { - try { - SDP sdp; - if (oh.get().type == msgpack::type::POSITIVE_INTEGER) { - // Version 1 - result = pac.next(oh); - if (!result) break; - std::tie(sdp.ufrag, sdp.pwd) = oh.get().as<std::pair<std::string, std::string>>(); - result = pac.next(oh); - if (!result) break; - auto comp_cnt = oh.get().as<uint8_t>(); - while (comp_cnt-- > 0) { - result = pac.next(oh); - if (!result) break; - auto candidates = oh.get().as<std::vector<std::string>>(); - sdp.candidates.reserve(sdp.candidates.size() + candidates.size()); - sdp.candidates.insert(sdp.candidates.end(), candidates.begin(), candidates.end()); - } - } else { - oh.get().convert(sdp); - } - sdp_list.emplace_back(sdp); - } catch (const msgpack::unpack_error &e) { - break; - } - } - - return sdp_list; -} - -bool -IceTransport::isTCPEnabled() -{ - return pimpl_->config_.protocol == PJ_ICE_TP_TCP; -} - //============================================================================== IceTransportFactory::IceTransportFactory() @@ -1488,7 +1442,6 @@ IceSocketTransport::maxPayload() const int IceSocketTransport::waitForData(unsigned ms_timeout, std::error_code& ec) const { - if (!ice_->isRunning()) return -1; return ice_->waitForData(compId_, ms_timeout, ec); } @@ -1507,21 +1460,13 @@ IceSocketTransport::write(const ValueType* buf, std::size_t len, std::error_code std::size_t IceSocketTransport::read(ValueType* buf, std::size_t len, std::error_code& ec) { - if (!ice_->isRunning()) return 0; - try { - auto res = reliable_ - ? ice_->recvfrom(compId_, reinterpret_cast<char *>(buf), len) - : ice_->recv(compId_, buf, len); - if (res < 0) { - ec.assign(errno, std::generic_category()); - return 0; - } - ec.clear(); - return res; - } catch (const std::exception &e) { - JAMI_ERR("IceSocketTransport::read exception: %s", e.what()); + auto res = ice_->recv(compId_, buf, len); + if (res < 0) { + ec.assign(errno, std::generic_category()); + return 0; } - return 0; + ec.clear(); + return res; } IpAddr diff --git a/src/ice_transport.h b/src/ice_transport.h index 6ab72536c62db36ca359f34f1353924622e12f4f..7e862d0100d2625f32d94288b1fe1a2091a0351f 100644 --- a/src/ice_transport.h +++ b/src/ice_transport.h @@ -29,7 +29,6 @@ #include <functional> #include <memory> -#include <msgpack.hpp> #include <vector> namespace jami { @@ -74,14 +73,6 @@ struct IceTransportOptions { bool aggressive {false}; // If we use the aggressive nomination strategy }; -struct SDP { - std::string ufrag; - std::string pwd; - - std::vector<std::string> candidates; - MSGPACK_DEFINE(ufrag, pwd, candidates) -}; - class IceTransport { public: using Attribute = struct { @@ -94,6 +85,7 @@ public: */ IceTransport(const char* name, int component_count, bool master, const IceTransportOptions& options = {}); + /** * Get current state */ @@ -108,7 +100,7 @@ public: */ bool start(const Attribute& rem_attrs, const std::vector<IceCandidate>& rem_candidates); - bool start(const SDP& sdp); + bool start(const std::vector<uint8_t>& attrs_candidates); /** * Stop a started or completed transport. @@ -133,12 +125,6 @@ public: */ bool isRunning() const; - /** - * Return true if a start operations fails or if stop() has been called - * [mutex protected] - */ - bool isStopped() const; - /** * Returns true if ICE transport is in failure state * [mutex protected] @@ -170,7 +156,7 @@ public: /** * Returns serialized ICE attributes and candidates. */ - std::vector<uint8_t> packIceMsg(uint8_t version = 1) const; + std::vector<uint8_t> packIceMsg() const; bool getCandidateFromSDP(const std::string& line, IceCandidate& cand); @@ -202,15 +188,6 @@ public: bool setSlaveSession(); bool setInitiatorSession(); - /** - * Get SDP messages list - * @param msg The payload to parse - * @return the list of SDP messages - */ - static std::vector<SDP> parseSDPList(const std::vector<uint8_t>& msg); - - bool isTCPEnabled(); - private: class Impl; std::unique_ptr<Impl> pimpl_; diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index dbe4dae4c3a02ef2970d5a0af22958e6f6e5599d..d31fa7aca6a3128f33348f8cd0eca75224439fcf 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -138,7 +138,6 @@ struct JamiAccount::PendingCall { std::chrono::steady_clock::time_point start; std::shared_ptr<IceTransport> ice_sp; - std::shared_ptr<IceTransport> ice_tcp_sp; std::weak_ptr<SIPCall> call; std::future<size_t> listen_key; dht::InfoHash call_key; @@ -412,30 +411,6 @@ JamiAccount::newOutgoingCall(const std::string& toUrl, return call; } -void -initICE(const std::vector<uint8_t> &msg, const std::shared_ptr<IceTransport> &ice, - const std::shared_ptr<IceTransport> &ice_tcp, bool &udp_failed, bool &tcp_failed) -{ - auto sdp_list = IceTransport::parseSDPList(msg); - for (const auto &sdp : sdp_list) { - if (sdp.candidates.size() > 0) { - if (sdp.candidates[0].find("TCP") != std::string::npos) { - // It is a SDP for the TCP component - tcp_failed = (ice_tcp && !ice_tcp->start(sdp)); - } else { - // For UDP - udp_failed = (ice && !ice->start(sdp)); - } - } - } - - // During the ICE reply we can start the ICE negotiation - if (tcp_failed) { - ice_tcp->stop(); - JAMI_WARN("ICE over TCP not started, will only use UDP"); - } -} - void JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std::string& toUri) { @@ -480,21 +455,9 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: return; } - auto ice_config = getIceOptions(); - ice_config.tcpEnable = true; - ice_config.aggressive = true; // This will directly select the first candidate. - auto ice_tcp = -#ifdef _WIN32 - std::shared_ptr<IceTransport>(nullptr); -#else - createIceTransport(("sip:" + dev_call->getCallId()).c_str(), ICE_COMPONENTS, true, ice_config); -#endif - if (not ice_tcp) { - JAMI_WARN("Can't create ICE over TCP, will only use UDP"); - } call->addSubCall(*dev_call); - manager.addTask([sthis=shared(), weak_dev_call, ice, ice_tcp, dev, toUri, peer_account] { + manager.addTask([sthis=shared(), weak_dev_call, ice, dev, toUri, peer_account] { auto call = weak_dev_call.lock(); // call aborted? @@ -507,27 +470,18 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: return false; } - if (ice_tcp && ice_tcp->isFailed()) { - JAMI_WARN("[call:%s] ice tcp init failed, will only use UDP", call->getCallId().c_str()); - } - // Loop until ICE transport is initialized. // Note: we suppose that ICE init routine has a an internal timeout (bounded in time) // and we let upper layers decide when the call shall be aborded (our first check upper). - if ((not ice->isInitialized()) || (ice_tcp && !ice_tcp->isInitialized())) + if (not ice->isInitialized()) return true; sthis->registerDhtAddress(*ice); - if (ice_tcp) sthis->registerDhtAddress(*ice_tcp); + // Next step: sent the ICE data to peer through DHT const dht::Value::Id callvid = ValueIdDist()(sthis->rand); const auto callkey = dht::InfoHash::get("callto:" + dev.toString()); - auto blob = ice->packIceMsg(); - if (ice_tcp) { - auto ice_tcp_msg = ice_tcp->packIceMsg(2); - blob.insert(blob.end(), ice_tcp_msg.begin(), ice_tcp_msg.end()); - } - dht::Value val { dht::IceCandidates(callvid, blob) }; + dht::Value val { dht::IceCandidates(callvid, ice->packIceMsg()) }; sthis->dht_.putEncrypted( callkey, dev, @@ -544,7 +498,7 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: auto listenKey = sthis->dht_.listen<dht::IceCandidates>( callkey, - [weak_dev_call, ice, ice_tcp, callvid, dev] (dht::IceCandidates&& msg) { + [weak_dev_call, ice, callvid, dev] (dht::IceCandidates&& msg) { if (msg.id != callvid or msg.from != dev) return true; // remove unprintable characters @@ -555,10 +509,7 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: JAMI_WARN("ICE request replied from DHT peer %s\nData: %s", dev.toString().c_str(), iceData.c_str()); if (auto call = weak_dev_call.lock()) { call->setState(Call::ConnectionState::PROGRESSING); - - auto udp_failed = true, tcp_failed = true; - initICE(msg.ice_data, ice, ice_tcp, udp_failed, tcp_failed); - if (udp_failed && tcp_failed) { + if (!ice->start(msg.ice_data)) { call->onFailure(); return true; } @@ -570,7 +521,7 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: std::lock_guard<std::mutex> lock(sthis->callsMutex_); sthis->pendingCalls_.emplace_back(PendingCall{ std::chrono::steady_clock::now(), - ice, ice_tcp, weak_dev_call, + ice, weak_dev_call, std::move(listenKey), callkey, dev, @@ -1872,47 +1823,25 @@ bool JamiAccount::handlePendingCall(PendingCall& pc, bool incoming) { auto call = pc.call.lock(); - // Cleanup pending call if call is over (cancelled by user or any other reason) - if (not call || call->getState() == Call::CallState::OVER) + if (not call) return true; - if ((std::chrono::steady_clock::now() - pc.start) >= ICE_NEGOTIATION_TIMEOUT) { - JAMI_WARN("[call:%s] Timeout on ICE negotiation", call->getCallId().c_str()); + auto ice = pc.ice_sp.get(); + if (not ice or ice->isFailed()) { + JAMI_ERR("[call:%s] Null or failed ICE transport", call->getCallId().c_str()); call->onFailure(); return true; } - auto ice_tcp = pc.ice_tcp_sp.get(); - auto ice = pc.ice_sp.get(); - - bool tcp_finished = ice_tcp == nullptr || ice_tcp->isStopped(); - bool udp_finished = ice == nullptr || ice->isStopped(); - - if (not udp_finished and ice->isFailed()) { - udp_finished = true; - } - - if (not tcp_finished and ice_tcp->isFailed()) { - tcp_finished = true; - } - - // At least wait for TCP - if (not tcp_finished and not ice_tcp->isRunning()) { - return false; - } else if (tcp_finished and (not ice_tcp or not ice_tcp->isRunning())) { - // If TCP is finished but not running, wait for UDP - if (not udp_finished and ice and not ice->isRunning()) { - return false; + // Return to pending list if not negotiated yet and not in timeout + if (not ice->isRunning()) { + if ((std::chrono::steady_clock::now() - pc.start) >= ICE_NEGOTIATION_TIMEOUT) { + JAMI_WARN("[call:%s] Timeout on ICE negotiation", call->getCallId().c_str()); + call->onFailure(); + return true; } - } - - udp_finished = ice && ice->isRunning(); - tcp_finished = ice_tcp && ice_tcp->isRunning(); - // If both transport are not running, the negotiation failed - if (not udp_finished and not tcp_finished) { - JAMI_ERR("[call:%s] Both ICE negotations failed", call->getCallId().c_str()); - call->onFailure(); - return true; + // Cleanup pending call if call is over (cancelled by user or any other reason) + return call->getState() == Call::CallState::OVER; } // Securize a SIP transport with TLS (on top of ICE tranport) and assign the call with it @@ -1964,15 +1893,9 @@ JamiAccount::handlePendingCall(PendingCall& pc, bool incoming) } }; - auto best_transport = pc.ice_tcp_sp; - if (!tcp_finished) { - JAMI_DBG("TCP not running, will use SIP over UDP"); - best_transport = pc.ice_sp; - } - // Following can create a transport that need to be negotiated (TLS). // This is a asynchronous task. So we're going to process the SIP after this negotiation. - auto transport = link_->sipTransportBroker->getTlsIceTransport(best_transport, + auto transport = link_->sipTransportBroker->getTlsIceTransport(pc.ice_sp, ICE_COMP_SIP_TRANSPORT, tlsParams); if (!transport) @@ -1987,7 +1910,7 @@ JamiAccount::handlePendingCall(PendingCall& pc, bool incoming) // Be acknowledged on transport connection/disconnection auto lid = reinterpret_cast<uintptr_t>(this); auto remote_id = remote_device.toString(); - auto remote_addr = best_transport->getRemoteAddress(ICE_COMP_SIP_TRANSPORT); + auto remote_addr = ice->getRemoteAddress(ICE_COMP_SIP_TRANSPORT); auto& tr_self = *transport; transport->addStateListener(lid, [&tr_self, lid, wcall, waccount, remote_id, remote_addr](pjsip_transport_state state, @@ -2010,7 +1933,7 @@ JamiAccount::handlePendingCall(PendingCall& pc, bool incoming) call->setState(Call::ConnectionState::PROGRESSING); return true; - } +} bool JamiAccount::mapPortUPnP() @@ -2558,18 +2481,9 @@ JamiAccount::incomingCall(dht::IceCandidates&& msg, const std::shared_ptr<dht::c { auto call = Manager::instance().callFactory.newCall<SIPCall, JamiAccount>(*this, Manager::instance().getNewCallID(), Call::CallType::INCOMING); auto ice = createIceTransport(("sip:"+call->getCallId()).c_str(), ICE_COMPONENTS, false, getIceOptions()); - auto ice_config = getIceOptions(); - ice_config.tcpEnable = true; - ice_config.aggressive = true; // This will directly select the first candidate. - auto ice_tcp = -#ifdef _WIN32 - std::shared_ptr<IceTransport>(nullptr); -#else - createIceTransport(("sip:" + call->getCallId()).c_str(), ICE_COMPONENTS, true, ice_config); -#endif std::weak_ptr<SIPCall> wcall = call; - Manager::instance().addTask([account=shared(), wcall, ice, ice_tcp, msg, from_cert, from] { + Manager::instance().addTask([account=shared(), wcall, ice, msg, from_cert, from] { auto call = wcall.lock(); // call aborted? @@ -2585,10 +2499,10 @@ JamiAccount::incomingCall(dht::IceCandidates&& msg, const std::shared_ptr<dht::c // Loop until ICE transport is initialized. // Note: we suppose that ICE init routine has a an internal timeout (bounded in time) // and we let upper layers decide when the call shall be aborted (our first check upper). - if ((not ice->isInitialized()) || (ice_tcp && !ice_tcp->isInitialized())) + if (not ice->isInitialized()) return true; - account->replyToIncomingIceMsg(call, ice, ice_tcp, msg, from_cert, from); + account->replyToIncomingIceMsg(call, ice, msg, from_cert, from); return false; }); } @@ -2661,7 +2575,6 @@ JamiAccount::foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& cr void JamiAccount::replyToIncomingIceMsg(const std::shared_ptr<SIPCall>& call, const std::shared_ptr<IceTransport>& ice, - const std::shared_ptr<IceTransport>& ice_tcp, const dht::IceCandidates& peer_ice_msg, const std::shared_ptr<dht::crypto::Certificate>& from_cert, const dht::InfoHash& from_id) @@ -2678,20 +2591,13 @@ JamiAccount::replyToIncomingIceMsg(const std::shared_ptr<SIPCall>& call, } }); #endif - registerDhtAddress(*ice); - if (ice_tcp) registerDhtAddress(*ice_tcp); - - auto blob = ice->packIceMsg(); - if (ice_tcp) { - auto ice_tcp_msg = ice_tcp->packIceMsg(2); - blob.insert(blob.end(), ice_tcp_msg.begin(), ice_tcp_msg.end()); - } + registerDhtAddress(*ice); // Asynchronous DHT put of our local ICE data dht_.putEncrypted( callKey_, peer_ice_msg.from, - dht::Value {dht::IceCandidates(peer_ice_msg.id, blob)}, + dht::Value {dht::IceCandidates(peer_ice_msg.id, ice->packIceMsg())}, [wcall](bool ok) { if (!ok) { JAMI_WARN("Can't put ICE descriptor reply on DHT"); @@ -2703,11 +2609,8 @@ JamiAccount::replyToIncomingIceMsg(const std::shared_ptr<SIPCall>& call, auto started_time = std::chrono::steady_clock::now(); - auto sdp_list = IceTransport::parseSDPList(peer_ice_msg.ice_data); - auto udp_failed = true, tcp_failed = true; - initICE(peer_ice_msg.ice_data, ice, ice_tcp, udp_failed, tcp_failed); - - if (udp_failed && tcp_failed) { + // During the ICE reply we can start the ICE negotiation + if (!ice->start(peer_ice_msg.ice_data)) { call->onFailure(EIO); return; } @@ -2717,16 +2620,15 @@ JamiAccount::replyToIncomingIceMsg(const std::shared_ptr<SIPCall>& call, // Let the call handled by the PendingCall handler loop { std::lock_guard<std::mutex> lock(callsMutex_); - pendingCalls_.emplace_back( - PendingCall{/*.start = */ started_time, - /*.ice_sp = */ udp_failed ? nullptr : ice, - /*.ice_tcp_sp = */ tcp_failed ? nullptr : ice_tcp, - /*.call = */ wcall, - /*.listen_key = */ {}, - /*.call_key = */ {}, - /*.from = */ peer_ice_msg.from, - /*.from_account = */ from_id, - /*.from_cert = */ from_cert}); + pendingCalls_.emplace_back(PendingCall { + /*.start = */started_time, + /*.ice_sp = */ice, + /*.call = */wcall, + /*.listen_key = */{}, + /*.call_key = */{}, + /*.from = */peer_ice_msg.from, + /*.from_account = */from_id, + /*.from_cert = */from_cert }); checkPendingCallsTask(); } } diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h index eafc84794a193c21788fe32bb7170184072dabe5..2327a038d75055381126c7ad6740dc36abcd9989 100644 --- a/src/jamidht/jamiaccount.h +++ b/src/jamidht/jamiaccount.h @@ -615,7 +615,6 @@ class JamiAccount : public SIPAccountBase { void saveKnownDevices() const; void replyToIncomingIceMsg(const std::shared_ptr<SIPCall>&, - const std::shared_ptr<IceTransport>&, const std::shared_ptr<IceTransport>&, const dht::IceCandidates&, const std::shared_ptr<dht::crypto::Certificate>& from_cert, diff --git a/src/jamidht/sips_transport_ice.cpp b/src/jamidht/sips_transport_ice.cpp index 1c5af73b2454186e6e5e9deda9e245b090735b3e..963d193c9702f24f7f810c3249088443341d5bfb 100644 --- a/src/jamidht/sips_transport_ice.cpp +++ b/src/jamidht/sips_transport_ice.cpp @@ -236,7 +236,7 @@ SipsIceTransport::SipsIceTransport(pjsip_endpoint* endpt, std::memset(&localCertInfo_, 0, sizeof(pj_ssl_cert_info)); std::memset(&remoteCertInfo_, 0, sizeof(pj_ssl_cert_info)); - iceSocket_ = std::make_unique<IceSocketTransport>(ice_, comp_id, PJSIP_TRANSPORT_IS_RELIABLE(&trData_.base)); + iceSocket_ = std::make_unique<IceSocketTransport>(ice_, comp_id); TlsSession::TlsSessionCallbacks cbs = { /*.onStateChange = */[this](TlsSessionState state){ onTlsStateChange(state); }, @@ -249,22 +249,11 @@ SipsIceTransport::SipsIceTransport(pjsip_endpoint* endpt, if (pjsip_transport_register(base.tpmgr, &base) != PJ_SUCCESS) throw std::runtime_error("Can't register PJSIP transport."); - - if (PJSIP_TRANSPORT_IS_RELIABLE(&trData_.base)) { - eventLoop_ = std::thread([this] { - try { - eventLoop(); - } catch (const std::exception& e) { - JAMI_ERR() << "SipIceTransport: eventLoop() failure: " << e.what(); - } - }); - } } SipsIceTransport::~SipsIceTransport() { JAMI_DBG("~SipIceTransport@%p {tr=%p}", this, &trData_.base); - stopLoop_ = true; // Flush send queue with ENOTCONN error for (auto tdata : txQueue_) { @@ -277,8 +266,6 @@ SipsIceTransport::~SipsIceTransport() auto base = getTransportBase(); // Stop low-level transport first - tls_->shutdown(); - if (eventLoop_.joinable()) eventLoop_.join(); tls_.reset(); // If delete not trigged by pjsip_transport_destroy (happen if objet not given to pjsip) @@ -513,10 +500,7 @@ SipsIceTransport::getInfo(pj_ssl_sock_info* info, bool established) std::memset(info, 0, sizeof(*info)); info->established = established; - if (PJSIP_TRANSPORT_IS_RELIABLE(&trData_.base)) - info->proto = PJSIP_SSL_DEFAULT_PROTO; - else - info->proto = PJ_SSL_SOCK_PROTO_DTLS1; + info->proto = PJ_SSL_SOCK_PROTO_DTLS1; pj_sockaddr_cp(&info->local_addr, local_.pjPtr()); @@ -724,23 +708,4 @@ SipsIceTransport::getTlsSessionMtu() return tls_->maxPayload(); } -void -SipsIceTransport::eventLoop() -{ - while(!stopLoop_) { - std::error_code err; - if (tls_ && tls_->waitForData(100, err)) { - std::vector<uint8_t> pkt; - pkt.resize(PJSIP_MAX_PKT_LEN); - auto read = tls_->read(pkt.data(), PJSIP_MAX_PKT_LEN, err); - if (read > 0) { - pkt.resize(read); - std::lock_guard<std::mutex> l(rxMtx_); - rxPending_.emplace_back(std::move(pkt)); - scheduler_.run([this]{ handleEvents(); }); - } - } - } -} - }} // namespace jami::tls diff --git a/src/jamidht/sips_transport_ice.h b/src/jamidht/sips_transport_ice.h index c5290c8068049ffc8738516d902da1acf902533b..8af70f69690d801a6700a4be667a1cdb3dfc5a58 100644 --- a/src/jamidht/sips_transport_ice.h +++ b/src/jamidht/sips_transport_ice.h @@ -138,10 +138,6 @@ private: void onRxData(std::vector<uint8_t>&&); void onCertificatesUpdate(const gnutls_datum_t*, const gnutls_datum_t*, unsigned int); int verifyCertificate(gnutls_session_t); - - std::thread eventLoop_; - void eventLoop(); - std::atomic_bool stopLoop_ {false}; }; }} // namespace jami::tls diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index ae924ad69a6250f5a99241ec5b964d2f3c383ac5..580ffb73d0f1fa478688b40102de7cd37022063a 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -334,7 +334,7 @@ IceSocketEndpoint::waitForData(unsigned ms_timeout, std::error_code& ec) const { if (ice_) { if (!ice_->isRunning()) return -1; - return iceIsSender ? ice_->isDataAvailable(compId_) : ice_->waitForData(compId_, ms_timeout, ec); + return iceIsSender ? ice_->isDataAvailable(1) : ice_->waitForData(1, ms_timeout, ec); } return -1; } @@ -345,7 +345,7 @@ IceSocketEndpoint::read(ValueType* buf, std::size_t len, std::error_code& ec) if (ice_) { if (!ice_->isRunning()) return 0; try { - auto res = ice_->recvfrom(compId_, reinterpret_cast<char *>(buf), len); + auto res = ice_->recvfrom(1, reinterpret_cast<char *>(buf), len); if (res < 0) ec.assign(errno, std::generic_category()); else @@ -365,7 +365,7 @@ IceSocketEndpoint::write(const ValueType* buf, std::size_t len, std::error_code& if (ice_) { if (!ice_->isRunning()) return 0; auto res = 0; - res = ice_->send(compId_, reinterpret_cast<const unsigned char *>(buf), len); + res = ice_->send(0, reinterpret_cast<const unsigned char *>(buf), len); if (res < 0) { ec.assign(errno, std::generic_category()); } else { diff --git a/src/peer_connection.h b/src/peer_connection.h index 001369437a1fc91014506693208d7fd5e85df288..f14a54d203110342ba149836150486ced4eed709 100644 --- a/src/peer_connection.h +++ b/src/peer_connection.h @@ -157,7 +157,7 @@ public: void setOnRecv(RecvCb&& cb) override { if (ice_) { - ice_->setOnRecv(compId_, cb); + ice_->setOnRecv(0, cb); } } @@ -165,7 +165,6 @@ private: std::shared_ptr<IceTransport> ice_ {nullptr}; std::atomic_bool iceStopped{false}; std::atomic_bool iceIsSender{false}; - uint8_t compId_ {0}; }; //============================================================================== diff --git a/src/security/tls_session.cpp b/src/security/tls_session.cpp index 4ad166f36c622d78d104f9fa8ffa5d8ee7106fd4..cd80be34455b4939a3e3ad3d6a2242611a095d15 100644 --- a/src/security/tls_session.cpp +++ b/src/security/tls_session.cpp @@ -234,7 +234,6 @@ public: std::unique_ptr<TlsAnonymousClientCredendials> cacred_; // ctor init. std::unique_ptr<TlsAnonymousServerCredendials> sacred_; // ctor init. std::unique_ptr<TlsCertificateCredendials> xcred_; // ctor init. - std::mutex sessionMutex_; gnutls_session_t session_ {nullptr}; gnutls_datum_t cookie_key_ {nullptr, 0}; gnutls_dtls_prestate_st prestate_ {}; @@ -725,16 +724,13 @@ TlsSession::TlsSessionImpl::cleanup() state_ = TlsSessionState::SHUTDOWN; // be sure to block any user operations stateCondition_.notify_all(); - { - std::lock_guard<std::mutex> lk(sessionMutex_); - if (session_) { - if (transport_.isReliable()) - gnutls_bye(session_, GNUTLS_SHUT_RDWR); - else - gnutls_bye(session_, GNUTLS_SHUT_WR); // not wait for a peer answer - gnutls_deinit(session_); - session_ = nullptr; - } + if (session_) { + if (transport_.isReliable()) + gnutls_bye(session_, GNUTLS_SHUT_RDWR); + else + gnutls_bye(session_, GNUTLS_SHUT_WR); // not wait for a peer answer + gnutls_deinit(session_); + session_ = nullptr; } if (cookie_key_.data) @@ -1222,7 +1218,7 @@ TlsSession::TlsSession(SocketType& transport, const TlsParams& params, TlsSession::~TlsSession() { - if (pimpl_) shutdown(); + shutdown(); } bool @@ -1241,8 +1237,8 @@ int TlsSession::maxPayload() const { if (pimpl_->state_ == TlsSessionState::SHUTDOWN) - throw std::runtime_error("Getting maxPayload from non-valid TLS session"); - return pimpl_->transport_.maxPayload(); + throw std::runtime_error("Getting MTU from non-valid TLS session"); + return gnutls_dtls_get_data_mtu(pimpl_->session_); } const char* @@ -1299,22 +1295,15 @@ TlsSession::read(ValueType* data, std::size_t size, std::error_code& ec) } while (true) { - ssize_t ret; - { - std::lock_guard<std::mutex> lk(pimpl_->sessionMutex_); - if (!pimpl_->session_) return 0; - ret = gnutls_record_recv(pimpl_->session_, data, size); - } + auto ret = gnutls_record_recv(pimpl_->session_, data, size); if (ret > 0) { ec.clear(); return ret; } if (ret == 0) { - if (pimpl_) { - JAMI_ERR("[TLS] eof"); - shutdown(); - } + JAMI_DBG("[TLS] eof"); + shutdown(); error = std::errc::broken_pipe; break; } else if (ret == GNUTLS_E_REHANDSHAKE) { @@ -1323,10 +1312,8 @@ TlsSession::read(ValueType* data, std::size_t size, std::error_code& ec) pimpl_->rxCv_.notify_one(); // unblock waiting FSM pimpl_->stateCondition_.notify_all(); } else if (gnutls_error_is_fatal(ret)) { - if (pimpl_ && pimpl_->state_ != TlsSessionState::SHUTDOWN) { - JAMI_ERR("[TLS] fatal error in recv: %s", gnutls_strerror(ret)); - shutdown(); - } + JAMI_ERR("[TLS] fatal error in recv: %s", gnutls_strerror(ret)); + shutdown(); error = std::errc::io_error; break; } diff --git a/src/sip/siptransport.cpp b/src/sip/siptransport.cpp index 049fab02e8e3448361859a0a35094d3a2c126f0e..bfa574484adde8faa0346c959cea255ee294d734 100644 --- a/src/sip/siptransport.cpp +++ b/src/sip/siptransport.cpp @@ -440,9 +440,6 @@ SipTransportBroker::getTlsIceTransport(const std::shared_ptr<jami::IceTransport> { auto ipv6 = ice->getLocalAddress(comp_id).isIpv6(); auto type = ipv6 ? PJSIP_TRANSPORT_DTLS6 : PJSIP_TRANSPORT_DTLS; - if (ice->isTCPEnabled()) { - type = ipv6 ? PJSIP_TRANSPORT_TLS6 : PJSIP_TRANSPORT_TLS; - } auto sip_ice_tr = std::unique_ptr<tls::SipsIceTransport>( new tls::SipsIceTransport(endpt_, type, params, ice, comp_id)); auto tr = sip_ice_tr->getTransportBase();