diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 6d647607..b387c3e9 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -67,6 +67,9 @@ cc_library( "bluetooth_pairing.h", "bluez.h", "dbus.h", + "network_manager.h", + "network_manager_active_connection.h", + "network_manager_access_point.h", "stream.h", "wifi_direct.h", "wifi_direct_server_socket.h", @@ -133,6 +136,8 @@ cc_library( "bluez.cc", "dbus.cc", "executor.cc", + "network_manager.cc", + "network_manager_active_connection.cc", "platform.cc", "preferences_manager.cc", "preferences_repository.cc", diff --git a/internal/platform/implementation/linux/network_manager.cc b/internal/platform/implementation/linux/network_manager.cc new file mode 100644 index 00000000..32297138 --- /dev/null +++ b/internal/platform/implementation/linux/network_manager.cc @@ -0,0 +1,93 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/network_manager.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" + +namespace nearby { +namespace linux { +std::unique_ptr +NetworkManagerObjectManager::GetActiveConnectionForAccessPoint( + const sdbus::ObjectPath &access_point, + const sdbus::ObjectPath &device_path) { + std::map>> + objects; + try { + objects = GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); + return nullptr; + } + + for (auto &[object_path, interfaces] : objects) { + if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/") == + 0) { + if (interfaces.count(org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME) == 1) { + auto props = interfaces[org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME]; + sdbus::ObjectPath specific_object = props["SpecificObject"]; + if (specific_object == access_point) { + std::vector devices = props["Devices"]; + for (auto &path : devices) { + if (path == device_path) { + return std::make_unique( + getProxy().getConnection(), object_path); + } + } + } + } + } + } + return nullptr; +} + +std::unique_ptr +NetworkManagerObjectManager::GetIp4Config( + const sdbus::ObjectPath &active_connection) { + std::map>> + objects; + try { + objects = GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); + return nullptr; + } + + for (auto &[object_path, interfaces] : objects) { + if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/", + 0) == 0) { + if (interfaces.count(org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME) == 1) { + auto props = interfaces[org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME]; + sdbus::ObjectPath specific_object = props["SpecificObject"]; + sdbus::ObjectPath ip4config = props["Ip4Config"]; + + if (specific_object == active_connection) + return std::make_unique( + getProxy().getConnection(), ip4config); + } + } + } + + return nullptr; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/network_manager.h b/internal/platform/implementation/linux/network_manager.h new file mode 100644 index 00000000..1c7c51af --- /dev/null +++ b/internal/platform/implementation/linux/network_manager.h @@ -0,0 +1,147 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_NETWORK_MANAGER_H_ +#define PLATFORM_IMPL_LINUX_NETWORK_MANAGER_H_ + +#include + +#include +#include + +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/ip4config_client.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" + +namespace nearby { +namespace linux { +class NetworkManager final + : public sdbus::ProxyInterfaces { + public: + NetworkManager(const NetworkManager &) = delete; + NetworkManager(NetworkManager &&) = delete; + NetworkManager &operator=(const NetworkManager &) = delete; + NetworkManager &operator=(NetworkManager &&) = delete; + explicit NetworkManager(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager"), + state_(kNMStateUnknown) { + registerProxy(); + try { + setState(State()); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); + } + } + ~NetworkManager() { unregisterProxy(); } + + // https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMState + enum NMState { + kNMStateUnknown = 0, + kNMStateAsleep = 10, + kNMStateDisconnected = 20, + kNMStateDisconnecting = 30, + kNMStateConnecting = 40, + kNMStateConnectedLocal = 50, + kNMStateConnectedSite = 60, + kNMStateConnectedGlobal = 70, + }; + + NMState getState() const { return state_; } + + protected: + void onCheckPermissions() override {} + void onStateChanged(const uint32_t &state) override { setState(state); } + void onDeviceAdded(const sdbus::ObjectPath &device_path) override {} + void onDeviceRemoved(const sdbus::ObjectPath &device_path) override {} + + private: + void inline setState(std::uint32_t val) { +#define NM_STATE_CASE_SET(k) \ + case (k): \ + state_ = (k); \ + break + + switch (val) { + NM_STATE_CASE_SET(kNMStateAsleep); + NM_STATE_CASE_SET(kNMStateDisconnected); + NM_STATE_CASE_SET(kNMStateDisconnecting); + NM_STATE_CASE_SET(kNMStateConnecting); + NM_STATE_CASE_SET(kNMStateConnectedLocal); + NM_STATE_CASE_SET(kNMStateConnectedSite); + NM_STATE_CASE_SET(kNMStateConnectedGlobal); + default: + NEARBY_LOGS(ERROR) << __func__ << "invalid NMState value: " << val + << ", setting state to unknown"; + NM_STATE_CASE_SET(kNMStateUnknown); + } +#undef NM_STATE_CASE_SET + }; + + std::atomic state_; +}; + +class NetworkManagerIP4Config + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::IP4Config_proxy> { + public: + NetworkManagerIP4Config(const NetworkManagerIP4Config &) = delete; + NetworkManagerIP4Config(NetworkManagerIP4Config &&) = delete; + NetworkManagerIP4Config &operator=(const NetworkManagerIP4Config &) = delete; + NetworkManagerIP4Config &operator=(NetworkManagerIP4Config &&) = delete; + NetworkManagerIP4Config(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &config_object_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + config_object_path) { + registerProxy(); + } + ~NetworkManagerIP4Config() { unregisterProxy(); } +}; + +class NetworkManagerObjectManager final + : public sdbus::ProxyInterfaces { + public: + NetworkManagerObjectManager(const NetworkManagerObjectManager &) = delete; + NetworkManagerObjectManager(NetworkManagerObjectManager &&) = delete; + NetworkManagerObjectManager &operator=(const NetworkManagerObjectManager &) = + delete; + NetworkManagerObjectManager &operator=(NetworkManagerObjectManager &&) = + delete; + explicit NetworkManagerObjectManager(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + "/org/freedesktop") { + registerProxy(); + } + ~NetworkManagerObjectManager() { unregisterProxy(); } + + std::unique_ptr GetIp4Config( + const sdbus::ObjectPath &access_point); + std::unique_ptr + GetActiveConnectionForAccessPoint(const sdbus::ObjectPath &access_point_path, + const sdbus::ObjectPath &device_path); + + protected: + void onInterfacesAdded( + const sdbus::ObjectPath &objectPath, + const std::map> + &interfacesAndProperties) override {} + void onInterfacesRemoved( + const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override {} +}; + +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/network_manager_access_point.h b/internal/platform/implementation/linux/network_manager_access_point.h new file mode 100644 index 00000000..131e4f6f --- /dev/null +++ b/internal/platform/implementation/linux/network_manager_access_point.h @@ -0,0 +1,43 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_NETWORK_MANAGER_ACCESS_POINT_H_ +#define PLATFORM_IMPL_LINUX_NETWORK_MANAGER_ACCESS_POINT_H_ +#include + +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/access_point_client.h" + +namespace nearby { +namespace linux { +class NetworkManagerAccessPoint + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::AccessPoint_proxy> { + public: + NetworkManagerAccessPoint(const NetworkManagerAccessPoint &) = delete; + NetworkManagerAccessPoint(NetworkManagerAccessPoint &&) = delete; + NetworkManagerAccessPoint &operator=(const NetworkManagerAccessPoint &) = + delete; + NetworkManagerAccessPoint &operator=(NetworkManagerAccessPoint &&) = delete; + NetworkManagerAccessPoint(sdbus::IConnection &system_bus, + sdbus::ObjectPath access_point_object_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + std::move(access_point_object_path)) { + registerProxy(); + } + ~NetworkManagerAccessPoint() { unregisterProxy(); } +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/network_manager_active_connection.cc b/internal/platform/implementation/linux/network_manager_active_connection.cc new file mode 100644 index 00000000..b97c2f2d --- /dev/null +++ b/internal/platform/implementation/linux/network_manager_active_connection.cc @@ -0,0 +1,124 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include + +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/network_manager.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" + +namespace nearby { +namespace linux { +std::ostream &operator<<( + std::ostream &stream, + const NetworkManagerActiveConnection::ActiveConnectionStateReason &reason) { + switch (reason) { + case NetworkManagerActiveConnection::kStateReasonUnknown: + return stream + << "The reason for the active connection state change is unknown."; + case NetworkManagerActiveConnection::kStateReasonNone: + return stream + << "No reason was given for the active connection state change."; + case NetworkManagerActiveConnection::kStateReasonUserDisconnected: + return stream << "The active connection changed state because the user " + "disconnected it."; + case NetworkManagerActiveConnection::kStateReasonDeviceDisconnected: + return stream + << "The active connection changed state because the device it was " + "using was disconnected."; + case NetworkManagerActiveConnection::kStateReasonServiceStopped: + return stream << "The service providing the VPN connection was stopped."; + case NetworkManagerActiveConnection::kStateReasonIPConfigInvalid: + return stream << "The IP config of the active connection was invalid."; + case NetworkManagerActiveConnection::kStateReasonConnectTimeout: + return stream << "The connection attempt to the VPN service timed out."; + case NetworkManagerActiveConnection::kStateReasonServiceStartTimeout: + return stream + << "A timeout occurred while starting the service providing the " + "VPN connection."; + case NetworkManagerActiveConnection::kStateReasonServiceStartFailed: + return stream + << "Starting the service providing the VPN connection failed."; + case NetworkManagerActiveConnection::kStateReasonNoSecrets: + return stream + << "Necessary secrets for the connection were not provided."; + case NetworkManagerActiveConnection::kStateReasonLoginFailed: + return stream << "Authentication to the server failed."; + case NetworkManagerActiveConnection::kStateReasonConnectionRemoved: + return stream << "The connection was deleted from settings."; + case NetworkManagerActiveConnection::kStateReasonDependencyFailed: + return stream + << "Master connection of this connection failed to activate."; + case NetworkManagerActiveConnection::kStateReasonDeviceRealizeFailed: + return stream << "Could not create the software device link."; + case NetworkManagerActiveConnection::kStateReasonDeviceRemoved: + return stream << "The device this connection depended on disappeared."; + } +} + +std::vector NetworkManagerActiveConnection::GetIP4Addresses() { + sdbus::ObjectPath ip4config_path; + try { + ip4config_path = Ip4Config(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "Ip4Config", e); + return {}; + } + + NetworkManagerIP4Config ip4config(getProxy().getConnection(), ip4config_path); + std::vector> address_data; + try { + address_data = ip4config.AddressData(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "AddressData", e); + return {}; + } + + std::vector ip4addresses; + for (auto &data : address_data) { + if (data.count("address") == 1) { + ip4addresses.push_back(data["address"]); + } + } + return ip4addresses; +} + +std::pair, bool> +NetworkManagerActiveConnection::WaitForConnection(absl::Duration timeout) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Waiting for an update to " + << getObjectPath() << "'s state"; + + auto state_changed = [this]() { + this->state_mutex_.AssertReaderHeld(); + return this->state_ == kStateActivated || this->state_ == kStateDeactivated; + }; + + absl::Condition cond(&state_changed); + auto success = state_mutex_.ReaderLockWhenWithTimeout(cond, timeout); + auto reason = reason_; + auto state = state_; + state_mutex_.ReaderUnlock(); + + if (!success) { + return {reason, true}; + } + + return state == kStateActivated ? std::pair{std::nullopt, false} + : std::pair{std::optional(reason), false}; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/network_manager_active_connection.h b/internal/platform/implementation/linux/network_manager_active_connection.h new file mode 100644 index 00000000..1d4aeb91 --- /dev/null +++ b/internal/platform/implementation/linux/network_manager_active_connection.h @@ -0,0 +1,113 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_NETWORK_MANAGER_ACTIVE_CONNECTION_H_ +#define PLATFORM_IMPL_LINUX_NETWORK_MANAGER_ACTIVE_CONNECTION_H_ + +#include + +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" + +namespace nearby { +namespace linux { +class NetworkManagerActiveConnection + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::Connection::Active_proxy> { + public: + enum ActiveConnectionState { + kStateUnknown = 0, + kStateActivating = 1, + kStateActivated = 2, + kStateDeactivating = 3, + kStateDeactivated = 4 + }; + enum ActiveConnectionStateReason { + kStateReasonUnknown = 0, + kStateReasonNone = 1, + kStateReasonUserDisconnected = 2, + kStateReasonDeviceDisconnected = 3, + kStateReasonServiceStopped = 4, + kStateReasonIPConfigInvalid = 5, + kStateReasonConnectTimeout = 6, + kStateReasonServiceStartTimeout = 7, + kStateReasonServiceStartFailed = 8, + kStateReasonNoSecrets = 9, + kStateReasonLoginFailed = 10, + kStateReasonConnectionRemoved = 11, + kStateReasonDependencyFailed = 12, + kStateReasonDeviceRealizeFailed = 13, + kStateReasonDeviceRemoved = 14, + }; + + NetworkManagerActiveConnection(const NetworkManagerActiveConnection &) = + delete; + NetworkManagerActiveConnection(NetworkManagerActiveConnection &&) = delete; + NetworkManagerActiveConnection &operator=( + const NetworkManagerActiveConnection &) = delete; + NetworkManagerActiveConnection &operator=(NetworkManagerActiveConnection &&) = + delete; + explicit NetworkManagerActiveConnection( + sdbus::IConnection &system_bus, sdbus::ObjectPath active_connection_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + std::move(active_connection_path)), + state_(kStateUnknown), + reason_(kStateReasonUnknown) { + registerProxy(); + try { + auto state = State(); + if (state >= kStateUnknown && state <= kStateDeactivated) { + state_ = static_cast(state); + } + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); + } + } + virtual ~NetworkManagerActiveConnection() { unregisterProxy(); } + + protected: + void onStateChanged(const uint32_t &state, const uint32_t &reason) override + ABSL_LOCKS_EXCLUDED(state_mutex_) { + absl::MutexLock l(&state_mutex_); + if (state >= kStateUnknown && state <= kStateDeactivated) { + state_ = static_cast(state); + } + if (reason >= kStateReasonUnknown && reason <= kStateReasonDeviceRemoved) { + reason_ = static_cast(reason); + } + } + + public: + std::pair, bool> WaitForConnection( + absl::Duration timeout = absl::Seconds(10)) + ABSL_LOCKS_EXCLUDED(state_mutex_); + std::vector GetIP4Addresses(); + + private: + absl::Mutex state_mutex_; + ActiveConnectionState state_ ABSL_GUARDED_BY(state_mutex_); + ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_); +}; + +extern std::ostream &operator<<( + std::ostream &stream, + const NetworkManagerActiveConnection::ActiveConnectionStateReason &reason); + +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 9ff06cf2..33bdcce5 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -27,124 +27,12 @@ #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi.h" namespace nearby { namespace linux { - -std::ostream &operator<<(std::ostream &s, - const ActiveConnectionStateReason &reason) { - switch (reason) { - case kStateReasonUnknown: - return s - << "The reason for the active connection state change is unknown."; - case kStateReasonNone: - return s << "No reason was given for the active connection state change."; - case kStateReasonUserDisconnected: - return s << "The active connection changed state because the user " - "disconnected it."; - case kStateReasonDeviceDisconnected: - return s - << "The active connection changed state because the device it was " - "using was disconnected."; - case kStateReasonServiceStopped: - return s << "The service providing the VPN connection was stopped."; - case kStateReasonIPConfigInvalid: - return s << "The IP config of the active connection was invalid."; - case kStateReasonConnectTimeout: - return s << "The connection attempt to the VPN service timed out."; - case kStateReasonServiceStartTimeout: - return s << "A timeout occurred while starting the service providing the " - "VPN connection."; - case kStateReasonServiceStartFailed: - return s << "Starting the service providing the VPN connection failed."; - case kStateReasonNoSecrets: - return s << "Necessary secrets for the connection were not provided."; - case kStateReasonLoginFailed: - return s << "Authentication to the server failed."; - case kStateReasonConnectionRemoved: - return s << "The connection was deleted from settings."; - case kStateReasonDependencyFailed: - return s << "Master connection of this connection failed to activate."; - case kStateReasonDeviceRealizeFailed: - return s << "Could not create the software device link."; - case kStateReasonDeviceRemoved: - return s << "The device this connection depended on disappeared."; - } -} - -std::unique_ptr -NetworkManagerObjectManager::GetIp4Config( - const sdbus::ObjectPath &active_connection) { - std::map>> - objects; - try { - objects = GetManagedObjects(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); - return nullptr; - } - - for (auto &[object_path, interfaces] : objects) { - if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/", - 0) == 0) { - if (interfaces.count(org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME) == 1) { - auto props = interfaces[org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME]; - sdbus::ObjectPath specific_object = props["SpecificObject"]; - sdbus::ObjectPath ip4config = props["Ip4Config"]; - - if (specific_object == active_connection) - return std::make_unique( - getProxy().getConnection(), ip4config); - } - } - } - - return nullptr; -} - -std::unique_ptr -NetworkManagerObjectManager::GetActiveConnectionForAccessPoint( - const sdbus::ObjectPath &access_point, - const sdbus::ObjectPath &device_path) { - std::map>> - objects; - try { - objects = GetManagedObjects(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); - return nullptr; - } - - for (auto &[object_path, interfaces] : objects) { - if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/") == - 0) { - if (interfaces.count(org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME) == 1) { - auto props = interfaces[org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME]; - sdbus::ObjectPath specific_object = props["SpecificObject"]; - if (specific_object == access_point) { - std::vector devices = props["Devices"]; - for (auto &path : devices) { - if (path == device_path) { - return std::make_unique( - getProxy().getConnection(), object_path); - } - } - } - } - } - } - - return nullptr; -} - api::WifiCapability &NetworkManagerWifiMedium::GetCapability() { try { auto cap_mask = WirelessCapabilities(); @@ -222,16 +110,9 @@ void NetworkManagerWifiMedium::onPropertiesChanged( return; } - for (auto &[property, val] : changedProperties) { - if (property == "LastScan") { - { - absl::MutexLock l(&last_scan_lock_); - last_scan_ = val; - } - // absl::ReaderMutexLock l(&scan_result_callback_lock_); - // if (scan_result_callback_.has_value()) { - // } - } + if (changedProperties.count("LastScan") == 1) { + absl::MutexLock l(&last_scan_lock_); + last_scan_ = changedProperties.at("LastScan"); } } @@ -413,8 +294,8 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( << active_conn_path << " failed to activate, NMActiveConnectionStateReason:" << *reason; - if (*reason == ActiveConnectionStateReason::kStateReasonNoSecrets || - *reason == ActiveConnectionStateReason::kStateReasonLoginFailed) + if (*reason == NetworkManagerActiveConnection::kStateReasonNoSecrets || + *reason == NetworkManagerActiveConnection::kStateReasonLoginFailed) return api::WifiConnectionStatus::kAuthFailure; } diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 53821eb3..788741c9 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -20,288 +20,22 @@ #include #include #include +#include #include #include #include #include -#include #include "absl/synchronization/mutex.h" -#include "internal/platform/implementation/linux/dbus.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/access_point_client.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/ip4config_client.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h" +#include "internal/platform/implementation/linux/network_manager.h" +#include "internal/platform/implementation/linux/network_manager_access_point.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" #include "internal/platform/implementation/wifi.h" -#include "internal/platform/logging.h" namespace nearby { namespace linux { -class NetworkManager final - : public sdbus::ProxyInterfaces { - public: - NetworkManager(const NetworkManager &) = delete; - NetworkManager(NetworkManager &&) = delete; - NetworkManager &operator=(const NetworkManager &) = delete; - NetworkManager &operator=(NetworkManager &&) = delete; - explicit NetworkManager(sdbus::IConnection &system_bus) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - "/org/freedesktop/NetworkManager"), - state_(kNMStateUnknown) { - registerProxy(); - try { - setState(State()); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); - } - } - ~NetworkManager() { unregisterProxy(); } - - // https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMState - enum NMState { - kNMStateUnknown = 0, - kNMStateAsleep = 10, - kNMStateDisconnected = 20, - kNMStateDisconnecting = 30, - kNMStateConnecting = 40, - kNMStateConnectedLocal = 50, - kNMStateConnectedSite = 60, - kNMStateConnectedGlobal = 70, - }; - - NMState getState() const { return state_; } - - protected: - void onCheckPermissions() override {} - void onStateChanged(const uint32_t &state) override { setState(state); } - void onDeviceAdded(const sdbus::ObjectPath &device_path) override {} - void onDeviceRemoved(const sdbus::ObjectPath &device_path) override {} - - private: - void inline setState(std::uint32_t val) { -#define NM_STATE_CASE_SET(k) \ - case (k): \ - state_ = (k); \ - break - - switch (val) { - NM_STATE_CASE_SET(kNMStateAsleep); - NM_STATE_CASE_SET(kNMStateDisconnected); - NM_STATE_CASE_SET(kNMStateDisconnecting); - NM_STATE_CASE_SET(kNMStateConnecting); - NM_STATE_CASE_SET(kNMStateConnectedLocal); - NM_STATE_CASE_SET(kNMStateConnectedSite); - NM_STATE_CASE_SET(kNMStateConnectedGlobal); - default: - NEARBY_LOGS(ERROR) << __func__ << "invalid NMState value: " << val - << ", setting state to unknown"; - NM_STATE_CASE_SET(kNMStateUnknown); - } -#undef NM_STATE_CASE_SET - }; - - std::atomic state_; -}; - -class NetworkManagerIP4Config - : public sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::IP4Config_proxy> { - public: - NetworkManagerIP4Config(const NetworkManagerIP4Config &) = delete; - NetworkManagerIP4Config(NetworkManagerIP4Config &&) = delete; - NetworkManagerIP4Config &operator=(const NetworkManagerIP4Config &) = delete; - NetworkManagerIP4Config &operator=(NetworkManagerIP4Config &&) = delete; - NetworkManagerIP4Config(sdbus::IConnection &system_bus, - const sdbus::ObjectPath &config_object_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - config_object_path) { - registerProxy(); - } - ~NetworkManagerIP4Config() { unregisterProxy(); } -}; - -class NetworkManagerAccessPoint - : public sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::AccessPoint_proxy> { - public: - NetworkManagerAccessPoint(const NetworkManagerAccessPoint &) = delete; - NetworkManagerAccessPoint(NetworkManagerAccessPoint &&) = delete; - NetworkManagerAccessPoint &operator=(const NetworkManagerAccessPoint &) = - delete; - NetworkManagerAccessPoint &operator=(NetworkManagerAccessPoint &&) = delete; - NetworkManagerAccessPoint(sdbus::IConnection &system_bus, - sdbus::ObjectPath access_point_object_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - std::move(access_point_object_path)) { - registerProxy(); - } - ~NetworkManagerAccessPoint() { unregisterProxy(); } -}; - -enum ActiveConnectionState { - kStateUnknown = 0, - kStateActivating = 1, - kStateActivated = 2, - kStateDeactivating = 3, - kStateDeactivated = 4 -}; -enum ActiveConnectionStateReason { - kStateReasonUnknown = 0, - kStateReasonNone = 1, - kStateReasonUserDisconnected = 2, - kStateReasonDeviceDisconnected = 3, - kStateReasonServiceStopped = 4, - kStateReasonIPConfigInvalid = 5, - kStateReasonConnectTimeout = 6, - kStateReasonServiceStartTimeout = 7, - kStateReasonServiceStartFailed = 8, - kStateReasonNoSecrets = 9, - kStateReasonLoginFailed = 10, - kStateReasonConnectionRemoved = 11, - kStateReasonDependencyFailed = 12, - kStateReasonDeviceRealizeFailed = 13, - kStateReasonDeviceRemoved = 14, -}; - -extern std::ostream &operator<<(std::ostream &s, - const ActiveConnectionStateReason &reason); - -class NetworkManagerActiveConnection - : public sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::Connection::Active_proxy> { - public: - NetworkManagerActiveConnection(const NetworkManagerActiveConnection &) = - delete; - NetworkManagerActiveConnection(NetworkManagerActiveConnection &&) = delete; - NetworkManagerActiveConnection &operator=( - const NetworkManagerActiveConnection &) = delete; - NetworkManagerActiveConnection &operator=(NetworkManagerActiveConnection &&) = - delete; - explicit NetworkManagerActiveConnection( - sdbus::IConnection &system_bus, sdbus::ObjectPath active_connection_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - std::move(active_connection_path)), - state_(kStateUnknown), - reason_(kStateReasonUnknown) { - registerProxy(); - try { - auto state = State(); - if (state >= kStateUnknown && state <= kStateDeactivated) { - state_ = static_cast(state); - } - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); - } - } - virtual ~NetworkManagerActiveConnection() { unregisterProxy(); } - - protected: - void onStateChanged(const uint32_t &state, const uint32_t &reason) override - ABSL_LOCKS_EXCLUDED(state_mutex_) { - absl::MutexLock l(&state_mutex_); - if (state >= kStateUnknown && state <= kStateDeactivated) { - state_ = static_cast(state); - } - if (reason >= kStateReasonUnknown && reason <= kStateReasonDeviceRemoved) { - reason_ = static_cast(reason); - } - } - - public: - std::pair, bool> WaitForConnection( - absl::Duration timeout = absl::Seconds(10)) - ABSL_LOCKS_EXCLUDED(state_mutex_) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Waiting for an update to " - << getObjectPath() << "'s state"; - - auto state_changed = [this]() { - this->state_mutex_.AssertReaderHeld(); - return this->state_ == kStateActivated || - this->state_ == kStateDeactivated; - }; - - absl::Condition cond(&state_changed); - auto success = state_mutex_.ReaderLockWhenWithTimeout(cond, timeout); - auto reason = reason_; - auto state = state_; - state_mutex_.ReaderUnlock(); - - if (!success) { - return {reason, true}; - } - - return state == kStateActivated ? std::pair{std::nullopt, false} - : std::pair{std::optional(reason), false}; - } - - std::vector GetIP4Addresses() { - sdbus::ObjectPath ip4config_path; - try { - ip4config_path = Ip4Config(); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(this, "Ip4Config", e); - return {}; - } - - NetworkManagerIP4Config ip4config(getProxy().getConnection(), - ip4config_path); - std::vector> address_data; - try { - address_data = ip4config.AddressData(); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "AddressData", e); - return {}; - } - - std::vector ip4addresses; - for (auto &data : address_data) { - if (data.count("address") == 1) { - ip4addresses.push_back(data["address"]); - } - } - return ip4addresses; - } - - private: - absl::Mutex state_mutex_; - ActiveConnectionState state_ ABSL_GUARDED_BY(state_mutex_); - ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_); -}; - -class NetworkManagerObjectManager final - : public sdbus::ProxyInterfaces { - public: - NetworkManagerObjectManager(const NetworkManagerObjectManager &) = delete; - NetworkManagerObjectManager(NetworkManagerObjectManager &&) = delete; - NetworkManagerObjectManager &operator=(const NetworkManagerObjectManager &) = - delete; - NetworkManagerObjectManager &operator=(NetworkManagerObjectManager &&) = - delete; - explicit NetworkManagerObjectManager(sdbus::IConnection &system_bus) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - "/org/freedesktop") { - registerProxy(); - } - ~NetworkManagerObjectManager() { unregisterProxy(); } - - std::unique_ptr GetIp4Config( - const sdbus::ObjectPath &access_point); - std::unique_ptr - GetActiveConnectionForAccessPoint(const sdbus::ObjectPath &access_point_path, - const sdbus::ObjectPath &device_path); - - protected: - void onInterfacesAdded( - const sdbus::ObjectPath &objectPath, - const std::map> - &interfacesAndProperties) override {} - void onInterfacesRemoved( - const sdbus::ObjectPath &objectPath, - const std::vector &interfaces) override {} -}; - class NetworkManagerWifiMedium : public api::WifiMedium, public sdbus::ProxyInterfaces<