diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml index 8af7f278d703f09928760b6331f31c13d720c8cd..ae47f0778a52b570346f8afce316b505a0b17110 100644 --- a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml +++ b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml @@ -1103,5 +1103,15 @@ </arg> </signal> + <method name="connectivityChanged" tp:name-for-bindings="connectivityChanged"> + <tp:added version="2.3.0"/> + <tp:docstring> + This notifies the daemon that the network connectivity has changed, eg: + - interface has disconnected from the network + - interface connected to a different network + - connected interface has changed (wifi to eth) + </tp:docstring> + </method> + </interface> </node> diff --git a/bin/dbus/dbusconfigurationmanager.cpp b/bin/dbus/dbusconfigurationmanager.cpp index 85c718e489cf1d3d74d69c7a051ba27728d7b6e3..129ba9ffdc55c1ca291d5f8a3f0708fb0c3a65dd 100644 --- a/bin/dbus/dbusconfigurationmanager.cpp +++ b/bin/dbus/dbusconfigurationmanager.cpp @@ -540,3 +540,9 @@ DBusConfigurationManager::importAccounts(const std::string& archivePath, const s { return DRing::importAccounts(archivePath, password); } + +void +DBusConfigurationManager::connectivityChanged() +{ + DRing::connectivityChanged(); +} diff --git a/bin/dbus/dbusconfigurationmanager.h b/bin/dbus/dbusconfigurationmanager.h index 8471eec8b13e5e365b52856cbc2c2a8b9a8fb413..743d40952dd0ea8cd7e61de9fa2aae52091620be 100644 --- a/bin/dbus/dbusconfigurationmanager.h +++ b/bin/dbus/dbusconfigurationmanager.h @@ -139,6 +139,7 @@ class DBusConfigurationManager : void sendTrustRequest(const std::string& accountId, const std::string& to, const std::vector<uint8_t>& payload); int exportAccounts(const std::vector<std::string>& accountIDs, const std::string& filepath, const std::string& password); int importAccounts(const std::string& archivePath, const std::string& password); + void connectivityChanged(); }; #endif // __RING_DBUSCONFIGURATIONMANAGER_H__ diff --git a/src/account.h b/src/account.h index 64e1913006ef14e6dccffe416b2863cb9c2c30fe..d35be2c0e6c00819db8cc925f8d6ebc0640981df 100644 --- a/src/account.h +++ b/src/account.h @@ -296,6 +296,11 @@ class Account : public Serializable, public std::enable_shared_from_this<Account */ mutable std::mt19937_64 rand_; + /** + * Inform the account that the network status has changed. + */ + virtual void connectivityChanged() {}; + private: NON_COPYABLE(Account); diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp index 233e335df87c24592a5ce5e19658e723ed8ee5cc..32275f0280f559d22fa76401bf586bede8c1eaf0 100644 --- a/src/client/configurationmanager.cpp +++ b/src/client/configurationmanager.cpp @@ -40,6 +40,7 @@ #include "system_codec_container.h" #include "account_const.h" #include "client/ring_signal.h" +#include "upnp/upnp_context.h" #include <dirent.h> @@ -790,4 +791,24 @@ setCredentials(const std::string& accountID, } } +void +connectivityChanged() +{ + RING_WARN("received connectivity changed - trying to re-connect enabled accounts"); + + // reset the UPnP context + try { + ring::upnp::getUPnPContext()->connectivityChanged(); + } catch (std::runtime_error& e) { + RING_ERR("UPnP context error: %s", e.what()); + } + + auto account_list = ring::Manager::instance().getAccountList(); + for (auto account_id : account_list) { + if (auto account = ring::Manager::instance().getAccount(account_id)) { + account->connectivityChanged(); + } + } +} + } // namespace DRing diff --git a/src/dring/configurationmanager_interface.h b/src/dring/configurationmanager_interface.h index 8419f33ce87df0c89d7149deb6bba0b57c81ddec..46efa792d04a6d0305806070de86d13911cd5da5 100644 --- a/src/dring/configurationmanager_interface.h +++ b/src/dring/configurationmanager_interface.h @@ -156,6 +156,11 @@ void sendTrustRequest(const std::string& accountId, const std::string& to, const int exportAccounts(std::vector<std::string> accountIDs, std::string filepath, std::string password); int importAccounts(std::string archivePath, std::string password); +/* + * Network connectivity + */ +void connectivityChanged(); + struct AudioSignal { struct DeviceEvent { constexpr static const char* name = "audioDeviceEvent"; diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index 0d38b9115a688b87f200d71f10dbc5e3a72d5fa0..697c458bf646b5f8c5c0e1b79ef8644c319ee202 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -755,7 +755,7 @@ RingAccount::mapPortUPnP() std::weak_ptr<RingAccount> w = std::static_pointer_cast<RingAccount>(shared_from_this()); upnp_->setIGDListener([w] { if (auto shared = w.lock()) - shared->connectivityChanged(); + shared->igdChanged(); }); return added; } @@ -1065,6 +1065,22 @@ RingAccount::doUnregister(std::function<void(bool)> released_cb) released_cb(false); } +void +RingAccount::connectivityChanged() +{ + if (not isUsable()) { + // nothing to do + return; + } + + auto shared = std::static_pointer_cast<RingAccount>(shared_from_this()); + doUnregister([shared](bool /* transport_free */) { + if (shared->isUsable()) + shared->doRegister(); + }); +} + + bool RingAccount::findCertificate(const dht::InfoHash& h, std::function<void(const std::shared_ptr<dht::crypto::Certificate>)> cb) { @@ -1402,7 +1418,7 @@ RingAccount::sendTrustRequest(const std::string& to, const std::vector<uint8_t>& } void -RingAccount::connectivityChanged() +RingAccount::igdChanged() { if (not dht_.isRunning()) return; diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index dd16a51e6198886c5c6d38d2b8617e8d21b03789..94e30770bd2638be72a93bf4ca7963805d46c288 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -254,7 +254,7 @@ class RingAccount : public SIPAccountBase { void sendTrustRequest(const std::string& to, const std::vector<uint8_t>& payload); virtual void sendTextMessage(const std::string& to, const std::map<std::string, std::string>& payloads, uint64_t id) override; - void connectivityChanged(); + void connectivityChanged() override; private: NON_COPYABLE(RingAccount); @@ -287,6 +287,8 @@ class RingAccount : public SIPAccountBase { */ bool mapPortUPnP(); + void igdChanged(); + dht::DhtRunner dht_ {}; dht::InfoHash callKey_; diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp index 3f8fa4016b522685272221741d3d8abea589b667..b5b6dd8a8099614af77e01bfae23da6ffa929587 100644 --- a/src/sip/sipaccount.cpp +++ b/src/sip/sipaccount.cpp @@ -892,6 +892,21 @@ void SIPAccount::doUnregister(std::function<void(bool)> released_cb) upnp_->removeMappings(); } +void +SIPAccount::connectivityChanged() +{ + if (not isUsable()) { + // nothing to do + return; + } + + auto shared = std::static_pointer_cast<SIPAccount>(shared_from_this()); + doUnregister([shared](bool /* transport_free */) { + if (shared->isUsable()) + shared->doRegister(); + }); +} + void SIPAccount::startKeepAliveTimer() { if (isTlsEnabled()) diff --git a/src/sip/sipaccount.h b/src/sip/sipaccount.h index 5ad7e2942778ed49ba47d69d41a498570fc2cd0f..ee27d86bbf4ce2cea129a1bc2ea3a5ba2c5cb446 100644 --- a/src/sip/sipaccount.h +++ b/src/sip/sipaccount.h @@ -493,6 +493,8 @@ class SIPAccount : public SIPAccountBase { const std::map<std::string, std::string>& payloads, uint64_t id) override; + void connectivityChanged() override; + private: void doRegister1_(); void doRegister2_(); diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index a4fd8284257a356bfc36f31d667c37e963ff110d..ee96aab6e9df6c63818fc25ab19b0efb97c32429 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -247,6 +247,8 @@ public: void onTextMessage(const std::string& from, const std::map<std::string, std::string>& payloads); + void connectivityChanged() override {}; + protected: virtual void serialize(YAML::Emitter &out) override; virtual void serializeTls(YAML::Emitter &out); diff --git a/src/upnp/upnp_context.cpp b/src/upnp/upnp_context.cpp index 8c95f4ab116e0bf8b72c18f054fcc4a01b9e7a4c..c7fc190991558963992439c92a62852b9f7079ae 100644 --- a/src/upnp/upnp_context.cpp +++ b/src/upnp/upnp_context.cpp @@ -179,6 +179,26 @@ UPnPContext::~UPnPContext() #endif } +void +UPnPContext::connectivityChanged() +{ + { + std::lock_guard<std::mutex> lock(validIGDMutex_); + + /* when the network changes, we're likely no longer connected to the same IGD, or if we are + * we might now have a different IP, thus we clear the list of IGDs and notify the listeners + * so that they can attempt to re-do the port mappings once we detect an IGD + */ + validIGDs_.clear(); + validIGDCondVar_.notify_all(); + for (const auto& l : igdListeners_) + l.second(); + } + + // send out a new search request + searchForIGD(); +} + void UPnPContext::searchForIGD() { diff --git a/src/upnp/upnp_context.h b/src/upnp/upnp_context.h index 72d06b75eafdcb2871f38755105c9e5d217512e0..9d749c7a08d137984fe5955b9486d6bca1b2bfeb 100644 --- a/src/upnp/upnp_context.h +++ b/src/upnp/upnp_context.h @@ -110,6 +110,12 @@ public: */ int handleUPnPEvents(Upnp_EventType event_type, void* event); + /** + * Inform the UPnP context that the network status has changed. This clears the list of known + * IGDs + */ + void connectivityChanged(); + #else /* use default constructor and destructor */ UPnPContext() = default;