diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml index 0b2c8f6bd538b63f5ddb86321d211c76c98def36..b991b6f974dd4fcb08efcdfce0023373ae2b0ac6 100644 --- a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml +++ b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml @@ -38,6 +38,7 @@ <li>REALM</li> <li>CONFIG_ACCOUNT_MAILBOX: Number to dial to access the voicemail box</li> <li>CONFIG_ACCOUNT_REGISTRATION_EXPIRE: SIP header expiration value (Default: 1600)</li> + <li>BIND_ADDRESS: Custom bind SIP ip address</li> <li>LOCAL_INTERFACE: The network interface (Default: eth0)</li> <li>PUBLISHED_SAMEAS_LOCAL: If False, the published address equals the local address. This is the default.</li> <li>PUBLISHED_ADDRESS: The SIP published address</li> diff --git a/src/account_schema.h b/src/account_schema.h index 8641361fd74af55304d0ef1e8e5846079eae097a..f6b71e899b900515eefb96adee8b8ff75c8bd30f 100644 --- a/src/account_schema.h +++ b/src/account_schema.h @@ -60,6 +60,7 @@ static const char *const CONFIG_ACCOUNT_AUDIO_PORT_MAX = "Account.audio static const char *const CONFIG_ACCOUNT_VIDEO_PORT_MIN = "Account.videoPortMin"; static const char *const CONFIG_ACCOUNT_VIDEO_PORT_MAX = "Account.videoPortMax"; +static const char *const CONFIG_BIND_ADDRESS = "Account.bindAddress"; static const char *const CONFIG_LOCAL_INTERFACE = "Account.localInterface"; static const char *const CONFIG_PUBLISHED_SAMEAS_LOCAL = "Account.publishedSameAsLocal"; static const char *const CONFIG_LOCAL_PORT = "Account.localPort"; diff --git a/src/dring/account_const.h b/src/dring/account_const.h index 81e18131f5ab8f55e6ced3e7ce7002a3233c08b7..4030f901f8c6b26c2923538dcd167baeb7dc5c68 100644 --- a/src/dring/account_const.h +++ b/src/dring/account_const.h @@ -118,6 +118,7 @@ constexpr static const char AUTOANSWER [] = "Account.autoAnswer"; constexpr static const char ACTIVE_CALL_LIMIT [] = "Account.activeCallLimit"; constexpr static const char HOSTNAME [] = "Account.hostname"; constexpr static const char USERNAME [] = "Account.username"; +constexpr static const char BIND_ADDRESS [] = "Account.bindAddress"; constexpr static const char ROUTE [] = "Account.routeset"; constexpr static const char PASSWORD [] = "Account.password"; constexpr static const char REALM [] = "Account.realm"; diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp index 34687411c89c65f2497cc2858862052b196784c0..62debcd1df849831e67c310da45cf3c947fb1c27 100644 --- a/src/sip/sipaccount.cpp +++ b/src/sip/sipaccount.cpp @@ -404,6 +404,7 @@ void SIPAccount::serialize(YAML::Emitter &out) const out << YAML::BeginMap; SIPAccountBase::serialize(out); + out << YAML::Key << Conf::BIND_ADDRESS_KEY << YAML::Value << bindAddress_; out << YAML::Key << Conf::PORT_KEY << YAML::Value << localPort_; out << YAML::Key << USERNAME_KEY << YAML::Value << username_; @@ -479,6 +480,8 @@ void SIPAccount::unserialize(const YAML::Node &node) if (not publishedSameasLocal_) usePublishedAddressPortInVIA(); + parseValue(node, Conf::BIND_ADDRESS_KEY, bindAddress_); + int port = sip_utils::DEFAULT_SIP_PORT; parseValue(node, Conf::PORT_KEY, port); localPort_ = port; @@ -562,6 +565,7 @@ void SIPAccount::setAccountDetails(const std::map<std::string, std::string> &det parseString(details, Conf::CONFIG_TLS_PASSWORD, tlsPassword_); // SIP specific account settings + parseString(details, Conf::CONFIG_BIND_ADDRESS, bindAddress_); parseString(details, Conf::CONFIG_ACCOUNT_ROUTESET, serviceRoute_); if (not publishedSameasLocal_) @@ -629,6 +633,7 @@ SIPAccount::getAccountDetails() const } a.emplace(Conf::CONFIG_ACCOUNT_PASSWORD, std::move(password)); + a.emplace(Conf::CONFIG_BIND_ADDRESS, bindAddress_); a.emplace(Conf::CONFIG_LOCAL_PORT, std::to_string(localPort_)); a.emplace(Conf::CONFIG_ACCOUNT_ROUTESET, serviceRoute_); a.emplace(Conf::CONFIG_ACCOUNT_REGISTRATION_EXPIRE, std::to_string(registrationExpire_)); @@ -771,18 +776,22 @@ void SIPAccount::doRegister1_() void SIPAccount::doRegister2_() { - bool ipv6 = false; - if (isIP2IP()) { - JAMI_DBG("doRegister isIP2IP."); - ipv6 = ip_utils::getInterfaceAddr(interface_).isIpv6(); - } else if (!hostIp_) { + if (not isIP2IP() and not hostIp_) { setRegistrationState(RegistrationState::ERROR_GENERIC, PJSIP_SC_NOT_FOUND); JAMI_ERR("Hostname not resolved."); return; - } else { - ipv6 = hostIp_.isIpv6(); } + IpAddr bindAddress = createBindingAddress(); + if (not bindAddress) { + setRegistrationState(RegistrationState::ERROR_GENERIC, PJSIP_SC_NOT_FOUND); + JAMI_ERR("Can't compute address to bind."); + return; + } + + bool ipv6 = bindAddress.isIpv6(); + transportType_ = tlsEnable_ ? (ipv6 ? PJSIP_TRANSPORT_TLS6 : PJSIP_TRANSPORT_TLS) : (ipv6 ? PJSIP_TRANSPORT_UDP6 : PJSIP_TRANSPORT_UDP); + // Init TLS settings if the user wants to use TLS if (tlsEnable_) { JAMI_DBG("TLS is enabled for account %s", accountID_.c_str()); @@ -790,14 +799,10 @@ void SIPAccount::doRegister2_() // Dropping current calls already using the transport is currently required // with TLS. freeAccount(); - - transportType_ = ipv6 ? PJSIP_TRANSPORT_TLS6 : PJSIP_TRANSPORT_TLS; initTlsConfiguration(); if (!tlsListener_) { - tlsListener_ = link_->sipTransportBroker->getTlsListener( - SipTransportDescr {getTransportType(), getTlsListenerPort(), getLocalInterface()}, - getTlsSetting()); + tlsListener_ = link_->sipTransportBroker->getTlsListener(bindAddress, getTlsSetting()); if (!tlsListener_) { setRegistrationState(RegistrationState::ERROR_GENERIC); JAMI_ERR("Error creating TLS listener."); @@ -806,7 +811,6 @@ void SIPAccount::doRegister2_() } } else { tlsListener_.reset(); - transportType_ = ipv6 ? PJSIP_TRANSPORT_UDP6 : PJSIP_TRANSPORT_UDP; } // Init STUN settings for this account if the user selected it @@ -819,10 +823,9 @@ void SIPAccount::doRegister2_() // no registration should be performed if (isIP2IP()) { // If we use Tls for IP2IP, transports will be created on connection. - if (!tlsEnable_) - setTransport(link_->sipTransportBroker->getUdpTransport( - SipTransportDescr { getTransportType(), getLocalPort(), getLocalInterface() } - )); + if (!tlsEnable_){ + setTransport(link_->sipTransportBroker->getUdpTransport(bindAddress)); + } setRegistrationState(RegistrationState::REGISTERED); return; } @@ -833,9 +836,7 @@ void SIPAccount::doRegister2_() if (isTlsEnabled()) { setTransport(link_->sipTransportBroker->getTlsTransport(tlsListener_, hostIp_, tlsServerName_.empty() ? hostname_ : tlsServerName_)); } else { - setTransport(link_->sipTransportBroker->getUdpTransport( - SipTransportDescr { getTransportType(), getLocalPort(), getLocalInterface() } - )); + setTransport(link_->sipTransportBroker->getUdpTransport(bindAddress)); } if (!transport_) throw VoipLinkException("Can't create transport"); @@ -2203,4 +2204,22 @@ SIPAccount::getUserUri() const return getFromUri(); } +IpAddr +SIPAccount::createBindingAddress() +{ + auto family = hostIp_ ? hostIp_.getFamily() : PJ_AF_INET; + + IpAddr ret = bindAddress_.empty() + ? (interface_ == ip_utils::DEFAULT_INTERFACE + ? ip_utils::getAnyHostAddr(family) + : ip_utils::getInterfaceAddr(getLocalInterface(), family)) + : IpAddr(bindAddress_, family); + + if (ret.getPort() == 0) { + ret.setPort(tlsEnable_ ? getTlsListenerPort() : getLocalPort()); + } + + return ret; +} + } // namespace jami diff --git a/src/sip/sipaccount.h b/src/sip/sipaccount.h index d798599e8ffb8e45e3d0ce6b3a3d9c5086898fb5..4375f59eec88a69e4a176dd1e11c691f999be6b9 100644 --- a/src/sip/sipaccount.h +++ b/src/sip/sipaccount.h @@ -293,6 +293,24 @@ class SIPAccount : public SIPAccountBase { localPort_ = port; } + /** + * Get the bind ip address on which the account should use, or is + * actually using. + * Note: if it is NULL, this address should not be used + * @return std::string The bind ip address used for that account + */ + std::string getBindAddress() const { + return bindAddress_; + } + + /** + * Set the new bind ip address on which this account is bind on. + * @pram address The bind ip address used by this account. + */ + void setBindAddress(const std::string &address) { + bindAddress_ = address; + } + /** * @return pjsip_tls_setting structure, filled from the configuration * file, that can be used directly by PJSIP to initialize @@ -509,6 +527,12 @@ class SIPAccount : public SIPAccountBase { std::string getUserUri() const override; + /** + * Create the Ip address that the transport uses + * @return IpAddr created + */ + IpAddr createBindingAddress(); + private: void doRegister1_(); void doRegister2_(); @@ -680,6 +704,11 @@ class SIPAccount : public SIPAccountBase { */ pj_uint16_t localPort_ {sip_utils::DEFAULT_SIP_PORT}; + /** + * Potential ip addresss on which this account is bound + */ + std::string bindAddress_; + /** * The TLS listener port */ diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index df6a09e16bb45d358ad1a2de763eb5ed7069e7ae..df3c943f08e20410d98828260e2095dbb0460033 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -54,6 +54,7 @@ namespace jami { namespace Conf { // SIP specific configuration keys + const char *const BIND_ADDRESS_KEY = "bindAddress"; const char *const INTERFACE_KEY = "interface"; const char *const PORT_KEY = "port"; const char *const PUBLISH_ADDR_KEY = "publishAddr"; diff --git a/src/sip/siptransport.cpp b/src/sip/siptransport.cpp index 049fab02e8e3448361859a0a35094d3a2c126f0e..23707ec4dd69d0342cb9a4fa91abc0b6447f584d 100644 --- a/src/sip/siptransport.cpp +++ b/src/sip/siptransport.cpp @@ -55,14 +55,6 @@ constexpr const char* TRANSPORT_STATE_STR[] = { }; constexpr const size_t TRANSPORT_STATE_SZ = arraySize(TRANSPORT_STATE_STR); -std::string -SipTransportDescr::toString() const -{ - std::stringstream ss; - ss << "{" << pjsip_transport_get_type_desc(type) << " on " << interface << ":" << listenerPort << "}"; - return ss.str(); -} - void SipTransport::deleteTransport(pjsip_transport* t) { @@ -253,7 +245,7 @@ SipTransportBroker::transportStateChanged(pjsip_transport* tp, if (type == PJSIP_TRANSPORT_UDP or type == PJSIP_TRANSPORT_UDP6) { const auto updKey = std::find_if( udpTransports_.cbegin(), udpTransports_.cend(), - [tp](const std::pair<SipTransportDescr, pjsip_transport*>& pair) { + [tp](const std::pair<IpAddr, pjsip_transport*>& pair) { return pair.second == tp; }); if (updKey != udpTransports_.cend()) @@ -303,79 +295,66 @@ SipTransportBroker::shutdown() } std::shared_ptr<SipTransport> -SipTransportBroker::getUdpTransport(const SipTransportDescr& descr) +SipTransportBroker::getUdpTransport(const IpAddr& ipAddress) { std::lock_guard<std::mutex> lock(transportMapMutex_); - auto itp = udpTransports_.find(descr); + auto itp = udpTransports_.find(ipAddress); if (itp != udpTransports_.end()) { auto it = transports_.find(itp->second); if (it != transports_.end()) { if (auto spt = it->second.lock()) { - JAMI_DBG("Reusing transport %s", descr.toString().c_str()); + JAMI_DBG("Reusing transport %s", ipAddress.toString().c_str()); return spt; } else { // Transport still exists but have not been destroyed yet. - JAMI_WARN("Recycling transport %s", descr.toString().c_str()); + JAMI_WARN("Recycling transport %s", ipAddress.toString().c_str()); auto ret = std::make_shared<SipTransport>(itp->second); it->second = ret; return ret; } } else { - JAMI_WARN("Cleaning up UDP transport %s", descr.toString().c_str()); + JAMI_WARN("Cleaning up UDP transport %s", ipAddress.toString().c_str()); udpTransports_.erase(itp); } } - auto ret = createUdpTransport(descr); + auto ret = createUdpTransport(ipAddress); if (ret) { - udpTransports_[descr] = ret->get(); + udpTransports_[ipAddress] = ret->get(); transports_[ret->get()] = ret; } return ret; } std::shared_ptr<SipTransport> -SipTransportBroker::createUdpTransport(const SipTransportDescr& d) +SipTransportBroker::createUdpTransport(const IpAddr& ipAddress) { - RETURN_IF_FAIL(d.listenerPort != 0, nullptr, "Could not determine port for this transport"); - auto family = pjsip_transport_type_get_af(d.type); - - IpAddr listeningAddress = (d.interface == ip_utils::DEFAULT_INTERFACE) ? - ip_utils::getAnyHostAddr(family) : - ip_utils::getInterfaceAddr(d.interface, family); - listeningAddress.setPort(d.listenerPort); - RETURN_IF_FAIL(listeningAddress, nullptr, "Could not determine IP address for this transport"); + RETURN_IF_FAIL(ipAddress.getPort() != 0, nullptr, "Could not determine port for this transport"); + RETURN_IF_FAIL(ipAddress, nullptr, "Could not determine IP address for this transport"); pjsip_udp_transport_cfg pj_cfg; - pjsip_udp_transport_cfg_default(&pj_cfg, family); - pj_cfg.bind_addr = listeningAddress; + pjsip_udp_transport_cfg_default(&pj_cfg, ipAddress.getFamily()); + pj_cfg.bind_addr = ipAddress; pjsip_transport *transport = nullptr; if (pj_status_t status = pjsip_udp_transport_start2(endpt_, &pj_cfg, &transport)) { JAMI_ERR("pjsip_udp_transport_start2 failed with error %d: %s", status, sip_utils::sip_strerror(status).c_str()); JAMI_ERR("UDP IPv%s Transport did not start on %s", - listeningAddress.isIpv4() ? "4" : "6", - listeningAddress.toString(true).c_str()); + ipAddress.isIpv4() ? "4" : "6", + ipAddress.toString(true).c_str()); return nullptr; } - JAMI_DBG("Created UDP transport on %s : %s", d.interface.c_str(), listeningAddress.toString(true).c_str()); + JAMI_DBG("Created UDP transport on address %s", ipAddress.toString(true).c_str()); return std::make_shared<SipTransport>(transport); } std::shared_ptr<TlsListener> -SipTransportBroker::getTlsListener(const SipTransportDescr& d, const pjsip_tls_setting* settings) +SipTransportBroker::getTlsListener(const IpAddr& ipAddress, const pjsip_tls_setting* settings) { RETURN_IF_FAIL(settings, nullptr, "TLS settings not specified"); - auto family = pjsip_transport_type_get_af(d.type); - - IpAddr listeningAddress = (d.interface == ip_utils::DEFAULT_INTERFACE) ? - ip_utils::getAnyHostAddr(family) : - ip_utils::getInterfaceAddr(d.interface, family); - listeningAddress.setPort(d.listenerPort); - - RETURN_IF_FAIL(listeningAddress, nullptr, "Could not determine IP address for this transport"); - JAMI_DBG("Creating TLS listener %s on %s...", d.toString().c_str(), listeningAddress.toString(true).c_str()); + RETURN_IF_FAIL(ipAddress, nullptr, "Could not determine IP address for this transport"); + JAMI_DBG("Creating TLS listener on %s...", ipAddress.toString(true).c_str()); #if 0 JAMI_DBG(" ca_list_file : %s", settings->ca_list_file.ptr); JAMI_DBG(" cert_file : %s", settings->cert_file.ptr); @@ -385,7 +364,7 @@ SipTransportBroker::getTlsListener(const SipTransportDescr& d, const pjsip_tls_s #endif pjsip_tpfactory *listener = nullptr; - const pj_status_t status = pjsip_tls_transport_start2(endpt_, settings, listeningAddress.pjPtr(), nullptr, 1, &listener); + const pj_status_t status = pjsip_tls_transport_start2(endpt_, settings, ipAddress.pjPtr(), nullptr, 1, &listener); if (status != PJ_SUCCESS) { JAMI_ERR("TLS listener did not start: %s", sip_utils::sip_strerror(status).c_str()); return nullptr; @@ -406,6 +385,7 @@ SipTransportBroker::getTlsTransport(const std::shared_ptr<TlsListener>& l, const pjsip_tpselector sel; sel.type = PJSIP_TPSELECTOR_LISTENER; sel.u.listener = l->get(); + sel.disable_connection_reuse = PJ_FALSE; pjsip_tx_data tx_data; tx_data.dest_info.name = pj_str_t{(char*)remote_name.data(), (pj_ssize_t)remote_name.size()}; diff --git a/src/sip/siptransport.h b/src/sip/siptransport.h index 3be21163eda13666e59e4d775f541056a9952b42..8f4f3fed629443a4123cb943c6ff6e538a0d1286 100644 --- a/src/sip/siptransport.h +++ b/src/sip/siptransport.h @@ -50,37 +50,6 @@ struct Certificate; namespace jami { -struct SipTransportDescr -{ - SipTransportDescr() {} - SipTransportDescr(pjsip_transport_type_e t) - : type(t), listenerPort(pjsip_transport_get_default_port_for_type(t)) {} - SipTransportDescr(pjsip_transport_type_e t, pj_uint16_t port, const std::string& i) - : type(t), listenerPort(port), interface(i) {} - - static inline pjsip_transport_type_e actualType(pjsip_transport_type_e t) { - return (t == PJSIP_TRANSPORT_START_OTHER) ? PJSIP_TRANSPORT_UDP : t; - } - - inline bool operator==(SipTransportDescr const& o) const { - return actualType(type) == actualType(o.type) - && listenerPort == o.listenerPort - && interface == o.interface; - } - - inline bool operator<(SipTransportDescr const& o) const { - return actualType(type) < actualType(o.type) - || listenerPort < o.listenerPort - || std::hash<std::string>()(interface) < std::hash<std::string>()(o.interface); - } - - std::string toString() const; - - pjsip_transport_type_e type {PJSIP_TRANSPORT_UNSPECIFIED}; - pj_uint16_t listenerPort {sip_utils::DEFAULT_SIP_PORT}; - std::string interface {"default"}; -}; - struct TlsListener { TlsListener() {} @@ -175,10 +144,10 @@ public: SipTransportBroker(pjsip_endpoint *endpt, pj_caching_pool& cp, pj_pool_t& pool); ~SipTransportBroker(); - std::shared_ptr<SipTransport> getUdpTransport(const SipTransportDescr&); + std::shared_ptr<SipTransport> getUdpTransport(const IpAddr&); std::shared_ptr<TlsListener> - getTlsListener(const SipTransportDescr&, const pjsip_tls_setting*); + getTlsListener(const IpAddr&, const pjsip_tls_setting*); std::shared_ptr<SipTransport> getTlsTransport(const std::shared_ptr<TlsListener>&, const IpAddr& remote, const std::string& remote_name = {}); @@ -205,7 +174,7 @@ private: * @param IP protocol version to use, can be pj_AF_INET() or pj_AF_INET6() * @return a pointer to the new transport */ - std::shared_ptr<SipTransport> createUdpTransport(const SipTransportDescr&); + std::shared_ptr<SipTransport> createUdpTransport(const IpAddr&); /** * List of transports so we can bubble the events up. @@ -217,7 +186,7 @@ private: * Transports are stored in this map in order to retrieve them in case * several accounts would share the same port number. */ - std::map<SipTransportDescr, pjsip_transport*> udpTransports_; + std::map<IpAddr, pjsip_transport*> udpTransports_; /** * Storage for SIP/ICE transport instances.