More bluetooth medium code.

This commit is contained in:
Vibhav Pant
2023-07-30 02:10:58 +05:30
parent 1f6a9ccc67
commit ab3ec3d257
12 changed files with 873 additions and 1 deletions
@@ -0,0 +1,107 @@
#include <map>
#include <memory>
#include <systemd/sd-bus-vtable.h>
#include <systemd/sd-bus.h>
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/logging.h"
const char *BLUEZ_PROFILEMANAGER_INTERFACE = "org.bluez.ProfileManager1";
static int profile_release(sd_bus_message *m, void *userdata,
sd_bus_error *error) {
// TODO
}
static int profile_new_connection(sd_bus_message *m, void *userdata,
sd_bus_error *error) {
// TODO
}
static int profile_new(sd_bus_message *m, void *userdata, sd_bus_error *error) {
// TODO
}
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_new,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END};
namespace nearby {
namespace linux {
std::unique_ptr<ProfileManager> NewProfileManager() {
sd_bus *system_bus;
if (auto ret = sd_bus_default_system(&system_bus); ret < 0) {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
sd_bus_error_set_errno(&err, ret);
NEARBY_LOGS(ERROR) << __func__
<< "Error connecting to system bus: " << err.name << ": "
<< err.message;
return nullptr;
}
sd_bus_slot *slot = nullptr;
auto manager = new ProfileManager(system_bus, slot);
if (auto ret = sd_bus_add_object_vtable(
system_bus, &slot, "/com/github/google/nearby", "org.bluez.Profile1",
vtable, manager->GetMethodData());
ret < 0) {
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
sd_bus_error_set_errno(&err, ret);
NEARBY_LOGS(ERROR) << __func__
<< "Error adding object /com/github/google/nearby: "
<< err.name << ": " << err.message;
return nullptr;
}
return std::unique_ptr<ProfileManager>(manager);
}
bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) {
registered_service_uuids_lock_.ReaderLock();
bool registered =
registered_service_uuids_.count(std::string(service_uuid)) == 1;
registered_service_uuids_lock_.ReaderUnlock();
return registered;
}
bool ProfileManager::RegisterProfile(absl::string_view service_uuid) {
if (ProfileRegistered(service_uuid)) {
return true;
}
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
std::string uuid(service_uuid);
registered_service_uuids_lock_.Lock();
if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez",
BLUEZ_PROFILEMANAGER_INTERFACE, "RegisterProfile", &err,
nullptr, "osa{sq}", "/com/github/google/nearby",
uuid.c_str(), 0, nullptr) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< "Error calling RegisterProfile: " << err.name << ": "
<< err.message;
registered_service_uuids_lock_.Unlock();
return false;
}
registered_service_uuids_.insert(uuid);
registered_service_uuids_lock_.Unlock();
return true;
}
} // namespace linux
} // namespace nearby
@@ -0,0 +1,58 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_
#include <map>
#include <optional>
#include <set>
#include <string>
#include <tuple>
#include <systemd/sd-bus.h>
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/bluetooth_classic.h"
namespace nearby {
namespace linux {
class ProfileManager {
public:
ProfileManager(sd_bus *system_bus, sd_bus_slot *slot) {
system_bus_ = system_bus;
slot_ = slot;
}
~ProfileManager() { sd_bus_unref(system_bus_); }
bool ProfileRegistered(absl::string_view service_uuid);
bool RegisterProfile(absl::string_view sevice_uuid);
std::optional<int> GetServiceRecordFD(api::BluetoothDevice &remote_device,
absl::string_view service_uuid);
struct MethodData {
std::map<std::tuple<std::tuple<std::string, std::string>>, int> &connections_;
absl::Mutex &connections_lock_;
};
struct MethodData *GetMethodData() { return &data_; }
private:
bool InitManagerObj();
// Maps (mac address, service uuid) tuples to FDs. Probably
// an awful way to do this, but whatever.
std::map<std::tuple<std::tuple<std::string, std::string>>, int> connections_;
absl::Mutex connections_lock_;
MethodData data_{connections_, connections_lock_};
std::set<std::string> registered_service_uuids_;
absl::Mutex registered_service_uuids_lock_;
sd_bus *system_bus_;
sd_bus_slot *slot_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -0,0 +1,78 @@
#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(absl::string_view adapter,
absl::string_view address) {
mac_addr_ = std::string(address);
object_path_ = absl::Substitute("/org/bluez/$0/dev_$1", adapter,
absl::StrReplaceAll(address, {{":", "_"}}));
if (sd_bus_default_system(&system_bus) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus";
}
}
BluetoothDevice::BluetoothDevice(absl::string_view device_object_path) {
if (sd_bus_default_system(&system_bus) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus";
return;
}
object_path_ = device_object_path;
}
std::string BluetoothDevice::GetName() const {
if (!system_bus) {
return std::string();
}
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
char *cname = nullptr;
if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE,
object_path_.c_str(), BLUEZ_DEVICE_INTERFACE,
"Alias", &err, &cname) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error getting alias for device "
<< object_path_ << " :" << err.message;
return std::string();
}
std::string name(cname);
free(cname);
return name;
}
std::string BluetoothDevice::GetMacAddress() const {
if (!system_bus) {
return std::string();
}
if (!mac_addr_.empty()) {
return mac_addr_;
}
__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err =
SD_BUS_ERROR_NULL;
char *c_addr = nullptr;
if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE,
object_path_.c_str(), BLUEZ_DEVICE_INTERFACE,
"Address", &err, &c_addr) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error getting address for device "
<< object_path_ << " :" << err.message;
return std::string();
}
std::string addr(c_addr);
free(c_addr);
return addr;
}
} // namespace linux
} // namespace nearby
@@ -0,0 +1,34 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_
#include <systemd/sd-bus.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/bluetooth_classic.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 {
public:
BluetoothDevice(absl::string_view adapter, absl::string_view address);
BluetoothDevice(absl::string_view device_object_path);
virtual ~BluetoothDevice() override { sd_bus_unref(system_bus); };
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName()
std::string GetName() const override;
// Returns BT MAC address assigned to this device.
std::string GetMacAddress() const override;
private:
sd_bus *system_bus;
std::string object_path_;
std::string mac_addr_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -0,0 +1,171 @@
#include <cstring>
#include <memory>
#include <systemd/sd-bus.h>
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "absl/strings/str_replace.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
#include "internal/platform/implementation/linux/bluetooth_classic_medium.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/logging.h"
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 0;
}
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;
}
if (ret == 0)
break;
if (strcmp(interface_name, "org.bluez.Device1") == 0) {
NEARBY_LOGS(INFO) << __func__ << "Encountered new device at "
<< c_object_path;
auto bluetoothDevice =
std::make_unique<BluetoothDevice>(BluetoothDevice(object_path));
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;
}
}
return 0;
}
BluetoothClassicMedium::BluetoothClassicMedium(absl::string_view adapter) {
if (sd_bus_default_system(&system_bus_) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus";
}
adapter_object_path_ = absl::Substitute("/org/bluez/$0/", adapter);
}
BluetoothClassicMedium::~BluetoothClassicMedium() {
if (system_bus_)
sd_bus_unref(system_bus_);
if (system_bus_slot_)
sd_bus_slot_unref(system_bus_slot_);
}
bool BluetoothClassicMedium::StartDiscovery(
DiscoveryCallback discovery_callback) {
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;
discovery_params_.cb = std::move(discovery_callback);
discovery_params_.adapter_object_path = adapter_object_path_;
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;
return false;
}
return true;
}
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;
return false;
}
const sd_bus_error *m_err = sd_bus_message_get_error(reply);
if (m_err) {
NEARBY_LOGS(ERROR) << __func__ << "Error calling StopDiscovery on "
<< adapter_object_path_ << ": " << err.message;
return false;
}
return true;
}
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());
}
std::string
BluetoothClassicMedium::GetDeviceObjectPath(absl::string_view mac_address) {
return absl::Substitute("$0/dev_$1", adapter_object_path_, absl::StrReplaceAll(mac_address, {{":", "_"}}));
}
} // namespace linux
} // namespace nearby
@@ -0,0 +1,99 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_
#include <map>
#include <memory>
#include <systemd/sd-bus.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 {
// Container of operations that can be performed over the Bluetooth Classic
// medium.
class BluetoothClassicMedium : public api::BluetoothClassicMedium {
public:
BluetoothClassicMedium(absl::string_view adapter);
~BluetoothClassicMedium();
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery()
//
// Returns true once the process of discovery has been initiated.
bool StartDiscovery(DiscoveryCallback discovery_callback) override;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#cancelDiscovery()
//
// Returns true once discovery is well and truly stopped; after this returns,
// there must be no more invocations of the DiscoveryCallback passed in to
// StartDiscovery().
bool StopDiscovery() override;
// A combination of
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createInsecureRfcommSocketToServiceRecord
// followed by
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#connect().
//
// service_uuid is the canonical textual representation
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of a
// type 3 name-based
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based))
// UUID.
//
// On success, returns a new BluetoothSocket.
// On error, returns nullptr.
std::unique_ptr<api::BluetoothSocket>
ConnectToService(api::BluetoothDevice &remote_device,
const std::string &service_uuid,
CancellationFlag *cancellation_flag) override;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#listenUsingInsecureRfcommWithServiceRecord
//
// service_uuid is the canonical textual representation
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of a
// type 3 name-based
// (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based))
// UUID.
//
// Returns nullptr error.
std::unique_ptr<api::BluetoothServerSocket>
ListenForService(const std::string &service_name,
const std::string &service_uuid) override;
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond()
//
// Start the bonding (pairing) process with the remote device.
// Return a Bluetooth pairing instance to handle the pairing process with the
// remote device.
std::unique_ptr<api::BluetoothPairing>
CreatePairing(api::BluetoothDevice &remote_device) override;
api::BluetoothDevice *
GetRemoteDevice(const std::string &mac_address) override;
void AddObserver(Observer *observer) override;
void RemoveObserver(Observer *observer) override;
struct DiscoveryParams {
std::string &adapter_object_path;
std::map<std::string, std::unique_ptr<BluetoothDevice>> &devices_by_path;
ObserverList<Observer> &observers_;
BluetoothClassicMedium::DiscoveryCallback cb;
};
private:
std::string GetDeviceObjectPath(absl::string_view mac_address);
sd_bus *system_bus_ = nullptr;
sd_bus_slot *system_bus_slot_ = nullptr;
std::string adapter_object_path_ = std::string();
std::map<std::string, std::unique_ptr<BluetoothDevice>> devices_by_id_;
ObserverList<Observer> observers_;
DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_id_, observers_};
};
} // namespace linux
} // namespace nearby
#endif
@@ -0,0 +1,32 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/exception.h"
namespace nearby {
namespace linux {
class BluetoothServerSocket : api::BluetoothServerSocket {
public:
~BluetoothServerSocket() = default;
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept()
//
// Blocks until either:
// - at least one incoming connection request is available, or
// - ServerSocket is closed.
// On success, returns connected socket, ready to exchange data.
// Returns nullptr on error.
// Once error is reported, it is permanent, and ServerSocket has to be
// closed.
std::unique_ptr<api::BluetoothSocket> Accept() override;
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close()
//
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override;
};
} // namespace linux
} // namespace nearby
#endif
@@ -0,0 +1,68 @@
#include <array>
#include <cerrno>
#include <cstdint>
#include <unistd.h>
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/linux/bluetooth_classic_socket.h"
namespace nearby {
namespace linux {
ExceptionOr<ByteArray> BluetoothInputStream::Read(std::int64_t size) {
char *data = new char[size];
ssize_t ret = read(fd_, data, size);
if (ret == 0) {
delete[] data;
return ExceptionOr(ByteArray());
} else if (ret < 0) {
delete[] data;
return Exception::kIo;
}
return ExceptionOr(ByteArray(data, size));
}
ExceptionOr<std::size_t> BluetoothInputStream::Skip(std::size_t offset) {
auto off = lseek(fd_, offset, SEEK_CUR);
if (off != offset) {
auto end = lseek(fd_, 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) {
char *data = new char[size];
ssize_t ret = read(fd_, data, size);
if (ret < 0) {
delete[] data;
return Exception::kIo;
}
return ExceptionOr(ByteArray(data, size));
}
Exception BluetoothOutputStream::Write(const ByteArray &data) {
ssize_t written = 0;
while (written < data.size()) {
ssize_t ret = write(fd_, data.data(), data.size());
if (ret < 1) {
return Exception{Exception::kIo};
}
written += ret;
}
return Exception{Exception::kSuccess};
}
Exception BluetoothOutputStream::Flush() {
return Exception{Exception::kSuccess};
}
Exception BluetoothOutputStream::Close() {
return close(fd_) < 0 ? Exception{Exception::kIo}
: Exception{Exception::kSuccess};
}
} // namespace linux
} // namespace nearby
@@ -0,0 +1,61 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_
#include <memory>
#include <systemd/sd-bus.h>
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/bluetooth_classic.h"
namespace nearby {
namespace linux {
class BluetoothInputStream : public InputStream {
public:
BluetoothInputStream(int fd) { fd_ = fd; };
ExceptionOr<ByteArray> Read(std::int64_t size) override;
ExceptionOr<size_t> Skip(size_t offset) override;
ExceptionOr<ByteArray> ReadExactly(std::size_t size);
Exception Close() override;
private:
int fd_;
};
class BluetoothOutputStream : public OutputStream {
public:
BluetoothOutputStream(int fd) { fd_ = fd; };
Exception Write(const ByteArray &data) override;
Exception Flush() override;
Exception Close() override;
private:
int fd_;
};
class BluetoothSocket : public api::BluetoothSocket {
public:
BluetoothSocket(std::string object, int fd) {
fd_ = fd;
object_ = object;
input_stream_ = BluetoothInputStream(fd_);
output_stream_ = BluetoothOutputStream(fd_);
}
InputStream &GetInputStream() override { return input_stream_; }
OutputStream &GetOutputStream() override { return output_stream_; }
private:
int fd_;
std::string object_;
BluetoothInputStream input_stream_ = {-1};
BluetoothOutputStream output_stream_ = {-1};
};
} // namespace linux
} // namespace nearby
#endif
@@ -0,0 +1,132 @@
#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_pairing.h"
#include "internal/platform/implementation/linux/bluez.h"
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);
} else {
pairing_cb->on_pairing_error_cb(
api::BluetoothPairingCallback::PairingError::kAuthFailed);
}
return 0;
}
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();
}
return 0;
}
BluetoothPairing::BluetoothPairing(absl::string_view object_path) {
object_path_ = object_path;
if (sd_bus_default_system(&system_bus_) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus";
}
}
bool BluetoothPairing::InitiatePairing(
api::BluetoothPairingCallback pairing_cb) {
if (!system_bus_)
return false;
pairing_cb_ = std::move(pairing_cb);
if (sd_bus_call_method_async(system_bus_, nullptr, BLUEZ_SERVICE,
object_path_.c_str(), BLUEZ_DEVICE_INTERFACE,
"Pair", &pairing_reply_handler, &pairing_cb_,
nullptr) < 0) {
NEARBY_LOGS(ERROR) << __func__ << "Error calling method Pair on 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) {
return true;
}
bool BluetoothPairing::CancelPairing() {
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, object_path_.c_str(),
BLUEZ_DEVICE_INTERFACE, "CancelPairing", &err, nullptr,
nullptr)) {
NEARBY_LOGS(ERROR) << __func__
<< "Error calling method CancelPairing on device "
<< object_path_ << ": " << err.message;
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", object_path_.c_str())) {
NEARBY_LOGS(ERROR) << __func__
<< "Error calling method CancelPairing on device "
<< object_path_ << ": " << err.message;
return false;
}
return true;
}
bool BluetoothPairing::IsPaired() {
if (!system_bus_)
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,
object_path_.c_str(), BLUEZ_DEVICE_INTERFACE,
"Bonded", &err, 'b', &paired) < 0) {
NEARBY_LOGS(ERROR) << __func__
<< "Error getting Bonded property for device "
<< object_path_ << ": " << err.message;
}
return paired;
}
} // namespace linux
} // namespace nearby
@@ -0,0 +1,33 @@
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PROFILE_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_
#include <string>
#include <systemd/sd-bus.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
class BluetoothPairing : public api::BluetoothPairing {
public:
BluetoothPairing(absl::string_view object_path);
~BluetoothPairing() { sd_bus_unref(system_bus_); }
bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override;
bool FinishPairing(std::optional<absl::string_view> pin_code) override;
bool CancelPairing() override;
bool Unpair() override;
bool IsPaired() override;
private:
std::string object_path_;
sd_bus *system_bus_;
api::BluetoothPairingCallback pairing_cb_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -4,7 +4,6 @@
namespace nearby {
namespace linux {
const char *BLUEZ_SERVICE = "org.bluez";
const char *BLUEZ_ADAPTER_INTERFACE = "org.bluez.Adapter1";
} // namespace linux