mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
WIP: wifi direct support. merged from upstream
This commit is contained in:
@@ -115,9 +115,10 @@ cc_library(
|
||||
"network_manager_access_point.h",
|
||||
"stream.h",
|
||||
"tcp_server_socket.h",
|
||||
# "wifi_direct.h",
|
||||
"wifi_direct.h",
|
||||
"wifi_direct_utils.h",
|
||||
# "wifi_direct_server_socket.h",
|
||||
# "wifi_direct_socket.h",
|
||||
"wifi_direct_socket.h",
|
||||
"wifi_hotspot.h",
|
||||
"wifi_hotspot_server_socket.h",
|
||||
"wifi_hotspot_socket.h",
|
||||
@@ -224,7 +225,8 @@ cc_library(
|
||||
"submittable_executor.cc",
|
||||
"thread_pool.cc",
|
||||
"utils.cc",
|
||||
# "wifi_direct.cc",
|
||||
"wifi_direct.cc",
|
||||
"wifi_direct_utils.cc",
|
||||
# "wifi_direct_server_socket.cc",
|
||||
"wifi_hotspot.cc",
|
||||
"wifi_hotspot_server_socket.cc",
|
||||
@@ -308,6 +310,7 @@ cc_test(
|
||||
"atomic_reference_test.cc",
|
||||
"mutex_test.cc",
|
||||
"utils_test.cc",
|
||||
"wifi_direct_utils_test.cc",
|
||||
"ble_l2cap_socket_test.cc",
|
||||
"bluetooth_classic_socket_test.cc",
|
||||
# "bluetooth_adapter_test.cc",
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#define PLATFORM_IMPL_LINUX_API_BLUEZ_BLE_ADVERTISEMENT_H_
|
||||
|
||||
#include <future>
|
||||
#include <absl/log/log.h>
|
||||
#include <sdbus-c++/AdaptorInterfaces.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<node name="/">
|
||||
<interface name="org.freedesktop.NetworkManager.WifiP2PPeer">
|
||||
<property name="Name" type="s" access="read"/>
|
||||
<property name="Flags" type="u" access="read"/>
|
||||
<property name="Manufacturer" type="s" access="read"/>
|
||||
<property name="Model" type="s" access="read"/>
|
||||
<property name="ModelNumber" type="s" access="read"/>
|
||||
<property name="Serial" type="s" access="read"/>
|
||||
<property name="WfdIEs" type="ay" access="read"/>
|
||||
<property name="HwAddress" type="s" access="read"/>
|
||||
<property name="Strength" type="y" access="read"/>
|
||||
<property name="LastSeen" type="i" access="read"/>
|
||||
</interface>
|
||||
</node>
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__internal_platform_implementation_linux_generated_dbus_networkmanager_wifi_p2p_peer_client_h__proxy__H__
|
||||
#define __sdbuscpp__internal_platform_implementation_linux_generated_dbus_networkmanager_wifi_p2p_peer_client_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace freedesktop {
|
||||
namespace NetworkManager {
|
||||
|
||||
class WifiP2PPeer_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.WifiP2PPeer";
|
||||
|
||||
protected:
|
||||
WifiP2PPeer_proxy(sdbus::IProxy& proxy)
|
||||
: m_proxy(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
WifiP2PPeer_proxy(const WifiP2PPeer_proxy&) = delete;
|
||||
WifiP2PPeer_proxy& operator=(const WifiP2PPeer_proxy&) = delete;
|
||||
WifiP2PPeer_proxy(WifiP2PPeer_proxy&&) = delete;
|
||||
WifiP2PPeer_proxy& operator=(WifiP2PPeer_proxy&&) = delete;
|
||||
|
||||
~WifiP2PPeer_proxy() = default;
|
||||
|
||||
void registerProxy()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
std::string Name()
|
||||
{
|
||||
return m_proxy.getProperty("Name").onInterface(INTERFACE_NAME).get<std::string>();
|
||||
}
|
||||
|
||||
uint32_t Flags()
|
||||
{
|
||||
return m_proxy.getProperty("Flags").onInterface(INTERFACE_NAME).get<uint32_t>();
|
||||
}
|
||||
|
||||
std::string Manufacturer()
|
||||
{
|
||||
return m_proxy.getProperty("Manufacturer").onInterface(INTERFACE_NAME).get<std::string>();
|
||||
}
|
||||
|
||||
std::string Model()
|
||||
{
|
||||
return m_proxy.getProperty("Model").onInterface(INTERFACE_NAME).get<std::string>();
|
||||
}
|
||||
|
||||
std::string ModelNumber()
|
||||
{
|
||||
return m_proxy.getProperty("ModelNumber").onInterface(INTERFACE_NAME).get<std::string>();
|
||||
}
|
||||
|
||||
std::string Serial()
|
||||
{
|
||||
return m_proxy.getProperty("Serial").onInterface(INTERFACE_NAME).get<std::string>();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> WfdIEs()
|
||||
{
|
||||
return m_proxy.getProperty("WfdIEs").onInterface(INTERFACE_NAME).get<std::vector<uint8_t>>();
|
||||
}
|
||||
|
||||
std::string HwAddress()
|
||||
{
|
||||
return m_proxy.getProperty("HwAddress").onInterface(INTERFACE_NAME).get<std::string>();
|
||||
}
|
||||
|
||||
uint8_t Strength()
|
||||
{
|
||||
return m_proxy.getProperty("Strength").onInterface(INTERFACE_NAME).get<uint8_t>();
|
||||
}
|
||||
|
||||
int32_t LastSeen()
|
||||
{
|
||||
return m_proxy.getProperty("LastSeen").onInterface(INTERFACE_NAME).get<int32_t>();
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& m_proxy;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -79,7 +79,7 @@ std::vector<std::string> ActiveConnection::GetIP4Addresses() {
|
||||
sdbus::ObjectPath ip4config_path;
|
||||
try {
|
||||
ip4config_path = Ip4Config();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(this, "Ip4Config", e);
|
||||
return {};
|
||||
}
|
||||
@@ -88,13 +88,13 @@ std::vector<std::string> ActiveConnection::GetIP4Addresses() {
|
||||
std::vector<std::map<std::string, sdbus::Variant>> address_data;
|
||||
try {
|
||||
address_data = ip4config.AddressData();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "AddressData", e);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> ip4addresses;
|
||||
for (auto &data : address_data) {
|
||||
for (auto& data : address_data) {
|
||||
if (data.count("address") == 1) {
|
||||
ip4addresses.push_back(data["address"].get<std::string>());
|
||||
}
|
||||
@@ -102,10 +102,32 @@ std::vector<std::string> ActiveConnection::GetIP4Addresses() {
|
||||
return ip4addresses;
|
||||
}
|
||||
|
||||
std::string ActiveConnection::GetIP4Gateway() {
|
||||
sdbus::ObjectPath ip4config_path;
|
||||
try {
|
||||
ip4config_path = Ip4Config();
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(this, "Ip4Config", e);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (ip4config_path.empty() || ip4config_path == "/") {
|
||||
return {};
|
||||
}
|
||||
|
||||
IP4Config ip4config(system_bus_, ip4config_path);
|
||||
try {
|
||||
return ip4config.Gateway();
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "Gateway", e);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<std::optional<ActiveConnection::ActiveConnectionStateReason>, bool>
|
||||
ActiveConnection::WaitForConnection(absl::Duration timeout) {
|
||||
LOG(INFO) << __func__ << ": Waiting for an update to "
|
||||
<< getProxy().getObjectPath() << "'s state";
|
||||
<< getProxy().getObjectPath() << "'s state";
|
||||
|
||||
auto state_changed = [this]() {
|
||||
this->state_mutex_.AssertReaderHeld();
|
||||
|
||||
@@ -61,10 +61,10 @@ class ActiveConnection
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
ActiveConnection(const ActiveConnection &) = delete;
|
||||
ActiveConnection(ActiveConnection &&) = delete;
|
||||
ActiveConnection &operator=(const ActiveConnection &) = delete;
|
||||
ActiveConnection &operator=(ActiveConnection &&) = delete;
|
||||
ActiveConnection(const ActiveConnection&) = delete;
|
||||
ActiveConnection(ActiveConnection&&) = delete;
|
||||
ActiveConnection& operator=(const ActiveConnection&) = delete;
|
||||
ActiveConnection& operator=(ActiveConnection&&) = delete;
|
||||
explicit ActiveConnection(std::shared_ptr<sdbus::IConnection> system_bus,
|
||||
sdbus::ObjectPath active_connection_path)
|
||||
: ProxyInterfaces(*system_bus,
|
||||
@@ -80,14 +80,14 @@ class ActiveConnection
|
||||
if (state >= kStateUnknown && state <= kStateDeactivated) {
|
||||
state_ = static_cast<ActiveConnectionState>(state);
|
||||
}
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e);
|
||||
}
|
||||
}
|
||||
virtual ~ActiveConnection() { unregisterProxy(); }
|
||||
|
||||
protected:
|
||||
void onStateChanged(const uint32_t &state, const uint32_t &reason) override
|
||||
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) {
|
||||
@@ -107,6 +107,7 @@ class ActiveConnection
|
||||
absl::Duration timeout = absl::Seconds(10))
|
||||
ABSL_LOCKS_EXCLUDED(state_mutex_);
|
||||
std::vector<std::string> GetIP4Addresses();
|
||||
std::string GetIP4Gateway();
|
||||
|
||||
private:
|
||||
std::shared_ptr<sdbus::IConnection> system_bus_;
|
||||
@@ -116,9 +117,9 @@ class ActiveConnection
|
||||
ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_);
|
||||
};
|
||||
|
||||
extern std::ostream &operator<<(
|
||||
std::ostream &stream,
|
||||
const ActiveConnection::ActiveConnectionStateReason &reason);
|
||||
extern std::ostream& operator<<(
|
||||
std::ostream& stream,
|
||||
const ActiveConnection::ActiveConnectionStateReason& reason);
|
||||
|
||||
} // namespace networkmanager
|
||||
} // namespace linux
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "internal/platform/implementation/input_file.h"
|
||||
#include "internal/platform/implementation/linux/atomic_boolean.h"
|
||||
#include "internal/platform/implementation/linux/atomic_uint32.h"
|
||||
//#include "internal/platform/implementation/linux/ble_v2_medium.h"
|
||||
// #include "internal/platform/implementation/linux/ble_v2_medium.h"
|
||||
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
|
||||
#include "internal/platform/implementation/linux/bluetooth_classic_medium.h"
|
||||
#include "internal/platform/implementation/linux/bluez.h"
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "internal/platform/implementation/linux/preferences_manager.h"
|
||||
#include "internal/platform/implementation/linux/submittable_executor.h"
|
||||
#include "internal/platform/implementation/linux/timer.h"
|
||||
// #include "internal/platform/implementation/linux/wifi_direct.h"
|
||||
#include "internal/platform/implementation/linux/wifi_direct.h"
|
||||
// #include "internal/platform/implementation/linux/wifi_hotspot.h"
|
||||
#include "internal/platform/implementation/linux/wifi_lan.h"
|
||||
// #include "internal/platform/implementation/linux/wifi_medium.h"
|
||||
@@ -56,22 +56,22 @@
|
||||
#include "internal/platform/implementation/wifi_lan.h"
|
||||
#include "internal/platform/payload_id.h"
|
||||
#include "scheduled_executor.h"
|
||||
// #include "wifi_direct.h"
|
||||
#include "wifi_direct.h"
|
||||
#include "wifi_hotspot.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
std::string ImplementationPlatform::GetCustomSavePath(
|
||||
const std::string &parent_folder, const std::string &file_name) {
|
||||
const std::string& parent_folder, const std::string& file_name) {
|
||||
auto fs = std::filesystem::path(parent_folder);
|
||||
return (fs / file_name).string();
|
||||
}
|
||||
|
||||
std::string ImplementationPlatform::GetDownloadPath(
|
||||
const std::string &parent_folder, const std::string &file_name) {
|
||||
const std::string& parent_folder, const std::string& file_name) {
|
||||
std::filesystem::path downloads;
|
||||
const char* download_dir = getenv("XDG_DOWNLOAD_DIR");
|
||||
|
||||
|
||||
if (download_dir != nullptr) {
|
||||
downloads = std::filesystem::path(download_dir);
|
||||
} else {
|
||||
@@ -83,16 +83,17 @@ std::string ImplementationPlatform::GetDownloadPath(
|
||||
downloads = "/tmp/Downloads";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (downloads / std::filesystem::path(parent_folder).filename() /
|
||||
std::filesystem::path(file_name).filename()).string();
|
||||
std::filesystem::path(file_name).filename())
|
||||
.string();
|
||||
}
|
||||
|
||||
std::string ImplementationPlatform::GetDownloadPath(
|
||||
const std::string &file_name) {
|
||||
const std::string& file_name) {
|
||||
std::filesystem::path downloads;
|
||||
const char* download_dir = getenv("XDG_DOWNLOAD_DIR");
|
||||
|
||||
|
||||
if (download_dir != nullptr) {
|
||||
downloads = std::filesystem::path(download_dir);
|
||||
} else {
|
||||
@@ -104,15 +105,15 @@ std::string ImplementationPlatform::GetDownloadPath(
|
||||
downloads = "/tmp/Downloads";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (downloads / std::filesystem::path(file_name).filename()).string();
|
||||
}
|
||||
|
||||
std::string ImplementationPlatform::GetAppDataPath(
|
||||
const std::string &file_name) {
|
||||
const std::string& file_name) {
|
||||
std::filesystem::path state;
|
||||
const char* state_home = getenv("XDG_STATE_HOME");
|
||||
|
||||
|
||||
if (state_home != nullptr) {
|
||||
state = std::filesystem::path(state_home);
|
||||
} else {
|
||||
@@ -124,11 +125,13 @@ std::string ImplementationPlatform::GetAppDataPath(
|
||||
state = "/tmp/state";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (state / std::filesystem::path(file_name).filename()).string();
|
||||
}
|
||||
|
||||
OSName ImplementationPlatform::GetCurrentOS() { return OSName::kWindows; }
|
||||
OSName ImplementationPlatform::GetCurrentOS() {
|
||||
return OSName::kWindows;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
|
||||
bool initial_value) {
|
||||
@@ -154,7 +157,7 @@ std::unique_ptr<api::Mutex> ImplementationPlatform::CreateMutex(
|
||||
#pragma pop_macro("CreateMutex")
|
||||
|
||||
std::unique_ptr<api::ConditionVariable>
|
||||
ImplementationPlatform::CreateConditionVariable(api::Mutex *mutex) {
|
||||
ImplementationPlatform::CreateConditionVariable(api::Mutex* mutex) {
|
||||
return std::make_unique<linux::ConditionVariable>(mutex);
|
||||
}
|
||||
|
||||
@@ -171,7 +174,7 @@ std::unique_ptr<api::InputFile> ImplementationPlatform::CreateInputFile(
|
||||
}
|
||||
|
||||
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
|
||||
const std::string &file_path) {
|
||||
const std::string& file_path) {
|
||||
return nearby::shared::IOFile::CreateInputFile(file_path);
|
||||
}
|
||||
|
||||
@@ -182,20 +185,20 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
|
||||
}
|
||||
|
||||
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
|
||||
const std::string &file_path) {
|
||||
const std::string& file_path) {
|
||||
std::filesystem::path path(file_path);
|
||||
try {
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
} catch (std::filesystem::filesystem_error const &err) {
|
||||
} catch (std::filesystem::filesystem_error const& err) {
|
||||
LOG(ERROR) << __func__ << ": error creating directory tree "
|
||||
<< path.parent_path() << ": " << err.what();
|
||||
<< path.parent_path() << ": " << err.what();
|
||||
}
|
||||
|
||||
return nearby::shared::IOFile::CreateOutputFile(path.string());
|
||||
}
|
||||
|
||||
std::unique_ptr<api::LogMessage> ImplementationPlatform::CreateLogMessage(
|
||||
const char *file, int line, LogMessage::Severity severity) {
|
||||
const char* file, int line, LogMessage::Severity severity) {
|
||||
return nullptr;
|
||||
// Disabled LogMessage
|
||||
// return std::make_unique<linux::LogMessage>(file, line, severity);
|
||||
@@ -223,33 +226,34 @@ ImplementationPlatform::CreateBluetoothAdapter() {
|
||||
auto manager = linux::bluez::BluezObjectManager(*system_bus);
|
||||
try {
|
||||
auto interfaces = manager.GetManagedObjects();
|
||||
for (auto &[object, properties] : interfaces) {
|
||||
if (properties.count(sdbus::InterfaceName(org::bluez::Adapter1_proxy::INTERFACE_NAME)) == 1) {
|
||||
for (auto& [object, properties] : interfaces) {
|
||||
if (properties.count(sdbus::InterfaceName(
|
||||
org::bluez::Adapter1_proxy::INTERFACE_NAME)) == 1) {
|
||||
LOG(INFO) << __func__ << ": found bluetooth adapter " << object;
|
||||
return std::make_unique<linux::BluetoothAdapter>(system_bus, object);
|
||||
}
|
||||
}
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(&manager, "GetManagedObjects", e);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOG(ERROR) << __func__
|
||||
<< ": couldn't find a bluetooth adapter on this system";
|
||||
<< ": couldn't find a bluetooth adapter on this system";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::BluetoothClassicMedium>
|
||||
ImplementationPlatform::CreateBluetoothClassicMedium(
|
||||
BluetoothAdapter &adapter) {
|
||||
BluetoothAdapter& adapter) {
|
||||
return std::make_unique<linux::BluetoothClassicMedium>(
|
||||
dynamic_cast<linux::BluetoothAdapter &>(adapter));
|
||||
dynamic_cast<linux::BluetoothAdapter&>(adapter));
|
||||
}
|
||||
|
||||
std::unique_ptr<api::ble::BleMedium> ImplementationPlatform::CreateBleMedium(
|
||||
BluetoothAdapter &adapter) {
|
||||
BluetoothAdapter& adapter) {
|
||||
return std::make_unique<linux::BleV2Medium>(
|
||||
dynamic_cast<linux::BluetoothAdapter &>(adapter));
|
||||
dynamic_cast<linux::BluetoothAdapter&>(adapter));
|
||||
}
|
||||
|
||||
std::unique_ptr<api::CredentialStorage>
|
||||
@@ -265,7 +269,7 @@ static std::unique_ptr<linux::NetworkManagerWifiMedium> createWifiMedium(
|
||||
|
||||
try {
|
||||
device_paths = nm->GetAllDevices();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(nm, "GetAllDevices", e);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -273,38 +277,39 @@ static std::unique_ptr<linux::NetworkManagerWifiMedium> createWifiMedium(
|
||||
auto manager = linux::networkmanager::ObjectManager(nm->GetConnection());
|
||||
|
||||
std::map<sdbus::ObjectPath,
|
||||
std::map<sdbus::InterfaceName, std::map<sdbus::PropertyName, sdbus::Variant>>>
|
||||
std::map<sdbus::InterfaceName,
|
||||
std::map<sdbus::PropertyName, sdbus::Variant>>>
|
||||
objects;
|
||||
try {
|
||||
objects = manager.GetManagedObjects();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(nm, "GetManagedObjects", e);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto &device_path : device_paths) {
|
||||
for (auto& device_path : device_paths) {
|
||||
if (objects.count(device_path) == 1) {
|
||||
auto device = objects[device_path];
|
||||
if (device.count(sdbus::InterfaceName(org::freedesktop::NetworkManager::Device::
|
||||
Wireless_proxy::INTERFACE_NAME)) == 1) {
|
||||
if (device.count(
|
||||
sdbus::InterfaceName(org::freedesktop::NetworkManager::Device::
|
||||
Wireless_proxy::INTERFACE_NAME)) == 1) {
|
||||
LOG(INFO) << __func__
|
||||
<< ": Found a wireless device at :" << device_path;
|
||||
<< ": Found a wireless device at :" << device_path;
|
||||
return std::make_unique<linux::NetworkManagerWifiMedium>(nm,
|
||||
device_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG(ERROR) << __func__
|
||||
<< ": couldn't find a wireless device on this system";
|
||||
LOG(ERROR) << __func__ << ": couldn't find a wireless device on this system";
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<api::WifiMedium> ImplementationPlatform::CreateWifiMedium() {
|
||||
// return nullptr;
|
||||
auto nm =
|
||||
std::make_shared<linux::networkmanager::NetworkManager>(linux::getSystemBusConnection());
|
||||
auto nm = std::make_shared<linux::networkmanager::NetworkManager>(
|
||||
linux::getSystemBusConnection());
|
||||
return createWifiMedium(nm);
|
||||
}
|
||||
|
||||
@@ -317,8 +322,8 @@ ImplementationPlatform::CreateWifiLanMedium() {
|
||||
|
||||
std::unique_ptr<api::WifiHotspotMedium>
|
||||
ImplementationPlatform::CreateWifiHotspotMedium() {
|
||||
auto nm =
|
||||
std::make_shared<linux::networkmanager::NetworkManager>(linux::getSystemBusConnection());
|
||||
auto nm = std::make_shared<linux::networkmanager::NetworkManager>(
|
||||
linux::getSystemBusConnection());
|
||||
auto wifiMedium = createWifiMedium(nm);
|
||||
|
||||
if (wifiMedium == nullptr) {
|
||||
@@ -332,18 +337,45 @@ ImplementationPlatform::CreateWifiHotspotMedium() {
|
||||
|
||||
std::unique_ptr<api::WifiDirectMedium>
|
||||
ImplementationPlatform::CreateWifiDirectMedium() {
|
||||
auto nm = std::make_shared<linux::networkmanager::NetworkManager>(
|
||||
linux::getSystemBusConnection());
|
||||
auto manager = linux::networkmanager::ObjectManager(nm->GetConnection());
|
||||
|
||||
std::map<sdbus::ObjectPath,
|
||||
std::map<sdbus::InterfaceName,
|
||||
std::map<sdbus::PropertyName, sdbus::Variant>>>
|
||||
objects;
|
||||
try {
|
||||
objects = manager.GetManagedObjects();
|
||||
} catch (const sdbus::Error& error) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(nm, "GetManagedObjects", error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const sdbus::InterfaceName wifi_p2p_interface(
|
||||
org::freedesktop::NetworkManager::Device::WifiP2P_proxy::INTERFACE_NAME);
|
||||
const sdbus::InterfaceName device_interface(
|
||||
"org.freedesktop.NetworkManager.Device");
|
||||
const sdbus::PropertyName managed_property("Managed");
|
||||
for (const auto& [object_path, interfaces] : objects) {
|
||||
if (!interfaces.contains(wifi_p2p_interface)) {
|
||||
continue;
|
||||
}
|
||||
auto device = interfaces.find(device_interface);
|
||||
if (device != interfaces.end()) {
|
||||
auto managed = device->second.find(managed_property);
|
||||
if (managed != device->second.end() && !managed->second.get<bool>()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
LOG(INFO) << __func__ << ": Found Wi-Fi P2P device at " << object_path;
|
||||
return std::make_unique<linux::NetworkManagerWifiDirectMedium>(
|
||||
nm, object_path);
|
||||
}
|
||||
|
||||
LOG(WARNING) << __func__
|
||||
<< ": NetworkManager exposes no managed Wi-Fi P2P device";
|
||||
return nullptr;
|
||||
// auto nm =
|
||||
// std::make_shared<linux::networkmanager::NetworkManager>(linux::getSystemBusConnection());
|
||||
// auto wifiMedium = createWifiMedium(nm);
|
||||
//
|
||||
// if (wifiMedium == nullptr) {
|
||||
// LOG(ERROR) << __func__ << ": Could not create a WiFi medium";
|
||||
// return nullptr;
|
||||
// }
|
||||
//
|
||||
// return std::make_unique<linux::NetworkManagerWifiDirectMedium>(
|
||||
// nm, std::move(wifiMedium));
|
||||
}
|
||||
|
||||
std::unique_ptr<api::Timer> ImplementationPlatform::CreateTimer() {
|
||||
@@ -354,18 +386,18 @@ std::unique_ptr<api::DeviceInfo> ImplementationPlatform::CreateDeviceInfo() {
|
||||
return std::make_unique<linux::DeviceInfo>(linux::getSystemBusConnection());
|
||||
}
|
||||
|
||||
std::unique_ptr<AwdlMedium> ImplementationPlatform::CreateAwdlMedium() {
|
||||
std::unique_ptr<AwdlMedium> ImplementationPlatform::CreateAwdlMedium() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
absl::StatusOr<api::WebResponse> ImplementationPlatform::SendRequest(
|
||||
const WebRequest &request) {
|
||||
const WebRequest& request) {
|
||||
if (request.body.size() >= (8 * 1024 * 1024)) {
|
||||
return absl::Status(absl::StatusCode::kResourceExhausted,
|
||||
"request body too large");
|
||||
}
|
||||
|
||||
CURL *handle = curl_easy_init();
|
||||
CURL* handle = curl_easy_init();
|
||||
char errbuf[CURL_ERROR_SIZE];
|
||||
errbuf[0] = '\0';
|
||||
|
||||
@@ -381,9 +413,9 @@ absl::StatusOr<api::WebResponse> ImplementationPlatform::SendRequest(
|
||||
|
||||
curl_easy_setopt(handle, CURLOPT_UPLOAD, request.body.c_str());
|
||||
|
||||
struct curl_slist *headers_slist = nullptr;
|
||||
struct curl_slist* headers_slist = nullptr;
|
||||
|
||||
for (auto &[key, value] : request.headers) {
|
||||
for (auto& [key, value] : request.headers) {
|
||||
auto hdr = absl::StrCat(key, ": ", value);
|
||||
auto temp = curl_slist_append(headers_slist, hdr.c_str());
|
||||
if (temp == nullptr) {
|
||||
@@ -400,27 +432,26 @@ absl::StatusOr<api::WebResponse> ImplementationPlatform::SendRequest(
|
||||
api::WebResponse response;
|
||||
|
||||
if (curl_easy_perform(handle) != CURLE_OK) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Error performing HTTP request: " << errbuf;
|
||||
LOG(ERROR) << __func__ << ": Error performing HTTP request: " << errbuf;
|
||||
return absl::Status(absl::StatusCode::kUnknown, errbuf);
|
||||
}
|
||||
|
||||
struct curl_header *prev = nullptr;
|
||||
struct curl_header *h;
|
||||
struct curl_header* prev = nullptr;
|
||||
struct curl_header* h;
|
||||
|
||||
h = curl_easy_nextheader(handle, CURLH_HEADER, 0, prev);
|
||||
while (h != nullptr) {
|
||||
response.headers.emplace(h->name, h->value);
|
||||
}
|
||||
|
||||
auto writefn = [](char *ptr, size_t size, size_t nmemb, void *userdata) {
|
||||
std::string *body = static_cast<std::string *>(userdata);
|
||||
auto writefn = [](char* ptr, size_t size, size_t nmemb, void* userdata) {
|
||||
std::string* body = static_cast<std::string*>(userdata);
|
||||
body->append(ptr, size * nmemb);
|
||||
};
|
||||
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writefn);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA,
|
||||
static_cast<void *>(&response.body));
|
||||
static_cast<void*>(&response.body));
|
||||
long status;
|
||||
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &status);
|
||||
response.status_code = status;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "internal/platform/exception.h"
|
||||
@@ -33,18 +34,34 @@ class TCPSocket {
|
||||
public:
|
||||
explicit TCPSocket(int fd)
|
||||
: fd_(fd), closed_(false), output_stream_(fd), input_stream_(fd) {}
|
||||
TCPSocket(const TCPSocket&) = delete;
|
||||
TCPSocket& operator=(const TCPSocket&) = delete;
|
||||
TCPSocket(TCPSocket&& other) noexcept
|
||||
: fd_(std::exchange(other.fd_, -1)),
|
||||
closed_(std::exchange(other.closed_, true)),
|
||||
output_stream_(fd_),
|
||||
input_stream_(fd_) {}
|
||||
TCPSocket& operator=(TCPSocket&& other) noexcept {
|
||||
if (this == &other) return *this;
|
||||
Close();
|
||||
fd_ = std::exchange(other.fd_, -1);
|
||||
closed_ = std::exchange(other.closed_, true);
|
||||
output_stream_ = OutputStream(fd_);
|
||||
input_stream_ = InputStream(fd_);
|
||||
return *this;
|
||||
}
|
||||
~TCPSocket() { Close(); }
|
||||
|
||||
static std::optional<TCPSocket> Connect(const std::string& ip_address,
|
||||
int port) {
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Error opening socket: " << std::strerror(errno);
|
||||
<< ": Error opening socket: " << std::strerror(errno);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
LOG(INFO) << __func__ << ": Connecting to " << ip_address << ":"
|
||||
<< port;
|
||||
LOG(INFO) << __func__ << ": Connecting to " << ip_address << ":" << port;
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_addr.s_addr = inet_addr(ip_address.c_str());
|
||||
addr.sin_family = AF_INET;
|
||||
@@ -53,8 +70,8 @@ class TCPSocket {
|
||||
auto ret =
|
||||
connect(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
|
||||
if (ret < 0) {
|
||||
LOG(ERROR) << __func__ << ": Error connecting to socket: "
|
||||
<< std::strerror(errno);
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Error connecting to socket: " << std::strerror(errno);
|
||||
close(sock);
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -66,7 +83,7 @@ class TCPSocket {
|
||||
OutputStream& GetOutputStream() { return output_stream_; }
|
||||
|
||||
Exception Close() {
|
||||
if (closed_) return {Exception::kFailed};
|
||||
if (closed_) return {Exception::kSuccess};
|
||||
|
||||
closed_ = true;
|
||||
input_stream_.Close();
|
||||
@@ -97,7 +114,7 @@ class TCPServerSocket {
|
||||
auto sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Error opening socket: " << std::strerror(errno);
|
||||
<< ": Error opening socket: " << std::strerror(errno);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -109,19 +126,19 @@ class TCPServerSocket {
|
||||
addr.sin_addr.s_addr = inet_addr(ip_address->get().c_str());
|
||||
else
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
|
||||
auto ret =
|
||||
bind(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr));
|
||||
if (ret < 0) {
|
||||
LOG(ERROR) << __func__ << ": Error binding to socket: "
|
||||
<< std::strerror(errno);
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Error binding to socket: " << std::strerror(errno);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ret = listen(sock, 0);
|
||||
if (ret < 0) {
|
||||
LOG(ERROR) << __func__ << ": Error listening on socket: "
|
||||
<< std::strerror(errno);
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Error listening on socket: " << std::strerror(errno);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -131,12 +148,11 @@ class TCPServerSocket {
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
|
||||
auto conn =
|
||||
accept(fd_, reinterpret_cast<struct sockaddr*>(&addr), &len);
|
||||
auto conn = accept(fd_, reinterpret_cast<struct sockaddr*>(&addr), &len);
|
||||
if (conn < 0) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Error accepting incoming connections on socket "
|
||||
<< fd_ << ": " << std::strerror(errno);
|
||||
<< ": Error accepting incoming connections on socket " << fd_
|
||||
<< ": " << std::strerror(errno);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -153,7 +169,7 @@ class TCPServerSocket {
|
||||
auto ret = close(fd);
|
||||
if (ret < 0) {
|
||||
LOG(ERROR) << __func__ << ": Error closing socket " << fd << ": "
|
||||
<< std::strerror(errno);
|
||||
<< std::strerror(errno);
|
||||
return {Exception::kFailed};
|
||||
}
|
||||
|
||||
@@ -163,12 +179,10 @@ class TCPServerSocket {
|
||||
int GetPort() const {
|
||||
struct sockaddr_in sin;
|
||||
socklen_t len = sizeof(sin);
|
||||
auto ret =
|
||||
getsockname(fd_, reinterpret_cast<struct sockaddr*>(&sin), &len);
|
||||
auto ret = getsockname(fd_, reinterpret_cast<struct sockaddr*>(&sin), &len);
|
||||
if (ret < 0) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Error getting information for socket "
|
||||
<< fd_ << ": " << std::strerror(errno);
|
||||
LOG(ERROR) << __func__ << ": Error getting information for socket " << fd_
|
||||
<< ": " << std::strerror(errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,127 +12,426 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <memory>
|
||||
|
||||
#include "internal/platform/implementation/linux/tcp_server_socket.h"
|
||||
#include "internal/platform/implementation/linux/wifi_direct.h"
|
||||
#include "internal/platform/implementation/linux/wifi_direct_server_socket.h"
|
||||
#include "internal/platform/implementation/linux/wifi_direct_socket.h"
|
||||
#include "internal/platform/implementation/linux/wifi_hotspot.h"
|
||||
#include "internal/platform/implementation/linux/wifi_medium.h"
|
||||
#include "internal/platform/implementation/wifi_direct.h"
|
||||
#include "internal/platform/wifi_credential.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/flags/nearby_flags.h"
|
||||
#include "internal/platform/flags/nearby_platform_feature_flags.h"
|
||||
#include "internal/platform/implementation/linux/dbus.h"
|
||||
#include "internal/platform/implementation/linux/generated/dbus/networkmanager/wifi_p2p_peer_client.h"
|
||||
#include "internal/platform/implementation/linux/network_manager_active_connection.h"
|
||||
#include "internal/platform/implementation/linux/tcp_server_socket.h"
|
||||
#include "internal/platform/implementation/linux/utils.h"
|
||||
#include "internal/platform/implementation/linux/wifi_direct_socket.h"
|
||||
#include "internal/platform/implementation/linux/wifi_direct_utils.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby::linux {
|
||||
namespace {
|
||||
|
||||
constexpr absl::Duration kPeerDiscoveryTimeout = absl::Seconds(30);
|
||||
constexpr absl::Duration kActivationTimeout = absl::Seconds(30);
|
||||
constexpr absl::Duration kPeerUpdatePollInterval = absl::Milliseconds(500);
|
||||
constexpr int kCancellationPollMillis = 100;
|
||||
class NetworkManagerWifiP2PPeer
|
||||
: public sdbus::ProxyInterfaces<
|
||||
org::freedesktop::NetworkManager::WifiP2PPeer_proxy> {
|
||||
public:
|
||||
NetworkManagerWifiP2PPeer(
|
||||
const std::shared_ptr<sdbus::IConnection>& system_bus,
|
||||
const sdbus::ObjectPath& object_path)
|
||||
: ProxyInterfaces(*system_bus,
|
||||
sdbus::ServiceName("org.freedesktop.NetworkManager"),
|
||||
object_path) {
|
||||
registerProxy();
|
||||
}
|
||||
~NetworkManagerWifiP2PPeer() { unregisterProxy(); }
|
||||
};
|
||||
|
||||
bool WaitForTcpConnect(int fd, absl::Duration timeout,
|
||||
CancellationFlag* cancellation_flag) {
|
||||
const absl::Time deadline = absl::Now() + timeout;
|
||||
while (absl::Now() < deadline) {
|
||||
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int remaining_ms = static_cast<int>(std::max<std::int64_t>(
|
||||
1, absl::ToInt64Milliseconds(deadline - absl::Now())));
|
||||
pollfd descriptor{.fd = fd, .events = POLLOUT, .revents = 0};
|
||||
int result;
|
||||
do {
|
||||
result =
|
||||
poll(&descriptor, 1, std::min(kCancellationPollMillis, remaining_ms));
|
||||
} while (result < 0 && errno == EINTR);
|
||||
|
||||
if (result < 0) {
|
||||
return false;
|
||||
}
|
||||
if (result == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int socket_error = 0;
|
||||
socklen_t socket_error_length = sizeof(socket_error);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &socket_error,
|
||||
&socket_error_length) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (socket_error == 0) {
|
||||
return true;
|
||||
}
|
||||
errno = socket_error;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<TCPSocket> ConnectTcp(const std::string& ip_address, int port,
|
||||
absl::Duration timeout,
|
||||
CancellationFlag* cancellation_flag) {
|
||||
sockaddr_in address{};
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(port);
|
||||
if (inet_pton(AF_INET, ip_address.c_str(), &address.sin_addr) != 1) {
|
||||
LOG(ERROR) << __func__ << ": Invalid IPv4 address " << ip_address;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0) {
|
||||
LOG(ERROR) << __func__ << ": socket failed: " << std::strerror(errno);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
LOG(ERROR) << __func__ << ": fcntl failed: " << std::strerror(errno);
|
||||
close(fd);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int result =
|
||||
connect(fd, reinterpret_cast<const sockaddr*>(&address), sizeof(address));
|
||||
if (result != 0 && errno != EINPROGRESS) {
|
||||
close(fd);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (result != 0 && !WaitForTcpConnect(fd, timeout, cancellation_flag)) {
|
||||
close(fd);
|
||||
return std::nullopt;
|
||||
}
|
||||
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
|
||||
close(fd);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return TCPSocket(fd);
|
||||
}
|
||||
|
||||
void SleepWithCancellation(absl::Duration duration,
|
||||
CancellationFlag* cancellation_flag) {
|
||||
const absl::Time deadline = absl::Now() + duration;
|
||||
while (absl::Now() < deadline) {
|
||||
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
|
||||
return;
|
||||
}
|
||||
absl::SleepFor(std::min(absl::Milliseconds(kCancellationPollMillis),
|
||||
deadline - absl::Now()));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NetworkManagerWifiDirectMedium::~NetworkManagerWifiDirectMedium() {
|
||||
DisconnectWifiDirect();
|
||||
unregisterProxy();
|
||||
}
|
||||
|
||||
void NetworkManagerWifiDirectMedium::onPeerAdded(const sdbus::ObjectPath&) {
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
peer_changed_.SignalAll();
|
||||
}
|
||||
|
||||
void NetworkManagerWifiDirectMedium::onPeerRemoved(const sdbus::ObjectPath&) {
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
peer_changed_.SignalAll();
|
||||
}
|
||||
|
||||
std::optional<NetworkManagerWifiDirectMedium::Peer>
|
||||
NetworkManagerWifiDirectMedium::FindPeerByName(absl::string_view device_name) {
|
||||
std::vector<sdbus::ObjectPath> paths;
|
||||
try {
|
||||
paths = Peers();
|
||||
} catch (const sdbus::Error& error) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(this, "Peers", error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<Peer> peers;
|
||||
peers.reserve(paths.size());
|
||||
for (const sdbus::ObjectPath& path : paths) {
|
||||
NetworkManagerWifiP2PPeer peer(system_bus_, path);
|
||||
try {
|
||||
peers.push_back(Peer{.path = path,
|
||||
.name = peer.Name(),
|
||||
.hardware_address = peer.HwAddress(),
|
||||
.strength = peer.Strength(),
|
||||
.last_seen = peer.LastSeen()});
|
||||
} catch (const sdbus::Error& error) {
|
||||
LOG(WARNING) << __func__ << ": Failed to inspect peer " << path << ": "
|
||||
<< error.getName() << ": " << error.getMessage();
|
||||
}
|
||||
}
|
||||
return wifi_direct_internal::SelectPeerByName(peers, device_name);
|
||||
}
|
||||
|
||||
void NetworkManagerWifiDirectMedium::StopDiscovery() {
|
||||
bool should_stop = false;
|
||||
{
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
should_stop = discovering_;
|
||||
discovering_ = false;
|
||||
peer_changed_.SignalAll();
|
||||
}
|
||||
if (!should_stop) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
StopFind();
|
||||
} catch (const sdbus::Error& error) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(this, "StopFind", error);
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiDirectMedium::ActivatePeer(const Peer& peer) {
|
||||
auto uuid = NewUuidStr();
|
||||
if (!uuid.has_value()) {
|
||||
LOG(ERROR) << __func__ << ": Could not generate connection UUID";
|
||||
return false;
|
||||
}
|
||||
|
||||
wifi_direct_internal::ConnectionSettings settings =
|
||||
wifi_direct_internal::BuildGcConnectionSettings(*uuid,
|
||||
peer.hardware_address);
|
||||
|
||||
sdbus::ObjectPath active_path;
|
||||
try {
|
||||
auto [connection_path, returned_active_path, result] =
|
||||
network_manager_->AddAndActivateConnection2(
|
||||
settings, wifi_p2p_device_path_, peer.path,
|
||||
{{"persist", sdbus::Variant(std::string("volatile"))},
|
||||
{"bind-activation", sdbus::Variant(std::string("dbus-client"))}});
|
||||
active_path = std::move(returned_active_path);
|
||||
} catch (const sdbus::Error& error) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "AddAndActivateConnection2",
|
||||
error);
|
||||
return false;
|
||||
}
|
||||
|
||||
networkmanager::ActiveConnection active_connection(system_bus_, active_path);
|
||||
auto [reason, timed_out] =
|
||||
active_connection.WaitForConnection(kActivationTimeout);
|
||||
if (timed_out || reason.has_value()) {
|
||||
LOG(ERROR) << __func__ << ": Wi-Fi Direct activation failed for "
|
||||
<< active_path;
|
||||
try {
|
||||
network_manager_->DeactivateConnection(active_path);
|
||||
} catch (const sdbus::Error& error) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactivateConnection",
|
||||
error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> addresses = active_connection.GetIP4Addresses();
|
||||
if (addresses.empty()) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Activated Wi-Fi Direct connection has no IPv4 address";
|
||||
try {
|
||||
network_manager_->DeactivateConnection(active_path);
|
||||
} catch (const sdbus::Error& error) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactivateConnection",
|
||||
error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string gateway = active_connection.GetIP4Gateway();
|
||||
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
active_connection_path_ = active_path;
|
||||
local_ip_address_ = addresses.front();
|
||||
remote_ip_address_ = std::move(gateway);
|
||||
connected_ = true;
|
||||
LOG(INFO) << __func__
|
||||
<< ": Wi-Fi Direct GC connected; local IPv4=" << local_ip_address_
|
||||
<< ", GO IPv4=" << remote_ip_address_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiDirectMedium::ConnectWifiDirect(
|
||||
const WifiDirectCredentials& wifi_direct_credentials) {
|
||||
if (wifi_direct_credentials.GetDeviceName().empty()) {
|
||||
LOG(ERROR) << __func__ << ": Device name is empty";
|
||||
return false;
|
||||
}
|
||||
|
||||
DisconnectWifiDirect();
|
||||
{
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
discovering_ = true;
|
||||
}
|
||||
try {
|
||||
StartFind({{"timeout", sdbus::Variant(std::int32_t(30))}});
|
||||
} catch (const sdbus::Error& error) {
|
||||
{
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
discovering_ = false;
|
||||
}
|
||||
DBUS_LOG_METHOD_CALL_ERROR(this, "StartFind", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
const absl::Time deadline = absl::Now() + kPeerDiscoveryTimeout;
|
||||
std::optional<Peer> peer;
|
||||
while (absl::Now() < deadline) {
|
||||
peer = FindPeerByName(wifi_direct_credentials.GetDeviceName());
|
||||
if (peer.has_value()) {
|
||||
break;
|
||||
}
|
||||
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
if (!discovering_) {
|
||||
break;
|
||||
}
|
||||
peer_changed_.WaitWithTimeout(
|
||||
&state_mutex_,
|
||||
std::min(kPeerUpdatePollInterval, deadline - absl::Now()));
|
||||
}
|
||||
StopDiscovery();
|
||||
|
||||
if (!peer.has_value()) {
|
||||
LOG(WARNING) << __func__ << ": Timed out finding Wi-Fi Direct peer "
|
||||
<< wifi_direct_credentials.GetDeviceName();
|
||||
return false;
|
||||
}
|
||||
return ActivatePeer(*peer);
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiDirectMedium::DisconnectWifiDirect() {
|
||||
StopDiscovery();
|
||||
|
||||
std::string active_path;
|
||||
{
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
active_path = std::move(active_connection_path_);
|
||||
connected_ = false;
|
||||
local_ip_address_.clear();
|
||||
remote_ip_address_.clear();
|
||||
}
|
||||
|
||||
if (active_path.empty()) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
network_manager_->DeactivateConnection(sdbus::ObjectPath(active_path));
|
||||
return true;
|
||||
} catch (const sdbus::Error& error) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactivateConnection", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiDirectSocket>
|
||||
NetworkManagerWifiDirectMedium::ConnectToService(
|
||||
absl::string_view ip_address, int port,
|
||||
CancellationFlag *cancellation_flag) {
|
||||
auto socket = TCPSocket::Connect(std::string(ip_address), port);
|
||||
if (!socket.has_value()) return nullptr;
|
||||
CancellationFlag* cancellation_flag) {
|
||||
std::string remote_ip;
|
||||
{
|
||||
absl::MutexLock lock(state_mutex_);
|
||||
if (!connected_) {
|
||||
LOG(ERROR) << __func__ << ": Wi-Fi Direct GC is not connected";
|
||||
return nullptr;
|
||||
}
|
||||
remote_ip = remote_ip_address_;
|
||||
}
|
||||
if (remote_ip.empty()) {
|
||||
remote_ip = std::string(ip_address);
|
||||
}
|
||||
if (remote_ip.empty() || port <= 0 || port > 65535) {
|
||||
LOG(ERROR) << __func__ << ": Invalid service address or port";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<WifiDirectSocket>(std::move(*socket));
|
||||
const std::int64_t retries = std::max<std::int64_t>(
|
||||
1, NearbyFlags::GetInstance().GetInt64Flag(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kWifiHotspotConnectionMaxRetries));
|
||||
const absl::Duration retry_interval =
|
||||
absl::Milliseconds(NearbyFlags::GetInstance().GetInt64Flag(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kWifiHotspotConnectionIntervalMillis));
|
||||
const absl::Duration connect_timeout =
|
||||
absl::Milliseconds(NearbyFlags::GetInstance().GetInt64Flag(
|
||||
platform::config_package_nearby::nearby_platform_feature::
|
||||
kWifiHotspotConnectionTimeoutMillis));
|
||||
|
||||
for (std::int64_t attempt = 0; attempt < retries; ++attempt) {
|
||||
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto socket =
|
||||
ConnectTcp(remote_ip, port, connect_timeout, cancellation_flag);
|
||||
if (socket.has_value()) {
|
||||
return std::make_unique<WifiDirectSocket>(std::move(*socket));
|
||||
}
|
||||
if (attempt + 1 < retries) {
|
||||
SleepWithCancellation(retry_interval, cancellation_flag);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(ERROR) << __func__ << ": Failed to connect to Wi-Fi Direct service "
|
||||
<< remote_ip << ":" << port;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiDirectServerSocket>
|
||||
NetworkManagerWifiDirectMedium::ListenForService(int port) {
|
||||
auto active_connection = wireless_device_->GetActiveConnection();
|
||||
if (active_connection == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ip4addresses = active_connection->GetIP4Addresses();
|
||||
if (ip4addresses.empty()) {
|
||||
LOG(ERROR)
|
||||
<< __func__
|
||||
<< "Could not find any IPv4 addresses for active connection "
|
||||
<< active_connection->getProxy().getObjectPath();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto socket = TCPServerSocket::Listen(std::ref(ip4addresses[0]), port);
|
||||
if (!socket.has_value()) return nullptr;
|
||||
|
||||
return std::make_unique<NetworkManagerWifiDirectServerSocket>(
|
||||
std::move(*socket), std::move(active_connection), network_manager_);
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiDirectMedium::ConnectWifiDirect(
|
||||
WifiDirectCredentials *wifi_direct_credentials) {
|
||||
if (wifi_direct_credentials == nullptr) {
|
||||
LOG(ERROR) << __func__ << ": hotspot_credentials cannot be null";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ssid = wifi_direct_credentials->GetSSID();
|
||||
auto password = wifi_direct_credentials->GetPassword();
|
||||
|
||||
return wireless_device_->ConnectToNetwork(ssid, password,
|
||||
api::WifiAuthType::kWpaPsk) ==
|
||||
api::WifiConnectionStatus::kConnected;
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiDirectMedium::DisconnectWifiDirect() {
|
||||
if (!ConnectedToWifi()) {
|
||||
LOG(ERROR) << __func__ << ": Not connected to a WiFi hotspot";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto active_connection = wireless_device_->GetActiveConnection();
|
||||
if (active_connection == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
network_manager_->DeactivateConnection(active_connection->getProxy().getObjectPath());
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactivateConnection", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiDirectMedium::ConnectedToWifi() {
|
||||
try {
|
||||
auto mode = wireless_device_->Mode();
|
||||
return mode == 2; // NM_802_11_MODE_INFRA
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e);
|
||||
return false;
|
||||
}
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Linux Wi-Fi Direct is GC-only; listening is unsupported";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiDirectMedium::StartWifiDirect(
|
||||
WifiDirectCredentials *wifi_direct_credentials) {
|
||||
// According to the comments in the windows implementation, the wifi direct
|
||||
// medium is currently just a regular wifi hotspot.
|
||||
auto wireless_device = std::make_unique<NetworkManagerWifiMedium>(
|
||||
network_manager_, wireless_device_->getProxy().getObjectPath());
|
||||
auto hotspot = NetworkManagerWifiHotspotMedium(network_manager_,
|
||||
std::move(wireless_device));
|
||||
|
||||
HotspotCredentials hotspot_creds;
|
||||
if (!hotspot.StartWifiHotspot(&hotspot_creds)) return false;
|
||||
|
||||
wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID());
|
||||
wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword());
|
||||
wifi_direct_credentials->SetFrequency(hotspot_creds.GetFrequency());
|
||||
return true;
|
||||
WifiDirectCredentials* wifi_direct_credentials) {
|
||||
LOG(WARNING) << __func__
|
||||
<< ": Linux Wi-Fi Direct autonomous GO is unsupported";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiDirectMedium::StopWifiDirect() {
|
||||
auto wireless_device = std::make_unique<NetworkManagerWifiMedium>(
|
||||
network_manager_, wireless_device_->getProxy().getObjectPath());
|
||||
auto hotspot = NetworkManagerWifiHotspotMedium(network_manager_,
|
||||
std::move(wireless_device));
|
||||
|
||||
return hotspot.DisconnectWifiHotspot();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
} // namespace nearby::linux
|
||||
|
||||
@@ -14,51 +14,89 @@
|
||||
|
||||
#ifndef PLATFORM_IMPL_LINUX_WIFI_DIRECT_H_
|
||||
#define PLATFORM_IMPL_LINUX_WIFI_DIRECT_H_
|
||||
#include <memory>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wifip2p_client.h"
|
||||
#include "internal/platform/implementation/linux/network_manager.h"
|
||||
#include "internal/platform/implementation/linux/wifi_medium.h"
|
||||
#include "internal/platform/implementation/linux/wifi_direct_utils.h"
|
||||
#include "internal/platform/implementation/wifi_direct.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium {
|
||||
class NetworkManagerWifiDirectMedium
|
||||
: public api::WifiDirectMedium,
|
||||
public sdbus::ProxyInterfaces<
|
||||
org::freedesktop::NetworkManager::Device::WifiP2P_proxy> {
|
||||
public:
|
||||
NetworkManagerWifiDirectMedium(
|
||||
std::shared_ptr<networkmanager::NetworkManager> network_manager,
|
||||
std::unique_ptr<NetworkManagerWifiMedium> wireless_device)
|
||||
: system_bus_(network_manager->GetConnection()),
|
||||
const sdbus::ObjectPath& wifi_p2p_device_path)
|
||||
: ProxyInterfaces(*network_manager->GetConnection(),
|
||||
sdbus::ServiceName("org.freedesktop.NetworkManager"),
|
||||
wifi_p2p_device_path),
|
||||
system_bus_(network_manager->GetConnection()),
|
||||
network_manager_(std::move(network_manager)),
|
||||
wireless_device_(std::move(wireless_device)) {}
|
||||
wifi_p2p_device_path_(wifi_p2p_device_path) {
|
||||
registerProxy();
|
||||
}
|
||||
~NetworkManagerWifiDirectMedium() override;
|
||||
|
||||
bool IsInterfaceValid() const override { return true; }
|
||||
bool IsInterfaceValid() const override {
|
||||
return !wifi_p2p_device_path_.empty();
|
||||
}
|
||||
std::unique_ptr<api::WifiDirectSocket> ConnectToService(
|
||||
absl::string_view ip_address, int port,
|
||||
CancellationFlag *cancellation_flag) override;
|
||||
CancellationFlag* cancellation_flag) override;
|
||||
std::unique_ptr<api::WifiDirectServerSocket> ListenForService(
|
||||
int port) override;
|
||||
bool ConnectWifiDirect(
|
||||
WifiDirectCredentials *wifi_direct_credentials) override;
|
||||
const WifiDirectCredentials& wifi_direct_credentials) override;
|
||||
bool DisconnectWifiDirect() override;
|
||||
|
||||
bool StartWifiDirect(WifiDirectCredentials *wifi_direct_credentials) override;
|
||||
bool StartWifiDirect(WifiDirectCredentials* wifi_direct_credentials) override;
|
||||
bool StopWifiDirect() override;
|
||||
|
||||
absl::optional<std::pair<std::int32_t, std::int32_t>> GetDynamicPortRange()
|
||||
std::optional<std::pair<std::int32_t, std::int32_t>> GetDynamicPortRange()
|
||||
override {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<WifiDirectAuthType> GetSupportedWifiDirectAuthTypes()
|
||||
const override {
|
||||
return {WifiDirectAuthType::WIFI_DIRECT_WITH_DEVICE_NAME};
|
||||
}
|
||||
|
||||
protected:
|
||||
void onPeerAdded(const sdbus::ObjectPath& peer) override;
|
||||
void onPeerRemoved(const sdbus::ObjectPath& peer) override;
|
||||
|
||||
private:
|
||||
bool ConnectedToWifi();
|
||||
using Peer = wifi_direct_internal::PeerInfo;
|
||||
|
||||
std::optional<Peer> FindPeerByName(absl::string_view device_name);
|
||||
bool ActivatePeer(const Peer& peer);
|
||||
void StopDiscovery();
|
||||
|
||||
std::shared_ptr<sdbus::IConnection> system_bus_;
|
||||
std::shared_ptr<networkmanager::NetworkManager> network_manager_;
|
||||
std::unique_ptr<NetworkManagerWifiMedium> wireless_device_;
|
||||
sdbus::ObjectPath wifi_p2p_device_path_;
|
||||
|
||||
mutable absl::Mutex state_mutex_;
|
||||
bool discovering_ ABSL_GUARDED_BY(state_mutex_) = false;
|
||||
bool connected_ ABSL_GUARDED_BY(state_mutex_) = false;
|
||||
std::string active_connection_path_ ABSL_GUARDED_BY(state_mutex_);
|
||||
std::string local_ip_address_ ABSL_GUARDED_BY(state_mutex_);
|
||||
std::string remote_ip_address_ ABSL_GUARDED_BY(state_mutex_);
|
||||
absl::CondVar peer_changed_;
|
||||
};
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
@@ -25,9 +25,10 @@ namespace linux {
|
||||
class WifiDirectSocket : public api::WifiDirectSocket {
|
||||
public:
|
||||
explicit WifiDirectSocket(TCPSocket socket) : socket_(std::move(socket)) {}
|
||||
~WifiDirectSocket() override { socket_.Close(); }
|
||||
|
||||
InputStream &GetInputStream() override { return socket_.GetInputStream(); }
|
||||
OutputStream &GetOutputStream() override { return socket_.GetOutputStream(); }
|
||||
InputStream& GetInputStream() override { return socket_.GetInputStream(); }
|
||||
OutputStream& GetOutputStream() override { return socket_.GetOutputStream(); }
|
||||
|
||||
Exception Close() override { return socket_.Close(); };
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2026 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 "internal/platform/implementation/linux/wifi_direct_utils.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
|
||||
namespace nearby::linux::wifi_direct_internal {
|
||||
namespace {
|
||||
|
||||
constexpr std::uint32_t kWpsMethodPushButton = 0x4;
|
||||
|
||||
} // namespace
|
||||
|
||||
std::optional<PeerInfo> SelectPeerByName(const std::vector<PeerInfo>& peers,
|
||||
absl::string_view device_name) {
|
||||
std::optional<PeerInfo> selected;
|
||||
for (const PeerInfo& peer : peers) {
|
||||
if (peer.hardware_address.empty() ||
|
||||
!absl::EqualsIgnoreCase(peer.name, device_name)) {
|
||||
continue;
|
||||
}
|
||||
if (!selected.has_value() || peer.strength > selected->strength ||
|
||||
(peer.strength == selected->strength &&
|
||||
peer.last_seen > selected->last_seen)) {
|
||||
selected = peer;
|
||||
}
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
ConnectionSettings BuildGcConnectionSettings(absl::string_view uuid,
|
||||
absl::string_view peer_address) {
|
||||
return {
|
||||
{"connection",
|
||||
{{"uuid", sdbus::Variant(std::string(uuid))},
|
||||
{"id", sdbus::Variant(std::string("Nearby Wi-Fi Direct"))},
|
||||
{"type", sdbus::Variant(std::string("wifi-p2p"))},
|
||||
{"autoconnect", sdbus::Variant(false)}}},
|
||||
{"wifi-p2p",
|
||||
{{"peer", sdbus::Variant(std::string(peer_address))},
|
||||
{"wps-method", sdbus::Variant(kWpsMethodPushButton)}}},
|
||||
{"ipv4", {{"method", sdbus::Variant(std::string("auto"))}}},
|
||||
{"ipv6", {{"method", sdbus::Variant(std::string("disabled"))}}},
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace nearby::linux::wifi_direct_internal
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2026 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_WIFI_DIRECT_UTILS_H_
|
||||
#define PLATFORM_IMPL_LINUX_WIFI_DIRECT_UTILS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace nearby::linux::wifi_direct_internal {
|
||||
|
||||
struct PeerInfo {
|
||||
sdbus::ObjectPath path;
|
||||
std::string name;
|
||||
std::string hardware_address;
|
||||
std::uint8_t strength = 0;
|
||||
std::int32_t last_seen = -1;
|
||||
};
|
||||
|
||||
using ConnectionSettings =
|
||||
std::map<std::string, std::map<std::string, sdbus::Variant>>;
|
||||
|
||||
std::optional<PeerInfo> SelectPeerByName(const std::vector<PeerInfo>& peers,
|
||||
absl::string_view device_name);
|
||||
|
||||
ConnectionSettings BuildGcConnectionSettings(absl::string_view uuid,
|
||||
absl::string_view peer_address);
|
||||
|
||||
} // namespace nearby::linux::wifi_direct_internal
|
||||
|
||||
#endif // PLATFORM_IMPL_LINUX_WIFI_DIRECT_UTILS_H_
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2026 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 "internal/platform/implementation/linux/wifi_direct_utils.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nearby::linux::wifi_direct_internal {
|
||||
namespace {
|
||||
|
||||
TEST(WifiDirectUtilsTest, SelectsPeerCaseInsensitively) {
|
||||
std::vector<PeerInfo> peers{
|
||||
{.path = sdbus::ObjectPath("/peer/1"),
|
||||
.name = "Android_1234",
|
||||
.hardware_address = "02:00:00:00:00:01",
|
||||
.strength = 50,
|
||||
.last_seen = 10},
|
||||
};
|
||||
|
||||
auto selected = SelectPeerByName(peers, "android_1234");
|
||||
|
||||
ASSERT_TRUE(selected.has_value());
|
||||
EXPECT_EQ(selected->path, "/peer/1");
|
||||
}
|
||||
|
||||
TEST(WifiDirectUtilsTest, SelectsStrongestThenMostRecentDuplicate) {
|
||||
std::vector<PeerInfo> peers{
|
||||
{.path = sdbus::ObjectPath("/peer/old"),
|
||||
.name = "Android",
|
||||
.hardware_address = "02:00:00:00:00:01",
|
||||
.strength = 60,
|
||||
.last_seen = 10},
|
||||
{.path = sdbus::ObjectPath("/peer/weak"),
|
||||
.name = "Android",
|
||||
.hardware_address = "02:00:00:00:00:02",
|
||||
.strength = 40,
|
||||
.last_seen = 30},
|
||||
{.path = sdbus::ObjectPath("/peer/new"),
|
||||
.name = "Android",
|
||||
.hardware_address = "02:00:00:00:00:03",
|
||||
.strength = 60,
|
||||
.last_seen = 20},
|
||||
};
|
||||
|
||||
auto selected = SelectPeerByName(peers, "Android");
|
||||
|
||||
ASSERT_TRUE(selected.has_value());
|
||||
EXPECT_EQ(selected->path, "/peer/new");
|
||||
}
|
||||
|
||||
TEST(WifiDirectUtilsTest, IgnoresWrongNameAndMissingAddress) {
|
||||
std::vector<PeerInfo> peers{
|
||||
{.path = sdbus::ObjectPath("/peer/1"),
|
||||
.name = "Other",
|
||||
.hardware_address = "aa:bb"},
|
||||
{.path = sdbus::ObjectPath("/peer/2"),
|
||||
.name = "Android",
|
||||
.hardware_address = ""},
|
||||
};
|
||||
|
||||
EXPECT_FALSE(SelectPeerByName(peers, "Android").has_value());
|
||||
}
|
||||
|
||||
TEST(WifiDirectUtilsTest, BuildsVolatileP2pProfilePayload) {
|
||||
ConnectionSettings settings =
|
||||
BuildGcConnectionSettings("uuid-1", "02:00:00:00:00:01");
|
||||
|
||||
EXPECT_EQ(settings.at("connection").at("uuid").get<std::string>(), "uuid-1");
|
||||
EXPECT_EQ(settings.at("connection").at("type").get<std::string>(),
|
||||
"wifi-p2p");
|
||||
EXPECT_FALSE(settings.at("connection").at("autoconnect").get<bool>());
|
||||
EXPECT_EQ(settings.at("wifi-p2p").at("peer").get<std::string>(),
|
||||
"02:00:00:00:00:01");
|
||||
EXPECT_EQ(settings.at("wifi-p2p").at("wps-method").get<std::uint32_t>(),
|
||||
std::uint32_t{0x4});
|
||||
EXPECT_EQ(settings.at("ipv4").at("method").get<std::string>(), "auto");
|
||||
EXPECT_EQ(settings.at("ipv6").at("method").get<std::string>(), "disabled");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby::linux::wifi_direct_internal
|
||||
@@ -41,23 +41,23 @@ namespace {
|
||||
constexpr char kDeviceIpv4TxtRecord[] = "IPv4";
|
||||
|
||||
std::string GetActiveIpv4Address(
|
||||
const std::shared_ptr<networkmanager::NetworkManager> &network_manager,
|
||||
const std::shared_ptr<sdbus::IConnection> &system_bus) {
|
||||
const std::shared_ptr<networkmanager::NetworkManager>& network_manager,
|
||||
const std::shared_ptr<sdbus::IConnection>& system_bus) {
|
||||
std::vector<sdbus::ObjectPath> connection_paths;
|
||||
try {
|
||||
connection_paths = network_manager->ActiveConnections();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(network_manager, "ActiveConnections", e);
|
||||
return {};
|
||||
}
|
||||
|
||||
for (auto &path : connection_paths) {
|
||||
for (auto& path : connection_paths) {
|
||||
auto active_connection =
|
||||
std::make_unique<networkmanager::ActiveConnection>(system_bus, path);
|
||||
std::string conn_type;
|
||||
try {
|
||||
conn_type = active_connection->Type();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(active_connection, "Type", e);
|
||||
continue;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ bool WifiLanMedium::IsNetworkConnected() const {
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, std::string>> entry_group_key(
|
||||
const NsdServiceInfo &nsd_service_info) {
|
||||
const NsdServiceInfo& nsd_service_info) {
|
||||
auto name = nsd_service_info.GetServiceName();
|
||||
if (name.empty()) {
|
||||
LOG(ERROR) << __func__ << ": service name cannot be empty";
|
||||
@@ -103,7 +103,7 @@ std::optional<std::pair<std::string, std::string>> entry_group_key(
|
||||
return std::make_pair(std::move(name), std::move(type));
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) {
|
||||
bool WifiLanMedium::StartAdvertising(const NsdServiceInfo& nsd_service_info) {
|
||||
auto key = entry_group_key(nsd_service_info);
|
||||
if (!key.has_value()) {
|
||||
return false;
|
||||
@@ -113,7 +113,7 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) {
|
||||
absl::ReaderMutexLock l(&entry_groups_mutex_);
|
||||
if (entry_groups_.count(*key) == 1) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": advertising is already active for this service";
|
||||
<< ": advertising is already active for this service";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -137,14 +137,15 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) {
|
||||
sdbus::ObjectPath entry_group_path;
|
||||
try {
|
||||
entry_group_path = avahi_->EntryGroupNew();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(avahi_, "EntryGroupNew", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto entry_group =
|
||||
std::make_unique<avahi::EntryGroup>(*system_bus_, entry_group_path);
|
||||
LOG(INFO) << __func__ << ": Adding avahi service with service type: " << nsd_service_info.GetServiceType();
|
||||
LOG(INFO) << __func__ << ": Adding avahi service with service type: "
|
||||
<< nsd_service_info.GetServiceType();
|
||||
|
||||
try {
|
||||
entry_group->AddService(
|
||||
@@ -153,10 +154,10 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) {
|
||||
0, nsd_service_info.GetServiceName(), nsd_service_info.GetServiceType(),
|
||||
std::string(), std::string(), nsd_service_info.GetPort(), txt_records);
|
||||
entry_group->Commit();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
LOG(ERROR) << __func__ << ": Got error '" << e.getName()
|
||||
<< "' with message '" << e.getMessage()
|
||||
<< "' while adding service";
|
||||
<< "' with message '" << e.getMessage()
|
||||
<< "' while adding service";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) {
|
||||
bool WifiLanMedium::StopAdvertising(const NsdServiceInfo& nsd_service_info) {
|
||||
auto key = entry_group_key(nsd_service_info);
|
||||
if (!key.has_value()) {
|
||||
return false;
|
||||
@@ -175,7 +176,7 @@ bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) {
|
||||
absl::MutexLock l(&entry_groups_mutex_);
|
||||
if (entry_groups_.count(*key) == 0) {
|
||||
LOG(ERROR) << __func__
|
||||
<< ": Advertising is already inactive for this service.";
|
||||
<< ": Advertising is already inactive for this service.";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -184,15 +185,15 @@ bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) {
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartDiscovery(
|
||||
const std::string &service_type,
|
||||
const std::string& service_type,
|
||||
api::WifiLanMedium::DiscoveredServiceCallback callback) {
|
||||
{
|
||||
absl::ReaderMutexLock l(&service_browsers_mutex_);
|
||||
if (service_browsers_.count(service_type) != 0) {
|
||||
auto &object = service_browsers_[service_type];
|
||||
auto& object = service_browsers_[service_type];
|
||||
LOG(ERROR) << __func__ << ": A service browser for service type "
|
||||
<< service_type << " already exists at "
|
||||
<< object->getProxy().getObjectPath();
|
||||
<< service_type << " already exists at "
|
||||
<< object->getProxy().getObjectPath();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -210,24 +211,23 @@ bool WifiLanMedium::StartDiscovery(
|
||||
<< browser_object_path << " for service_type: " << service_type;
|
||||
|
||||
absl::MutexLock l(&service_browsers_mutex_);
|
||||
service_browsers_.emplace(
|
||||
service_type,
|
||||
std::make_unique<avahi::ServiceBrowser>(
|
||||
*system_bus_, browser_object_path, avahi_));
|
||||
} catch (const sdbus::Error &e) {
|
||||
service_browsers_.emplace(service_type,
|
||||
std::make_unique<avahi::ServiceBrowser>(
|
||||
*system_bus_, browser_object_path, avahi_));
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(avahi_, "ServiceBrowserPrepare", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
service_browsers_mutex_.ReaderLock();
|
||||
auto &browser = service_browsers_[service_type];
|
||||
auto& browser = service_browsers_[service_type];
|
||||
service_browsers_mutex_.ReaderUnlock();
|
||||
|
||||
try {
|
||||
LOG(INFO) << __func__ << ": Starting service discovery for "
|
||||
<< browser->getProxy().getObjectPath();
|
||||
<< browser->getProxy().getObjectPath();
|
||||
browser->Start();
|
||||
} catch (const sdbus::Error &e) {
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(browser, "Start", e);
|
||||
return false;
|
||||
}
|
||||
@@ -235,12 +235,12 @@ bool WifiLanMedium::StartDiscovery(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopDiscovery(const std::string &service_type) {
|
||||
bool WifiLanMedium::StopDiscovery(const std::string& service_type) {
|
||||
absl::MutexLock l(&service_browsers_mutex_);
|
||||
|
||||
if (service_browsers_.count(service_type) == 0) {
|
||||
LOG(ERROR) << __func__ << ": Service type " << service_type
|
||||
<< " has not been registered for discovery";
|
||||
<< " has not been registered for discovery";
|
||||
return false;
|
||||
}
|
||||
service_browsers_.erase(service_type);
|
||||
@@ -249,16 +249,16 @@ bool WifiLanMedium::StopDiscovery(const std::string &service_type) {
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanMedium::ConnectToService(
|
||||
const std::string &ip_address, int port,
|
||||
CancellationFlag *cancellation_flag) {
|
||||
const std::string& ip_address, int port,
|
||||
CancellationFlag* cancellation_flag) {
|
||||
auto socket = TCPSocket::Connect(ip_address, port);
|
||||
if (!socket.has_value()) return nullptr;
|
||||
return std::make_unique<WifiLanSocket>(*socket);
|
||||
return std::make_unique<WifiLanSocket>(std::move(*socket));
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiLanServerSocket> WifiLanMedium::ListenForService(
|
||||
int port) {
|
||||
LOG(INFO)<< __func__ << ": Listening for service WifiLanMedium";
|
||||
LOG(INFO) << __func__ << ": Listening for service WifiLanMedium";
|
||||
auto socket = TCPServerSocket::Listen(std::nullopt, port);
|
||||
if (!socket.has_value()) return nullptr;
|
||||
|
||||
@@ -330,7 +330,7 @@ api::UpgradeAddressInfo WifiLanMedium::GetUpgradeAddressCandidates(
|
||||
// Convert to vector of chars in network byte order
|
||||
std::vector<char> addr_bytes(4);
|
||||
std::memcpy(addr_bytes.data(), &addr.s_addr, 4);
|
||||
|
||||
|
||||
ipv4_addresses.push_back(
|
||||
ServiceAddress{.address = std::move(addr_bytes), .port = port});
|
||||
has_ipv4_address = true;
|
||||
|
||||
Reference in New Issue
Block a user