From c8af59666df17bffb024ab82016a376a7f2422bd Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 15 Aug 2023 20:52:51 +0530 Subject: [PATCH] Rewrite dbus code using sdbus-c++ --- internal/platform/implementation/linux/BUILD | 1 + .../implementation/linux/bluetooth_adapter.cc | 172 +++++----- .../implementation/linux/bluetooth_adapter.h | 23 +- .../linux/bluetooth_bluez_profile.cc | 298 ++++++++++------- .../linux/bluetooth_bluez_profile.h | 92 ++++-- .../linux/bluetooth_classic_device.cc | 149 ++++++--- .../linux/bluetooth_classic_device.h | 72 +++- .../linux/bluetooth_classic_medium.cc | 312 +++++++++--------- .../linux/bluetooth_classic_medium.h | 43 ++- .../linux/bluetooth_classic_server_socket.h | 15 +- .../linux/bluetooth_classic_socket.cc | 51 ++- .../linux/bluetooth_classic_socket.h | 33 +- .../implementation/linux/bluetooth_devices.cc | 49 +++ .../implementation/linux/bluetooth_devices.h | 42 +++ .../implementation/linux/bluetooth_pairing.cc | 163 ++++----- .../implementation/linux/bluetooth_pairing.h | 26 +- .../linux/bluetoth_classic_server_socket.cc | 19 +- .../platform/implementation/linux/bluez.cc | 32 ++ .../platform/implementation/linux/bluez.h | 33 +- .../linux/bluez_adapter_client_glue.h | 179 ++++++++++ .../linux/bluez_device_client_glue.h | 215 ++++++++++++ .../implementation/linux/bluez_profile_glue.h | 43 +++ .../linux/bluez_profile_manager_client_glue.h | 46 +++ .../implementation/linux/device_info.cc | 139 +++----- .../implementation/linux/device_info.h | 12 +- .../linux/org.bluez.Adapter1.xml | 36 ++ .../linux/org.bluez.Device1.xml | 44 +++ .../linux/org.bluez.Profile1.xml | 17 + .../linux/org.bluez.ProfileManager1.xml | 14 + 29 files changed, 1632 insertions(+), 738 deletions(-) create mode 100644 internal/platform/implementation/linux/bluetooth_devices.cc create mode 100644 internal/platform/implementation/linux/bluetooth_devices.h create mode 100644 internal/platform/implementation/linux/bluez.cc create mode 100644 internal/platform/implementation/linux/bluez_adapter_client_glue.h create mode 100644 internal/platform/implementation/linux/bluez_device_client_glue.h create mode 100644 internal/platform/implementation/linux/bluez_profile_glue.h create mode 100644 internal/platform/implementation/linux/bluez_profile_manager_client_glue.h create mode 100644 internal/platform/implementation/linux/org.bluez.Adapter1.xml create mode 100644 internal/platform/implementation/linux/org.bluez.Device1.xml create mode 100644 internal/platform/implementation/linux/org.bluez.Profile1.xml create mode 100644 internal/platform/implementation/linux/org.bluez.ProfileManager1.xml diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 3006bf08..067a3c51 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -16,6 +16,7 @@ cc_library( "//internal/platform:logging", "@com_google_absl//absl/strings", "@libsystemd//:lib", + "@sdbus_cpp//:lib", ], ) diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index b24c5395..5d30dc0f 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -1,71 +1,68 @@ -#include +#include +#include #include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { -using namespace api; - bool BluetoothAdapter::SetStatus(Status status) { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - - if (sd_bus_set_property( - system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Powered", &err, "b", - status == api::BluetoothAdapter::Status::kEnabled ? 1 : 0) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error setting adaptor status: " << err.message; + try { + bool val = status == api::BluetoothAdapter::Status::kEnabled; + Powered(val); + return true; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to set Powered status for adapter " + << getObjectPath(); return false; } - return true; } bool BluetoothAdapter::IsEnabled() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - int enabled = 0; + auto proxy = sdbus::createProxy(getProxy().getConnection(), + bluez::SERVICE_DEST, getObjectPath()); + proxy->finishRegistration(); - if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b', - &enabled) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adaptor status: " << err.message; + try { + return proxy->getProperty("Powered").onInterface(INTERFACE_NAME); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Powered status for adapter " + << getObjectPath(); + return false; } - return enabled; } BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - int powered = 0; - int discoverable = 0; - - if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b', - &powered) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adaptor status: " << err.message; - return ScanMode::kUnknown; - } + bool powered = IsEnabled(); if (!powered) { return ScanMode::kNone; } - if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, - 'b', &powered) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adaptor's discoverable status: " - << err.message; + try { + auto proxy = sdbus::createProxy(getProxy().getConnection(), + bluez::SERVICE_DEST, getObjectPath()); + proxy->finishRegistration(); + + bool discoverable = + proxy->getProperty("Discoverable").onInterface(INTERFACE_NAME); + return discoverable ? ScanMode::kConnectableDiscoverable + : ScanMode::kConnectable; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ << ": Got error '" << e.getName() << "' with message '" + << e.getMessage() + << "' while trying to get Discoverable status for adapter " + << getObjectPath(); return ScanMode::kUnknown; } - return discoverable ? ScanMode::kConnectableDiscoverable - : ScanMode::kConnectable; } bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { @@ -76,16 +73,18 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { if (!SetStatus(Status::kEnabled)) { return false; } - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - if (sd_bus_set_property(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, "b", - 1) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error setting adapter's discoverable status: " - << err.message; + + try { + Discoverable(true); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ << ": Got error '" << e.getName() << "' with message '" + << e.getMessage() + << "' while trying to set Discoverable status for adapter " + << getObjectPath(); return false; } + return true; } case ScanMode::kNone: @@ -96,65 +95,52 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { } std::string BluetoothAdapter::GetName() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *cname = nullptr; - if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Alias", &err, - &cname) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adapter's name: " << err.message; + auto proxy = sdbus::createProxy(getProxy().getConnection(), + bluez::SERVICE_DEST, getObjectPath()); + proxy->finishRegistration(); + + try { + return proxy->getProperty("Alias").onInterface(INTERFACE_NAME); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Alias for adapter " + << getObjectPath(); return std::string(); } - std::string name(cname); - free(cname); - return name; } bool BluetoothAdapter::SetName(absl::string_view name, bool persist) { - if (persist) { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - std::string pretty_hostname(name); - if (sd_bus_set_property(system_bus_, "org.freedesktop.hostname1", - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", "PrettyHostname", &err, - "s", pretty_hostname.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error setting PrettyHostname: " << err.message; - } - } return SetName(name); } bool BluetoothAdapter::SetName(absl::string_view name) { - std::string alias(name); - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - if (sd_bus_set_property(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Alias", &err, "s", - alias.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error setting adapter's name: " << err.message; + try { + Alias(std::string(name)); + return true; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to set Alias for adapter " + << getObjectPath(); return false; } - return true; } std::string BluetoothAdapter::GetMacAddress() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *caddr = nullptr; - if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Address", &err, - &caddr) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adapter's name: " << err.message; + auto proxy = sdbus::createProxy(getProxy().getConnection(), + bluez::SERVICE_DEST, getObjectPath()); + proxy->finishRegistration(); + + try { + return proxy->getProperty("Address").onInterface(INTERFACE_NAME); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Address for adapter " + << getObjectPath(); return std::string(); } - std::string addr(caddr); - free(caddr); - return addr; } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index b9c4b2c2..0bfe5f99 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -1,18 +1,26 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ - -#include +#include +#include #include "absl/strings/string_view.h" #include "internal/platform/implementation/bluetooth_adapter.h" -#include +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" namespace nearby { namespace linux { -class BluetoothAdapter : public api::BluetoothAdapter { +class BluetoothAdapter + : public api::BluetoothAdapter, + public sdbus::ProxyInterfaces { public: - BluetoothAdapter(sd_bus *bus) { system_bus_ = bus; } - ~BluetoothAdapter() override { sd_bus_unref(system_bus_); }; + BluetoothAdapter(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path) + : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, adapter_object_path) { + registerProxy(); + } + + ~BluetoothAdapter() override { unregisterProxy(); } bool SetStatus(Status status) override; bool IsEnabled() const override; @@ -25,9 +33,6 @@ public: bool SetName(absl::string_view name) override; bool SetName(absl::string_view name, bool persist) override; std::string GetMacAddress() const override; - -private: - sd_bus *system_bus_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index afb7d1a9..8503c503 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -1,80 +1,26 @@ -#include +#include #include #include #include +#include #include #include -#include -#include -#include +#include +#include +#include +#include +#include -#include "absl/strings/substitute.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" -const char *BLUEZ_PROFILEMANAGER_INTERFACE = "org.bluez.ProfileManager1"; - namespace nearby { namespace linux { -static int profile_release(sd_bus_message *m, void *userdata, - sd_bus_error *error) { - return 0; -} -static int profile_new_connection(sd_bus_message *m, void *userdata, - sd_bus_error *error) { - char *c_device_object = nullptr; - int fd = 0, ret; - - ret = sd_bus_message_read(m, "oh", &c_device_object, &fd); - if (ret < 0) { - return ret; - } - - std::string device_object(c_device_object); - fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); - if (fd < 0) { - return sd_bus_error_set_errno(error, errno); - } - - sd_bus *bus; - sd_bus_default_system(&bus); - - BluetoothDevice device(bus, device_object); - auto mac_addr = device.GetMacAddress(); - if (mac_addr.empty()) { - return -1; - } - - struct RegisteredService *service = - static_cast(userdata); - service->connections_lock.Lock(); - service->connections[mac_addr] = fd; - service->connections_lock.Unlock(); - - return 0; -} - -static int profile_request_disconnection(sd_bus_message *m, void *userdata, - sd_bus_error *error) { - // TODO - return 0; -} - -static const sd_bus_vtable vtable[] = { - SD_BUS_VTABLE_START(0), - SD_BUS_METHOD_WITH_ARGS("Release", SD_BUS_NO_ARGS, SD_BUS_NO_RESULT, - profile_release, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD_WITH_ARGS( - "NewConnection", SD_BUS_ARGS("o", path, "h", fd, "a{sq}", properties), - SD_BUS_NO_RESULT, profile_new_connection, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD_WITH_ARGS("RequestDisconnection", SD_BUS_ARGS("o", object), - SD_BUS_NO_RESULT, profile_request_disconnection, - SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_VTABLE_END}; bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { registered_service_uuids_lock_.ReaderLock(); @@ -83,99 +29,209 @@ bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { return registered; } -bool ProfileManager::RegisterProfile(absl::string_view name, - absl::string_view service_uuid) { +void Profile::Release() { + released_ = true; + NEARBY_LOGS(VERBOSE) << __func__ << "Profile object " << getObjectPath() + << " has been released"; +} + +void Profile::NewConnection( + const sdbus::ObjectPath &device_object_path, const sdbus::UnixFd &fd, + const std::map &fd_props) { + if (released_) { + NEARBY_LOGS(ERROR) << __func__ << "NewConnection called on released object " + << getObjectPath(); + throw sdbus::Error("org.bluez.Error.Rejected", + "NewConnection called on released object"); + } + + auto device = devices_.get_device_by_path(device_object_path); + + if (!device.has_value()) { + NEARBY_LOGS(ERROR) + << __func__ + << "NewConection called with a device object we don't know about: " + << device_object_path; + throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); + } + + auto alias = device->get().Alias(); + auto mac_addr = device->get().Address(); + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << ": Connected to " << device->get().getObjectPath(); + + FDProperties props(fd_props); + + absl::MutexLock l(&connections_lock_); + if (connections_.count(mac_addr) != 0) { + connections_[mac_addr].push_back(std::pair(fd, std::move(props))); + } else { + connections_[mac_addr] = std::vector{std::pair(fd, std::move(props))}; + } +} + +void Profile::RequestDisconnection( + const sdbus::ObjectPath &device_object_path) { + auto device = devices_.get_device_by_path(device_object_path); + if (!device.has_value()) { + NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() + << ": RequestDisconnection called with a device object " + "we don't know about: " + << device_object_path; + throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); + } + + auto mac_addr = device->get().Address(); + NEARBY_LOGS(VERBOSE) << __func__ << ": Disconnection requested for device " + << device_object_path; + + absl::MutexLock l(&connections_lock_); + if (connections_.count(mac_addr) == 0) { + NEARBY_LOGS(ERROR) + << __func__ + << "Disconnection requested, but we are not connected to this device"; + return; + } + + connections_.erase(mac_addr); +} + +bool ProfileManager::Register(std::optional name, + absl::string_view service_uuid) { if (ProfileRegistered(service_uuid)) { + NEARBY_LOGS(WARNING) << __func__ << ": Trying to register profile " + << service_uuid << " which was already registered."; return true; } - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - std::string uuid(service_uuid); - - auto profile_object_path = - absl::Substitute("/com/github/google/nearby/profiles/$0", uuid); - struct RegisteredService *service = new struct RegisteredService(uuid); - service->slot = nullptr; - - registered_service_uuids_lock_.Lock(); - auto ret = sd_bus_add_object_vtable(system_bus_, &service->slot, - profile_object_path.c_str(), - "org.bluez.Profile1", vtable, service); - if (ret < 0) { - sd_bus_error_set_errno(&err, ret); - - NEARBY_LOGS(ERROR) << __func__ << "Error adding object " - << profile_object_path << ": " << err.message; - registered_service_uuids_lock_.Unlock(); + auto profile_object_path = bluez::profile_object_path(service_uuid); + try { + std::map options; + if (name.has_value()) { + options["Name"] = std::string(*name); + } + RegisterProfile(profile_object_path, std::string(service_uuid), options); + } catch (const sdbus::Error &e) { + BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "RegisterProfile", e); return false; } - NEARBY_LOGS(VERBOSE) << __func__ - << "Registered a ProfileManager for service UUID " - << uuid << " at " << profile_object_path; - - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez", - BLUEZ_PROFILEMANAGER_INTERFACE, "RegisterProfile", - &err, nullptr, "osa{sq}", "/com/github/google/nearby", - uuid.c_str(), 1, "Name", - std::string(name).c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error calling RegisterProfile: " << err.name << ": " - << err.message; - registered_service_uuids_lock_.Unlock(); - return false; + { + absl::MutexLock l(®istered_service_uuids_lock_); + registered_services_.emplace( + std::string(service_uuid), + std::make_shared(getProxy().getConnection(), + profile_object_path, devices_)); } - registered_services_[uuid] = service; - registered_service_uuids_lock_.Unlock(); + NEARBY_LOGS(INFO) << __func__ + << ": Registered profile instancefor service uuid " + << service_uuid; + return true; } -std::optional -ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device, - absl::string_view service_uuid) { +void ProfileManager::Unregister(absl::string_view service_uuid) { if (!ProfileRegistered(service_uuid)) { + NEARBY_LOGS(WARNING) + << __func__ + << ": attempted to unregister a profile that is not registered"; + return; + } + + auto profile_object_path = bluez::profile_object_path(service_uuid); + NEARBY_LOGS(VERBOSE) << __func__ << ": Unregistering profile " + << profile_object_path; + + try { + UnregisterProfile(profile_object_path); + } catch (const sdbus::Error &e) { + BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "UnregisterProfile", e); + } + + { + absl::MutexLock l(®istered_service_uuids_lock_); + registered_services_.erase(std::string(service_uuid)); + } +} + +// Get a service record FD for a connected profile (identified by service_uuid) +// to the given device. +std::optional +ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device, + absl::string_view service_uuid, + CancellationFlag *cancellation_flag) { + if (!ProfileRegistered(service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << ": Service " << service_uuid + << " is not registered"; return std::nullopt; } auto mac_addr = remote_device.GetMacAddress(); registered_service_uuids_lock_.ReaderLock(); - auto service = registered_services_[std::string(service_uuid)]; + auto profile = registered_services_[std::string(service_uuid)]; registered_service_uuids_lock_.ReaderUnlock(); - service->connections_lock.Lock(); - auto cond = [mac_addr, service]() { - return service->connections.count(mac_addr) == 1; + NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() + << ": Attempting to get a FD for service " + << service_uuid << " on device " << mac_addr; + + auto cond = [mac_addr, profile, cancellation_flag]() { + return profile->connections_.count(mac_addr) != 0 || + (cancellation_flag != nullptr && cancellation_flag->Cancelled()); }; - service->connections_lock.Await(absl::Condition(&cond)); - int fd = service->connections[mac_addr]; - service->connections.erase(mac_addr); - service->connections_lock.Unlock(); + profile->connections_lock_.Lock(); + profile->connections_lock_.Await(absl::Condition(&cond)); + + if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) { + NEARBY_LOGS(WARNING) + << __func__ << ": " << profile->getObjectPath() << ": " + << remote_device.GetMacAddress() + << ": Cancelled waiting for a service record for profile " + << service_uuid; + profile->connections_lock_.Unlock(); + return std::nullopt; + } + + auto [fd, properties] = profile->connections_[mac_addr].back(); + profile->connections_[mac_addr].pop_back(); + if (profile->connections_[mac_addr].empty()) + profile->connections_.erase(mac_addr); + profile->connections_lock_.Unlock(); return fd; } -std::optional> +// Listen for a connected profile on any device, returning the connected device +// with its FD. +std::optional, sdbus::UnixFd>> ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { if (!ProfileRegistered(service_uuid)) { return std::nullopt; } registered_service_uuids_lock_.ReaderLock(); - auto service = registered_services_[std::string(service_uuid)]; + auto profile = registered_services_[std::string(service_uuid)]; registered_service_uuids_lock_.ReaderUnlock(); - service->connections_lock.Lock(); - auto cond = [service]() { return !service->connections.empty(); }; - service->connections_lock.Await(absl::Condition(&cond)); - auto it = service->connections.begin(); - auto mac_addr = it->first; - auto fd = it->second; - service->connections.erase(it); - service->connections_lock.Unlock(); - return std::pair(mac_addr, fd); + NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() + << ": Attempting to get a FD for service " + << profile->getObjectPath(); + + profile->connections_lock_.Lock(); + auto cond = [profile]() { return !profile->connections_.empty(); }; + profile->connections_lock_.Await(absl::Condition(&cond)); + + auto it = profile->connections_.begin(); + auto mac_addr = it->first; + auto [fd, properties] = it->second.back(); + it->second.pop_back(); + if (it->second.empty()) + profile->connections_.erase(it); + profile->connections_lock_.Unlock(); + + return std::pair(devices_.get_device_by_address(mac_addr).value(), fd); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index b579ddbc..e6ea176c 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -2,56 +2,102 @@ #define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ #include +#include #include +#include #include #include #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_profile_glue.h" +#include "internal/platform/implementation/linux/bluez_profile_manager_client_glue.h" namespace nearby { namespace linux { - -struct RegisteredService { +class Profile : public sdbus::AdaptorInterfaces { public: - sd_bus_slot *slot; - absl::Mutex connections_lock; - // Maps mac addresses to unclaimed FDs. Probably an awful way to do this, but - // whatever. - std::map connections; - std::string &uuid; - RegisteredService(std::string &uuid) : uuid(uuid) {} + Profile(sdbus::IConnection &system_bus, absl::string_view profile_object_path, + BluetoothDevices &devices) + : AdaptorInterfaces(system_bus, std::string(profile_object_path)), + released_(false), devices_(devices) { + registerAdaptor(); + } + ~Profile() { unregisterAdaptor(); } + + struct FDProperties { + FDProperties(const std::map &fd_props) { + if (fd_props.count("Version") == 1) { + version = fd_props.at("Version"); + } + if (fd_props.count("Features") == 1) { + features = fd_props.at("Features"); + } + } + + std::optional version; + std::optional features; + }; + + void Release() override; + void NewConnection(const sdbus::ObjectPath &, const sdbus::UnixFd &, + const std::map &) override; + void RequestDisconnection(const sdbus::ObjectPath &) override; + + std::atomic_bool released_; + + absl::Mutex connections_lock_; + std::map>> + connections_; + + BluetoothDevices &devices_; }; -class ProfileManager { +class ProfileManager + : private sdbus::ProxyInterfaces { public: - ProfileManager(sd_bus *system_bus) { system_bus_ = system_bus; } - ~ProfileManager() { sd_bus_unref(system_bus_); } + ProfileManager(sdbus::IConnection &system_bus, BluetoothDevices &devices) + : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, "/org/bluez"), + devices_(devices) { + registerProxy(); + } + ~ProfileManager() { unregisterProxy(); } bool ProfileRegistered(absl::string_view service_uuid); - bool RegisterProfile(absl::string_view service_name, - absl::string_view service_uuid); - bool RegisterProfile(absl::string_view service_uuid) { - return RegisterProfile("", service_uuid); + bool Register(std::optional service_name, + absl::string_view service_uuid); + bool Register(absl::string_view service_uuid) { + return Register(std::nullopt, service_uuid); } + void Unregister(absl::string_view service_uuid); - std::optional GetServiceRecordFD(api::BluetoothDevice &remote_device, - absl::string_view service_uuid); - std::optional> + std::optional + GetServiceRecordFD(api::BluetoothDevice &remote_device, + absl::string_view service_uuid, + CancellationFlag *cancellation_flag); + std::optional< + std::pair, sdbus::UnixFd>> GetServiceRecordFD(absl::string_view service_uuid); private: + BluetoothDevices &devices_; // Maps service UUIDs to RegisteredService - std::map registered_services_; + std::map> registered_services_; absl::Mutex registered_service_uuids_lock_; - - sd_bus *system_bus_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index ad325e71..b9df13e9 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -1,73 +1,124 @@ +#include +#include #include -#include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" -#include "absl/strings/substitute.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { - -BluetoothDevice::BluetoothDevice(sd_bus *system_bus, absl::string_view adapter, - absl::string_view address) { - mac_addr_ = std::string(address); - object_path_ = absl::Substitute("/org/bluez/$0/dev_$1", adapter, - absl::StrReplaceAll(address, {{":", "_"}})); - system_bus_ = system_bus; -} - -BluetoothDevice::BluetoothDevice(sd_bus *system_bus, - absl::string_view device_object_path) { - system_bus_ = system_bus; - object_path_ = device_object_path; -} - -BluetoothDevice::BluetoothDevice(const BluetoothDevice &device) { - if (!device.mac_addr_.empty()) { - mac_addr_ = device.mac_addr_; - } - object_path_ = device.object_path_; - system_bus_ = sd_bus_ref(device.system_bus_); +BluetoothDevice::BluetoothDevice(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &device_object_path) + : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, + std::string(device_object_path)) { + registerProxy(); } std::string BluetoothDevice::GetName() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *cname = nullptr; - if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, - object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "Alias", &err, &cname) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error getting alias for device " - << object_path_ << " :" << err.message; + auto bluez_device = + sdbus::createProxy(getProxy().getConnection(), bluez::SERVICE_DEST, + getProxy().getObjectPath()); + + try { + std::string alias = + bluez_device->getProperty("Alias").onInterface(bluez::DEVICE_INTERFACE); + return alias; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Alias for device " + << bluez_device->getObjectPath(); return std::string(); } - - std::string name(cname); - free(cname); - return name; } std::string BluetoothDevice::GetMacAddress() const { - if (!mac_addr_.empty()) { - return mac_addr_; - } + auto bluez_device = + sdbus::createProxy(getProxy().getConnection(), bluez::SERVICE_DEST, + getProxy().getObjectPath()); - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *c_addr = nullptr; - if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, - object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "Address", &err, &c_addr) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error getting address for device " - << object_path_ << " :" << err.message; + try { + std::string addr = bluez_device->getProperty("Address").onInterface( + bluez::DEVICE_INTERFACE); + return addr; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Address for device " + << bluez_device->getObjectPath(); return std::string(); } +} - std::string addr(c_addr); - free(c_addr); - return addr; +void BluetoothDevice::onConnectProfileReply(const sdbus::Error *error) { + if (error != nullptr && error->getName() != "org.bluez.Error.InProgress") { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << error->getName() + << "' with message '" << error->getMessage() + << " while connecting to profile."; + } +} + +bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { + try { + ConnectProfile(std::string(service_uuid)); + return true; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to asynchronously connect to profile " + << service_uuid << " on device " << getObjectPath(); + return false; + } +} + +MonitoredBluetoothDevice::MonitoredBluetoothDevice( + sdbus::IConnection &system_bus, const sdbus::ObjectPath &device_object_path, + ObserverList &observers) + : BluetoothDevice(system_bus, device_object_path), + ProxyInterfaces(system_bus, bluez::SERVICE_DEST, + std::string(device_object_path)), + observers_(observers) { + registerProxy(); +} + +void MonitoredBluetoothDevice::onPropertiesChanged( + const std::string &interfaceName, + const std::map &changedProperties, + const std::vector &invalidatedProperties) { + if (interfaceName != bluez::DEVICE_INTERFACE) { + return; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << ": Received PropertiesChanged signal for interface " + << interfaceName; + + for (auto it = changedProperties.begin(); it != changedProperties.end(); + it++) { + if (it->first == bluez::DEVICE_PROP_ADDRESS) { + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << ": Notifying observers about address change"; + std::string address = it->second; + for (auto &observer : observers_.GetObservers()) { + observer->DeviceAddressChanged(*this, address); + } + } else if (it->first == bluez::DEVICE_PROP_PAIRED) { + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << "Notifying observers about paired status change."; + for (auto &observer : observers_.GetObservers()) { + observer->DevicePairedChanged(*this, it->second); + } + } else if (it->first == bluez::DEVICE_PROP_CONNECTED) { + NEARBY_LOGS(VERBOSE) + << __func__ << ": " << getObjectPath() + << "Notifying observers about connected status change"; + for (auto &observer : observers_.GetObservers()) { + observer->DeviceConnectedStateChanged(*this, it->second); + } + } + } } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 18e93795..cab3058a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -1,23 +1,27 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ -#include +#include +#include +#include +#include +#include +#include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" +#include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluez_device_client_glue.h" namespace nearby { namespace linux { -const char *BLUEZ_DEVICE_INTERFACE = "org.bluez.Device1"; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. -class BluetoothDevice : public api::BluetoothDevice { +class BluetoothDevice + : public api::BluetoothDevice, + public sdbus::ProxyInterfaces { public: - BluetoothDevice(sd_bus *system_bus, absl::string_view adapter, - absl::string_view address); - BluetoothDevice(sd_bus *system_bus, absl::string_view device_object_path); - BluetoothDevice(const BluetoothDevice &device); - - ~BluetoothDevice() override { sd_bus_unref(system_bus_); }; + BluetoothDevice(sdbus::IConnection &system_bus, const sdbus::ObjectPath &); + ~BluetoothDevice() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() std::string GetName() const override; @@ -25,11 +29,55 @@ public: // Returns BT MAC address assigned to this device. std::string GetMacAddress() const override; + bool ConnectToProfile(absl::string_view service_uuid); + + void + set_pair_reply_callback(absl::AnyInvocable cb) { + absl::MutexLock l(&pair_callback_lock_); + on_pair_reply_cb_ = std::move(cb); + } + + void reset_pair_reply_callback() { + absl::MutexLock l(&pair_callback_lock_); + on_pair_reply_cb_ = DefaultCallback(); + } + +protected: + void onConnectProfileReply(const sdbus::Error *error) override; + void onPairReply(const sdbus::Error *error) override { + absl::ReaderMutexLock l(&pair_callback_lock_); + on_pair_reply_cb_(error); + }; + private: - sd_bus *system_bus_; - std::string object_path_; - std::string mac_addr_; + absl::Mutex pair_callback_lock_; + absl::AnyInvocable on_pair_reply_cb_ = + DefaultCallback(); }; + +class MonitoredBluetoothDevice + : public BluetoothDevice, + public sdbus::ProxyInterfaces { +public: + using sdbus::ProxyInterfaces::registerProxy; + using sdbus::ProxyInterfaces::unregisterProxy; + using sdbus::ProxyInterfaces::getObjectPath; + + MonitoredBluetoothDevice( + sdbus::IConnection &system_bus, const sdbus::ObjectPath &, + ObserverList &observers); + ~MonitoredBluetoothDevice() { unregisterProxy(); } + +protected: + void onPropertiesChanged( + const std::string &interfaceName, + const std::map &changedProperties, + const std::vector &invalidatedProperties) override; + +private: + ObserverList &observers_; +}; + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 6340179e..2115684f 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -1,9 +1,9 @@ #include #include -#include +#include +#include -#include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" #include "internal/platform/implementation/bluetooth_classic.h" @@ -18,120 +18,127 @@ namespace nearby { namespace linux { - -int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, - sd_bus_error *ret_error) { - const sd_bus_error *reply_err = sd_bus_message_get_error(m); - if (reply_err) { - NEARBY_LOGS(ERROR) << __func__ - << "Received error while listening for InterfacesAdded: " - << reply_err->message; - return 0; - } - - struct BluetoothClassicMedium::DiscoveryParams *params = - static_cast(userdata); - char *c_object_path = nullptr; - int ret = sd_bus_message_read(m, "o", &c_object_path); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error reading object path from message: " << ret; - return ret; - } - - std::string object_path(c_object_path); - - if (!absl::StrContains(object_path, absl::StrCat(params->adapter_object_path, - "/", "dev_"))) { - // Interface added for an object we dont care about. - return 0; - } - - if (params->devices_by_path.count(object_path) != 0) { - // Object already exists - return 0; - } - - ret = sd_bus_message_enter_container(m, 'a', "{sa{sv}}"); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error entering container: " << ret; - return ret; - } - - while (true) { - const char *interface_name = nullptr; - ret = sd_bus_message_read(m, "s", &interface_name); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error reading dict entry: " << ret; - return ret; - } - if (ret == 0) - break; - - if (strcmp(interface_name, "org.bluez.Device1") == 0) { - NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " - << object_path; - sd_bus *system_bus = nullptr; - sd_bus_default_system(&system_bus); - - auto bluetoothDevice = std::make_unique( - BluetoothDevice(system_bus, object_path)); - params->devices_by_path[object_path] = std::move(bluetoothDevice); - - if (params->cb.device_discovered_cb != nullptr) { - params->cb.device_discovered_cb(*params->devices_by_path[object_path]); - } - for (auto &observer : params->observers_.GetObservers()) { - observer->DeviceAdded(*params->devices_by_path[object_path]); - } - return 0; - } - ret = sd_bus_message_skip(m, "a{sv}"); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error skipping dict entry: " << ret; - return -1; - } - } - - return 0; -} - -BluetoothClassicMedium::BluetoothClassicMedium(sd_bus *system_bus, +BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, absl::string_view adapter) - : profile_manager_(sd_bus_ref(system_bus)) { - system_bus_ = system_bus; - adapter_object_path_ = absl::Substitute("/org/bluez/$0/", adapter); + : devices_(system_bus, absl::Substitute("/org/bluez/$0/", adapter), + observers_), + profile_manager_(system_bus) { + bluez_adapter_proxy_ = sdbus::createProxy( + "org.bluez", absl::Substitute("/org/bluez/$0/", adapter)); + bluez_adapter_proxy_->finishRegistration(); + bluez_proxy_ = sdbus::createProxy("org.bluez", "/"); + bluez_proxy_->finishRegistration(); } -BluetoothClassicMedium::~BluetoothClassicMedium() { - sd_bus_unref(system_bus_); - if (system_bus_slot_) - sd_bus_slot_unref(system_bus_slot_); +void BluetoothClassicMedium::onInterfacesAdded(sdbus::Signal &signal) { + sdbus::ObjectPath object; + signal >> object; + + NEARBY_LOGS(VERBOSE) << __func__ << "New intefaces added at " << object; + + auto path_prefix = + absl::Substitute("$0/dev_", bluez_adapter_proxy_->getObjectPath()); + if (object.find(path_prefix) != 0) { + return; + } + + if (devices_.get_device_by_path(object).has_value()) { + // Device already exists. + return; + } + + std::map> interfaces; + signal >> interfaces; + + for (auto it = interfaces.begin(); it != interfaces.end(); it++) { + auto interface = it->first; + + if (interface == "org.bluez.Device1") { + NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " << object; + + auto &device = devices_.add_new_device(object); + + discovery_cb_lock_.ReaderLock(); + if (discovery_cb_.has_value() && + discovery_cb_->device_discovered_cb != nullptr) { + discovery_cb_->device_discovered_cb(device); + } + discovery_cb_lock_.ReaderUnlock(); + + for (auto &observer : observers_.GetObservers()) { + observer->DeviceAdded(device); + } + } + } +} + +void BluetoothClassicMedium::onInterfacesRemoved(sdbus::Signal &signal) { + sdbus::ObjectPath object; + signal >> object; + + NEARBY_LOGS(VERBOSE) << __func__ << ": Intefaces removed at " << object; + + auto path_prefix = + absl::Substitute("$0/dev_", bluez_adapter_proxy_->getObjectPath()); + if (object.find(path_prefix) != 0) { + return; + } + + std::vector interfaces; + signal >> interfaces; + + for (auto &interface : interfaces) { + if (interface == bluez::DEVICE_INTERFACE) { + + { + auto device = get_device_by_path(object); + if (!device.has_value()) { + NEARBY_LOGS(WARNING) << __func__ + << ": received InterfacesRemoved for a device " + "we don't know about: " + << object; + return; + } + + NEARBY_LOGS(INFO) << __func__ << ": " << object << " has been removed"; + for (auto &observer : observers_.GetObservers()) { + observer->DeviceRemoved(*device); + } + discovery_cb_lock_.ReaderLock(); + if (discovery_cb_.has_value() && + discovery_cb_->device_lost_cb != nullptr) { + discovery_cb_->device_lost_cb(*device); + } + discovery_cb_lock_.ReaderUnlock(); + } + remove_device_by_path(object); + } + } } bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { - if (!system_bus_) - return false; + discovery_cb_lock_.Lock(); + discovery_cb_ = std::move(discovery_callback); + discovery_cb_lock_.Unlock(); - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = - nullptr; + NEARBY_LOGS(VERBOSE) << __func__ + << ": Subscribing to InterfacesAdded on / at org.bluez"; - discovery_params_.cb = std::move(discovery_callback); - discovery_params_.adapter_object_path = adapter_object_path_; + bluez_proxy_->registerSignalHandler( + "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", + [this](sdbus::Signal &signal) { this->onInterfacesAdded(signal); }); + bluez_proxy_->registerSignalHandler( + "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", + [this](sdbus::Signal &signal) { this->onInterfacesRemoved(signal); }); - sd_bus_match_signal(system_bus_, &system_bus_slot_, BLUEZ_SERVICE, "/", - "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", - bluez_interfaces_added_signal_handler, - &discovery_params_); - - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, - adapter_object_path_.c_str(), BLUEZ_ADAPTER_INTERFACE, - "StartDiscovery", &err, &reply, nullptr) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error calling StartDiscovery on adapter " - << adapter_object_path_ << ": " << err.message; + try { + NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on " + << bluez_adapter_proxy_->getObjectPath(); + bluez_adapter_proxy_->callMethod("StartDiscovery") + .onInterface(bluez::ADAPTER_INTERFACE); + } catch (const sdbus::Error &e) { + BLUEZ_LOG_METHOD_CALL_ERROR(bluez_adapter_proxy_, "StartDiscovery", e); return false; } @@ -139,20 +146,24 @@ bool BluetoothClassicMedium::StartDiscovery( } bool BluetoothClassicMedium::StopDiscovery() { - if (!system_bus_) - return false; - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = - nullptr; - - int ret = sd_bus_call_method( - system_bus_, BLUEZ_SERVICE, adapter_object_path_.c_str(), - BLUEZ_ADAPTER_INTERFACE, "StopDiscovery", &err, &reply, nullptr); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error calling StopDiscovery on " - << adapter_object_path_ << ": " << err.message; + NEARBY_LOGS(VERBOSE) + << __func__ << ": Unsubscribing to InterfacesAdded on / at org.bluez"; + bluez_proxy_->unregisterSignalHandler("org.freedesktop.DBus.ObjectManager", + "InterfacesAdded"); + bluez_proxy_->unregisterSignalHandler("org.freedesktop.DBus.ObjectManager", + "InterfacesRemoved"); + try { + NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " + << bluez_adapter_proxy_->getObjectPath(); + bluez_adapter_proxy_->callMethodAsync("StopDiscovery") + .onInterface(bluez::ADAPTER_INTERFACE) + .uponReplyInvoke([this](const sdbus::Error *err) { + this->discovery_cb_lock_.Lock(); + this->discovery_cb_.reset(); + this->discovery_cb_lock_.Unlock(); + }); + } catch (const sdbus::Error &e) { + BLUEZ_LOG_METHOD_CALL_ERROR(bluez_adapter_proxy_, "StopDiscovery", e); return false; } @@ -163,24 +174,31 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, const std::string &service_uuid, CancellationFlag *cancellation_flag) { - auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress()); + auto device_object_path = bluez::device_object_path( + bluez_adapter_proxy_->getObjectPath(), remote_device.GetMacAddress()); if (!profile_manager_.ProfileRegistered(service_uuid)) { - if (!profile_manager_.RegisterProfile(service_uuid)) { - NEARBY_LOGS(ERROR) << __func__ << "Could not register profile " + if (!profile_manager_.Register("", service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " << service_uuid << " with Bluez"; return nullptr; } } - auto fd = profile_manager_.GetServiceRecordFD(remote_device, service_uuid); + + auto &device = devices_.get_device_by_path(device_object_path).value().get(); + device.ConnectToProfile(service_uuid); + + auto fd = profile_manager_.GetServiceRecordFD(remote_device, service_uuid, + cancellation_flag); if (!fd.has_value()) { - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get a new connection for profile " - << service_uuid << " for device " << device_object_path; + NEARBY_LOGS(WARNING) << __func__ + << ": Failed to get a new connection for profile " + << service_uuid << " for device " + << device_object_path; return nullptr; } - return std::unique_ptr(new BluetoothSocket( - remote_device, device_object_path, service_uuid, fd.value())); + return std::unique_ptr( + new BluetoothSocket(remote_device, fd.value())); } std::unique_ptr @@ -188,49 +206,33 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, const std::string &service_uuid) { if (!profile_manager_.ProfileRegistered(service_uuid)) { if (!profile_manager_.RegisterProfile(service_name, service_uuid)) { - NEARBY_LOGS(ERROR) << __func__ << "Could not register profile " + NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " << service_name << " " << service_uuid << " with Bluez"; return nullptr; } } - auto pair = profile_manager_.GetServiceRecordFD(service_uuid); - if (!pair.has_value()) { - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get a new connection for profile " - << service_uuid << " for device "; - return nullptr; - } - - auto device_object_path = GetDeviceObjectPath(pair->first); - auto device = BluetoothDevice(sd_bus_ref(system_bus_), device_object_path); - return std::unique_ptr( - new BluetoothServerSocket(sd_bus_ref(system_bus_), profile_manager_, - adapter_object_path_, service_uuid)); + new BluetoothServerSocket(profile_manager_, service_uuid)); } api::BluetoothDevice * BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { - if (devices_by_path_.count(mac_address) == 1) { - return devices_by_path_[mac_address].get(); - } + auto device = get_device_by_address(mac_address); + if (device.has_value()) + return nullptr; - return nullptr; + return &(device->get()); } std::unique_ptr BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) { - auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress()); + auto device_object_path = bluez::device_object_path( + bluez_adapter_proxy_->getObjectPath(), remote_device.GetMacAddress()); return std::unique_ptr( - new BluetoothPairing(sd_bus_ref(system_bus_), device_object_path)); -} - -std::string -BluetoothClassicMedium::GetDeviceObjectPath(absl::string_view mac_address) { - return absl::Substitute("$0/dev_$1", adapter_object_path_, - absl::StrReplaceAll(mac_address, {{":", "_"}})); + new BluetoothPairing(bluez_adapter_proxy_->getObjectPath(), remote_device, + bluez_adapter_proxy_->getConnection())); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index c4d5217d..783cc728 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -1,15 +1,22 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_ +#include #include #include +#include +#include +#include +#include #include +#include "absl/synchronization/mutex.h" #include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" namespace nearby { namespace linux { @@ -17,8 +24,9 @@ namespace linux { // medium. class BluetoothClassicMedium : public api::BluetoothClassicMedium { public: - BluetoothClassicMedium(sd_bus *system_bus, absl::string_view adapter); - ~BluetoothClassicMedium(); + BluetoothClassicMedium(sdbus::IConnection &system_bus, + absl::string_view adapter); + ~BluetoothClassicMedium() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() // @@ -80,27 +88,28 @@ public: observers_.RemoveObserver(observer); }; - struct DiscoveryParams { - std::string &adapter_object_path; - std::map> &devices_by_path; - ObserverList &observers_; - BluetoothClassicMedium::DiscoveryCallback cb; - }; + std::optional> + get_device_by_path(const sdbus::ObjectPath &); + std::optional> + get_device_by_address(const std::string &); + void remove_device_by_path(const sdbus::ObjectPath &); private: + void onInterfacesAdded(sdbus::Signal &signal); + void onInterfacesRemoved(sdbus::Signal &signal); + + BluetoothDevices devices_; + + absl::Mutex discovery_cb_lock_; + std::optional discovery_cb_; + ProfileManager profile_manager_; - - std::string GetDeviceObjectPath(absl::string_view mac_address); - - sd_bus *system_bus_ = nullptr; - sd_bus_slot *system_bus_slot_ = nullptr; - std::string adapter_object_path_ = std::string(); - std::map> devices_by_path_; ObserverList observers_; - DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_path_, - observers_}; + std::unique_ptr bluez_adapter_proxy_; + std::unique_ptr bluez_proxy_; }; + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h index ce0f2e7d..817c33ed 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -9,14 +9,9 @@ namespace nearby { namespace linux { class BluetoothServerSocket : public api::BluetoothServerSocket { public: - BluetoothServerSocket(sd_bus *system_bus, ProfileManager &profile_manager, - absl::string_view adapter_object_path, - absl::string_view service_uuid) - : profile_manager_(profile_manager) { - system_bus_ = system_bus; - adapter_object_path_ = adapter_object_path; - service_uuid_ = service_uuid; - } + BluetoothServerSocket(ProfileManager &profile_manager, + const std::string &service_uuid) + : profile_manager_(profile_manager), service_uuid_(service_uuid) {} ~BluetoothServerSocket() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept() @@ -36,10 +31,8 @@ public: Exception Close() override; private: - sd_bus *system_bus_; ProfileManager &profile_manager_; - std::string adapter_object_path_; - std::string service_uuid_; + const std::string &service_uuid_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 4ef2bade..2ad0acec 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -7,17 +7,18 @@ #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" -#include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" -#include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { ExceptionOr BluetoothInputStream::Read(std::int64_t size) { + if (!fd_.has_value()) + return Exception::kIo; + char *data = new char[size]; - ssize_t ret = read(fd_, data, size); + ssize_t ret = read(fd_->get(), data, size); if (ret == 0) { delete[] data; return ExceptionOr(ByteArray()); @@ -30,17 +31,23 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { } ExceptionOr BluetoothInputStream::Skip(std::size_t offset) { - auto off = lseek(fd_, offset, SEEK_CUR); + if (!fd_.has_value()) + return Exception::kIo; + + auto off = lseek(fd_->get(), offset, SEEK_CUR); if (off != offset) { - auto end = lseek(fd_, 0, SEEK_END); + auto end = lseek(fd_->get(), 0, SEEK_END); return off == end ? ExceptionOr((std::size_t)off) : Exception::kIo; } return ExceptionOr((std::size_t)(off)); } ExceptionOr BluetoothInputStream::ReadExactly(std::size_t size) { + if (!fd_.has_value()) + return Exception::kIo; + char *data = new char[size]; - ssize_t ret = read(fd_, data, size); + ssize_t ret = read(fd_->get(), data, size); if (ret < 0) { delete[] data; return Exception::kIo; @@ -50,9 +57,12 @@ ExceptionOr BluetoothInputStream::ReadExactly(std::size_t size) { } Exception BluetoothOutputStream::Write(const ByteArray &data) { + if (!fd_.has_value()) + return Exception{Exception::kIo}; + ssize_t written = 0; while (written < data.size()) { - ssize_t ret = write(fd_, data.data(), data.size()); + ssize_t ret = write(fd_->get(), data.data(), data.size()); if (ret < 1) { return Exception{Exception::kIo}; } @@ -66,32 +76,13 @@ Exception BluetoothOutputStream::Flush() { } Exception BluetoothOutputStream::Close() { - return close(fd_) < 0 ? Exception{Exception::kIo} - : Exception{Exception::kSuccess}; + return close(fd_->get()) < 0 ? Exception{Exception::kIo} + : Exception{Exception::kSuccess}; } Exception BluetoothSocket::Close() { - __attribute__((cleanup(sd_bus_unrefp))) sd_bus *system_bus = NULL; - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - - if (auto ret = sd_bus_default_system(&system_bus); ret < 0) { - sd_bus_error_set_errno(&err, ret); - NEARBY_LOGS(ERROR) << __func__ - << "Error connecting to system bus: " << err.name << ": " - << err.message; - return Exception{Exception::kFailed}; - } - - if (sd_bus_call_method(system_bus, BLUEZ_SERVICE, device_object_path_.c_str(), - BLUEZ_DEVICE_INTERFACE, "DisconnectProfile", &err, - nullptr, "s", connected_profile_uuid_.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error disconnecting from profile " - << connected_profile_uuid_ << " on device " - << device_object_path_ << ": " << err.name << ": " - << err.message; - return Exception{Exception::kFailed}; - } + input_stream_.fd_.reset(); + output_stream_.fd_.reset(); return Exception{Exception::kSuccess}; } diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index 7a40fc0a..a64ea74a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -2,7 +2,9 @@ #define PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_ #include +#include +#include #include #include "internal/platform/byte_array.h" @@ -14,7 +16,7 @@ namespace linux { class BluetoothInputStream : public InputStream { public: - BluetoothInputStream(int fd) { fd_ = fd; }; + BluetoothInputStream(sdbus::UnixFd &fd) : fd_(fd){}; ExceptionOr Read(std::int64_t size) override; ExceptionOr Skip(size_t offset) override; @@ -23,33 +25,29 @@ public: Exception Close() override; private: - int fd_; + friend class BluetoothSocket; + + std::optional fd_; }; class BluetoothOutputStream : public OutputStream { public: - BluetoothOutputStream(int fd) { fd_ = fd; }; + BluetoothOutputStream(sdbus::UnixFd &fd) : fd_(fd){}; Exception Write(const ByteArray &data) override; Exception Flush() override; Exception Close() override; private: - int fd_; + friend class BluetoothSocket; + + std::optional fd_; }; class BluetoothSocket : public api::BluetoothSocket { public: - BluetoothSocket(api::BluetoothDevice &device, - absl::string_view device_object_path, - absl::string_view connected_profile_uuid, int fd) - : device_(device) { - fd_ = fd; - device_object_path_ = device_object_path; - connected_profile_uuid_ = connected_profile_uuid; - input_stream_ = BluetoothInputStream(fd_); - output_stream_ = BluetoothOutputStream(fd_); - } + BluetoothSocket(api::BluetoothDevice &device, sdbus::UnixFd fd) + : device_(device), output_stream_(fd), input_stream_(fd) {} InputStream &GetInputStream() override { return input_stream_; } OutputStream &GetOutputStream() override { return output_stream_; } @@ -57,12 +55,9 @@ public: api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; private: - int fd_; - std::string device_object_path_; api::BluetoothDevice &device_; - std::string connected_profile_uuid_; - BluetoothInputStream input_stream_ = {-1}; - BluetoothOutputStream output_stream_ = {-1}; + BluetoothOutputStream output_stream_; + BluetoothInputStream input_stream_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc new file mode 100644 index 00000000..e3212857 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -0,0 +1,49 @@ +#include +#include + +#include + +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "absl/synchronization/mutex.h" + +namespace nearby { +namespace linux { +std::optional> +BluetoothDevices::get_device_by_path( + const sdbus::ObjectPath &device_object_path) { + absl::ReaderMutexLock l(&devices_by_path_lock_); + + if (devices_by_path_.count(device_object_path) == 0) { + return std::nullopt; + } + + auto &device = devices_by_path_[device_object_path]; + return device; +} + +std::optional> +BluetoothDevices::get_device_by_address(const std::string &addr) { + auto device_object_path = + bluez::device_object_path(adapter_object_path_, addr); + return get_device_by_path(device_object_path); +} + +void BluetoothDevices::remove_device_by_path( + const sdbus::ObjectPath &device_object_path) { + absl::MutexLock l(&devices_by_path_lock_); + + devices_by_path_.erase(device_object_path); +} + +BluetoothDevice & +BluetoothDevices::add_new_device(sdbus::ObjectPath device_object_path) { + absl::MutexLock l(&devices_by_path_lock_); + auto pair = + devices_by_path_.emplace(device_object_path, system_bus_, + std::move(device_object_path), observers_); + return pair.first->second; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h new file mode 100644 index 00000000..093ebaa0 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -0,0 +1,42 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_ + +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/base/observer_list.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" + +namespace nearby { +namespace linux { +class BluetoothDevices { +public: + BluetoothDevices( + sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path, + ObserverList &observers) + : system_bus_(system_bus), observers_(observers), + adapter_object_path_(adapter_object_path) {} + + std::optional> + get_device_by_path(const sdbus::ObjectPath &); + std::optional> + get_device_by_address(const std::string &); + void remove_device_by_path(const sdbus::ObjectPath &); + BluetoothDevice &add_new_device(sdbus::ObjectPath); + +private: + absl::Mutex devices_by_path_lock_; + std::map devices_by_path_; + + sdbus::IConnection &system_bus_; + ObserverList &observers_; + sdbus::ObjectPath adapter_object_path_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 3d82511f..08d893d4 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -1,8 +1,11 @@ +#include +#include +#include #include #include #include "internal/platform/implementation/bluetooth_classic.h" -#include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_pairing.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" @@ -10,117 +13,119 @@ namespace nearby { namespace linux { -int pairing_reply_handler(sd_bus_message *m, void *userdata, - sd_bus_error *err) { - auto pairing_cb = static_cast(userdata); - if (sd_bus_message_is_method_error(m, nullptr)) { - if (sd_bus_message_is_method_error( - m, "org.bluez.Error.AuthenticationCanceled")) { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthCanceled); - } else if (sd_bus_message_is_method_error( - m, "org.bluez.Error.AuthenticationFailed")) { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthFailed); - } else if (sd_bus_message_is_method_error( - m, "org.bluez.Error.AuthenticationRejected")) { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthRejected); - } else if (sd_bus_message_is_method_error( - m, "org.bluez.Error.AuthenticationTimeout")) { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthTimeout); +void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { + if (error != nullptr && error->isValid()) { + auto name = error->getName(); + api::BluetoothPairingCallback::PairingError err; + + NEARBY_LOGS(ERROR) << __func__ << ": " + << "Got error '" << error->getName() + << "' with message '" << error->getMessage() + << "' while pairing with device " + << device_.getObjectPath(); + + if (name == "org.bluez.Error.AuthenticationCanceled") { + err = api::BluetoothPairingCallback::PairingError::kAuthCanceled; + } else if (name == "org.bluez.Error.AuthenticationFailed") { + err = api::BluetoothPairingCallback::PairingError::kAuthFailed; + } else if (name == "org.bluez.Error.AuthenticationRejected") { + err = api::BluetoothPairingCallback::PairingError::kAuthRejected; + } else if (name == "org.bluez.Error.AuthenticationTimeout") { + err = api::BluetoothPairingCallback::PairingError::kAuthTimeout; } else { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthFailed); + err = api::BluetoothPairingCallback::PairingError::kAuthFailed; } - return 0; + + if (pairing_cb_.on_pairing_error_cb != nullptr) { + pairing_cb_.on_pairing_error_cb(err); + } + + return; } - if (err) { - NEARBY_LOGS(ERROR) << __func__ - << "Error pairing with device: " << err->message; - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kUnknown); - } else { - pairing_cb->on_paired_cb(); + if (pairing_cb_.on_paired_cb != nullptr) { + pairing_cb_.on_paired_cb(); } - return 0; + return; } +BluetoothPairing::BluetoothPairing(const sdbus::ObjectPath &adapter_object_path, + BluetoothDevice &remote_device, + BluetoothAdapter &adapter, + sdbus::IConnection &system_bus) + : device_(remote_device), adapter_(adapter) {} + bool BluetoothPairing::InitiatePairing( api::BluetoothPairingCallback pairing_cb) { - if (!system_bus_) - return false; - pairing_cb_ = std::move(pairing_cb); + if (pairing_cb_.on_pairing_initiated_cb != nullptr) + pairing_cb_.on_pairing_initiated_cb(api::PairingParams{ + api::PairingParams::PairingType::kConsent, std::string()}); - if (sd_bus_call_method_async( - system_bus_, nullptr, BLUEZ_SERVICE, device_object_path_.c_str(), - BLUEZ_DEVICE_INTERFACE, "Pair", &pairing_reply_handler, &pairing_cb_, - nullptr) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error calling method Pair on device " - << device_object_path_; - return false; - } - pairing_cb.on_pairing_initiated_cb(api::PairingParams{ - api::PairingParams::PairingType::kConsent, std::string()}); return true; } bool BluetoothPairing::FinishPairing( std::optional pin_code) { + device_.set_pair_reply_callback([this](const sdbus::Error *error) { + this->pairing_reply_handler(error); + }); + + try { + pair_async_call_ = device_.Pair(); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to initiate pairing for device " + << device_.getObjectPath(); + return false; + } + return true; } bool BluetoothPairing::CancelPairing() { - if (!system_bus_) - return false; + try { + if (pair_async_call_.isPending()) { + pair_async_call_.cancel(); + } - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, - device_object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "CancelPairing", &err, nullptr, nullptr) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error calling method CancelPairing on device " - << device_object_path_ << ": " << err.message; + device_.CancelPairing(); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to cancel pairing for device " + << device_.getObjectPath(); return false; } + return true; } bool BluetoothPairing::Unpair() { - if (!system_bus_) - return false; - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "RemoveDevice", &err, nullptr, - "o", device_object_path_.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error calling method CancelPairing on device " - << device_object_path_ << ": " << err.message; + try { + adapter_.RemoveDevice(device_.getObjectPath()); + return true; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to unpair device " + << device_.getObjectPath() << " on adapter " + << adapter_.getObjectPath(); return false; } - return true; } bool BluetoothPairing::IsPaired() { - if (!system_bus_) + try { + bool bonded = device_.Bonded(); + return bonded; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Bonded state for device " + << device_.getObjectPath(); return false; - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - int paired = 0; - if (sd_bus_get_property_trivial( - system_bus_, BLUEZ_SERVICE, device_object_path_.c_str(), - BLUEZ_DEVICE_INTERFACE, "Bonded", &err, 'b', &paired) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error getting Bonded property for device " - << device_object_path_ << ": " << err.message; } - return paired; } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index fa0f321d..157f095e 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -1,22 +1,26 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PROFILE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_ +#include #include +#include +#include +#include #include #include "absl/strings/string_view.h" -#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" namespace nearby { namespace linux { class BluetoothPairing : public api::BluetoothPairing { public: - BluetoothPairing(sd_bus *system_bus, absl::string_view device_object_path) { - system_bus_ = system_bus; - device_object_path_ = device_object_path; - } - ~BluetoothPairing() { sd_bus_unref(system_bus_); } + BluetoothPairing(const sdbus::ObjectPath &adapter_object_path, + BluetoothDevice &remote_device, BluetoothAdapter &adapter, + sdbus::IConnection &system_bus); + ~BluetoothPairing() override = default; bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; bool FinishPairing(std::optional pin_code) override; @@ -25,8 +29,14 @@ public: bool IsPaired() override; private: - std::string device_object_path_; - sd_bus *system_bus_; + void pairing_reply_handler(const sdbus::Error *e); + + sdbus::PendingAsyncCall pair_async_call_; + + BluetoothDevice &device_; + BluetoothAdapter &adapter_; + + std::unique_ptr bluez_adapter_proxy_; api::BluetoothPairingCallback pairing_cb_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc index efe5dcac..c9215949 100644 --- a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc @@ -19,27 +19,16 @@ std::unique_ptr BluetoothServerSocket::Accept() { << service_uuid_ << " for device "; return nullptr; } - auto device_object_path = - absl::Substitute("$0/dev_$1", adapter_object_path_, - absl::StrReplaceAll(pair->first, {{":", "_"}})); - auto device = BluetoothDevice(sd_bus_ref(system_bus_), device_object_path); - return std::unique_ptr(new BluetoothSocket( - device, device_object_path, service_uuid_, pair->second)); + + auto [device, fd] = *pair; + return std::unique_ptr(new BluetoothSocket(device, fd)); } Exception BluetoothServerSocket::Close() { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; auto profile_object_path = absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid_); - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez", - "org.bluez.ProfileManager1", "UnregisterProfile", &err, - nullptr, "o", profile_object_path.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error unregistering profile object " - << profile_object_path << ": " << err.message; - return {Exception::kFailed}; - } + profile_manager_.Unregister(service_uuid_); return {Exception::kSuccess}; } diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc new file mode 100644 index 00000000..2fde4c17 --- /dev/null +++ b/internal/platform/implementation/linux/bluez.cc @@ -0,0 +1,32 @@ +#include "absl/strings/substitute.h" +#include "absl/strings/string_view.h" +#include "absl/strings/str_replace.h" +#include "internal/platform/implementation/linux/bluez.h" +#include + +namespace nearby { +namespace linux { +namespace bluez { +const char *SERVICE = "org.bluez"; + +const char *ADAPTER_INTEFACE = "org.bluez.Adapter1"; + +const char *DEVICE_INTERFACE = "org.bluez.Device1"; +const char *DEVICE_PROP_ADDRESS = "Address"; +const char *DEVICE_PROP_ALIAS = "Alias"; +const char *DEVICE_PROP_PAIRED = "Paired"; +const char *DEVICE_PROP_CONNECTED = "Connected"; + +std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, + absl::string_view mac_address) { + return absl::Substitute("$0/dev_$1", adapter_object_path, + absl::StrReplaceAll(mac_address, {{":", "_"}})); +} + +sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) { + return absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid); +} + +} // namespace bluez +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 50316c95..45471fea 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -1,11 +1,40 @@ #ifndef PLATFORM_IMPL_LINUX_BLUEZ_H_ #define PLATFORM_IMPL_LINUX_BLUEZ_H_ +#include + +#include "absl/strings/string_view.h" + +#include + +#define BLUEZ_LOG_METHOD_CALL_ERROR(proxy, method, err) \ + do { \ + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (err).getName() \ + << "' with message '" << (err).getMessage() \ + << "' while calling " << method << " on object " \ + << (proxy)->getObjectPath(); \ + } while (false) + namespace nearby { namespace linux { -const char *BLUEZ_SERVICE = "org.bluez"; -const char *BLUEZ_ADAPTER_INTERFACE = "org.bluez.Adapter1"; +namespace bluez { +extern const char *SERVICE_DEST; +extern const char *ADAPTER_INTERFACE; + +extern const char *DEVICE_INTERFACE; +extern const char *DEVICE_PROP_ADDRESS; +extern const char *DEVICE_PROP_ALIAS; +extern const char *DEVICE_PROP_PAIRED; +extern const char *DEVICE_PROP_CONNECTED; + +extern std::string +device_object_path(const sdbus::ObjectPath &adapter_object_path, + absl::string_view mac_address); + +extern sdbus::ObjectPath profile_object_path(absl::string_view service_uuid); + +} // namespace bluez } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluez_adapter_client_glue.h b/internal/platform/implementation/linux/bluez_adapter_client_glue.h new file mode 100644 index 00000000..23884e28 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_adapter_client_glue.h @@ -0,0 +1,179 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__bluez_adapter_client_glue_h__proxy__H__ +#define __sdbuscpp__bluez_adapter_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class Adapter1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.Adapter1"; + +protected: + Adapter1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Adapter1_proxy() = default; + +public: + void StartDiscovery() + { + proxy_.callMethod("StartDiscovery").onInterface(INTERFACE_NAME); + } + + void SetDiscoveryFilter(const std::map& properties) + { + proxy_.callMethod("SetDiscoveryFilter").onInterface(INTERFACE_NAME).withArguments(properties); + } + + void StopDiscovery() + { + proxy_.callMethod("StopDiscovery").onInterface(INTERFACE_NAME); + } + + void RemoveDevice(const sdbus::ObjectPath& device) + { + proxy_.callMethod("RemoveDevice").onInterface(INTERFACE_NAME).withArguments(device); + } + + std::vector GetDiscoveryFilters() + { + std::vector result; + proxy_.callMethod("GetDiscoveryFilters").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void ConnectDevice(const std::map& properties) + { + proxy_.callMethod("ConnectDevice").onInterface(INTERFACE_NAME).withArguments(properties); + } + +public: + std::string Address() + { + return proxy_.getProperty("Address").onInterface(INTERFACE_NAME); + } + + std::string AddressType() + { + return proxy_.getProperty("AddressType").onInterface(INTERFACE_NAME); + } + + std::string Name() + { + return proxy_.getProperty("Name").onInterface(INTERFACE_NAME); + } + + std::string Alias() + { + return proxy_.getProperty("Alias").onInterface(INTERFACE_NAME); + } + + void Alias(const std::string& value) + { + proxy_.setProperty("Alias").onInterface(INTERFACE_NAME).toValue(value); + } + + uint32_t Class() + { + return proxy_.getProperty("Class").onInterface(INTERFACE_NAME); + } + + bool Powered() + { + return proxy_.getProperty("Powered").onInterface(INTERFACE_NAME); + } + + void Powered(const bool& value) + { + proxy_.setProperty("Powered").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string PowerState() + { + return proxy_.getProperty("PowerState").onInterface(INTERFACE_NAME); + } + + bool Discoverable() + { + return proxy_.getProperty("Discoverable").onInterface(INTERFACE_NAME); + } + + void Discoverable(const bool& value) + { + proxy_.setProperty("Discoverable").onInterface(INTERFACE_NAME).toValue(value); + } + + uint32_t DiscoverableTimeout() + { + return proxy_.getProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME); + } + + void DiscoverableTimeout(const uint32_t& value) + { + proxy_.setProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME).toValue(value); + } + + bool Pairable() + { + return proxy_.getProperty("Pairable").onInterface(INTERFACE_NAME); + } + + void Pairable(const bool& value) + { + proxy_.setProperty("Pairable").onInterface(INTERFACE_NAME).toValue(value); + } + + uint32_t PairableTimeout() + { + return proxy_.getProperty("PairableTimeout").onInterface(INTERFACE_NAME); + } + + void PairableTimeout(const uint32_t& value) + { + proxy_.setProperty("PairableTimeout").onInterface(INTERFACE_NAME).toValue(value); + } + + bool Discovering() + { + return proxy_.getProperty("Discovering").onInterface(INTERFACE_NAME); + } + + std::vector UUIDs() + { + return proxy_.getProperty("UUIDs").onInterface(INTERFACE_NAME); + } + + std::string Modalias() + { + return proxy_.getProperty("Modalias").onInterface(INTERFACE_NAME); + } + + std::vector Roles() + { + return proxy_.getProperty("Roles").onInterface(INTERFACE_NAME); + } + + std::vector ExperimentalFeatures() + { + return proxy_.getProperty("ExperimentalFeatures").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/bluez_device_client_glue.h b/internal/platform/implementation/linux/bluez_device_client_glue.h new file mode 100644 index 00000000..54102d1e --- /dev/null +++ b/internal/platform/implementation/linux/bluez_device_client_glue.h @@ -0,0 +1,215 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__bluez_device_client_glue_h__proxy__H__ +#define __sdbuscpp__bluez_device_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class Device1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.Device1"; + +protected: + Device1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Device1_proxy() = default; + + virtual void onConnectProfileReply(const sdbus::Error* error) = 0; + virtual void onPairReply(const sdbus::Error* error) = 0; + +public: + void Disconnect() + { + proxy_.callMethod("Disconnect").onInterface(INTERFACE_NAME); + } + + void Connect() + { + proxy_.callMethod("Connect").onInterface(INTERFACE_NAME); + } + + sdbus::PendingAsyncCall ConnectProfile(const std::string& UUID) + { + return proxy_.callMethodAsync("ConnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID).uponReplyInvoke([this](const sdbus::Error* error){ this->onConnectProfileReply(error); }); + } + + void DisconnectProfile(const std::string& UUID) + { + proxy_.callMethod("DisconnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID); + } + + sdbus::PendingAsyncCall Pair() + { + return proxy_.callMethodAsync("Pair").onInterface(INTERFACE_NAME).uponReplyInvoke([this](const sdbus::Error* error){ this->onPairReply(error); }); + } + + void CancelPairing() + { + proxy_.callMethod("CancelPairing").onInterface(INTERFACE_NAME); + } + +public: + std::string Address() + { + return proxy_.getProperty("Address").onInterface(INTERFACE_NAME); + } + + std::string AddressType() + { + return proxy_.getProperty("AddressType").onInterface(INTERFACE_NAME); + } + + std::string Name() + { + return proxy_.getProperty("Name").onInterface(INTERFACE_NAME); + } + + std::string Alias() + { + return proxy_.getProperty("Alias").onInterface(INTERFACE_NAME); + } + + void Alias(const std::string& value) + { + proxy_.setProperty("Alias").onInterface(INTERFACE_NAME).toValue(value); + } + + uint32_t Class() + { + return proxy_.getProperty("Class").onInterface(INTERFACE_NAME); + } + + uint16_t Appearance() + { + return proxy_.getProperty("Appearance").onInterface(INTERFACE_NAME); + } + + std::string Icon() + { + return proxy_.getProperty("Icon").onInterface(INTERFACE_NAME); + } + + bool Paired() + { + return proxy_.getProperty("Paired").onInterface(INTERFACE_NAME); + } + + bool Bonded() + { + return proxy_.getProperty("Bonded").onInterface(INTERFACE_NAME); + } + + bool Trusted() + { + return proxy_.getProperty("Trusted").onInterface(INTERFACE_NAME); + } + + void Trusted(const bool& value) + { + proxy_.setProperty("Trusted").onInterface(INTERFACE_NAME).toValue(value); + } + + bool Blocked() + { + return proxy_.getProperty("Blocked").onInterface(INTERFACE_NAME); + } + + void Blocked(const bool& value) + { + proxy_.setProperty("Blocked").onInterface(INTERFACE_NAME).toValue(value); + } + + bool LegacyPairing() + { + return proxy_.getProperty("LegacyPairing").onInterface(INTERFACE_NAME); + } + + int16_t RSSI() + { + return proxy_.getProperty("RSSI").onInterface(INTERFACE_NAME); + } + + bool Connected() + { + return proxy_.getProperty("Connected").onInterface(INTERFACE_NAME); + } + + std::vector UUIDs() + { + return proxy_.getProperty("UUIDs").onInterface(INTERFACE_NAME); + } + + std::string Modalias() + { + return proxy_.getProperty("Modalias").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Adapter() + { + return proxy_.getProperty("Adapter").onInterface(INTERFACE_NAME); + } + + std::map ManufacturerData() + { + return proxy_.getProperty("ManufacturerData").onInterface(INTERFACE_NAME); + } + + std::map ServiceData() + { + return proxy_.getProperty("ServiceData").onInterface(INTERFACE_NAME); + } + + int16_t TxPower() + { + return proxy_.getProperty("TxPower").onInterface(INTERFACE_NAME); + } + + bool ServicesResolved() + { + return proxy_.getProperty("ServicesResolved").onInterface(INTERFACE_NAME); + } + + std::vector AdvertisingFlags() + { + return proxy_.getProperty("AdvertisingFlags").onInterface(INTERFACE_NAME); + } + + std::map AdvertisingData() + { + return proxy_.getProperty("AdvertisingData").onInterface(INTERFACE_NAME); + } + + bool WakeAllowed() + { + return proxy_.getProperty("WakeAllowed").onInterface(INTERFACE_NAME); + } + + void WakeAllowed(const bool& value) + { + proxy_.setProperty("WakeAllowed").onInterface(INTERFACE_NAME).toValue(value); + } + + std::map> Sets() + { + return proxy_.getProperty("Sets").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/bluez_profile_glue.h b/internal/platform/implementation/linux/bluez_profile_glue.h new file mode 100644 index 00000000..6ae6e00f --- /dev/null +++ b/internal/platform/implementation/linux/bluez_profile_glue.h @@ -0,0 +1,43 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__bluez_profile_glue_h__adaptor__H__ +#define __sdbuscpp__bluez_profile_glue_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class Profile1_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.Profile1"; + +protected: + Profile1_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); }); + object_.registerMethod("NewConnection").onInterface(INTERFACE_NAME).withInputParamNames("device", "fd", "fd_properties").implementedAs([this](const sdbus::ObjectPath& device, const sdbus::UnixFd& fd, const std::map& fd_properties){ return this->NewConnection(device, fd, fd_properties); }); + object_.registerMethod("RequestDisconnection").onInterface(INTERFACE_NAME).withInputParamNames("device").implementedAs([this](const sdbus::ObjectPath& device){ return this->RequestDisconnection(device); }); + } + + ~Profile1_adaptor() = default; + +private: + virtual void Release() = 0; + virtual void NewConnection(const sdbus::ObjectPath& device, const sdbus::UnixFd& fd, const std::map& fd_properties) = 0; + virtual void RequestDisconnection(const sdbus::ObjectPath& device) = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/bluez_profile_manager_client_glue.h b/internal/platform/implementation/linux/bluez_profile_manager_client_glue.h new file mode 100644 index 00000000..61ee8e46 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_profile_manager_client_glue.h @@ -0,0 +1,46 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__bluez_profile_manager_client_glue_h__proxy__H__ +#define __sdbuscpp__bluez_profile_manager_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class ProfileManager1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.ProfileManager1"; + +protected: + ProfileManager1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~ProfileManager1_proxy() = default; + +public: + void RegisterProfile(const sdbus::ObjectPath& profile, const std::string& UUID, const std::map& options) + { + proxy_.callMethod("RegisterProfile").onInterface(INTERFACE_NAME).withArguments(profile, UUID, options); + } + + void UnregisterProfile(const sdbus::ObjectPath& profile) + { + proxy_.callMethod("UnregisterProfile").onInterface(INTERFACE_NAME).withArguments(profile); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index c45bf230..f492c56c 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -1,12 +1,12 @@ #include #include #include -#include - #include +#include #include -#include +#include +#include #include #include "internal/platform/implementation/device_info.h" @@ -14,7 +14,6 @@ #include "internal/platform/logging.h" namespace nearby { - namespace linux { const char *HOSTNAME_DEST = "org.freedesktop.hostname1"; @@ -25,78 +24,49 @@ const char *LOGIN_DEST = "org.freedesktop.login1"; const char *LOGIN_PATH = "/org/freedesktop/login1/session/_"; const char *LOGIN_INTERFACE = "org.freedesktop.login1.Session"; +DeviceInfo::DeviceInfo(sdbus::IConnection &system_bus) { + hostname_proxy_ = + sdbus::createProxy(system_bus, HOSTNAME_DEST, HOSTNAME_PATH); + hostname_proxy_->finishRegistration(); + login_proxy_ = sdbus::createProxy(system_bus, LOGIN_PATH, LOGIN_PATH); + login_proxy_->finishRegistration(); +} + std::optional DeviceInfo::GetOsDeviceName() const { - __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus = nullptr; - if (sd_bus_default_system(&bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; + try { + std::string hostname = hostname_proxy_->getProperty("PrettyHostname") + .onInterface(HOSTNAME_INTERFACE); + std::wstring_convert, char16_t> convert; + return convert.from_bytes(hostname); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get PrettyHostname"; return std::nullopt; } - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - - char *hostname = nullptr; - if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, - HOSTNAME_INTERFACE, "PrettyHostname", &err, - &hostname) < 0) { - NEARBY_LOGS(ERROR) - << __func__ - << ": Error getting PrettyHostname from org.freedesktop.hostname1: " - << err.message; - } - if (!hostname || hostname[0] == '\0') { - int ret = sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, - HOSTNAME_INTERFACE, "Hostname", &err, - &hostname); - if (ret < 0) { - NEARBY_LOGS(ERROR) - << __func__ - << ": Error getting Hostname from org.freedesktop.hostname1: " - << err.message; - return std::nullopt; - } - } - - std::wstring_convert, char16_t> convert; - - std::u16string name = convert.from_bytes(hostname); - free(hostname); - return name; } api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { - __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus; - if (sd_bus_default_system(&bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; + try { + std::string chasis = hostname_proxy_->getProperty("PrettyHostname") + .onInterface(HOSTNAME_INTERFACE); + api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; + if (chasis == "phone") { + device = api::DeviceInfo::DeviceType::kPhone; + } else if (chasis == "laptop" || chasis == "desktop") { + device = api::DeviceInfo::DeviceType::kLaptop; + } else if (chasis == "tablet") { + device = api::DeviceInfo::DeviceType::kTablet; + } else if (chasis == "handset") { + device = api::DeviceInfo::DeviceType::kPhone; + } + return device; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get PrettyHostname"; return api::DeviceInfo::DeviceType::kUnknown; } - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *chasis = nullptr; - - if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, - HOSTNAME_INTERFACE, "Chasis", &err, - &chasis) < 0) { - NEARBY_LOGS(ERROR) - << __func__ << ": Error getting Chasis from org.freedesktop.hostname1: " - << err.message; - return api::DeviceInfo::DeviceType::kUnknown; - } - - api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; - - if (strcmp(chasis, "phone") == 0) { - device = api::DeviceInfo::DeviceType::kPhone; - } else if (strcmp(chasis, "laptop") == 0 || strcmp(chasis, "desktop") == 0) { - device = api::DeviceInfo::DeviceType::kLaptop; - } else if (strcmp(chasis, "tablet") == 0) { - device = api::DeviceInfo::DeviceType::kTablet; - } else if (strcmp(chasis, "handset") == 0) { - device = api::DeviceInfo::DeviceType::kPhone; - } - free(chasis); - return device; } std::optional DeviceInfo::GetFullName() const { @@ -170,34 +140,21 @@ bool DeviceInfo::IsScreenLocked() const { return false; } - __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus; - if (sd_bus_default_system(&bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; - free(session); - return false; - } - std::string session_path(LOGIN_PATH); session_path += session; - free(session); - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - bool locked; - - if (sd_bus_get_property_trivial(bus, LOGIN_DEST, session_path.c_str(), - LOGIN_INTERFACE, "LockedHint", &err, 'b', - &locked) < 0) { - - NEARBY_LOGS(ERROR) - << __func__ - << ": Error getting LockedState from org.freedesktop.login1: " - << err.message; - locked = false; + try { + bool locked = + login_proxy_->getProperty("LockedHint").onInterface(LOGIN_INTERFACE); + return locked; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get LockedHint for session " + << session_path; + return false; } - - return locked; } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 3d001486..3ca5b762 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -1,11 +1,12 @@ #ifndef PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ #define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ -#include - #include #include +#include +#include + #include "absl/strings/string_view.h" #include "internal/platform/implementation/device_info.h" @@ -14,7 +15,8 @@ namespace linux { class DeviceInfo : public api::DeviceInfo { public: - ~DeviceInfo() override; + DeviceInfo(sdbus::IConnection &system_bus); + ~DeviceInfo() override = default; std::optional GetOsDeviceName() const override; api::DeviceInfo::DeviceType GetDeviceType() const override; @@ -47,7 +49,9 @@ public: void UnregisterScreenLockedListener(absl::string_view listener_name) override{}; - sd_bus *system_bus; +private: + std::unique_ptr hostname_proxy_; + std::unique_ptr login_proxy_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/org.bluez.Adapter1.xml b/internal/platform/implementation/linux/org.bluez.Adapter1.xml new file mode 100644 index 00000000..b58180df --- /dev/null +++ b/internal/platform/implementation/linux/org.bluez.Adapter1.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.bluez.Device1.xml b/internal/platform/implementation/linux/org.bluez.Device1.xml new file mode 100644 index 00000000..afc55406 --- /dev/null +++ b/internal/platform/implementation/linux/org.bluez.Device1.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.bluez.Profile1.xml b/internal/platform/implementation/linux/org.bluez.Profile1.xml new file mode 100644 index 00000000..5ce94584 --- /dev/null +++ b/internal/platform/implementation/linux/org.bluez.Profile1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.bluez.ProfileManager1.xml b/internal/platform/implementation/linux/org.bluez.ProfileManager1.xml new file mode 100644 index 00000000..0a43476e --- /dev/null +++ b/internal/platform/implementation/linux/org.bluez.ProfileManager1.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + +