mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Rewrite dbus code using sdbus-c++
This commit is contained in:
@@ -16,6 +16,7 @@ cc_library(
|
||||
"//internal/platform:logging",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@libsystemd//:lib",
|
||||
"@sdbus_cpp//:lib",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,71 +1,68 @@
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_
|
||||
#define PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_
|
||||
|
||||
#include <string>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/implementation/bluetooth_adapter.h"
|
||||
#include <systemd/sd-bus.h>
|
||||
#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<org::bluez::Adapter1_proxy> {
|
||||
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
|
||||
|
||||
@@ -1,80 +1,26 @@
|
||||
#include <fcntl.h>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include <systemd/sd-bus-protocol.h>
|
||||
#include <systemd/sd-bus-vtable.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <sdbus-c++/AdaptorInterfaces.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#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<struct RegisteredService *>(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<std::string, sdbus::Variant> &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<absl::string_view> 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<std::string, sdbus::Variant> 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<Profile>(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<int>
|
||||
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<sdbus::UnixFd>
|
||||
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<std::pair<std::string, int>>
|
||||
// Listen for a connected profile on any device, returning the connected device
|
||||
// with its FD.
|
||||
std::optional<std::pair<std::reference_wrapper<BluetoothDevice>, 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<std::string, int>(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
|
||||
|
||||
@@ -2,56 +2,102 @@
|
||||
#define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <sdbus-c++/AdaptorInterfaces.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
#include <sdbus-c++/StandardInterfaces.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#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<org::bluez::Profile1_adaptor> {
|
||||
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) {}
|
||||
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<std::string, sdbus::Variant> &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<uint16_t> version;
|
||||
std::optional<uint16_t> features;
|
||||
};
|
||||
|
||||
void Release() override;
|
||||
void NewConnection(const sdbus::ObjectPath &, const sdbus::UnixFd &,
|
||||
const std::map<std::string, sdbus::Variant> &) override;
|
||||
void RequestDisconnection(const sdbus::ObjectPath &) override;
|
||||
|
||||
std::atomic_bool released_;
|
||||
|
||||
absl::Mutex connections_lock_;
|
||||
std::map<std::string, std::vector<std::pair<sdbus::UnixFd, FDProperties>>>
|
||||
connections_;
|
||||
|
||||
BluetoothDevices &devices_;
|
||||
};
|
||||
|
||||
class ProfileManager {
|
||||
class ProfileManager
|
||||
: private sdbus::ProxyInterfaces<org::bluez::ProfileManager1_proxy> {
|
||||
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<absl::string_view> 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<int> GetServiceRecordFD(api::BluetoothDevice &remote_device,
|
||||
absl::string_view service_uuid);
|
||||
std::optional<std::pair<std::string, int>>
|
||||
std::optional<sdbus::UnixFd>
|
||||
GetServiceRecordFD(api::BluetoothDevice &remote_device,
|
||||
absl::string_view service_uuid,
|
||||
CancellationFlag *cancellation_flag);
|
||||
std::optional<
|
||||
std::pair<std::reference_wrapper<BluetoothDevice>, sdbus::UnixFd>>
|
||||
GetServiceRecordFD(absl::string_view service_uuid);
|
||||
|
||||
private:
|
||||
BluetoothDevices &devices_;
|
||||
// Maps service UUIDs to RegisteredService
|
||||
std::map<std::string, struct RegisteredService *> registered_services_;
|
||||
std::map<std::string, std::shared_ptr<Profile>> registered_services_;
|
||||
absl::Mutex registered_service_uuids_lock_;
|
||||
|
||||
sd_bus *system_bus_;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
|
||||
@@ -1,73 +1,124 @@
|
||||
#include <sdbus-c++/IObject.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#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<api::BluetoothClassicMedium::Observer> &observers)
|
||||
: BluetoothDevice(system_bus, device_object_path),
|
||||
ProxyInterfaces<sdbus::Properties_proxy>(system_bus, bluez::SERVICE_DEST,
|
||||
std::string(device_object_path)),
|
||||
observers_(observers) {
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
void MonitoredBluetoothDevice::onPropertiesChanged(
|
||||
const std::string &interfaceName,
|
||||
const std::map<std::string, sdbus::Variant> &changedProperties,
|
||||
const std::vector<std::string> &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
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_
|
||||
#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
#include <sdbus-c++/StandardInterfaces.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#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<org::bluez::Device1_proxy> {
|
||||
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<void(const sdbus::Error *)> 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<const sdbus::Error *>();
|
||||
}
|
||||
|
||||
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<void(const sdbus::Error *)> on_pair_reply_cb_ =
|
||||
DefaultCallback<const sdbus::Error *>();
|
||||
};
|
||||
|
||||
class MonitoredBluetoothDevice
|
||||
: public BluetoothDevice,
|
||||
public sdbus::ProxyInterfaces<sdbus::Properties_proxy> {
|
||||
public:
|
||||
using sdbus::ProxyInterfaces<sdbus::Properties_proxy>::registerProxy;
|
||||
using sdbus::ProxyInterfaces<sdbus::Properties_proxy>::unregisterProxy;
|
||||
using sdbus::ProxyInterfaces<sdbus::Properties_proxy>::getObjectPath;
|
||||
|
||||
MonitoredBluetoothDevice(
|
||||
sdbus::IConnection &system_bus, const sdbus::ObjectPath &,
|
||||
ObserverList<api::BluetoothClassicMedium::Observer> &observers);
|
||||
~MonitoredBluetoothDevice() { unregisterProxy(); }
|
||||
|
||||
protected:
|
||||
void onPropertiesChanged(
|
||||
const std::string &interfaceName,
|
||||
const std::map<std::string, sdbus::Variant> &changedProperties,
|
||||
const std::vector<std::string> &invalidatedProperties) override;
|
||||
|
||||
private:
|
||||
ObserverList<api::BluetoothClassicMedium::Observer> &observers_;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#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<BluetoothClassicMedium::DiscoveryParams *>(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>(
|
||||
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<std::string, std::map<std::string, sdbus::Variant>> 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<std::string> 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<api::BluetoothSocket>
|
||||
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<api::BluetoothSocket>(new BluetoothSocket(
|
||||
remote_device, device_object_path, service_uuid, fd.value()));
|
||||
return std::unique_ptr<api::BluetoothSocket>(
|
||||
new BluetoothSocket(remote_device, fd.value()));
|
||||
}
|
||||
|
||||
std::unique_ptr<api::BluetoothServerSocket>
|
||||
@@ -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<api::BluetoothServerSocket>(
|
||||
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<api::BluetoothPairing>
|
||||
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<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, {{":", "_"}}));
|
||||
new BluetoothPairing(bluez_adapter_proxy_->getObjectPath(), remote_device,
|
||||
bluez_adapter_proxy_->getConnection()));
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_
|
||||
#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#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<std::string, std::unique_ptr<BluetoothDevice>> &devices_by_path;
|
||||
ObserverList<Observer> &observers_;
|
||||
BluetoothClassicMedium::DiscoveryCallback cb;
|
||||
};
|
||||
std::optional<std::reference_wrapper<BluetoothDevice>>
|
||||
get_device_by_path(const sdbus::ObjectPath &);
|
||||
std::optional<std::reference_wrapper<BluetoothDevice>>
|
||||
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<BluetoothClassicMedium::DiscoveryCallback> 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<std::string, std::unique_ptr<BluetoothDevice>> devices_by_path_;
|
||||
ObserverList<Observer> observers_;
|
||||
|
||||
DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_path_,
|
||||
observers_};
|
||||
std::unique_ptr<sdbus::IProxy> bluez_adapter_proxy_;
|
||||
std::unique_ptr<sdbus::IProxy> bluez_proxy_;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<ByteArray> 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<ByteArray> BluetoothInputStream::Read(std::int64_t size) {
|
||||
}
|
||||
|
||||
ExceptionOr<std::size_t> 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<ByteArray> 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<ByteArray> 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};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#define PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#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<ByteArray> Read(std::int64_t size) override;
|
||||
ExceptionOr<size_t> Skip(size_t offset) override;
|
||||
@@ -23,33 +25,29 @@ public:
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
friend class BluetoothSocket;
|
||||
|
||||
std::optional<sdbus::UnixFd> 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<sdbus::UnixFd> 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
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include <sdbus-c++/Types.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 "absl/synchronization/mutex.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
std::optional<std::reference_wrapper<BluetoothDevice>>
|
||||
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<std::reference_wrapper<BluetoothDevice>>
|
||||
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
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_
|
||||
#define PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#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<api::BluetoothClassicMedium::Observer> &observers)
|
||||
: system_bus_(system_bus), observers_(observers),
|
||||
adapter_object_path_(adapter_object_path) {}
|
||||
|
||||
std::optional<std::reference_wrapper<BluetoothDevice>>
|
||||
get_device_by_path(const sdbus::ObjectPath &);
|
||||
std::optional<std::reference_wrapper<BluetoothDevice>>
|
||||
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<std::string, MonitoredBluetoothDevice> devices_by_path_;
|
||||
|
||||
sdbus::IConnection &system_bus_;
|
||||
ObserverList<api::BluetoothClassicMedium::Observer> &observers_;
|
||||
sdbus::ObjectPath adapter_object_path_;
|
||||
};
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,11 @@
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <utility>
|
||||
|
||||
#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<api::BluetoothPairingCallback *>(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<absl::string_view> 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
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PROFILE_H_
|
||||
#define PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#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<absl::string_view> 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<sdbus::IProxy> bluez_adapter_proxy_;
|
||||
api::BluetoothPairingCallback pairing_cb_;
|
||||
};
|
||||
} // namespace linux
|
||||
|
||||
@@ -19,27 +19,16 @@ std::unique_ptr<api::BluetoothSocket> 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<api::BluetoothSocket>(new BluetoothSocket(
|
||||
device, device_object_path, service_uuid_, pair->second));
|
||||
|
||||
auto [device, fd] = *pair;
|
||||
return std::unique_ptr<api::BluetoothSocket>(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};
|
||||
}
|
||||
|
||||
@@ -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 <sdbus-c++/Types.h>
|
||||
|
||||
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
|
||||
@@ -1,11 +1,40 @@
|
||||
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_H_
|
||||
#define PLATFORM_IMPL_LINUX_BLUEZ_H_
|
||||
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
|
||||
|
||||
@@ -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 <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
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<std::string, sdbus::Variant>& 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<std::string> GetDiscoveryFilters()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
proxy_.callMethod("GetDiscoveryFilters").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ConnectDevice(const std::map<std::string, sdbus::Variant>& 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<std::string> UUIDs()
|
||||
{
|
||||
return proxy_.getProperty("UUIDs").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string Modalias()
|
||||
{
|
||||
return proxy_.getProperty("Modalias").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> Roles()
|
||||
{
|
||||
return proxy_.getProperty("Roles").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> ExperimentalFeatures()
|
||||
{
|
||||
return proxy_.getProperty("ExperimentalFeatures").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -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 <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
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<std::string> 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<uint16_t, sdbus::Variant> ManufacturerData()
|
||||
{
|
||||
return proxy_.getProperty("ManufacturerData").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::map<std::string, sdbus::Variant> 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<uint8_t> AdvertisingFlags()
|
||||
{
|
||||
return proxy_.getProperty("AdvertisingFlags").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::map<uint8_t, sdbus::Variant> 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<sdbus::ObjectPath, std::map<std::string, sdbus::Variant>> Sets()
|
||||
{
|
||||
return proxy_.getProperty("Sets").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -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 <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
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<std::string, sdbus::Variant>& 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<std::string, sdbus::Variant>& fd_properties) = 0;
|
||||
virtual void RequestDisconnection(const sdbus::ObjectPath& device) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -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 <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
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<std::string, sdbus::Variant>& 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
|
||||
@@ -1,12 +1,12 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <systemd/sd-login.h>
|
||||
|
||||
#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<std::u16string> 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<std::codecvt_utf8_utf16<char16_t>, 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<std::codecvt_utf8_utf16<char16_t>, 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<std::u16string> 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
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#ifndef PLATFORM_IMPL_LINUX_DEVICE_INFO_H_
|
||||
#define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
|
||||
#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<std::u16string> 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<sdbus::IProxy> hostname_proxy_;
|
||||
std::unique_ptr<sdbus::IProxy> login_proxy_;
|
||||
};
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.bluez.Adapter1">
|
||||
<method name="StartDiscovery" />
|
||||
<method name="SetDiscoveryFilter">
|
||||
<arg name="properties" type="a{sv}" direction="in" />
|
||||
</method>
|
||||
<method name="StopDiscovery" />
|
||||
<method name="RemoveDevice">
|
||||
<arg name="device" type="o" direction="in" />
|
||||
</method>
|
||||
<method name="GetDiscoveryFilters">
|
||||
<arg name="filters" type="as" direction="out" />
|
||||
</method>
|
||||
<method name="ConnectDevice">
|
||||
<arg name="properties" type="a{sv}" direction="in" />
|
||||
</method>
|
||||
<property name="Address" type="s" access="read" />
|
||||
<property name="AddressType" type="s" access="read" />
|
||||
<property name="Name" type="s" access="read" />
|
||||
<property name="Alias" type="s" access="readwrite" />
|
||||
<property name="Class" type="u" access="read" />
|
||||
<property name="Powered" type="b" access="readwrite" />
|
||||
<property name="PowerState" type="s" access="read" />
|
||||
<property name="Discoverable" type="b" access="readwrite" />
|
||||
<property name="DiscoverableTimeout" type="u" access="readwrite" />
|
||||
<property name="Pairable" type="b" access="readwrite" />
|
||||
<property name="PairableTimeout" type="u" access="readwrite" />
|
||||
<property name="Discovering" type="b" access="read" />
|
||||
<property name="UUIDs" type="as" access="read" />
|
||||
<property name="Modalias" type="s" access="read" />
|
||||
<property name="Roles" type="as" access="read" />
|
||||
<property name="ExperimentalFeatures" type="as" access="read" />
|
||||
</interface>
|
||||
</node>
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.bluez.Device1">
|
||||
<method name="Disconnect" />
|
||||
<method name="Connect" />
|
||||
<method name="ConnectProfile">
|
||||
<annotation name="org.freedesktop.DBus.Method.Async" value="client"/>
|
||||
<arg name="UUID" type="s" direction="in" />
|
||||
</method>
|
||||
<method name="DisconnectProfile">
|
||||
<arg name="UUID" type="s" direction="in" />
|
||||
</method>
|
||||
<method name="Pair">
|
||||
<annotation name="org.freedesktop.DBus.Method.Async" value="client"/>
|
||||
</method>
|
||||
<method name="CancelPairing" />
|
||||
<property name="Address" type="s" access="read" />
|
||||
<property name="AddressType" type="s" access="read" />
|
||||
<property name="Name" type="s" access="read" />
|
||||
<property name="Alias" type="s" access="readwrite" />
|
||||
<property name="Class" type="u" access="read" />
|
||||
<property name="Appearance" type="q" access="read" />
|
||||
<property name="Icon" type="s" access="read" />
|
||||
<property name="Paired" type="b" access="read" />
|
||||
<property name="Bonded" type="b" access="read" />
|
||||
<property name="Trusted" type="b" access="readwrite" />
|
||||
<property name="Blocked" type="b" access="readwrite" />
|
||||
<property name="LegacyPairing" type="b" access="read" />
|
||||
<property name="RSSI" type="n" access="read" />
|
||||
<property name="Connected" type="b" access="read" />
|
||||
<property name="UUIDs" type="as" access="read" />
|
||||
<property name="Modalias" type="s" access="read" />
|
||||
<property name="Adapter" type="o" access="read" />
|
||||
<property name="ManufacturerData" type="a{qv}" access="read" />
|
||||
<property name="ServiceData" type="a{sv}" access="read" />
|
||||
<property name="TxPower" type="n" access="read" />
|
||||
<property name="ServicesResolved" type="b" access="read" />
|
||||
<property name="AdvertisingFlags" type="ay" access="read" />
|
||||
<property name="AdvertisingData" type="a{yv}" access="read" />
|
||||
<property name="WakeAllowed" type="b" access="readwrite" />
|
||||
<property name="Sets" type="a{oa{sv}}" access="read" />
|
||||
</interface>
|
||||
</node>
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node>
|
||||
<interface name="org.bluez.Profile1">
|
||||
<method name='Release'>
|
||||
</method>
|
||||
<method name='NewConnection'>
|
||||
<arg type='o' name='device' direction='in'/>
|
||||
<arg type='h' name='fd' direction='in'/>
|
||||
<arg type='a{sv}' name='fd_properties' direction='in'/>
|
||||
</method>
|
||||
<method name='RequestDisconnection'>
|
||||
<arg type='o' name='device' direction='in'/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.bluez.ProfileManager1">
|
||||
<method name="RegisterProfile">
|
||||
<arg name="profile" type="o" direction="in" />
|
||||
<arg name="UUID" type="s" direction="in" />
|
||||
<arg name="options" type="a{sv}" direction="in" />
|
||||
</method>
|
||||
<method name="UnregisterProfile">
|
||||
<arg name="profile" type="o" direction="in" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
Reference in New Issue
Block a user