diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp index b0af4ac9c35a18ca370c96ee6b1e0cc0624b104a..4ecdbcce67782de2d2919d39702fe394c431ddbc 100644 --- a/src/ice_transport.cpp +++ b/src/ice_transport.cpp @@ -634,10 +634,6 @@ IceTransport::registerPublicIP(unsigned compId, const IpAddr& publicIP) if (not isInitialized()) return false; - // Register only if no NAT traversal methods exists - if (upnp_ or config_.stun.port > 0 or config_.turn.port > 0) - return false; - // Find the local candidate corresponding to local host, // then register a rflx candidate using given public address // and this local address as base. It's port is used for both address @@ -661,13 +657,54 @@ IceTransport::registerPublicIP(unsigned compId, const IpAddr& publicIP) void IceTransport::addReflectiveCandidate(int comp_id, const IpAddr& base, const IpAddr& addr) { + // HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK + // WARNING: following implementation is a HACK of PJNATH !! + // ice_strans doesn't have any API that permit to inject ICE any kind of candidates. + // So, the hack consists in accessing hidden ICE session using a patched PJPNATH + // library with a new API exposing this session (pj_ice_strans_get_ice_sess). + // Then call pj_ice_sess_add_cand() with a carfully forged candidate: + // the transport_id field uses an index in ICE transport STUN servers array + // corresponding to a STUN server with the same address familly. + // This implies we hope they'll not be modification of transport_id meaning in future + // and no conflics with the borrowed STUN config. + // HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK-HACK + + // borrowed from pjproject/pjnath/ice_strans.c, modified to be C++11'ized. + static auto CREATE_TP_ID = [](pj_uint8_t type, pj_uint8_t idx) { + return (pj_uint8_t)((type << 6) | idx); + }; + static constexpr int SRFLX_PREF = 65535; + static constexpr int TP_STUN = 1; + + // find a compatible STUN host with same address familly, normally all system enabled + // host addresses are represented, so we expect to always found this host + int idx = -1; + auto af = addr.getFamily(); + if (af == AF_UNSPEC) { + RING_ERR("[ice] Unable to add reflective IP %s: unknown addess familly", + addr.toString().c_str()); + return; + } + + for (unsigned i=0; i < config_.stun_tp_cnt; ++i) { + if (config_.stun_tp[i].af == af) { + idx = i; + break; + } + } + if (idx < 0) { + RING_ERR("[ice] Unable to add reflective IP %s: no suitable local STUN host found", + addr.toString().c_str()); + return; + } + pj_ice_sess_cand cand; cand.type = PJ_ICE_CAND_TYPE_SRFLX; - cand.status = PJ_EPENDING; /* not used */ + cand.status = PJ_EPENDING; // not used cand.comp_id = comp_id; - cand.transport_id = 1; /* 1 = STUN */ - cand.local_pref = 65535; /* host */ + cand.transport_id = CREATE_TP_ID(TP_STUN, idx); // HACK!! + cand.local_pref = SRFLX_PREF; // reflective /* cand.foundation = ? */ /* cand.prio = calculated by ice session */ /* make base and addr the same since we're not going through a server */