diff --git a/contrib/src/pjproject/fetch_and_patch.bat b/contrib/src/pjproject/fetch_and_patch.bat index dc3aa889f03bb8eaaf416ae376d778469a384a23..bc7e19b12a0f1c4e3806ed23248427b32d286033 100644 --- a/contrib/src/pjproject/fetch_and_patch.bat +++ b/contrib/src/pjproject/fetch_and_patch.bat @@ -36,6 +36,7 @@ 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/fix_first_packet_turn_tcp.patch" +bash -c "%PATCH_CMD% %UNIXPATH%pjproject/fix_ebusy_turn.patch" %APPLY_CMD% %SRC%\pjproject\win32_vs_gnutls.patch %APPLY_CMD% %SRC%\pjproject\win_config.patch diff --git a/contrib/src/pjproject/fix_ebusy_turn.patch b/contrib/src/pjproject/fix_ebusy_turn.patch new file mode 100644 index 0000000000000000000000000000000000000000..cde32247c443ba80825b9b12dddcdd0bae8085c4 --- /dev/null +++ b/contrib/src/pjproject/fix_ebusy_turn.patch @@ -0,0 +1,435 @@ + pjnath/include/pjnath/turn_session.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + pjnath/include/pjnath/turn_sock.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ + pjnath/src/pjnath/ice_strans.c | 14 ++++++++------ + pjnath/src/pjnath/turn_session.c | 22 +++++++++++++++++----- + pjnath/src/pjnath/turn_sock.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 5 files changed, 228 insertions(+), 12 deletions(-) + +diff --git a/pjnath/include/pjnath/turn_session.h b/pjnath/include/pjnath/turn_session.h +index 9984c1f57..890d70c90 100644 +--- a/pjnath/include/pjnath/turn_session.h ++++ b/pjnath/include/pjnath/turn_session.h +@@ -250,6 +250,35 @@ typedef struct pj_turn_session_cb + const pj_sockaddr_t *dst_addr, + unsigned addr_len); + ++ /** ++ * This callback will be called by the TURN session whenever it ++ * needs to send outgoing message. Since the TURN session doesn't ++ * have a socket on its own, this callback must be implemented. ++ * ++ * The difference with on_send_pkt is that this function returns ++ * the size of the packet actually sent to predict when a busy will ++ * occurs. Indeed, activesock send the data asynchronously. When the ++ * data are actually sent, on_data_sent will be triggered. ++ * ++ * @param sess The TURN session. ++ * @param pkt The packet/data to be sent. ++ * @param pkt_len Length of the packet/data. ++ * @param dst_addr Destination address of the packet. ++ * @param addr_len Length of the destination address. ++ * @param send_size Length sent. ++ * @param original_size The length of the packet without the HEADER ++ * ++ * @return The callback should return the status of the ++ * send operation. ++ */ ++ pj_status_t (*on_send_pkt2)(pj_turn_session *sess, ++ const pj_uint8_t *pkt, ++ unsigned pkt_len, ++ const pj_sockaddr_t *dst_addr, ++ unsigned addr_len, ++ unsigned* sent_size, ++ unsigned original_size); ++ + /** + * Notification when peer address has been bound successfully to + * a channel number. +@@ -770,6 +799,42 @@ PJ_DECL(pj_status_t) pj_turn_session_sendto(pj_turn_session *sess, + const pj_sockaddr_t *peer_addr, + unsigned addr_len); + ++/** ++ * Send a data to the specified peer address via the TURN relay. This ++ * function will encapsulate the data as STUN Send Indication or TURN ++ * ChannelData packet and send the message to the TURN server. The TURN ++ * server then will send the data to the peer. ++ * ++ * The allocation (pj_turn_session_alloc()) must have been successfully ++ * created before application can relay any data. ++ * ++ * Since TURN session is transport independent, this function will ++ * ultimately call \a on_send_pkt() callback to request the application ++ * to actually send the packet containing the data to the TURN server. ++ * ++ * The difference with pj_turn_session_sendto is that this function returns ++ * the size of the packet actually sent to predict when a busy will ++ * occurs. Indeed, activesock send the data asynchronously. When the ++ * data are actually sent, on_data_sent will be triggered. ++ * ++ * @param sess The TURN client session. ++ * @param pkt The data/packet to be sent to peer. ++ * @param pkt_len Length of the data. ++ * @param peer_addr The remote peer address (the ultimate destination ++ * of the data, and not the TURN server address). ++ * @param addr_len Length of the address. ++ * @param sent The size of the packet actually sent ++ * ++ * @return PJ_SUCCESS if the operation has been successful, ++ * or the appropriate error code on failure. ++ */ ++PJ_DECL(pj_status_t) pj_turn_session_sendto2(pj_turn_session *sess, ++ const pj_uint8_t *pkt, ++ unsigned pkt_len, ++ const pj_sockaddr_t *peer_addr, ++ unsigned addr_len, ++ unsigned *sent); ++ + /** + * Optionally establish channel binding for the specified a peer address. + * This function will assign a unique channel number for the peer address +diff --git a/pjnath/include/pjnath/turn_sock.h b/pjnath/include/pjnath/turn_sock.h +index 99570ac25..f86682c35 100644 +--- a/pjnath/include/pjnath/turn_sock.h ++++ b/pjnath/include/pjnath/turn_sock.h +@@ -86,6 +86,23 @@ typedef struct pj_turn_sock_cb + const pj_sockaddr_t *peer_addr, + unsigned addr_len); + ++ /** ++ * Notifification when asynchronous send operation has completed. ++ * ++ * @param turn_sock The TURN transport. ++ * @param sent If value is positive non-zero it indicates the ++ * number of data sent. When the value is negative, ++ * it contains the error code which can be retrieved ++ * by negating the value (i.e. status=-sent). ++ * ++ * @return Application should normally return PJ_TRUE to let ++ * the STUN transport continue its operation. However ++ * it must return PJ_FALSE if it has destroyed the ++ * STUN transport in this callback. ++ */ ++ pj_bool_t (*on_data_sent)(pj_turn_sock *sock, ++ pj_ssize_t sent); ++ + /** + * Notification when TURN session state has changed. Application should + * implement this callback to monitor the progress of the TURN session. +@@ -469,6 +486,33 @@ PJ_DECL(pj_status_t) pj_turn_sock_sendto(pj_turn_sock *turn_sock, + const pj_sockaddr_t *peer_addr, + unsigned addr_len); + ++/** ++ * Send a data to the specified peer address via the TURN relay. This ++ * function will encapsulate the data as STUN Send Indication or TURN ++ * ChannelData packet and send the message to the TURN server. The TURN ++ * server then will send the data to the peer. ++ * ++ * The allocation (pj_turn_sock_alloc()) must have been successfully ++ * created before application can relay any data. ++ * ++ * @param turn_sock The TURN transport instance. ++ * @param pkt The data/packet to be sent to peer. ++ * @param pkt_len Length of the data. ++ * @param peer_addr The remote peer address (the ultimate destination ++ * of the data, and not the TURN server address). ++ * @param addr_len Length of the address. ++ * @param sent Size actually sent. ++ * ++ * @return PJ_SUCCESS if the operation has been successful, ++ * or the appropriate error code on failure. ++ */ ++PJ_DECL(pj_status_t) pj_turn_sock_sendto2(pj_turn_sock *turn_sock, ++ const pj_uint8_t *pkt, ++ unsigned pkt_len, ++ const pj_sockaddr_t *peer_addr, ++ unsigned addr_len, ++ unsigned* sent); ++ + /** + * Optionally establish channel binding for the specified a peer address. + * This function will assign a unique channel number for the peer address +diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c +index d048adfd6..11992ac44 100644 +--- a/pjnath/src/pjnath/ice_strans.c ++++ b/pjnath/src/pjnath/ice_strans.c +@@ -391,6 +391,7 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st, + pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb)); + turn_sock_cb.on_rx_data = &turn_on_rx_data; + turn_sock_cb.on_state = &turn_on_state; ++ turn_sock_cb.on_data_sent = &turn_on_data_sent; + + /* Override with component specific QoS settings, if any */ + if (ice_st->cfg.comp[comp_idx].qos_type) +@@ -1654,9 +1655,9 @@ pj_ice_strans_sendto2(pj_ice_strans *ice_st, unsigned comp_id, const void *data, + 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_sendto2(comp->turn[tp_idx].sock, final_pkt, ++ final_len, dst_addr, dst_addr_len, size); ++ ice_st->is_pending = ((status == PJ_EPENDING || *size != data_len) && ice_st); + } else { + const pj_sockaddr_t *dest_addr; + unsigned dest_addr_len; +@@ -1860,9 +1861,10 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, + + 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; ++ status = pj_turn_sock_sendto2(comp->turn[tp_idx].sock, ++ final_pkt, final_len, dst_addr, dst_addr_len, &sent_size); ++ ice_st->is_pending = (status == PJ_EPENDING || (unsigned)sent_size != final_len); ++ + } else { + status = PJ_EINVALIDOP; + } +diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c +index 1c0430bc7..773427c82 100644 +--- a/pjnath/src/pjnath/turn_session.c ++++ b/pjnath/src/pjnath/turn_session.c +@@ -975,6 +975,18 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess, + unsigned pkt_len, + const pj_sockaddr_t *addr, + unsigned addr_len) ++{ ++ unsigned sent; ++ return pj_turn_session_sendto2(sess, pkt, pkt_len, addr, addr_len, &sent); ++} ++ ++ ++PJ_DEF(pj_status_t) pj_turn_session_sendto2( pj_turn_session *sess, ++ const pj_uint8_t *pkt, ++ unsigned pkt_len, ++ const pj_sockaddr_t *addr, ++ unsigned addr_len, ++ unsigned *sent) + { + struct ch_t *ch; + struct perm_t *perm; +@@ -1011,7 +1023,7 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess, + + /* If peer connection is TCP (RFC 6062), send it directly */ + if (sess->alloc_param.peer_conn_type == PJ_TURN_TP_TCP) { +- status = sess->cb.on_send_pkt(sess, pkt, pkt_len, addr, addr_len); ++ status = sess->cb.on_send_pkt2(sess, pkt, pkt_len, addr, addr_len, sent, pkt_len); + goto on_return; + } + +@@ -1039,9 +1051,9 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess, + + pj_assert(sess->srv_addr != NULL); + +- status = sess->cb.on_send_pkt(sess, sess->tx_pkt, total_len, ++ status = sess->cb.on_send_pkt2(sess, sess->tx_pkt, total_len, + sess->srv_addr, +- pj_sockaddr_get_len(sess->srv_addr)); ++ pj_sockaddr_get_len(sess->srv_addr), sent, pkt_len); + + } else { + /* Use Send Indication. */ +@@ -1079,10 +1091,10 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess, + goto on_return; + + /* Send the Send Indication */ +- status = sess->cb.on_send_pkt(sess, sess->tx_pkt, ++ status = sess->cb.on_send_pkt2(sess, sess->tx_pkt, + (unsigned)send_ind_len, + sess->srv_addr, +- pj_sockaddr_get_len(sess->srv_addr)); ++ pj_sockaddr_get_len(sess->srv_addr), sent, pkt_len); + } + + on_return: +diff --git a/pjnath/src/pjnath/turn_sock.c b/pjnath/src/pjnath/turn_sock.c +index 7033fd939..1a0890942 100644 +--- a/pjnath/src/pjnath/turn_sock.c ++++ b/pjnath/src/pjnath/turn_sock.c +@@ -89,6 +89,10 @@ struct pj_turn_sock + /* Data connection, when peer_conn_type==PJ_TURN_TP_TCP (RFC 6062) */ + unsigned data_conn_cnt; + tcp_data_conn_t data_conn[PJ_TURN_MAX_TCP_CONN_CNT]; ++ ++ // The following variables are used by the on_data_sent callback ++ unsigned current_pkt_len; ++ unsigned current_body_len; + }; + + +@@ -100,6 +104,13 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess, + unsigned pkt_len, + const pj_sockaddr_t *dst_addr, + unsigned dst_addr_len); ++static pj_status_t turn_on_send_pkt2(pj_turn_session *sess, ++ const pj_uint8_t *pkt, ++ unsigned pkt_len, ++ const pj_sockaddr_t *dst_addr, ++ unsigned dst_addr_len, ++ unsigned *sent, ++ unsigned body_len); + static void turn_on_channel_bound(pj_turn_session *sess, + const pj_sockaddr_t *peer_addr, + unsigned addr_len, +@@ -127,6 +138,9 @@ static pj_bool_t on_data_read(pj_activesock_t *asock, + pj_size_t size, + pj_status_t status, + pj_size_t *remainder); ++static pj_bool_t on_data_sent(pj_activesock_t *asock, ++ pj_ioqueue_op_key_t *send_key, ++ pj_ssize_t sent); + static pj_bool_t on_connect_complete(pj_activesock_t *asock, + pj_status_t status); + +@@ -135,6 +149,9 @@ static pj_bool_t dataconn_on_data_read(pj_activesock_t *asock, + pj_size_t size, + pj_status_t status, + pj_size_t *remainder); ++static pj_bool_t dataconn_on_data_sent(pj_activesock_t *asock, ++ pj_ioqueue_op_key_t *send_key, ++ pj_ssize_t sent); + static pj_bool_t dataconn_on_connect_complete(pj_activesock_t *asock, + pj_status_t status); + static void dataconn_cleanup(tcp_data_conn_t *conn); +@@ -236,6 +253,7 @@ PJ_DEF(pj_status_t) pj_turn_sock_create(pj_stun_config *cfg, + /* Init TURN session */ + pj_bzero(&sess_cb, sizeof(sess_cb)); + sess_cb.on_send_pkt = &turn_on_send_pkt; ++ sess_cb.on_send_pkt2 = &turn_on_send_pkt2; + sess_cb.on_channel_bound = &turn_on_channel_bound; + sess_cb.on_rx_data = &turn_on_rx_data; + sess_cb.on_state = &turn_on_state; +@@ -531,6 +549,22 @@ PJ_DEF(pj_status_t) pj_turn_sock_sendto( pj_turn_sock *turn_sock, + addr, addr_len); + } + ++PJ_DEF(pj_status_t) pj_turn_sock_sendto2( pj_turn_sock *turn_sock, ++ const pj_uint8_t *pkt, ++ unsigned pkt_len, ++ const pj_sockaddr_t *addr, ++ unsigned addr_len, ++ unsigned *sent) ++{ ++ PJ_ASSERT_RETURN(turn_sock && addr && addr_len, PJ_EINVAL); ++ ++ if (turn_sock->sess == NULL) ++ return PJ_EINVALIDOP; ++ ++ return pj_turn_session_sendto2(turn_sock->sess, pkt, pkt_len, ++ addr, addr_len, sent); ++} ++ + /* + * Bind a peer address to a channel number. + */ +@@ -710,6 +744,22 @@ on_return: + return ret; + } + ++pj_bool_t on_data_sent(pj_activesock_t *asock, ++ pj_ioqueue_op_key_t *send_key, ++ pj_ssize_t sent) ++{ ++ pj_turn_sock *turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock); ++ ++ unsigned header_len = turn_sock->current_pkt_len - turn_sock->current_body_len; ++ unsigned sent_size = (sent > header_len)? (sent - header_len) : 0; ++ ++ if (turn_sock->cb.on_data_sent) { ++ (*turn_sock->cb.on_data_sent)(turn_sock, sent_size); ++ } ++ ++ return PJ_TRUE; ++} ++ + + /* + * Callback from TURN session to send outgoing packet. +@@ -720,11 +770,28 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess, + const pj_sockaddr_t *dst_addr, + unsigned dst_addr_len) + { ++ unsigned sent = pkt_len; ++ return turn_on_send_pkt2(sess, pkt, pkt_len, dst_addr, dst_addr_len, &sent, pkt_len); ++} ++ ++ ++static pj_status_t turn_on_send_pkt2(pj_turn_session *sess, ++ const pj_uint8_t *pkt, ++ unsigned pkt_len, ++ const pj_sockaddr_t *dst_addr, ++ unsigned dst_addr_len, ++ unsigned *sent, ++ unsigned body_len) ++{ ++ *sent = pkt_len; + pj_turn_sock *turn_sock = (pj_turn_sock*) + pj_turn_session_get_user_data(sess); +- pj_ssize_t len = pkt_len; + pj_status_t status = PJ_SUCCESS; + ++ pj_ssize_t len = pkt_len; ++ turn_sock->current_body_len = body_len; ++ turn_sock->current_pkt_len = pkt_len; ++ + if (turn_sock == NULL || turn_sock->is_destroying) { + /* We've been destroyed */ + // https://trac.pjsip.org/repos/ticket/1316 +@@ -769,6 +836,11 @@ static pj_status_t turn_on_send_pkt(pj_turn_session *sess, + show_err(turn_sock, "socket send()", status); + } + ++ // Remove header from sent size. ++ // The application only wants to know if the packet is actually sent. ++ unsigned header_len = pkt_len - body_len; ++ *sent = (len > header_len)? (len - header_len) : 0; ++ + return status; + } + +@@ -960,6 +1032,7 @@ static void turn_on_state(pj_turn_session *sess, + + pj_bzero(&asock_cb, sizeof(asock_cb)); + asock_cb.on_data_read = &on_data_read; ++ asock_cb.on_data_sent = &on_data_sent; + asock_cb.on_connect_complete = &on_connect_complete; + status = pj_activesock_create(turn_sock->pool, sock, + sock_type, &asock_cfg, +@@ -1090,6 +1163,25 @@ on_return: + return PJ_TRUE; + } + ++pj_bool_t dataconn_on_data_sent(pj_activesock_t *asock, ++ pj_ioqueue_op_key_t *send_key, ++ pj_ssize_t sent) ++{ ++ tcp_data_conn_t *conn = (tcp_data_conn_t*) ++ pj_activesock_get_user_data(asock); ++ pj_turn_sock *turn_sock = conn->turn_sock; ++ ++ unsigned header_len = turn_sock->current_pkt_len - turn_sock->current_body_len; ++ unsigned sent_size = (sent > header_len)? (sent - header_len) : 0; ++ ++ if (turn_sock->cb.on_data_sent) { ++ (*turn_sock->cb.on_data_sent)(turn_sock, sent_size); ++ } ++ ++ return PJ_TRUE; ++} ++ ++ + static pj_bool_t dataconn_on_connect_complete(pj_activesock_t *asock, + pj_status_t status) + { +@@ -1268,6 +1360,7 @@ static void turn_on_connection_attempt(pj_turn_session *sess, + + pj_bzero(&asock_cb, sizeof(asock_cb)); + asock_cb.on_data_read = &dataconn_on_data_read; ++ asock_cb.on_data_sent = &dataconn_on_data_sent; + asock_cb.on_connect_complete = &dataconn_on_connect_complete; + status = pj_activesock_create(pool, sock, + pj_SOCK_STREAM(), &asock_cfg, diff --git a/contrib/src/pjproject/rules.mak b/contrib/src/pjproject/rules.mak index b37cc90a7a08e1ef1001fdef7535b5fa762e11e2..6a42353c6d85ac9ce1eed67886b8f283975390d5 100644 --- a/contrib/src/pjproject/rules.mak +++ b/contrib/src/pjproject/rules.mak @@ -65,6 +65,7 @@ endif $(APPLY) $(SRC)/pjproject/ice_config.patch $(APPLY) $(SRC)/pjproject/sip_config.patch $(APPLY) $(SRC)/pjproject/fix_first_packet_turn_tcp.patch + $(APPLY) $(SRC)/pjproject/fix_ebusy_turn.patch $(UPDATE_AUTOCONFIG) $(MOVE) diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h index eafc84794a193c21788fe32bb7170184072dabe5..19148a60431b4ad134503c567bd817956a726042 100644 --- a/src/jamidht/jamiaccount.h +++ b/src/jamidht/jamiaccount.h @@ -404,6 +404,11 @@ class JamiAccount : public SIPAccountBase { */ std::map<std::string, std::string> getNearbyPeers() const override; + /** + * Add public addresses to ice transport + */ + void registerDhtAddress(IceTransport&); + private: NON_COPYABLE(JamiAccount); @@ -694,7 +699,6 @@ class JamiAccount : public SIPAccountBase { template <class... Args> std::shared_ptr<IceTransport> createIceTransport(const Args&... args); - void registerDhtAddress(IceTransport&); std::unique_ptr<DhtPeerConnector> dhtPeerConnector_; diff --git a/src/jamidht/p2p.cpp b/src/jamidht/p2p.cpp index 6041f4ba1838830f1d22856c18831c7ab699d353..8d392d06208ba9f49dc04d2aa016cca81cfa1910 100644 --- a/src/jamidht/p2p.cpp +++ b/src/jamidht/p2p.cpp @@ -247,6 +247,13 @@ public: return res; } + bool hasPublicIp(const ICESDP& sdp) { + for (const auto& cand: sdp.rem_candidates) + if (cand.type == PJ_ICE_CAND_TYPE_SRFLX) + return true; + return false; + } + private: std::map<IpAddr, std::unique_ptr<ConnectedTurnTransport>> turnEndpoints_; std::map<std::pair<dht::InfoHash, IpAddr>, std::unique_ptr<AbstractSocketEndpoint>> p2pEndpoints_; @@ -326,6 +333,7 @@ public: for (auto& cb: listeners_) cb(nullptr); connection_.reset(); + } bool hasAlreadyAResponse() { @@ -369,6 +377,8 @@ private: return; } + parent_.account.registerDhtAddress(*parent_.ice_); + auto iceAttributes = parent_.ice_->getLocalAttributes(); std::stringstream icemsg; icemsg << iceAttributes.ufrag << "\n"; @@ -411,8 +421,10 @@ private: // Should be ICE SDP // P2P File transfer. We received an ice SDP message: auto sdp = parent_.parse_SDP(address); - - parent_.ice_->setInitiatorSession(); + // NOTE: hasPubIp is used for compability (because ICE is waiting for a certain state in old versions) + // This can be removed when old versions will be unsupported. + auto hasPubIp = parent_.hasPublicIp(sdp); + if (!hasPubIp) parent_.ice_->setInitiatorSession(); if (not parent_.ice_->start({sdp.rem_ufrag, sdp.rem_pwd}, sdp.rem_candidates)) { JAMI_WARN("[Account:%s] start ICE failed - fallback to TURN", @@ -425,6 +437,7 @@ private: peer_ep = std::make_shared<IceSocketEndpoint>(parent_.ice_, true); JAMI_DBG("[Account:%s] ICE negotiation succeed. Starting file transfer", parent_.account.getAccountID().c_str()); + if (hasPubIp) parent_.ice_->setInitiatorSession(); break; } else { JAMI_ERR("[Account:%s] ICE negotation failed", @@ -682,7 +695,7 @@ DhtPeerConnector::Impl::answerToRequest(PeerConnectionMsg&& request, // Save peer certificate for later TLS session (MUST BE DONE BEFORE TURN PEER AUTHORIZATION) certMap_.emplace(cert->getId(), std::make_pair(cert, peer_h)); - auto sendRelayV4 = false, sendRelayV6 = false, sendIce = false; + auto sendRelayV4 = false, sendRelayV6 = false, sendIce = false, hasPubIp = false; std::shared_ptr<bool> iceReady = std::make_shared<bool>(false); std::shared_ptr<std::condition_variable> cv = @@ -717,20 +730,28 @@ DhtPeerConnector::Impl::answerToRequest(PeerConnectionMsg&& request, continue; } + account.registerDhtAddress(*ice_); + auto sdp = parse_SDP(ip); + // NOTE: hasPubIp is used for compability (because ICE is waiting for a certain state in old versions) + // This can be removed when old versions will be unsupported (version before this patch) + hasPubIp = hasPublicIp(sdp); if (not ice_->start({sdp.rem_ufrag, sdp.rem_pwd}, sdp.rem_candidates)) { - JAMI_WARN("[Account:%s] start ICE failed - fallback to TURN", - account.getAccountID().c_str()); - continue; + JAMI_WARN("[Account:%s] start ICE failed - fallback to TURN", + account.getAccountID().c_str()); + continue; } - ice_->waitForNegotiation(10); - if (ice_->isRunning()) { - sendIce = true; - JAMI_DBG("[Account:%s] ICE negotiation succeed. Answering with local SDP", account.getAccountID().c_str()); - } else { - JAMI_WARN("[Account:%s] ICE negotation failed", account.getAccountID().c_str()); - } + if (!hasPubIp) { + ice_->waitForNegotiation(10); + if (ice_->isRunning()) { + sendIce = true; + JAMI_DBG("[Account:%s] ICE negotiation succeed. Answering with local SDP", account.getAccountID().c_str()); + } else { + JAMI_WARN("[Account:%s] ICE negotation failed", account.getAccountID().c_str()); + } + } else + sendIce = true; // Ice started with success, we can use it. } } catch (const std::exception& e) { JAMI_WARN() << account << "[CNX] ignored peer connection '" << ip << "', " << e.what(); @@ -773,18 +794,32 @@ DhtPeerConnector::Impl::answerToRequest(PeerConnectionMsg&& request, if (sendIce) { + if (hasPubIp) { + ice_->waitForNegotiation(10); + if (ice_->isRunning()) { + JAMI_DBG("[Account:%s] ICE negotiation succeed. Answering with local SDP", account.getAccountID().c_str()); + } else { + JAMI_WARN("[Account:%s] ICE negotation failed - Fallbacking to TURN", account.getAccountID().c_str()); + return; // wait for onTurnPeerConnection + } + } + std::mutex mtx; std::unique_lock<std::mutex> lk{mtx}; - ice_->setSlaveSession(); - cv->wait_for(lk, ICE_READY_TIMEOUT); if (!*iceReady) { - // This will fallback on TURN if ICE is not ready - return; + if (!hasPubIp) ice_->setSlaveSession(); + cv->wait_for(lk, ICE_READY_TIMEOUT); + if (!*iceReady) { + // This will fallback on TURN if ICE is not ready + return; + } } + std::unique_ptr<AbstractSocketEndpoint> peer_ep = std::make_unique<IceSocketEndpoint>(ice_, false); JAMI_DBG() << account << "[CNX] start TLS session"; auto ph = peer_h; + if (hasPubIp) ice_->setSlaveSession(); auto tls_ep = std::make_unique<TlsSocketEndpoint>( *peer_ep, account.identity(), account.dhParams(), [&, this](const dht::crypto::Certificate &cert) { diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index ae924ad69a6250f5a99241ec5b964d2f3c383ac5..a6cc488aa019597beb4d590c8355178c5f4cc0b0 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -316,15 +316,16 @@ IceSocketEndpoint::IceSocketEndpoint(std::shared_ptr<IceTransport> ice, bool isS IceSocketEndpoint::~IceSocketEndpoint() { - if (ice_) { - ice_->stop(); - return; - } + shutdown(); } void IceSocketEndpoint::shutdown() { if (ice_) { + // Sometimes the other peer never send any packet + // So, we cancel pending read to avoid to have + // any blocking operation. + ice_->cancelOperations(); ice_->stop(); } } @@ -496,7 +497,14 @@ TlsSocketEndpoint::TlsSocketEndpoint(AbstractSocketEndpoint& tr, } -TlsSocketEndpoint::~TlsSocketEndpoint() = default; +TlsSocketEndpoint::~TlsSocketEndpoint() { + shutdown(); +} + +void +TlsSocketEndpoint::shutdown() { + pimpl_->tr.shutdown(); +} bool TlsSocketEndpoint::isInitiator() const diff --git a/src/peer_connection.h b/src/peer_connection.h index 001369437a1fc91014506693208d7fd5e85df288..30698d6c7e2fa32a3fc0d4d1085f9fa99d7e78ae 100644 --- a/src/peer_connection.h +++ b/src/peer_connection.h @@ -188,6 +188,7 @@ public: std::function<bool(const dht::crypto::Certificate&)>&& cert_check); ~TlsSocketEndpoint(); + void shutdown() override; bool isReliable() const override { return true; } bool isInitiator() const override; int maxPayload() const override;