mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Add additional code for implementing BluetoothClassicMedium.
This commit is contained in:
@@ -1,26 +1,67 @@
|
||||
#include <fcntl.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include <systemd/sd-bus-protocol.h>
|
||||
#include <systemd/sd-bus-vtable.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#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<struct RegisteredService *>(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<ProfileManager> 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<ProfileManager>(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<int>
|
||||
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<std::pair<std::string, int>>
|
||||
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<std::string, int>(mac_addr, fd);
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_
|
||||
#define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
@@ -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<std::string, int> 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<int> GetServiceRecordFD(api::BluetoothDevice &remote_device,
|
||||
absl::string_view service_uuid);
|
||||
|
||||
struct MethodData {
|
||||
std::map<std::tuple<std::tuple<std::string, std::string>>, int> &connections_;
|
||||
absl::Mutex &connections_lock_;
|
||||
};
|
||||
struct MethodData *GetMethodData() { return &data_; }
|
||||
std::optional<std::pair<std::string, int>>
|
||||
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<std::tuple<std::tuple<std::string, std::string>>, int> connections_;
|
||||
absl::Mutex connections_lock_;
|
||||
|
||||
MethodData data_{connections_, connections_lock_};
|
||||
|
||||
std::set<std::string> registered_service_uuids_;
|
||||
// Maps service UUIDs to RegisteredService
|
||||
std::map<std::string, struct RegisteredService *> registered_services_;
|
||||
absl::Mutex registered_service_uuids_lock_;
|
||||
|
||||
sd_bus *system_bus_;
|
||||
sd_bus_slot *slot_;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
@@ -3,12 +3,16 @@
|
||||
#include <memory>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#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>(BluetoothDevice(object_path));
|
||||
<< object_path;
|
||||
sd_bus *system_bus = nullptr;
|
||||
sd_bus_default_system(&system_bus);
|
||||
|
||||
auto bluetoothDevice = std::make_unique<BluetoothDevice>(
|
||||
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<api::BluetoothSocket>(new BluetoothSocket(
|
||||
remote_device, device_object_path, service_uuid, fd.value()));
|
||||
}
|
||||
|
||||
std::unique_ptr<api::BluetoothServerSocket>
|
||||
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<api::BluetoothServerSocket>(
|
||||
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<api::BluetoothPairing>
|
||||
BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) {
|
||||
auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress());
|
||||
return std::unique_ptr<api::BluetoothPairing>(
|
||||
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
|
||||
|
||||
@@ -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<std::string, std::unique_ptr<BluetoothDevice>> devices_by_id_;
|
||||
ObserverList<Observer> 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
#include <cstdint>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user