From ef666b2311a213d3eaeeaa8574a9076a0d5fa40a Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 00:32:55 +0530 Subject: [PATCH] Add Wifi Direct medium --- .../platform/implementation/linux/platform.cc | 14 +- .../implementation/linux/wifi_direct.cc | 160 ++++++++++++++++++ .../implementation/linux/wifi_direct.h | 48 ++++++ .../linux/wifi_direct_server_socket.cc | 66 ++++++++ .../linux/wifi_direct_server_socket.h | 30 ++++ .../implementation/linux/wifi_direct_socket.h | 28 +++ 6 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 internal/platform/implementation/linux/wifi_direct.cc create mode 100644 internal/platform/implementation/linux/wifi_direct.h create mode 100644 internal/platform/implementation/linux/wifi_direct_server_socket.cc create mode 100644 internal/platform/implementation/linux/wifi_direct_server_socket.h create mode 100644 internal/platform/implementation/linux/wifi_direct_socket.h diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index b1d2c45c..f40831a5 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -24,6 +24,7 @@ #include "internal/platform/implementation/linux/mutex.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_hotspot.h" #include "internal/platform/implementation/linux/wifi_lan.h" #include "internal/platform/implementation/linux/wifi_medium.h" @@ -163,6 +164,7 @@ ImplementationPlatform::CreateBluetoothAdapter() { } } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(&manager, "GetManagedObjects", e); + return nullptr; } NEARBY_LOGS(ERROR) << __func__ @@ -259,7 +261,17 @@ ImplementationPlatform::CreateWifiHotspotMedium() { std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { - return nullptr; + auto nm = + std::make_shared(linux::getSystemBusConnection()); + auto wifiMedium = createWifiMedium(nm); + + if (wifiMedium == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": Could not create a WiFi medium"; + return nullptr; + } + + return std::make_unique( + linux::getSystemBusConnection(), nm, std::move(wifiMedium)); } std::unique_ptr ImplementationPlatform::CreateTimer() { diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc new file mode 100644 index 00000000..2e7884c0 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -0,0 +1,160 @@ +#include +#include +#include +#include + +#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 { +std::unique_ptr +NetworkManagerWifiDirectMedium::ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return nullptr; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" + << port; + struct sockaddr_in addr; + addr.sin_addr.s_addr = inet_addr(std::string(ip_address).c_str()); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + auto ret = + connect(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " + << std::strerror(errno); + return nullptr; + } + + return std::make_unique(sock); +} + +std::unique_ptr +NetworkManagerWifiDirectMedium::ListenForService(int port) { + auto active_connection = wireless_device_->GetActiveConnection(); + if (active_connection == nullptr) { + return nullptr; + } + + auto ip4addresses = active_connection->GetIP4Addresses(); + if (ip4addresses.empty()) { + NEARBY_LOGS(ERROR) + << __func__ + << "Could not find any IPv4 addresses for active connection " + << active_connection->getObjectPath(); + return nullptr; + } + + auto sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return nullptr; + } + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(ip4addresses[0].c_str()); + addr.sin_port = htons(port); + + auto ret = + bind(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error binding to socket: " << std::strerror(errno); + return nullptr; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": Listening for services on " + << ip4addresses[0] << ":" << port << " on device " + << wireless_device_->getObjectPath(); + + ret = listen(sock, 0); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " + << std::strerror(errno); + return nullptr; + } + + return std::make_unique( + sock, system_bus_, active_connection->getObjectPath(), network_manager_); +} + +bool NetworkManagerWifiDirectMedium::ConnectWifiDirect( + WifiDirectCredentials *wifi_direct_credentials) { + if (wifi_direct_credentials == nullptr) { + NEARBY_LOGS(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()) { + NEARBY_LOGS(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->getObjectPath()); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactivateConnection", e); + return false; + } + + return true; +} + +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( + network_manager_, system_bus_, wireless_device_->getObjectPath()); + auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, 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()); + return true; +} + +bool NetworkManagerWifiDirectMedium::StopWifiDirect() { + auto wireless_device = std::make_unique( + network_manager_, system_bus_, wireless_device_->getObjectPath()); + auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, + std::move(wireless_device)); + + return hotspot.DisconnectWifiHotspot(); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_direct.h b/internal/platform/implementation/linux/wifi_direct.h new file mode 100644 index 00000000..4c038c3e --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct.h @@ -0,0 +1,48 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_DIRECT_H_ +#define PLATFORM_IMPL_LINUX_WIFI_DIRECT_H_ +#include + +#include +#include + +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi_direct.h" + +namespace nearby { +namespace linux { +class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium { +public: + NetworkManagerWifiDirectMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + std::unique_ptr wireless_device) + : system_bus_(system_bus), network_manager_(network_manager), + wireless_device_(std::move(wireless_device)) {} + ~NetworkManagerWifiDirectMedium() {} + + bool IsInterfaceValid() const override { return true; } + std::unique_ptr + ConnectToService(absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr + ListenForService(int port) override; + bool + ConnectWifiDirect(WifiDirectCredentials *wifi_direct_credentials) override; + bool DisconnectWifiDirect() override; + + bool StartWifiDirect(WifiDirectCredentials *wifi_direct_credentials) override; + bool StopWifiDirect() override; + + absl::optional> + GetDynamicPortRange() override { + return std::nullopt; + } + + sdbus::IConnection &system_bus_; + std::shared_ptr network_manager_; + std::unique_ptr wireless_device_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.cc b/internal/platform/implementation/linux/wifi_direct_server_socket.cc new file mode 100644 index 00000000..65f4de96 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.cc @@ -0,0 +1,66 @@ +#include "internal/platform/implementation/linux/wifi_direct_server_socket.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/wifi_direct_socket.h" +#include +#include + +namespace nearby { +namespace linux { +std::string NetworkManagerWifiDirectServerSocket::GetIPAddress() const { + NetworkManagerActiveConnection active_conn(system_bus_, + active_connection_path_); + auto ip4addresses = active_conn.GetIP4Addresses(); + if (ip4addresses.empty()) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Could not find any IPv4 addresses for active connection " + << active_connection_path_; + return std::string(); + } + return ip4addresses[0]; +} + +int NetworkManagerWifiDirectServerSocket::GetPort() const { + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + auto ret = + getsockname(fd_.get(), reinterpret_cast(&sin), &len); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error getting information for socket " + << fd_.get() << ": " << std::strerror(errno); + return 0; + } + + return ntohs(sin.sin_port); +} + +std::unique_ptr +NetworkManagerWifiDirectServerSocket::Accept() { + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + + auto conn = + accept(fd_.get(), reinterpret_cast(&addr), &len); + if (conn < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error accepting incoming connections on socket " + << fd_.get() << ": " << std::strerror(errno); + return nullptr; + } + + return std::make_unique(conn); +} + +Exception NetworkManagerWifiDirectServerSocket::Close() { + int fd = fd_.release(); + auto ret = close(fd); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " + << std::strerror(errno); + return {Exception::kFailed}; + } + + return {Exception::kSuccess}; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.h b/internal/platform/implementation/linux/wifi_direct_server_socket.h new file mode 100644 index 00000000..713f5e07 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.h @@ -0,0 +1,30 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_DIRECT_SERVER_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_DIRECT_SERVER_SOCKET_H_ + +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi_direct.h" +#include +namespace nearby { + namespace linux { + class NetworkManagerWifiDirectServerSocket + : public api::WifiDirectServerSocket { +public: + NetworkManagerWifiDirectServerSocket(int socket, sdbus::IConnection &system_bus, + const sdbus::ObjectPath &active_connection_path, + std::shared_ptr network_manager) : fd_(socket), system_bus_(system_bus), active_connection_path_(active_connection_path), network_manager_(network_manager) {} + ~NetworkManagerWifiDirectServerSocket() {} + + std::string GetIPAddress() const override; + int GetPort() const override; + std::unique_ptr Accept() override; + Exception Close() override; +private: + sdbus::UnixFd fd_; + sdbus::IConnection &system_bus_; + sdbus::ObjectPath active_connection_path_; + std::shared_ptr network_manager_ ; + }; + } +} + +#endif diff --git a/internal/platform/implementation/linux/wifi_direct_socket.h b/internal/platform/implementation/linux/wifi_direct_socket.h new file mode 100644 index 00000000..79ec3556 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct_socket.h @@ -0,0 +1,28 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_DIRECT_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_DIRECT_SOCKET_H_ + +#include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/stream.h" +#include "internal/platform/implementation/wifi_direct.h" + +namespace nearby { +namespace linux { +class WifiDirectSocket : public api::WifiDirectSocket { +public: + WifiDirectSocket(int socket); + ~WifiDirectSocket() = default; + + InputStream &GetInputStream() override; + OutputStream &GetOutputStream() override; + + Exception Close() override; + +private: + sdbus::UnixFd fd_; + OutputStream output_stream_; + InputStream input_stream_; +}; +} // namespace linux +} // namespace nearby + +#endif