From b5ba24bc0605e069f5a450fe949c7bd3478a2ffb Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 1 Aug 2023 18:27:05 +0530 Subject: [PATCH] Add additional code for implementing BluetoothClassicMedium. --- .../linux/bluetooth_bluez_profile.cc | 169 +++++++++++++----- .../linux/bluetooth_bluez_profile.h | 45 ++--- .../linux/bluetooth_classic_device.cc | 34 ++-- .../linux/bluetooth_classic_device.h | 13 +- .../linux/bluetooth_classic_medium.cc | 88 +++++++-- .../linux/bluetooth_classic_medium.h | 18 +- .../linux/bluetooth_classic_server_socket.h | 19 +- .../linux/bluetooth_classic_socket.cc | 32 ++++ .../linux/bluetooth_classic_socket.h | 14 +- .../implementation/linux/bluetooth_pairing.cc | 37 ++-- .../implementation/linux/bluetooth_pairing.h | 7 +- 11 files changed, 332 insertions(+), 144 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index a2b2c8cc..afb7d1a9 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -1,26 +1,67 @@ +#include #include #include +#include +#include +#include +#include #include #include +#include "absl/strings/substitute.h" #include "absl/synchronization/mutex.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/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) { - // TODO + return 0; } static int profile_new_connection(sd_bus_message *m, void *userdata, sd_bus_error *error) { - // TODO + 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_new(sd_bus_message *m, void *userdata, sd_bus_error *error) { + +static int profile_request_disconnection(sd_bus_message *m, void *userdata, + sd_bus_error *error) { // TODO + return 0; } static const sd_bus_vtable vtable[] = { @@ -31,54 +72,19 @@ static const sd_bus_vtable vtable[] = { "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_new, + SD_BUS_NO_RESULT, profile_request_disconnection, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END}; -namespace nearby { -namespace linux { -std::unique_ptr NewProfileManager() { - sd_bus *system_bus; - if (auto ret = sd_bus_default_system(&system_bus); ret < 0) { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - sd_bus_error_set_errno(&err, ret); - - NEARBY_LOGS(ERROR) << __func__ - << "Error connecting to system bus: " << err.name << ": " - << err.message; - return nullptr; - } - - sd_bus_slot *slot = nullptr; - auto manager = new ProfileManager(system_bus, slot); - - if (auto ret = sd_bus_add_object_vtable( - system_bus, &slot, "/com/github/google/nearby", "org.bluez.Profile1", - vtable, manager->GetMethodData()); - ret < 0) { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - sd_bus_error_set_errno(&err, ret); - - NEARBY_LOGS(ERROR) << __func__ - << "Error adding object /com/github/google/nearby: " - << err.name << ": " << err.message; - return nullptr; - } - - return std::unique_ptr(manager); -} - bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { registered_service_uuids_lock_.ReaderLock(); - bool registered = - registered_service_uuids_.count(std::string(service_uuid)) == 1; + bool registered = registered_services_.count(std::string(service_uuid)) == 1; registered_service_uuids_lock_.ReaderUnlock(); return registered; } -bool ProfileManager::RegisterProfile(absl::string_view service_uuid) { +bool ProfileManager::RegisterProfile(absl::string_view name, + absl::string_view service_uuid) { if (ProfileRegistered(service_uuid)) { return true; } @@ -87,21 +93,90 @@ bool ProfileManager::RegisterProfile(absl::string_view service_uuid) { 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(); + 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(), 0, nullptr) < 0) { + 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; } - registered_service_uuids_.insert(uuid); + + registered_services_[uuid] = service; registered_service_uuids_lock_.Unlock(); return true; } +std::optional +ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device, + absl::string_view service_uuid) { + if (!ProfileRegistered(service_uuid)) { + return std::nullopt; + } + + auto mac_addr = remote_device.GetMacAddress(); + + registered_service_uuids_lock_.ReaderLock(); + auto service = 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; + }; + service->connections_lock.Await(absl::Condition(&cond)); + int fd = service->connections[mac_addr]; + service->connections.erase(mac_addr); + service->connections_lock.Unlock(); + + return fd; +} + +std::optional> +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)]; + 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); +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index ba7e6e3a..b579ddbc 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -1,11 +1,13 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ +#include #include #include #include #include #include +#include #include @@ -16,41 +18,40 @@ namespace nearby { namespace linux { +struct RegisteredService { +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) {} +}; + class ProfileManager { public: - ProfileManager(sd_bus *system_bus, sd_bus_slot *slot) { - system_bus_ = system_bus; - slot_ = slot; - } + ProfileManager(sd_bus *system_bus) { system_bus_ = system_bus; } ~ProfileManager() { sd_bus_unref(system_bus_); } bool ProfileRegistered(absl::string_view service_uuid); - bool RegisterProfile(absl::string_view sevice_uuid); + bool RegisterProfile(absl::string_view service_name, + absl::string_view service_uuid); + bool RegisterProfile(absl::string_view service_uuid) { + return RegisterProfile("", service_uuid); + } std::optional GetServiceRecordFD(api::BluetoothDevice &remote_device, absl::string_view service_uuid); - -struct MethodData { - std::map>, int> &connections_; - absl::Mutex &connections_lock_; - }; - struct MethodData *GetMethodData() { return &data_; } + std::optional> + GetServiceRecordFD(absl::string_view service_uuid); private: - bool InitManagerObj(); - - // Maps (mac address, service uuid) tuples to FDs. Probably - // an awful way to do this, but whatever. - std::map>, int> connections_; - absl::Mutex connections_lock_; - - MethodData data_{connections_, connections_lock_}; - - std::set registered_service_uuids_; + // Maps service UUIDs to RegisteredService + std::map registered_services_; absl::Mutex registered_service_uuids_lock_; sd_bus *system_bus_; - sd_bus_slot *slot_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 8f64ee2c..cda7e74a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -10,33 +10,25 @@ namespace nearby { namespace linux { -BluetoothDevice::BluetoothDevice(absl::string_view adapter, +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, {{":", "_"}})); - if (sd_bus_default_system(&system_bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; - } + system_bus_ = system_bus; } -BluetoothDevice::BluetoothDevice(absl::string_view device_object_path) { - if (sd_bus_default_system(&system_bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; - return; - } - - object_path_ = device_object_path; +BluetoothDevice::BluetoothDevice(sd_bus *system_bus, + absl::string_view device_object_path) { + system_bus_ = system_bus; + object_path_ = device_object_path; } std::string BluetoothDevice::GetName() const { - if (!system_bus) { - return std::string(); - } __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, + 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 " @@ -50,29 +42,25 @@ std::string BluetoothDevice::GetName() const { } std::string BluetoothDevice::GetMacAddress() const { - if (!system_bus) { - return std::string(); - } - if (!mac_addr_.empty()) { return mac_addr_; } - + __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, + 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; return std::string(); } - + std::string addr(c_addr); free(c_addr); return addr; } - + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index fcdb1d5f..098abc03 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -12,19 +12,20 @@ const char *BLUEZ_DEVICE_INTERFACE = "org.bluez.Device1"; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. class BluetoothDevice : public api::BluetoothDevice { public: - BluetoothDevice(absl::string_view adapter, absl::string_view address); - BluetoothDevice(absl::string_view device_object_path); - - virtual ~BluetoothDevice() override { sd_bus_unref(system_bus); }; + 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() override { sd_bus_unref(system_bus_); }; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() std::string GetName() const override; // Returns BT MAC address assigned to this device. std::string GetMacAddress() const override; - + private: - sd_bus *system_bus; + sd_bus *system_bus_; std::string object_path_; std::string mac_addr_; }; diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 713aa8cb..e53fa850 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -3,12 +3,16 @@ #include #include +#include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" -#include "absl/strings/str_replace.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_classic_medium.h" +#include "internal/platform/implementation/linux/bluetooth_classic_server_socket.h" +#include "internal/platform/implementation/linux/bluetooth_classic_socket.h" +#include "internal/platform/implementation/linux/bluetooth_pairing.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" @@ -65,9 +69,12 @@ int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, if (strcmp(interface_name, "org.bluez.Device1") == 0) { NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " - << c_object_path; - auto bluetoothDevice = - std::make_unique(BluetoothDevice(object_path)); + << 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) { @@ -83,16 +90,15 @@ int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, return 0; } -BluetoothClassicMedium::BluetoothClassicMedium(absl::string_view adapter) { - if (sd_bus_default_system(&system_bus_) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; - } +BluetoothClassicMedium::BluetoothClassicMedium(sd_bus *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); } BluetoothClassicMedium::~BluetoothClassicMedium() { - if (system_bus_) - sd_bus_unref(system_bus_); + sd_bus_unref(system_bus_); if (system_bus_slot_) sd_bus_slot_unref(system_bus_slot_); } @@ -159,12 +165,70 @@ BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, const std::string &service_uuid, CancellationFlag *cancellation_flag) { auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress()); - + if (!profile_manager_.ProfileRegistered(service_uuid)) { + if (!profile_manager_.RegisterProfile(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); + if (!fd.has_value()) { + NEARBY_LOGS(ERROR) << __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())); +} + +std::unique_ptr +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 " + << 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)); +} + +api::BluetoothDevice * +BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { + return new BluetoothDevice(sd_bus_ref(system_bus_), + GetDeviceObjectPath(mac_address)); +} + +std::unique_ptr +BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) { + auto device_object_path = GetDeviceObjectPath(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, {{":", "_"}})); + return absl::Substitute("$0/dev_$1", adapter_object_path_, + absl::StrReplaceAll(mac_address, {{":", "_"}})); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 84b3cca2..1fd6886c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -8,6 +8,7 @@ #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" namespace nearby { @@ -16,7 +17,7 @@ namespace linux { // medium. class BluetoothClassicMedium : public api::BluetoothClassicMedium { public: - BluetoothClassicMedium(absl::string_view adapter); + BluetoothClassicMedium(sd_bus *system_bus, absl::string_view adapter); ~BluetoothClassicMedium(); // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() @@ -72,8 +73,12 @@ public: api::BluetoothDevice * GetRemoteDevice(const std::string &mac_address) override; - void AddObserver(Observer *observer) override; - void RemoveObserver(Observer *observer) override; + void AddObserver(Observer *observer) override { + observers_.AddObserver(observer); + }; + void RemoveObserver(Observer *observer) override { + observers_.RemoveObserver(observer); + }; struct DiscoveryParams { std::string &adapter_object_path; @@ -83,15 +88,18 @@ public: }; private: + 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_id_; ObserverList observers_; - DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_id_, observers_}; + DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_id_, + observers_}; }; } // 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 1361557c..ce0f2e7d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -1,13 +1,22 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_ -#include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/exception.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" namespace nearby { namespace linux { -class BluetoothServerSocket : api::BluetoothServerSocket { +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() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept() @@ -25,6 +34,12 @@ public: // // Returns Exception::kIo on error, Exception::kSuccess otherwise. Exception Close() override; + +private: + sd_bus *system_bus_; + ProfileManager &profile_manager_; + std::string adapter_object_path_; + 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 c1552ea0..4ef2bade 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -3,9 +3,14 @@ #include #include +#include + #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 { @@ -64,5 +69,32 @@ Exception BluetoothOutputStream::Close() { return close(fd_) < 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}; + } + + return Exception{Exception::kSuccess}; +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index d7384b80..7a40fc0a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -40,19 +40,27 @@ private: class BluetoothSocket : public api::BluetoothSocket { public: - BluetoothSocket(std::string object, int fd) { + BluetoothSocket(api::BluetoothDevice &device, + absl::string_view device_object_path, + absl::string_view connected_profile_uuid, int fd) + : device_(device) { fd_ = fd; - object_ = object; + device_object_path_ = device_object_path; + connected_profile_uuid_ = connected_profile_uuid; input_stream_ = BluetoothInputStream(fd_); output_stream_ = BluetoothOutputStream(fd_); } InputStream &GetInputStream() override { return input_stream_; } OutputStream &GetOutputStream() override { return output_stream_; } + Exception Close() override; + api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; private: int fd_; - std::string object_; + std::string device_object_path_; + api::BluetoothDevice &device_; + std::string connected_profile_uuid_; BluetoothInputStream input_stream_ = {-1}; BluetoothOutputStream output_stream_ = {-1}; }; diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index e2007b4e..814a0162 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -46,13 +46,6 @@ int pairing_reply_handler(sd_bus_message *m, void *userdata, return 0; } -BluetoothPairing::BluetoothPairing(absl::string_view object_path) { - object_path_ = object_path; - if (sd_bus_default_system(&system_bus_) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; - } -} - bool BluetoothPairing::InitiatePairing( api::BluetoothPairingCallback pairing_cb) { if (!system_bus_) @@ -60,12 +53,12 @@ bool BluetoothPairing::InitiatePairing( pairing_cb_ = std::move(pairing_cb); - if (sd_bus_call_method_async(system_bus_, nullptr, BLUEZ_SERVICE, - object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "Pair", &pairing_reply_handler, &pairing_cb_, - nullptr) < 0) { + 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 " - << object_path_; + << device_object_path_; return false; } pairing_cb.on_pairing_initiated_cb(api::PairingParams{ @@ -84,12 +77,12 @@ bool BluetoothPairing::CancelPairing() { __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, object_path_.c_str(), - BLUEZ_DEVICE_INTERFACE, "CancelPairing", &err, nullptr, - nullptr)) { + if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, + device_object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, + "CancelPairing", &err, nullptr, nullptr)) { NEARBY_LOGS(ERROR) << __func__ << "Error calling method CancelPairing on device " - << object_path_ << ": " << err.message; + << device_object_path_ << ": " << err.message; return false; } return true; @@ -103,10 +96,10 @@ bool BluetoothPairing::Unpair() { SD_BUS_ERROR_NULL; if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "RemoveDevice", &err, nullptr, - "o", object_path_.c_str())) { + "o", device_object_path_.c_str())) { NEARBY_LOGS(ERROR) << __func__ << "Error calling method CancelPairing on device " - << object_path_ << ": " << err.message; + << device_object_path_ << ": " << err.message; return false; } return true; @@ -119,12 +112,12 @@ bool BluetoothPairing::IsPaired() { __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, - object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "Bonded", &err, 'b', &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 " - << object_path_ << ": " << err.message; + << device_object_path_ << ": " << err.message; } return paired; } diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 3e5ee4e4..1b1084f9 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -13,7 +13,10 @@ namespace nearby { namespace linux { class BluetoothPairing : public api::BluetoothPairing { public: - BluetoothPairing(absl::string_view object_path); + 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_); } bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; @@ -23,7 +26,7 @@ public: bool IsPaired() override; private: - std::string object_path_; + std::string device_object_path_; sd_bus *system_bus_; api::BluetoothPairingCallback pairing_cb_; };