diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index b9789e213a58ddfae724791ed91f29d0a03a6984..8d7987a8c2f1d674cf229932164073c5d27579a2 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -81,6 +81,7 @@ static constexpr int ICE_INIT_TIMEOUT {5}; static constexpr int ICE_NEGOTIATION_TIMEOUT {60}; constexpr const char * const RingAccount::ACCOUNT_TYPE; +constexpr const std::pair<uint16_t, uint16_t> RingAccount::DHT_PORT_RANGE; RingAccount::RingAccount(const std::string& accountID, bool /* presenceEnabled */) : SIPAccountBase(accountID), via_addr_() @@ -402,9 +403,9 @@ void RingAccount::unserialize(const YAML::Node &node) using yaml_utils::parseValue; SIPAccountBase::unserialize(node); - in_port_t port {DHT_DEFAULT_PORT}; - parseValue(node, Conf::DHT_PORT_KEY, port); - dhtPort_ = port ? port : DHT_DEFAULT_PORT; + parseValue(node, Conf::DHT_PORT_KEY, dhtPort_); + if (not dhtPort_) + dhtPort_ = getRandomEvenPort(DHT_PORT_RANGE); dhtPortUsed_ = dhtPort_; checkIdentityPath(); } @@ -498,8 +499,8 @@ void RingAccount::setAccountDetails(const std::map<std::string, std::string> &de if (hostname_ == "") hostname_ = DHT_DEFAULT_BOOTSTRAP; parseInt(details, Conf::CONFIG_DHT_PORT, dhtPort_); - if (dhtPort_ == 0) - dhtPort_ = DHT_DEFAULT_PORT; + if (not dhtPort_) + dhtPort_ = getRandomEvenPort(DHT_PORT_RANGE); dhtPortUsed_ = dhtPort_; checkIdentityPath(); } @@ -672,7 +673,7 @@ void RingAccount::doRegister_() dht_.join(); } auto identity = loadIdentity(); - dht_.run(dhtPortUsed_, identity.second, false, [=](dht::Dht::Status s4, dht::Dht::Status s6) { + dht_.run((in_port_t)dhtPortUsed_, identity.second, false, [=](dht::Dht::Status s4, dht::Dht::Status s6) { RING_WARN("Dht status : IPv4 %s; IPv6 %s", dhtStatusStr(s4), dhtStatusStr(s6)); auto status = std::max(s4, s6); switch(status) { diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index 84cb1411a5b3cf17e6dbc5bb3956e142671b86ca..073d93dbb43dc9c11ca7aa78c039e69b3e491f5c 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -79,6 +79,7 @@ class RingAccount : public SIPAccountBase { constexpr static const char * const ACCOUNT_TYPE = "RING"; constexpr static const in_port_t DHT_DEFAULT_PORT = 4222; constexpr static const char * const DHT_DEFAULT_BOOTSTRAP = "bootstrap.ring.cx"; + constexpr static const std::pair<uint16_t, uint16_t> DHT_PORT_RANGE {4000, 8888}; const char* getAccountType() const { return ACCOUNT_TYPE; @@ -340,7 +341,7 @@ class RingAccount : public SIPAccountBase { * selected in the configuration in the case that UPnP is used and the * configured port is already used by another client */ - in_port_t dhtPortUsed_ {DHT_DEFAULT_PORT}; + UsedPort dhtPortUsed_ {DHT_DEFAULT_PORT}; /** * The TLS settings, used only if tls is chosen as a sip transport. diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp index f497069459bb7875491f609ec7e28dbf40950b07..7302913c271bc0cd7116a7774f77b503d857880e 100644 --- a/src/sip/sipaccountbase.cpp +++ b/src/sip/sipaccountbase.cpp @@ -247,7 +247,17 @@ SIPAccountBase::getPortsReservation() noexcept -> decltype(getPortsReservation() return portsInUse; } -// returns even number in range [lower, upper] +uint16_t +SIPAccountBase::getRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const +{ + std::uniform_int_distribution<uint16_t> dist(range.first/2, range.second/2); + uint16_t result; + do { + result = 2 * dist(rand_); + } while (getPortsReservation()[result / 2]); + return result; +} + uint16_t SIPAccountBase::acquireRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const { @@ -262,6 +272,12 @@ SIPAccountBase::acquireRandomEvenPort(const std::pair<uint16_t, uint16_t>& range return result; } +uint16_t +SIPAccountBase::acquirePort(uint16_t port) +{ + getPortsReservation()[port / 2] = true; +} + void SIPAccountBase::releasePort(uint16_t port) noexcept { diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index 0874f81cf4f19bb611c6f23c26631e5255e38c35..1cef21d25a3876bf764e726f58c1235952ae65d5 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -292,7 +292,43 @@ protected: */ std::pair<uint16_t, uint16_t> videoPortRange_ {49152, (MAX_PORT) - 2}; + struct UsedPort { + UsedPort() {}; + UsedPort(UsedPort&& o) : port_(o.port_) { + o.port_ = 0; + } + UsedPort(in_port_t p) : port_(p) { + if (port_) + acquirePort(port_); + }; + ~UsedPort() { + if (port_) + releasePort(port_); + }; + UsedPort& operator=(UsedPort&& o) { + if (port_) + releasePort(port_); + port_ = o.port_; + o.port_ = 0; + return *this; + } + UsedPort& operator=(in_port_t p) { + if (port_) + releasePort(port_); + port_ = p; + if (port_) + acquirePort(port_); + return *this; + } + explicit operator in_port_t() const { return port_; } + private: + in_port_t port_ {0}; + NON_COPYABLE(UsedPort); + }; + static std::array<bool, HALF_MAX_PORT>& getPortsReservation() noexcept; + static uint16_t acquirePort(uint16_t port); + uint16_t getRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const; uint16_t acquireRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const; private: