From 47057e068da4cb2e0168d03e6797d646c3115500 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 15:09:28 +0530 Subject: [PATCH] Allow advertising multiple services. --- .../platform/implementation/linux/wifi_lan.cc | 130 ++++++++++-------- .../platform/implementation/linux/wifi_lan.h | 34 +++-- 2 files changed, 90 insertions(+), 74 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index c094ddee..3ebf1250 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -9,6 +9,7 @@ #include #include +#include #include "absl/strings/substitute.h" #include "internal/platform/implementation/linux/avahi.h" @@ -25,41 +26,45 @@ namespace linux { WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus) : system_bus_(system_bus), network_manager_(std::make_shared(system_bus)), - avahi_(std::make_shared(system_bus)), - entry_group_(nullptr) {} - -WifiLanMedium::~WifiLanMedium() { - if (entry_group_ != nullptr) { - entry_group_->Free(); - } -} + avahi_(std::make_unique(system_bus)) {} bool WifiLanMedium::IsNetworkConnected() const { auto state = network_manager_->getState(); return state >= 50; // NM_STATE_CONNECTED_LOCAL } -bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { - if (entry_group_ == nullptr) { - try { - auto object_path = avahi_->EntryGroupNew(); - entry_group_ = - std::make_unique(system_bus_, object_path); - NEARBY_LOGS(VERBOSE) << __func__ << "Created a new entry group at " - << entry_group_->getObjectPath(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(avahi_, "EntryGroupNew", e); - NEARBY_LOGS(ERROR) << __func__ << ": Could not create a new entry group."; - return false; - } +std::optional> +entry_group_key(const NsdServiceInfo &nsd_service_info) { + auto name = nsd_service_info.GetServiceName(); + if (name.empty()) { + NEARBY_LOGS(ERROR) << __func__ << ": service name cannot be empty"; + return std::nullopt; } - if (advertising_) { - NEARBY_LOGS(ERROR) << __func__ - << ": Cannot advertise while we are already advertising"; + auto type = nsd_service_info.GetServiceType(); + if (type.empty()) { + NEARBY_LOGS(ERROR) << __func__ << ": service type cannot be empty"; + return std::nullopt; + } + + return std::make_pair(std::move(name), std::move(type)); +} + +bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { + auto key = entry_group_key(nsd_service_info); + if (!key.has_value()) { return false; } + { + absl::ReaderMutexLock l(&entry_groups_mutex_); + if (entry_groups_.count(*key) == 1) { + NEARBY_LOGS(ERROR) << __func__ + << ": advertising is already active for this service"; + return false; + } + } + auto txt_records_map = nsd_service_info.GetTxtRecords(); std::vector> txt_records(txt_records_map.size()); std::size_t i = 0; @@ -69,13 +74,24 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { txt_records[i++] = std::vector(entry.begin(), entry.end()); } + sdbus::ObjectPath entry_group_path; try { - entry_group_->AddService( + entry_group_path = avahi_->EntryGroupNew(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(avahi_, "EntryGroupNew", e); + return false; + } + + auto entry_group = + std::make_unique(system_bus_, entry_group_path); + + try { + entry_group->AddService( -1, // AVAHI_IF_UNSPEC -1, // AVAHI_PROTO_UNSPED 0, nsd_service_info.GetServiceName(), nsd_service_info.GetServiceType(), std::string(), std::string(), nsd_service_info.GetPort(), txt_records); - entry_group_->Commit(); + entry_group->Commit(); } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() @@ -83,48 +99,42 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { return false; } - advertising_ = true; + absl::MutexLock l(&entry_groups_mutex_); + entry_groups_.insert({*key, std::move(entry_group)}); + return true; } bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) { - if (!advertising_) { - NEARBY_LOGS(ERROR) << __func__ << ": Advertising is already stopped."; - return false; - } - if (entry_group_ == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": No entry group registered."; + auto key = entry_group_key(nsd_service_info); + if (!key.has_value()) { return false; } - try { - if (entry_group_->IsEmpty()) { - NEARBY_LOGS(ERROR) - << __func__ << ": Cannot stop advertising on an empty entry group."; - return false; - } - entry_group_->Reset(); - entry_group_->Commit(); - } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while removing service"; + absl::MutexLock l(&entry_groups_mutex_); + if (entry_groups_.count(*key) == 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Advertising is already inactive for this service."; return false; } - advertising_ = false; + entry_groups_.erase(*key); return true; } bool WifiLanMedium::StartDiscovery( const std::string &service_type, api::WifiLanMedium::DiscoveredServiceCallback callback) { - if (service_browsers_.count(service_type) != 0) { - auto &object = service_browsers_[service_type]; - NEARBY_LOGS(ERROR) << __func__ << ": A service browser for service type " - << service_type << " already exists at " - << object->getObjectPath(); - return false; + + { + absl::ReaderMutexLock l(&service_browsers_mutex_); + if (service_browsers_.count(service_type) != 0) { + auto &object = service_browsers_[service_type]; + NEARBY_LOGS(ERROR) << __func__ << ": A service browser for service type " + << service_type << " already exists at " + << object->getObjectPath(); + return false; + } } try { @@ -136,6 +146,8 @@ bool WifiLanMedium::StartDiscovery( << __func__ << ": Created a new org.freedesktop.Avahi.ServiceBrowser object at " << browser_object_path; + + absl::MutexLock l(&service_browsers_mutex_); service_browsers_.emplace( service_type, std::make_unique( @@ -145,7 +157,10 @@ bool WifiLanMedium::StartDiscovery( return false; } + service_browsers_mutex_.ReaderLock(); auto &browser = service_browsers_[service_type]; + service_browsers_mutex_.ReaderUnlock(); + try { NEARBY_LOGS(VERBOSE) << __func__ << ": Starting service discovery for " << browser->getObjectPath(); @@ -159,20 +174,13 @@ bool WifiLanMedium::StartDiscovery( } bool WifiLanMedium::StopDiscovery(const std::string &service_type) { + absl::MutexLock l(&service_browsers_mutex_); + if (service_browsers_.count(service_type) == 0) { NEARBY_LOGS(ERROR) << __func__ << ": Service type " << service_type << " has not been registered for discovery"; return false; } - - auto &browser = service_browsers_[service_type]; - try { - browser->Free(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(browser, "Free", e); - return false; - } - service_browsers_.erase(service_type); return true; diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 3600f500..856cfc7a 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -1,9 +1,9 @@ #ifndef PLATFORM_IMPL_LINUX_WIFI_LAN_H_ #define PLATFORM_IMPL_LINUX_WIFI_LAN_H_ #include -#include #include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/avahi.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_lan.h" @@ -14,14 +14,21 @@ namespace linux { class WifiLanMedium : public api::WifiLanMedium { public: WifiLanMedium(sdbus::IConnection &system_bus); - ~WifiLanMedium() override; + ~WifiLanMedium() override = default; bool IsNetworkConnected() const override; - bool StartAdvertising(const NsdServiceInfo &nsd_service_info) override; - bool StopAdvertising(const NsdServiceInfo &nsd_service_info) override; + + bool StartAdvertising(const NsdServiceInfo &nsd_service_info) override + ABSL_LOCKS_EXCLUDED(entry_groups_mutex_); + bool StopAdvertising(const NsdServiceInfo &nsd_service_info) override + ABSL_LOCKS_EXCLUDED(entry_groups_mutex_); + bool StartDiscovery(const std::string &service_type, - DiscoveredServiceCallback callback) override; - bool StopDiscovery(const std::string &service_type) override; + DiscoveredServiceCallback callback) override + ABSL_LOCKS_EXCLUDED(service_browsers_mutex_); + bool StopDiscovery(const std::string &service_type) override + ABSL_LOCKS_EXCLUDED(service_browsers_mutex_); + std::unique_ptr ConnectToService(const NsdServiceInfo &remote_service_info, CancellationFlag *cancellation_flag) override { @@ -39,19 +46,20 @@ public: } private: - DiscoveredServiceCallback discovery_cb_; - sdbus::IConnection &system_bus_; std::shared_ptr network_manager_; - std::shared_ptr avahi_; - std::unique_ptr entry_group_; + std::unique_ptr avahi_; + absl::Mutex entry_groups_mutex_; + absl::flat_hash_map, + std::unique_ptr> + entry_groups_ ABSL_GUARDED_BY(entry_groups_mutex_); + + absl::Mutex service_browsers_mutex_; absl::flat_hash_map> - service_browsers_; - - bool advertising_; + service_browsers_ ABSL_GUARDED_BY(service_browsers_mutex_); }; } // namespace linux } // namespace nearby