diff --git a/src/account.cpp b/src/account.cpp index 5ed2b5c8197bd8be660b0832d7305af6f7920bbe..a9a123ebdbb3043a9ebc659bc1446a91118c523a 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -52,6 +52,7 @@ #include "string_utils.h" #include "config/yamlparser.h" #include "system_codec_container.h" +#include "ice_transport.h" #include <yaml-cpp/yaml.h> @@ -539,4 +540,12 @@ Account::getActiveAccountCodecInfoList(MediaType mediaType) const return accountCodecList; } +const IceTransportOptions +Account::getIceOptions() const noexcept +{ + IceTransportOptions opts; + opts.upnpEnable = getUPnPActive(); + return opts; +} + } // namespace ring diff --git a/src/account.h b/src/account.h index ff49a467ea76cc036c881a22ac7529d94e6f0211..470a59f5a5c2606a4f0c22fa1a31cca78badb6d5 100644 --- a/src/account.h +++ b/src/account.h @@ -68,6 +68,7 @@ namespace ring { class Call; class SystemCodecContainer; +class IceTransportOptions; class VoipLinkException : public std::runtime_error { @@ -271,6 +272,8 @@ class Account : public Serializable, public std::enable_shared_from_this<Account */ IpAddr getUPnPIpAddress() const; + virtual const IceTransportOptions getIceOptions() const noexcept; + private: NON_COPYABLE(Account); diff --git a/src/call.cpp b/src/call.cpp index e2f359e053943681958c6c64c8d189bda577d96b..99886a158aa2b07901a57126a2497b23aaadc194 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -271,8 +271,9 @@ bool Call::initIceTransport(bool master, unsigned channel_num) { auto& iceTransportFactory = Manager::instance().getIceTransportFactory(); - iceTransport_ = iceTransportFactory.createTransport(getCallId().c_str(), channel_num, - master, account_.getUPnPActive()); + iceTransport_ = iceTransportFactory.createTransport(getCallId().c_str(), + channel_num, master, + account_.getIceOptions()); return static_cast<bool>(iceTransport_); } diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp index cc04f170835bc204ce4d4f2a395cdf03cb4cef82..293c7891cf4531b856c245267899281ff348553c 100644 --- a/src/ice_transport.cpp +++ b/src/ice_transport.cpp @@ -96,21 +96,21 @@ IceTransport::cb_on_ice_complete(pj_ice_strans* ice_st, RING_WARN("null IceTransport"); } -IceTransport::IceTransport(const char* name, int component_count, - bool master, bool upnp_enabled, - IceTransportCompleteCb on_initdone_cb, - IceTransportCompleteCb on_negodone_cb) + +IceTransport::IceTransport(const char* name, int component_count, bool master, + const IceTransportOptions& options) : pool_(nullptr, pj_pool_release) - , on_initdone_cb_(on_initdone_cb) - , on_negodone_cb_(on_negodone_cb) + , on_initdone_cb_(options.onInitDone) + , on_negodone_cb_(options.onNegoDone) , component_count_(component_count) , compIO_(component_count) , initiator_session_(master) { - if (upnp_enabled) + if (options.upnpEnable) upnp_.reset(new upnp::Controller()); auto& iceTransportFactory = Manager::instance().getIceTransportFactory(); + config_ = iceTransportFactory.getIceCfg(); pool_.reset(pj_pool_create(iceTransportFactory.getPoolFactory(), "IceTransport.pool", 512, 512, NULL)); @@ -122,11 +122,46 @@ IceTransport::IceTransport(const char* name, int component_count, icecb.on_rx_data = cb_on_rx_data; icecb.on_ice_complete = cb_on_ice_complete; + /* STUN */ + if (not options.stunServer.empty()) { + const auto n = options.stunServer.rfind(':'); + if (n != std::string::npos) { + const auto p = options.stunServer.c_str(); + pj_strset(&config_.stun.server, (char*)p, n); + config_.stun.port = (pj_uint16_t)std::atoi(p+n+1); + } else { + pj_cstr(&config_.stun.server, options.stunServer.c_str()); + config_.stun.port = PJ_STUN_PORT; + } + RING_WARN("ICE: STUN='%s', PORT=%d", options.stunServer.c_str(), + config_.stun.port); + } + + /* TURN */ + if (not options.turnServer.empty()) { + const auto n = options.turnServer.rfind(':'); + if (n != std::string::npos) { + const auto p = options.turnServer.c_str(); + pj_strset(&config_.turn.server, (char*)p, n); + config_.turn.port = (pj_uint16_t)std::atoi(p+n+1); + } else { + pj_cstr(&config_.turn.server, options.turnServer.c_str()); + config_.turn.port = PJ_STUN_PORT; + } + + // No authorization yet + //config_.turn.auth_cred.type = PJ_STUN_AUTH_STATIC; + + // Only UDP yet + config_.turn.conn_type = PJ_TURN_TP_UDP; + + RING_WARN("ICE: TURN='%s', PORT=%d", options.turnServer.c_str(), + config_.turn.port); + } + pj_ice_strans* icest = nullptr; - pj_status_t status = pj_ice_strans_create(name, - iceTransportFactory.getIceCfg(), - component_count, this, &icecb, - &icest); + pj_status_t status = pj_ice_strans_create(name, &config_, component_count, + this, &icecb, &icest); if (status != PJ_SUCCESS || icest == nullptr) throw std::runtime_error("pj_ice_strans_create() failed"); } @@ -762,10 +797,6 @@ IceTransportFactory::IceTransportFactory() ice_cfg_.turn.cfg.max_pkt_size = 8192; //ice_cfg_.stun.max_host_cands = icedemo.opt.max_host; ice_cfg_.opt.aggressive = PJ_FALSE; - - // TODO: STUN server candidate - - // TODO: TURN server candidate } IceTransportFactory::~IceTransportFactory() @@ -841,17 +872,13 @@ IceTransportFactory::processThread() } std::shared_ptr<IceTransport> -IceTransportFactory::createTransport(const char* name, - int component_count, +IceTransportFactory::createTransport(const char* name, int component_count, bool master, - bool upnp_enabled, - IceTransportCompleteCb&& on_initdone_cb, - IceTransportCompleteCb&& on_negodone_cb) + const IceTransportOptions& options) { try { - return std::make_shared<IceTransport>(name, component_count, master, upnp_enabled, - std::forward<IceTransportCompleteCb>(on_initdone_cb), - std::forward<IceTransportCompleteCb>(on_negodone_cb)); + return std::make_shared<IceTransport>(name, component_count, master, + options); } catch(const std::exception& e) { RING_ERR("%s",e.what()); return nullptr; diff --git a/src/ice_transport.h b/src/ice_transport.h index 9420d960c39394df2c4588e11d79d194a480fb1a..c11d070e0238ac96ecc2a5cb49617bd6ea508dc1 100644 --- a/src/ice_transport.h +++ b/src/ice_transport.h @@ -59,6 +59,14 @@ using IceTransportCompleteCb = std::function<void(IceTransport&, bool)>; using IceRecvCb = std::function<ssize_t(unsigned char* buf, size_t len)>; using IceCandidate = pj_ice_sess_cand; +struct IceTransportOptions { + bool upnpEnable {false}; + IceTransportCompleteCb onInitDone {}; + IceTransportCompleteCb onNegoDone {}; + std::string stunServer {}; + std::string turnServer {}; +}; + class IceTransport { public: using Attribute = struct { @@ -69,11 +77,8 @@ class IceTransport { /** * Constructor */ - IceTransport(const char* name, int component_count, - bool master, - bool upnp_enabled = false, - IceTransportCompleteCb on_initdone_cb={}, - IceTransportCompleteCb on_negodone_cb={}); + IceTransport(const char* name, int component_count, bool master, + const IceTransportOptions& options = {}); /** * Destructor @@ -215,6 +220,7 @@ class IceTransport { pj_sockaddr remoteAddr_; std::condition_variable iceCV_ {}; mutable std::mutex iceMutex_ {}; + pj_ice_strans_cfg config_; struct Packet { Packet(void *pkt, pj_size_t size); @@ -258,16 +264,14 @@ class IceTransportFactory { std::shared_ptr<IceTransport> createTransport(const char* name, int component_count, bool master, - bool upnp_enabled = false, - IceTransportCompleteCb&& on_initdone_cb={}, - IceTransportCompleteCb&& on_negodone_cb={}); + const IceTransportOptions& options = {}); int processThread(); /** * PJSIP specifics */ - const pj_ice_strans_cfg* getIceCfg() const { return &ice_cfg_; } + pj_ice_strans_cfg getIceCfg() const { return ice_cfg_; } pj_pool_factory* getPoolFactory() { return &cp_.factory; } private: diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index 24e756fd4ec0e24ce12a11d3981e5c89061ac7b6..cbd16d7f649a2f3f75f2446e511aaa291d406ce3 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -163,7 +163,7 @@ RingAccount::newOutgoingCall(const std::string& toUrl) // Create an ICE transport for SIP channel auto& tfactory = manager.getIceTransportFactory(); auto ice = tfactory.createTransport(("sip:" + call->getCallId()).c_str(), - ICE_COMPONENTS, true, getUPnPActive()); + ICE_COMPONENTS, true, getIceOptions()); if (not ice) { call->removeCall(); return nullptr; @@ -840,11 +840,7 @@ void RingAccount::incomingCall(dht::IceCandidates&& msg) RING_WARN("Received incoming DHT call request from %s", from.c_str()); auto call = Manager::instance().callFactory.newCall<SIPCall, RingAccount>(*this, Manager::instance().getNewCallID(), Call::INCOMING); auto ice = Manager::instance().getIceTransportFactory().createTransport( - ("sip:"+call->getCallId()).c_str(), - ICE_COMPONENTS, - false, - getUPnPActive() - ); + ("sip:"+call->getCallId()).c_str(), ICE_COMPONENTS, false, getIceOptions()); if (ice->waitForInitialization(ICE_INIT_TIMEOUT) <= 0) throw std::runtime_error("Can't initialize ICE.."); diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp index 798957761b21710d42e8c2fd072a3f1ef5b9a243..9a182c5a119cd4fc452a5edcbfca2d5de4940002 100644 --- a/src/sip/sipaccountbase.cpp +++ b/src/sip/sipaccountbase.cpp @@ -39,6 +39,7 @@ #include "account_schema.h" #include "manager.h" +#include "ice_transport.h" #include "config/yamlparser.h" #include <yaml-cpp/yaml.h> @@ -324,4 +325,15 @@ SIPAccountBase::generateVideoPort() const } #endif +const IceTransportOptions +SIPAccountBase::getIceOptions() const noexcept +{ + auto opts = Account::getIceOptions(); + if (stunEnabled_) + opts.stunServer = stunServer_; + if (turnEnabled_) + opts.turnServer = turnServer_; + return opts; +} + } // namespace ring diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index 0a837e9e10b721aa4a4b0e7ea58bed5869067464..7d9f9f80a25b023e1fbbc0338c9c92cc147a26fa 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -242,6 +242,8 @@ public: stunServer_ = srv; } + const IceTransportOptions getIceOptions() const noexcept override; + protected: virtual void serialize(YAML::Emitter &out); virtual void serializeTls(YAML::Emitter &out);