removed non-core files

This commit is contained in:
kidfromjupiter
2026-01-14 15:01:59 +00:00
parent a61607360c
commit d23090a6b5
154 changed files with 80 additions and 19238 deletions
@@ -20,7 +20,6 @@ cc_library(
"atomic_boolean.h",
"atomic_reference.h",
"atomic_uint32.h",
"bluetooth_adapter.h",
"condition_variable.h",
"device_info.h",
"executor.h",
@@ -54,50 +53,8 @@ cc_library(
cc_library(
name = "comm",
hdrs = [
"avahi.h",
"ble_gatt_server.h",
# "ble_gatt_client.h",
# "ble_medium.h",
"ble_v2_medium.h",
"ble_v2_server_socket.h",
"ble_v2_socket.h",
"bluetooth_adapter.h",
"bluetooth_bluez_profile.h",
"bluetooth_classic_device.h",
"bluetooth_classic_medium.h",
"bluetooth_classic_server_socket.h",
"bluetooth_classic_socket.h",
"bluetooth_devices.h",
"bluetooth_pairing.h",
"bluez.h",
"bluez_device.h",
# "bluez_agent.h",
"bluez_advertisement_monitor.h",
"bluez_advertisement_monitor_manager.h",
# "bluez_gatt_characteristic_client.h",
"bluez_gatt_characteristic_server.h",
"bluez_gatt_manager.h",
"bluez_gatt_profile.h",
# "bluez_gatt_service_client.h",
"bluez_gatt_service_server.h",
"bluez_le_advertisement.h",
"dbus.h",
"network_manager.h",
"network_manager_active_connection.h",
"network_manager_access_point.h",
"stream.h",
"tcp_server_socket.h",
"wifi_direct.h",
"wifi_direct_server_socket.h",
"wifi_direct_socket.h",
"wifi_hotspot.h",
"wifi_hotspot_server_socket.h",
"wifi_hotspot_socket.h",
"wifi_lan.h",
"wifi_lan_server_socket.h",
"wifi_lan_socket.h",
"wifi_medium.h",
"wifi_socket.h",
],
deps = [
":crypto",
@@ -141,32 +98,8 @@ cc_library(
cc_library(
name = "linux",
srcs = [
"avahi.cc",
# "ble_gatt_client.cc",
"ble_gatt_server.cc",
# "ble_medium.cc",
"ble_v2_medium.cc",
"ble_v2_server_socket.cc",
"ble_v2_socket.cc",
"bluetooth_adapter.cc",
"bluetooth_bluez_profile.cc",
"bluetooth_classic_socket.cc",
"bluetooth_classic_device.cc",
"bluetooth_classic_medium.cc",
"bluetooth_classic_server_socket.cc",
"bluetooth_devices.cc",
"bluetooth_pairing.cc",
"bluez.cc",
#"bluez_agent.cc",
"bluez_advertisement_monitor.cc",
# "bluez_gatt_characteristic_client.cc",
"bluez_gatt_characteristic_server.cc",
"bluez_gatt_service_server.cc",
"bluez_le_advertisement.cc",
"dbus.cc",
"executor.cc",
"network_manager.cc",
"network_manager_active_connection.cc",
"platform.cc",
"preferences_manager.cc",
"preferences_repository.cc",
@@ -176,13 +109,6 @@ cc_library(
"system_clock.cc",
"thread_pool.cc",
"utils.cc",
"wifi_direct.cc",
"wifi_direct_server_socket.cc",
"wifi_hotspot.cc",
"wifi_hotspot_server_socket.cc",
"wifi_lan.cc",
"wifi_lan_server_socket.cc",
"wifi_medium.cc",
],
linkopts = ["-lcurl"],
visibility = [
@@ -1,72 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/atomic_reference.h"
#include "gtest/gtest.h"
TEST(atomic_reference, SuccessfulCreation) {
// Arrange
nearby::linux::AtomicUint32 atomicUint32;
uint32_t result = UINT32_MAX;
const uint32_t expected = 0;
// Act
result = atomicUint32.Get();
// Assert
EXPECT_EQ(result, expected);
}
TEST(atomic_reference, SuccessfulMaxSet) {
// Arrange
nearby::linux::AtomicUint32 atomicUint32;
uint32_t result = 0;
const uint32_t expected = UINT32_MAX;
// Act
atomicUint32.Set(UINT32_MAX);
result = atomicUint32.Get();
// Assert
EXPECT_EQ(result, expected);
}
TEST(atomic_reference, SuccessfulMinSet) {
// Arrange
nearby::linux::AtomicUint32 atomicUint32;
uint32_t result = UINT32_MAX;
const uint32_t expected = 0;
// Act
atomicUint32.Set(0);
result = atomicUint32.Get();
// Assert
EXPECT_EQ(result, expected);
}
TEST(atomic_reference, SetNegativeOneReturnsMAXUINT) {
// Arrange
nearby::linux::AtomicUint32 atomicUint32;
uint32_t result = 0;
const uint32_t expected = UINT32_MAX;
// Act
atomicUint32.Set(-1); // Try Set -1, should actually store UINT32_MAX
result = atomicUint32.Get();
// Assert
EXPECT_EQ(result, expected);
}
@@ -1,128 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/avahi.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/logging.h"
#include "internal/platform/nsd_service_info.h"
namespace nearby {
namespace linux {
namespace avahi {
void ServiceBrowser::onItemNew(const int32_t &interface,
const int32_t &protocol, const std::string &name,
const std::string &type,
const std::string &domain,
const uint32_t &flags) {
LOG(INFO) << __func__ << ": " << getObjectPath()
<< ": Found new item through the ServiceBrowser: "
<< "interface: " << interface << ", protocol: "
<< protocol << ", name: '" << name << "', type: '"
<< type << "', domain: '" << domain
<< "', flags: " << flags;
if (flags & kAvahiLookupResultLocal) {
LOG(INFO) << __func__ << ": Ignoring local service.";
return;
}
NsdServiceInfo info;
try {
auto [r_iface, r_protocol, r_name, r_type, r_domain, r_host, r_aprotocol,
r_address, r_port, r_txt, r_flags] =
server_->ResolveService(interface, protocol, name, type, domain,
0, // AVAHI_PROTO_INET
0);
info.SetServiceName(r_name);
info.SetIPAddress(r_address);
info.SetPort(r_port);
info.SetServiceType(r_type + "."); // discovery callback expects an extra period at t
for (auto &attr : r_txt) {
auto attr_str = std::string(attr.begin(), attr.end());
size_t pos = attr_str.find('=');
if (pos == 0 || pos == std::string::npos || pos == attr_str.size() - 1) {
LOG(WARNING) << " found invalid text attribute: " << attr_str;
continue;
}
info.SetTxtRecord(attr_str.substr(0, pos), attr_str.substr(pos + 1));
}
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(server_, "ResolveService", e);
}
discovery_cb_.service_discovered_cb(std::move(info));
}
void ServiceBrowser::onItemRemove(
const int32_t &interface, const int32_t &protocol, const std::string &name,
const std::string &type, const std::string &domain, const uint32_t &flags) {
// TODO: Can we even resolve removed items?
LOG(INFO) << __func__ << ": " << getObjectPath()
<< ": Item removed through the ServiceBrowser: "
<< "interface: " << interface << ", protocol: "
<< protocol << ", name: '" << name << "', type: '"
<< type << "', domain: '" << domain
<< "', flags: " << flags;
if (flags & kAvahiLookupResultLocal) {
LOG(INFO) << __func__ << ": Ignoring local service.";
return;
}
NsdServiceInfo info;
try {
auto [r_iface, r_protocol, r_name, r_type, r_domain, r_host, r_aprotocol,
r_address, r_port, r_txt, r_flags] =
server_->ResolveService(interface, protocol, name, type, domain,
0, // AVAHI_PROTO_INET
flags);
info.SetServiceName(r_name);
info.SetIPAddress(r_address);
info.SetPort(r_port);
info.SetServiceType(r_type);
for (auto &attr : r_txt) {
auto attr_str = std::string(attr.begin(), attr.end());
size_t pos = attr_str.find('=');
if (pos == 0 || pos == std::string::npos || pos == attr_str.size() - 1) {
LOG(WARNING) << " found invalid text attribute: " << attr_str;
continue;
}
info.SetTxtRecord(attr_str.substr(0, pos), attr_str.substr(pos + 1));
}
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(server_, "ResolveService", e);
}
discovery_cb_.service_lost_cb(std::move(info));
}
void ServiceBrowser::onFailure(const std::string &error) {
LOG(ERROR) << __func__ << ": " << getObjectPath()
<< ": ServiceBrowser reported a failure: " << error;
}
void ServiceBrowser::onAllForNow() {
LOG(INFO) << __func__ << ": " << getObjectPath()
<< ": notified via ServiceBrowser that all records have "
"been added for now";
}
void ServiceBrowser::onCacheExhausted() {
LOG(INFO) << __func__ << ": " << getObjectPath()
<< ": notified via ServiceBrowser of cache exhaustion";
}
} // namespace avahi
} // namespace linux
} // namespace nearby
@@ -1,127 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_AVAHI_H_
#define PLATFORM_IMPL_LINUX_AVAHI_H_
#include <memory>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/avahi/entrygroup_client.h"
#include "internal/platform/implementation/linux/generated/dbus/avahi/server2_client.h"
#include "internal/platform/implementation/linux/generated/dbus/avahi/servicebrowser_client.h"
#include "internal/platform/implementation/wifi_lan.h"
namespace nearby {
namespace linux {
namespace avahi {
class Server final
: public sdbus::ProxyInterfaces<org::freedesktop::Avahi::Server2_proxy> {
public:
Server(sdbus::IConnection &system_bus)
: ProxyInterfaces(system_bus, "org.freedesktop.Avahi", "/") {
registerProxy();
}
~Server() { unregisterProxy(); }
protected:
void onStateChanged(const int32_t &state, const std::string &error) override {
}
};
class EntryGroup final
: public sdbus::ProxyInterfaces<org::freedesktop::Avahi::EntryGroup_proxy> {
public:
EntryGroup(sdbus::IConnection &system_bus,
const sdbus::ObjectPath &entry_group_object_path)
: ProxyInterfaces(system_bus, "org.freedesktop.Avahi",
entry_group_object_path) {
registerProxy();
}
~EntryGroup() {
LOG(INFO) << __func__ << ": Freeing entry group "
<< getObjectPath();
try {
Free();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(this, "Free", e);
}
unregisterProxy();
}
protected:
void onStateChanged(const int32_t &state, const std::string &error) override {
}
};
class ServiceBrowser final
: public sdbus::ProxyInterfaces<
org::freedesktop::Avahi::ServiceBrowser_proxy> {
public:
ServiceBrowser(sdbus::IConnection &system_bus,
const sdbus::ObjectPath &service_browser_object_path,
api::WifiLanMedium::DiscoveredServiceCallback callback,
std::shared_ptr<Server> avahi_server)
: ProxyInterfaces(system_bus, "org.freedesktop.Avahi",
service_browser_object_path),
discovery_cb_(std::move(callback)),
server_(avahi_server) {
registerProxy();
}
~ServiceBrowser() {
LOG(INFO) << __func__ << ": Freeing service browser "
<< getObjectPath();
try {
Free();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(this, "Free", e);
}
unregisterProxy();
}
protected:
void onItemNew(const int32_t &interface, const int32_t &protocol,
const std::string &name, const std::string &type,
const std::string &domain, const uint32_t &flags) override;
void onItemRemove(const int32_t &interface, const int32_t &protocol,
const std::string &name, const std::string &type,
const std::string &domain, const uint32_t &flags) override;
void onFailure(const std::string &error) override;
void onAllForNow() override;
void onCacheExhausted() override;
private:
enum LookupResultFlags {
kAvahiLookupResultFlagCached = 1,
kAvahiLookupResultFlagWideArea = 2,
kAvahiLookupResultFlagMulticast = 4,
kAvahiLookupResultLocal = 8,
kAvahiLookupResultOurOwn = 16,
kAvahiLookupResultStatic = 32,
};
api::WifiLanMedium::DiscoveredServiceCallback discovery_cb_;
std::shared_ptr<Server> server_;
};
} // namespace avahi
} // namespace linux
} // namespace nearby
#endif
@@ -1,456 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <map>
#include <string>
#include <variant>
#include <sdbus-c++/Types.h>
#include "absl/strings/substitute.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/cancellation_flag_listener.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/ble_gatt_client.h"
#include "internal/platform/implementation/linux/bluez_gatt_characteristic_client.h"
#include "internal/platform/implementation/linux/bluez_gatt_service_client.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_client.h"
#include "internal/platform/implementation/linux/utils.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
bool GattClient::DiscoverServiceAndCharacteristics(
const Uuid &service_uuid, const std::vector<Uuid> &characteristic_uuids) {
return gatt_discovery_->DiscoverServiceAndCharacteristics(
peripheral_object_path_, service_uuid, characteristic_uuids,
discovery_cancel_);
}
absl::optional<api::ble_v2::GattCharacteristic> GattClient::GetCharacteristic(
const Uuid &service_uuid, const Uuid &characteristic_uuid) {
auto chr_proxy = gatt_discovery_->GetCharacteristic(
peripheral_object_path_, service_uuid, characteristic_uuid);
if (chr_proxy == nullptr) return std::nullopt;
api::ble_v2::GattCharacteristic chr;
chr.service_uuid = service_uuid;
chr.uuid = characteristic_uuid;
chr.property = api::ble_v2::GattCharacteristic::Property::kNone;
chr.permission = api::ble_v2::GattCharacteristic::Permission::kNone;
std::vector<std::string> flags;
try {
flags = chr_proxy->Flags();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(chr_proxy, "Flags", e);
return std::nullopt;
}
for (const auto &flag : flags) {
if (flag == "read") {
chr.property |= api::ble_v2::GattCharacteristic::Property::kRead;
chr.permission |= api::ble_v2::GattCharacteristic::Permission::kRead;
} else if (flag == "write") {
chr.property |= api::ble_v2::GattCharacteristic::Property::kWrite;
chr.permission |= api::ble_v2::GattCharacteristic::Permission::kWrite;
} else if (flag == "notify") {
chr.property |= api::ble_v2::GattCharacteristic::Property::kNotify;
} else if (flag == "indicate") {
chr.property |= api::ble_v2::GattCharacteristic::Property::kIndicate;
}
}
absl::MutexLock lock(&characteristics_mutex_);
characteristics_.emplace(chr, std::move(chr_proxy));
return chr;
}
absl::optional<std::string> GattClient::ReadCharacteristic(
const api::ble_v2::GattCharacteristic &characteristic) {
absl::ReaderMutexLock lock(&characteristics_mutex_);
if (characteristics_.count(characteristic) == 0) {
LOG(ERROR) << __func__ << ": Unknown characteristic '"
<< absl::Substitute("$0", characteristic) << "'";
return std::nullopt;
}
return std::visit(
[](auto &&chr) {
try {
auto value_bytes = chr->ReadValue({});
return std::optional<std::string>{
std::string(value_bytes.begin(), value_bytes.end())};
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(chr, "ReadValue", e);
return std::optional<std::string>();
}
},
characteristics_[characteristic]);
}
bool GattClient::WriteCharacteristic(
const api::ble_v2::GattCharacteristic &characteristic,
absl::string_view value, WriteType type) {
absl::ReaderMutexLock lock(&characteristics_mutex_);
if (characteristics_.count(characteristic) == 0) {
LOG(ERROR) << __func__ << ": Unknown characteristic '"
<< absl::Substitute("$0", characteristic) << "'";
return false;
}
return std::visit(
[value, type](auto &&chr) {
std::vector<uint8_t> value_bytes(value.begin(), value.end());
try {
chr->WriteValue(
value_bytes,
{{"type",
type == api::ble_v2::GattClient::WriteType::kWithResponse
? "request"
: "command"}});
return true;
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(chr, "WriteValue", e);
return false;
}
},
characteristics_[characteristic]);
}
bool GattClient::SetCharacteristicSubscription(
const api::ble_v2::GattCharacteristic &characteristic, bool enable,
absl::AnyInvocable<void(absl::string_view value)>
on_characteristic_changed_cb) {
absl::MutexLock lock(&characteristics_mutex_);
if (characteristics_.count(characteristic) == 0) {
LOG(ERROR) << __func__ << ": Unknown characteristic '"
<< absl::Substitute("$0", characteristic) << "'";
return false;
}
if (enable) {
auto subbed_chr = gatt_discovery_->GetSubscribedCharacteristic(
peripheral_object_path_, characteristic.service_uuid,
characteristic.uuid, std::move(on_characteristic_changed_cb));
if (subbed_chr == nullptr) return false;
try {
subbed_chr->StartNotify();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(subbed_chr, "StartNotify", e);
return false;
}
characteristics_[characteristic] = std::move(subbed_chr);
} else if (std::holds_alternative<
std::unique_ptr<bluez::SubscribedGattCharacteristicClient>>(
characteristics_[characteristic])) {
auto chr = gatt_discovery_->GetCharacteristic(peripheral_object_path_,
characteristic.service_uuid,
characteristic.uuid);
if (chr == nullptr) return false;
try {
chr->StopNotify();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(chr, "StopNotify", e);
return false;
}
characteristics_[characteristic] = std::move(chr);
}
return true;
}
void GattClient::Disconnect() {
absl::MutexLock lock(&disconnected_callback_mutex_);
if (!discovery_cancel_.Cancelled()) {
discovery_cancel_.Cancel();
if (*disconnected_callback_it_ != nullptr) (*disconnected_callback_it_)();
gatt_discovery_->RemovePeripheralConnection(peripheral_object_path_,
disconnected_callback_it_);
}
}
void BluezGattDiscovery::Shutdown() {
auto no_discovery = [&]() {
mutex_.AssertReaderHeld();
return pending_discovery_ == 0;
};
mutex_.Lock();
shutdown_ = true;
mutex_.Await(absl::Condition(&no_discovery));
mutex_.Unlock();
}
bool BluezGattDiscovery::InitializeKnownServices() {
std::map<sdbus::ObjectPath,
std::map<std::string, std::map<std::string, sdbus::Variant>>>
objects;
try {
objects = GetManagedObjects();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e);
return false;
}
absl::flat_hash_map<sdbus::ObjectPath, GattServiceClient> cached_services;
absl::MutexLock lock(&mutex_);
auto chr_it = std::find_if(
objects.cbegin(), objects.cend(),
[](std::pair<sdbus::ObjectPath,
std::map<std::string, std::map<std::string, sdbus::Variant>>>
object) {
return object.second.count(
org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME) == 1;
});
for (; chr_it != objects.cend(); ++chr_it) {
const auto& [path, ifaces] = *chr_it;
auto iface_it = ifaces.find(org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME);
if (iface_it == ifaces.end()) {
// Not a GattCharacteristic1 object (or interfaces map incomplete) -> skip
continue;
}
const auto& properties = iface_it->second;
auto maybe_props = characteristicProperties(path, properties);
if (!maybe_props.has_value()) continue;
auto [chr_uuid, service_uuid, device_path] = *maybe_props;
discovered_characteristics_.emplace(
std::make_tuple(chr_uuid, service_uuid, device_path), path);
characteristics_properties_.emplace(
path, std::make_tuple(chr_uuid, service_uuid, device_path));
}
return true;
}
BluezGattDiscovery::CallbackIter BluezGattDiscovery::AddPeripheralConnection(
const sdbus::ObjectPath &device_object_path,
absl::AnyInvocable<void()> disconnected_callback_) {
absl::MutexLock lock(&peripheral_disconnected_callbacks_mutex_);
if (peripheral_disconnected_callbacks_.count(device_object_path) == 0)
peripheral_disconnected_callbacks_.emplace(
device_object_path, std::list<absl::AnyInvocable<void()>>{});
auto &list = peripheral_disconnected_callbacks_[device_object_path];
list.push_back(std::move(disconnected_callback_));
return list.begin();
}
void BluezGattDiscovery::RemovePeripheralConnection(
const sdbus::ObjectPath &device_object_path,
BluezGattDiscovery::CallbackIter cb) {
absl::MutexLock lock(&peripheral_disconnected_callbacks_mutex_);
auto it = peripheral_disconnected_callbacks_.find(device_object_path);
if (it != peripheral_disconnected_callbacks_.end()) {
it->second.erase(cb);
if (it->second.empty())
peripheral_disconnected_callbacks_.erase(device_object_path);
}
}
bool BluezGattDiscovery::DiscoverServiceAndCharacteristics(
const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid,
const std::vector<Uuid> &characteristic_uuids, CancellationFlag &cancel) {
CancellationFlagListener cancel_listen(&cancel, [&]() {
mutex_.Lock();
mutex_.Unlock();
});
auto discovered = [this, device_object_path, service_uuid,
characteristic_uuids, &cancel]() {
mutex_.AssertReaderHeld();
return cancel.Cancelled() ||
std::all_of(
characteristic_uuids.cbegin(), characteristic_uuids.cend(),
[this, service_uuid, device_object_path](auto &chr_uuid) {
mutex_.AssertReaderHeld();
return discovered_characteristics_.count(
{service_uuid, chr_uuid, device_object_path}) == 1;
});
};
absl::ReaderMutexLock lock(&mutex_, absl::Condition(&discovered));
LOG(INFO) << __func__ << ": Finished discovering gatt services and characteristics";
return !cancel.Cancelled();
}
std::unique_ptr<bluez::GattCharacteristicClient>
BluezGattDiscovery::GetCharacteristic(
const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid,
const Uuid &characteristic_uuid) {
auto key =
std::make_tuple(service_uuid, characteristic_uuid, device_object_path);
absl::ReaderMutexLock lock(&mutex_);
auto path_it = discovered_characteristics_.find(key);
if (path_it == discovered_characteristics_.end()) {
LOG(ERROR) << __func__ << ": No characteristic known for device "
<< device_object_path << " with service "
<< std::string{service_uuid} << " and UUID "
<< std::string{characteristic_uuid};
return nullptr;
}
return std::make_unique<bluez::GattCharacteristicClient>(system_bus_,
path_it->second);
}
std::unique_ptr<bluez::GattCharacteristicClient>
BluezGattDiscovery::GetSubscribedCharacteristic(
const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid,
const Uuid &characteristic_uuid,
absl::AnyInvocable<void(absl::string_view value)>
on_characteristic_changed_cb) {
auto key =
std::make_tuple(service_uuid, characteristic_uuid, device_object_path);
absl::ReaderMutexLock lock(&mutex_);
auto path_it = discovered_characteristics_.find(key);
if (path_it == discovered_characteristics_.end()) {
LOG(ERROR) << __func__ << ": No characteristic known for device "
<< device_object_path << " with service "
<< std::string{service_uuid} << " and UUID "
<< std::string{characteristic_uuid};
return nullptr;
}
return std::make_unique<bluez::SubscribedGattCharacteristicClient>(
system_bus_, device_object_path, std::move(on_characteristic_changed_cb));
}
std::optional<std::tuple<Uuid, Uuid, sdbus::ObjectPath>>
BluezGattDiscovery::characteristicProperties(
const sdbus::ObjectPath &char_path,
const std::map<std::string, sdbus::Variant> &properties) {
mutex_.AssertHeld();
const std::string &chr_uuid_str = properties.at("UUID");
auto chr_uuid = UuidFromString(chr_uuid_str);
if (!chr_uuid.has_value()) {
LOG(ERROR) << ": Couldn't parse UUID '" << chr_uuid_str
<< "' in characteristic " << char_path;
return std::nullopt;
}
const sdbus::ObjectPath &service_path = properties.at("Service");
if (cached_services_.count(service_path) == 0) {
cached_services_.emplace(
service_path, std::make_unique<GattServiceClient>(system_bus_, service_path));
}
auto it = cached_services_.find(service_path);
if (it == cached_services_.end() || it->second == nullptr) {
LOG(ERROR) << ": cached_services_ missing service " << service_path
<< " (from characteristic " << char_path << ")";
return std::nullopt;
}
LOG(INFO) << ": Found service path " << service_path
<< " (from characteristic " << char_path << ")";
auto* service = it->second.get(); // service is GattServiceClient*
nearby::Uuid service_uuid;
try {
std::string service_uuid_str = service->UUID(); // copy (safe)
auto service_uuid_maybe = UuidFromString(service_uuid_str);
if (!service_uuid_maybe.has_value()) {
LOG(ERROR) << ": Couldn't parse UUID '" << service_uuid_str
<< "' in service " << service_path;
return std::nullopt;
}
service_uuid = *service_uuid_maybe;
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(service, "UUID", e);
return std::nullopt;
}
sdbus::ObjectPath device_path;
try {
device_path = service->Device();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(service, "Device", e);
return std::nullopt;
}
return std::make_tuple(*chr_uuid, service_uuid, device_path);
}
void BluezGattDiscovery::onInterfacesAdded(
const sdbus::ObjectPath &objectPath,
const std::map<std::string, std::map<std::string, sdbus::Variant>>
&interfacesAndProperties) {
if (interfacesAndProperties.count(
org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME) == 0)
return;
const auto &properties = interfacesAndProperties.at(
org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME);
absl::MutexLock lock(&mutex_);
auto maybe_props = characteristicProperties(objectPath, properties);
if (!maybe_props.has_value()) return;
auto [chr_uuid, service_uuid, device_path] = *maybe_props;
discovered_characteristics_.emplace(
std::make_tuple(chr_uuid, service_uuid, device_path), objectPath);
characteristics_properties_.emplace(
objectPath, std::make_tuple(chr_uuid, service_uuid, device_path));
}
void BluezGattDiscovery::onInterfacesRemoved(
const sdbus::ObjectPath &objectPath,
const std::vector<std::string> &interfaces) {
auto begin = interfaces.cbegin();
auto end = interfaces.cend();
auto service_it =
std::find(begin, end, org::bluez::GattService1_proxy::INTERFACE_NAME);
if (service_it != end) {
absl::MutexLock lock(&mutex_);
cached_services_.erase(objectPath);
return;
}
auto chr_it = std::find(
begin, end, org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME);
if (chr_it != end) {
absl::MutexLock lock(&mutex_);
{
auto it = characteristics_properties_.find(objectPath);
if (it == characteristics_properties_.end()) {
// Not tracked / already removed / never added.
// return; // or just `break;` / `continue;` depending on your context
return;
}
auto &props = it->second;
discovered_characteristics_.erase(props);
}
characteristics_properties_.erase(objectPath);
}
}
} // namespace linux
} // namespace nearby
@@ -1,210 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLE_GATT_CLIENT_H_
#define PLATFORM_IMPL_LINUX_API_BLE_GATT_CLIENT_H_
#include <list>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/Types.h>
#include "absl/container/flat_hash_map.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/bluez_gatt_characteristic_client.h"
#include "internal/platform/implementation/linux/bluez_gatt_service_client.h"
namespace nearby {
namespace linux {
class BluezGattDiscovery final : public bluez::BluezObjectManager {
public:
explicit BluezGattDiscovery(std::shared_ptr<sdbus::IConnection> system_bus)
: bluez::BluezObjectManager(*system_bus),
system_bus_(system_bus),
shutdown_(false),
pending_discovery_(0) {}
~BluezGattDiscovery() override { Shutdown(); }
bool InitializeKnownServices() ABSL_LOCKS_EXCLUDED(mutex_);
using CallbackIter = typename std::list<absl::AnyInvocable<void()>>::iterator;
CallbackIter AddPeripheralConnection(
const sdbus::ObjectPath &device_object_path,
absl::AnyInvocable<void()> disconnected_callback_)
ABSL_LOCKS_EXCLUDED(peripheral_disconnected_callbacks_mutex_);
void RemovePeripheralConnection(const sdbus::ObjectPath &device_object_path,
BluezGattDiscovery::CallbackIter cb)
ABSL_LOCKS_EXCLUDED(peripheral_disconnected_callbacks_mutex_);
bool DiscoverServiceAndCharacteristics(
const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid,
const std::vector<Uuid> &characteristic_uuids, CancellationFlag &cancel)
ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<bluez::GattCharacteristicClient> GetCharacteristic(
const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid,
const Uuid &characteristic_uuid) ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<bluez::GattCharacteristicClient> GetSubscribedCharacteristic(
const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid,
const Uuid &characteristic_uuid,
absl::AnyInvocable<void(absl::string_view value)>
on_characteristic_changed_cb) ABSL_LOCKS_EXCLUDED(mutex_);
protected:
void onInterfacesAdded(
const sdbus::ObjectPath &objectPath,
const std::map<std::string, std::map<std::string, sdbus::Variant>>
&interfacesAndProperties) override ABSL_LOCKS_EXCLUDED(mutex_);
void onInterfacesRemoved(const sdbus::ObjectPath &objectPath,
const std::vector<std::string> &interfaces) override
ABSL_LOCKS_EXCLUDED(mutex_);
private:
std::optional<std::tuple<Uuid, Uuid, sdbus::ObjectPath>>
characteristicProperties(
const sdbus::ObjectPath &char_path,
const std::map<std::string, sdbus::Variant> &properties)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void Shutdown() ABSL_LOCKS_EXCLUDED(mutex_);
std::shared_ptr<sdbus::IConnection> system_bus_;
absl::Mutex peripheral_disconnected_callbacks_mutex_;
absl::flat_hash_map<sdbus::ObjectPath, std::list<absl::AnyInvocable<void()>>>
peripheral_disconnected_callbacks_
ABSL_GUARDED_BY(peripheral_disconnected_callbacks_mutex_);
absl::Mutex mutex_;
absl::flat_hash_map<sdbus::ObjectPath, std::unique_ptr<GattServiceClient>>
cached_services_ ABSL_GUARDED_BY(mutex_);
// Tuple order: service uuid, characteristic uuid, device object path
absl::flat_hash_map<std::tuple<Uuid, Uuid, sdbus::ObjectPath>,
sdbus::ObjectPath>
discovered_characteristics_ ABSL_GUARDED_BY(mutex_);
absl::flat_hash_map<sdbus::ObjectPath,
std::tuple<Uuid, Uuid, sdbus::ObjectPath>>
characteristics_properties_ ABSL_GUARDED_BY(mutex_);
bool shutdown_ ABSL_GUARDED_BY(mutex_);
std::size_t pending_discovery_ ABSL_GUARDED_BY(mutex_);
};
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt
//
// Representation of a client GATT connection to a remote GATT server.
class GattClient : public api::ble_v2::GattClient {
public:
GattClient(const GattClient &) = delete;
GattClient(GattClient &&) = delete;
GattClient &operator=(const GattClient &) = delete;
GattClient &operator=(GattClient &&) = delete;
explicit GattClient(std::shared_ptr<sdbus::IConnection> system_bus,
const sdbus::ObjectPath &peripheral_object_path,
std::shared_ptr<BluezGattDiscovery> gatt_discovery,
absl::AnyInvocable<void()> disconnected_callback)
: system_bus_(std::move(system_bus)),
peripheral_object_path_(peripheral_object_path),
gatt_discovery_(std::move(gatt_discovery)),
discovery_cancel_(false) {
disconnected_callback_it_ = gatt_discovery->AddPeripheralConnection(
peripheral_object_path_, std::move(disconnected_callback));
}
~GattClient() override {
absl::MutexLock lock(&disconnected_callback_mutex_);
if (!discovery_cancel_.Cancelled()) {
discovery_cancel_.Cancel();
gatt_discovery_->RemovePeripheralConnection(peripheral_object_path_,
disconnected_callback_it_);
}
}
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#discoverServices()
//
// Discovers available service and characteristics on this connection.
// Returns whether or not discovery finished successfully.
//
// This function should block until discovery has finished.
bool DiscoverServiceAndCharacteristics(
const Uuid &service_uuid,
const std::vector<Uuid> &characteristic_uuids) override;
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#getService(java.util.UUID)
// https://developer.android.com/reference/android/bluetooth/BluetoothGattService.html#getCharacteristic(java.util.UUID)
//
// Retrieves a GATT characteristic. On error, does not return a value.
//
// DiscoverServiceAndCharacteristics() should be called before this method to
// fetch all available services and characteristics first.
//
// It is okay for duplicate services to exist, as long as the specified
// characteristic UUID is unique among all services of the same UUID.
// NOLINTNEXTLINE(google3-legacy-absl-backports)
absl::optional<api::ble_v2::GattCharacteristic> GetCharacteristic(
const Uuid &service_uuid, const Uuid &characteristic_uuid) override
ABSL_LOCKS_EXCLUDED(characteristics_mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#readCharacteristic(android.bluetooth.BluetoothGattCharacteristic)
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#getValue()
// NOLINTNEXTLINE(google3-legacy-absl-backports)
absl::optional<std::string> ReadCharacteristic(
const api::ble_v2::GattCharacteristic &characteristic) override
ABSL_LOCKS_EXCLUDED(characteristics_mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[])
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic)
//
// Sends a remote characteristic write request to the server and returns
// whether or not it was successful.
bool WriteCharacteristic(
const api::ble_v2::GattCharacteristic &characteristic,
absl::string_view value, WriteType type) override
ABSL_LOCKS_EXCLUDED(characteristics_mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic,%20boolean)
//
// Enable or disable notifications/indications for a given characteristic.
bool SetCharacteristicSubscription(
const api::ble_v2::GattCharacteristic &characteristic, bool enable,
absl::AnyInvocable<void(absl::string_view value)>
on_characteristic_changed_cb) override
ABSL_LOCKS_EXCLUDED(characteristics_mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#disconnect()
void Disconnect() override;
private:
std::shared_ptr<sdbus::IConnection> system_bus_;
sdbus::ObjectPath peripheral_object_path_;
std::shared_ptr<BluezGattDiscovery> gatt_discovery_;
absl::Mutex disconnected_callback_mutex_;
BluezGattDiscovery::CallbackIter disconnected_callback_it_
ABSL_GUARDED_BY(disconnected_callback_mutex_);
CancellationFlag discovery_cancel_;
using CharacteristicProxy =
std::variant<std::unique_ptr<bluez::GattCharacteristicClient>,
std::unique_ptr<bluez::SubscribedGattCharacteristicClient>>;
absl::Mutex characteristics_mutex_;
absl::flat_hash_map<api::ble_v2::GattCharacteristic, CharacteristicProxy>
characteristics_ ABSL_GUARDED_BY(characteristics_mutex_);
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,156 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/ble_gatt_server.h"
#include "absl/strings/substitute.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluez_gatt_characteristic_server.h"
#include "internal/platform/implementation/linux/bluez_gatt_manager.h"
#include "internal/platform/implementation/linux/bluez_gatt_service_server.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
absl::optional<api::ble_v2::GattCharacteristic>
GattServer::CreateCharacteristic(
const Uuid& service_uuid, const Uuid& characteristic_uuid,
api::ble_v2::GattCharacteristic::Permission permission,
api::ble_v2::GattCharacteristic::Property property) {
absl::MutexLock lock(&services_mutex_);
if (services_.count(service_uuid) == 1) {
if (services_[service_uuid]->AddCharacteristic(
service_uuid, characteristic_uuid, permission, property)) {
api::ble_v2::GattCharacteristic characteristic{
characteristic_uuid, service_uuid, permission, property};
return characteristic;
}
return std::nullopt;
}
auto count = services_.size();
auto service = std::make_unique<bluez::GattServiceServer>(
system_bus_, count, service_uuid, server_cb_, devices_);
try {
service->emitInterfacesAddedSignal(
{org::bluez::GattService1_adaptor::INTERFACE_NAME});
} catch (const sdbus::Error& e) {
LOG(ERROR)
<< __func__
<< ": error emitting InterfacesAdded signal for object path "
<< service->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
return std::nullopt;
}
auto profile = std::make_unique<bluez::GattProfile> (system_bus_, bluez::gatt_profile_object_path(
std::string(service_uuid)), std::string(service_uuid));
profile -> emitInterfacesAddedSignal();
if (service->AddCharacteristic(service_uuid, characteristic_uuid, permission,
property)) {
try {
LOG(INFO)<< __func__ << ": Registering service on gattmanager with characteristic_uuid: "
<< std::string(characteristic_uuid) << " and service_uuid: " << std::string(service_uuid);
gatt_manager_ -> RegisterApplication(gatt_service_root_object_manager -> getObjectPath(), {});
} catch (const sdbus::Error& e) {
LOG(ERROR)
<< __func__
<< ": error calling RegisterAplication for GattManager with object path "
<< gatt_manager_->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
return std::nullopt;
}
services_.insert({service_uuid, std::move(service)});
api::ble_v2::GattCharacteristic characteristic{
characteristic_uuid, service_uuid, permission, property};
return characteristic;
}
return std::nullopt;
}
bool GattServer::UpdateCharacteristic(
const api::ble_v2::GattCharacteristic& characteristic,
const nearby::ByteArray& value) {
std::shared_ptr<bluez::GattCharacteristicServer> chr = nullptr;
{
absl::ReaderMutexLock lock(&services_mutex_);
if (services_.count(characteristic.service_uuid) == 0) {
LOG(ERROR) << __func__ << ": GATT Service "
<< std::string{characteristic.service_uuid}
<< " doesn't exist";
return false;
}
chr = services_[characteristic.service_uuid]->GetCharacteristic(
characteristic.uuid);
}
if (chr == nullptr) {
LOG(ERROR) << __func__ << ": Characteristic "
<< std::string{characteristic.uuid}
<< " does not exist under service "
<< std::string{characteristic.service_uuid};
return false;
}
assert(chr != nullptr);
chr->Update(value);
return true;
}
absl::Status GattServer::NotifyCharacteristicChanged(
const api::ble_v2::GattCharacteristic& characteristic, bool confirm,
const ByteArray& new_value) {
std::shared_ptr<bluez::GattCharacteristicServer> chr = nullptr;
{
absl::ReaderMutexLock lock(&services_mutex_);
if (services_.count(characteristic.service_uuid) == 0) {
return absl::NotFoundError(
absl::Substitute("Service $0 doesn't exist",
std::string{characteristic.service_uuid}));
}
chr = services_[characteristic.service_uuid]->GetCharacteristic(
characteristic.uuid);
}
if (chr == nullptr) {
return absl::NotFoundError(
absl::Substitute("characteristic $0 doesn't exist under service $1",
std::string{characteristic.uuid},
std::string{characteristic.service_uuid}));
}
return chr->NotifyChanged(confirm, new_value);
}
void GattServer::Stop() {
bluez::GattManager manager(system_bus_, adapter_.GetObjectPath());
absl::MutexLock lock(&services_mutex_);
for (auto& [uuid, service] : services_) {
LOG(INFO) << __func__ << ": Unregistering service "
<< service->getObjectPath();
try {
manager.UnregisterApplication("/");
} catch (const sdbus::Error& e) {
DBUS_LOG_METHOD_CALL_ERROR(&manager, "UnregisterApplication", e);
}
}
// services_.clear();
}
} // namespace linux
} // namespace nearby
@@ -1,105 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLE_GATT_SERVER_H_
#define PLATFORM_IMPL_LINUX_API_BLE_GATT_SERVER_H_
#include <memory>
#include <regex>
#include <sdbus-c++/IConnection.h>
#include "bluez_gatt_manager.h"
#include "bluez_gatt_profile.h"
#include "absl/container/flat_hash_map.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/optional.h"
#include "internal/platform/bluetooth_utils.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_devices.h"
#include "internal/platform/implementation/linux/bluez_gatt_service_server.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
class LocalBlePeripheral : public api::ble_v2::BlePeripheral {
public:
explicit LocalBlePeripheral(BluetoothAdapter& adapter) : adapter_(adapter) {
// temp fix till everything transitions to GGetAddress()
unique_id_ = std::stoull(std::regex_replace(adapter_.GetMacAddress(),
std::regex("[:\\-]"), ""), nullptr, 16);
}
std::string GetAddress() const override { return adapter_.GetMacAddress(); }
UniqueId GetUniqueId() const override { return unique_id_; }
private:
BluetoothAdapter adapter_;
UniqueId unique_id_;
};
class GattServer : public api::ble_v2::GattServer {
public:
GattServer(const GattServer&) = delete;
GattServer(GattServer&&) = delete;
GattServer& operator=(const GattServer&) = delete;
GattServer& operator=(GattServer&&) = delete;
explicit GattServer(sdbus::IConnection& system_bus, BluetoothAdapter& adapter,
std::shared_ptr<BluetoothDevices> devices,
api::ble_v2::ServerGattConnectionCallback server_cb)
: system_bus_(system_bus),
devices_(std::move(devices)),
adapter_(adapter),
local_peripheral_(adapter_),
gatt_service_root_object_manager(std::make_unique<RootObjectManager>(system_bus_, "/com/google/nearby/medium/ble/gatt")),
gatt_manager_(std::make_unique<bluez::GattManager>(system_bus_, adapter_.GetObjectPath())),
server_cb_(std::make_shared<api::ble_v2::ServerGattConnectionCallback>(
std::move(server_cb))) {}
~GattServer() override = default;
absl::optional<api::ble_v2::GattCharacteristic> CreateCharacteristic(
const Uuid& service_uuid, const Uuid& characteristic_uuid,
api::ble_v2::GattCharacteristic::Permission permission,
api::ble_v2::GattCharacteristic::Property property) override;
bool UpdateCharacteristic(
const api::ble_v2::GattCharacteristic& characteristic,
const nearby::ByteArray& value) override;
absl::Status NotifyCharacteristicChanged(
const api::ble_v2::GattCharacteristic& characteristic, bool confirm,
const ByteArray& new_value) override;
void Stop() override;
private:
sdbus::IConnection& system_bus_;
std::shared_ptr<BluetoothDevices> devices_;
BluetoothAdapter adapter_;
LocalBlePeripheral local_peripheral_;
std::unique_ptr<RootObjectManager> gatt_service_root_object_manager;
absl::Mutex profiles_mutex_;
absl::flat_hash_map<Uuid, std::unique_ptr<bluez::GattProfile>> gatt_profiles_;
ABSL_GUARDED_BY(profiles_mutex_)
std::unique_ptr<bluez::GattManager> gatt_manager_;
std::shared_ptr<api::ble_v2::ServerGattConnectionCallback> server_cb_;
absl::Mutex services_mutex_;
absl::flat_hash_map<Uuid, std::unique_ptr<bluez::GattServiceServer>> services_
ABSL_GUARDED_BY(services_mutex_);
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,184 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/ble_l2cap_server_socket.h"
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include "internal/platform/logging.h"
#include "internal/platform/prng.h"
namespace nearby {
namespace linux {
BleL2capServerSocket::BleL2capServerSocket() : psm_(0) {}
BleL2capServerSocket::BleL2capServerSocket(int psm) : psm_(psm) {
}
BleL2capServerSocket::~BleL2capServerSocket() { Close(); }
void BleL2capServerSocket::SetPSM(int psm) { psm_ = psm; }
std::unique_ptr<api::ble_v2::BleL2capSocket> BleL2capServerSocket::Accept() {
if (stopped_.Cancelled()) {
LOG(ERROR) << __func__ << ": server socket has been stopped";
return nullptr;
}
absl::MutexLock lock(&mutex_);
Prng prng;
psm_ = 0x80 + (prng.NextUint32() % 0x80);
server_fd_ = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
int rcv = 1 << 20; // 1 MiB (kernel may clamp)
int snd = 1 << 20;
int err2 = setsockopt(server_fd_, SOL_SOCKET, SO_RCVBUF, &rcv, sizeof(rcv));
int err3 = setsockopt(server_fd_, SOL_SOCKET, SO_SNDBUF, &snd, sizeof(snd));
LOG(INFO) << __func__ << ": Using server_fd: " << server_fd_;
if (server_fd_ < 0 or err2 == -1 or err3 == -1) {
LOG(ERROR) << "Failed to create L2CAP server socket: "
<< std::strerror(errno);
return nullptr;
}
struct sockaddr_l2 addr;
std::memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(psm_);
addr.l2_cid = 0;
addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
// Set BDADDR_ANY (all zeros)
std::memset(&addr.l2_bdaddr, 0, sizeof(addr.l2_bdaddr));
if (bind(server_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
LOG(ERROR) << "Failed to bind L2CAP server socket: "
<< std::strerror(errno) << " (errno: " << errno << ")";
close(server_fd_);
server_fd_ = -1;
return nullptr;
}
if (listen(server_fd_, 5) < 0) {
LOG(ERROR) << "Failed to listen on L2CAP server socket: "
<< std::strerror(errno);
close(server_fd_);
server_fd_ = -1;
return nullptr;
}
socklen_t addr_len = sizeof(addr);
if (getsockname(server_fd_, (struct sockaddr*)&addr, &addr_len) == 0) {
psm_ = btohs(addr.l2_psm);
LOG(INFO) << "L2CAP server socket listening on PSM: " << psm_;
} else {
LOG(ERROR) << "Failed to get socket name: " << std::strerror(errno);
}
// // Return cached socket if it exists
// auto it = accepted_fds_.find(server_fd_);
// if (it != accepted_fds_.end()) {
// LOG(INFO) << __func__ << ": Socket exists. Returning cached socket";
// return std::make_unique<BleL2capSocket>(it->second.first, it->second.second); // I hate how this looks
// }
if (server_fd_ < 0) {
LOG(ERROR) << "Server socket not initialized";
return nullptr;
}
// Release the mutex while waiting for incoming connection
mutex_.Unlock();
struct sockaddr_l2 client_addr;
socklen_t client_len = sizeof(client_addr);
std::memset(&client_addr, 0, sizeof(client_addr));
LOG(INFO) << "Waiting for L2CAP connection on PSM " << psm_ << "...";
int client_fd = accept(server_fd_, (struct sockaddr*)&client_addr, &client_len);
// Re-acquire the mutex
mutex_.Lock();
if (client_fd < 0) {
if (errno == EINTR || errno == EAGAIN) {
LOG(WARNING) << "Accept interrupted, returning nullptr";
return nullptr;
}
LOG(ERROR) << "Failed to accept L2CAP connection: " << std::strerror(errno);
return nullptr;
}
if (closed_) {
close(client_fd);
return nullptr;
}
char client_addr_str[18];
ba2str(&client_addr.l2_bdaddr, client_addr_str);
LOG(INFO) << "Accepted L2CAP connection from " << client_addr_str
<< " on PSM " << btohs(client_addr.l2_psm);
LOG(INFO) << __func__ << ": Connected to client_fd: " << client_fd;
// Create a unique ID from the MAC address
api::ble_v2::BlePeripheral::UniqueId peripheral_id = 0;
for (int i = 0; i < 6; i++) {
peripheral_id = (peripheral_id << 8) | client_addr.l2_bdaddr.b[i];
}
accepted_fds_.emplace(server_fd_, std::pair(client_fd, peripheral_id));
return std::make_unique<BleL2capSocket>(client_fd, peripheral_id);
}
Exception BleL2capServerSocket::Close() {
LOG(ERROR) << __func__ << ": closing bluetooth server socket";
stopped_.Cancel();
return DoClose();
}
Exception BleL2capServerSocket::DoClose() {
closed_ = true;
if (server_fd_ >= 0) {
shutdown(server_fd_, SHUT_RDWR);
close(server_fd_);
server_fd_ = -1;
}
if (close_notifier_) {
auto notifier = std::move(close_notifier_);
mutex_.Unlock();
notifier();
mutex_.Lock();
}
return {Exception::kSuccess};
}
void BleL2capServerSocket::SetCloseNotifier(
absl::AnyInvocable<void()> notifier) {
absl::MutexLock lock(&mutex_);
close_notifier_ = std::move(notifier);
}
} // namespace linux
} // namespace nearby
@@ -1,65 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLE_L2CAP_SERVER_SOCKET_H_
#define PLATFORM_IMPL_LINUX_BLE_L2CAP_SERVER_SOCKET_H_
#include <memory>
#include <sdbus-c++/Types.h>
#include "absl/functional/any_invocable.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/ble_l2cap_socket.h"
#include "absl/container/flat_hash_map.h"
namespace nearby {
namespace linux {
class BleL2capServerSocket final : public api::ble_v2::BleL2capServerSocket {
public:
BleL2capServerSocket();
explicit BleL2capServerSocket(int psm);
~BleL2capServerSocket() override;
int GetPSM() const override { return psm_; }
void SetPSM(int psm);
std::unique_ptr<api::ble_v2::BleL2capSocket> Accept() override
ABSL_LOCKS_EXCLUDED(mutex_);
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
void SetCloseNotifier(absl::AnyInvocable<void()> notifier)
ABSL_LOCKS_EXCLUDED(mutex_);
private:
Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable absl::Mutex mutex_;
absl::CondVar cond_;
absl::AnyInvocable<void()> close_notifier_ ABSL_GUARDED_BY(mutex_);
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
int psm_ = 0;
int server_fd_ ABSL_GUARDED_BY(mutex_) = -1;
CancellationFlag stopped_;
// <server_fd, <client_fd, peripheral_id>>
absl::flat_hash_map<int, std::pair<int,api::ble_v2::BlePeripheral::UniqueId>> accepted_fds_ ABSL_GUARDED_BY(mutex_);
};
} // namespace linux
} // namespace nearby
#endif // PLATFORM_IMPL_LINUX_BLE_L2CAP_SERVER_SOCKET_H_
@@ -1,364 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/ble_l2cap_socket.h"
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <bluetooth/bluetooth.h>
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/logging.h"
#include <sys/ioctl.h>
#include "bluetooth_classic_socket.h"
namespace nearby {
namespace linux {
namespace {
constexpr size_t kLogMaxBytes = 64;
constexpr size_t kDefaultBleL2capMtu = 23;
size_t GetSocketMtu(int fd, int option_name) {
uint16_t mtu = 0;
socklen_t len = sizeof(mtu);
if (getsockopt(fd, SOL_BLUETOOTH, option_name, &mtu, &len) == 0 &&
mtu > 0) {
return static_cast<size_t>(mtu);
}
return 0;
}
std::string HexPreview(const char* data, size_t size) {
size_t count = std::min(size, kLogMaxBytes);
std::string hex =
absl::BytesToHexString(absl::string_view(data, count));
if (size > count) {
hex.append("...");
}
return hex;
}
size_t GetL2capOutputMtu(int fd) {
struct l2cap_options opts;
size_t mtu = GetSocketMtu(fd, BT_SNDMTU);
if (mtu > 0) {
return mtu;
}
return kDefaultBleL2capMtu;
}
Exception PollSocket(int fd, short event) {
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = event;
while (true) {
int ret = poll(fds, 1, -1);
if (ret < 0) {
if (errno == EINTR) continue;
LOG(ERROR) << "Error polling L2CAP socket: " << std::strerror(errno);
return {Exception::kIo};
}
if ((fds[0].revents & event) != 0) {
return {Exception::kSuccess};
}
if ((fds[0].revents & POLLHUP) != 0) {
LOG(ERROR) << "L2CAP socket disconnected";
return {Exception::kIo};
}
if ((fds[0].revents & (POLLERR | POLLNVAL)) != 0) {
LOG(ERROR) << "Error occurred on L2CAP socket";
return {Exception::kIo};
}
}
}
} // namespace
BleL2capInputStream::BleL2capInputStream(int fd) : fd_(fd) {}
BleL2capInputStream::~BleL2capInputStream() { Close(); }
static size_t GetBleCocRcvMtu(int fd) {
// Prefer BT_RCVMTU for LE CoC, but fall back to L2CAP_OPTIONS if needed.
uint16_t mtu = 0;
socklen_t len = sizeof(mtu);
if (getsockopt(fd, SOL_BLUETOOTH, BT_RCVMTU, &mtu, &len) == 0 && mtu > 0)
return mtu;
// Fallback ONLY (avoid 23 unless you're sure; 23 causes truncation if peer sends bigger SDUs).
return 512;
}
static size_t NextPacketSize(int fd) {
int pending = 0;
if (ioctl(fd, FIONREAD, &pending) == 0 && pending > 0) {
return static_cast<size_t>(pending);
}
return 0; // unknown
}
ExceptionOr<ByteArray> BleL2capInputStream::Read(std::int64_t size) {
int fd = fd_.load();
if (fd < 0) return Exception{Exception::kIo};
auto poller = Poller::CreateInputPoller(fd);
// Wait for readability
while (true) {
if (fd_.load() != fd) return {Exception::kIo};
auto result = poller.Ready();
if (result.Raised()) return result;
if (fd_.load() != fd) return {Exception::kIo};
// Peek the next message length without consuming it.
// For seqpacket/dgram, MSG_TRUNC makes recv() return the *full* message length
// even if the buffer is smaller.
ssize_t msg_len = ::recv(fd, nullptr, 0, MSG_PEEK | MSG_TRUNC);
if (msg_len < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
if (errno == EBADF) {
LOG(INFO) << __func__ << ": socket was closed during read";
return {Exception::kIo};
}
LOG(ERROR) << __func__ << ": error peeking message length: "
<< std::strerror(errno);
return {Exception::kIo};
}
if (msg_len == 0) {
LOG(INFO) << __func__ << ": socket closed (EOF)";
return {Exception::kIo};
}
// Decide how much we will actually read/return.
// If caller asked for 'size', cap to that.
size_t want = static_cast<size_t>(msg_len);
size_t cap = static_cast<size_t>(size);
size_t to_read = std::min(want, cap);
std::string buffer;
buffer.resize(to_read);
// Now read/consume the message. If the message is larger than to_read,
// the remainder will be discarded by the kernel for seqpacket/dgram.
// We can detect that and treat it as an error (or choose a different policy).
if (fd_.load() != fd) return {Exception::kIo};
ssize_t n = ::recv(fd, buffer.data(), to_read, 0);
if (n < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
if (errno == EBADF) {
LOG(INFO) << __func__ << ": socket was closed during read";
return {Exception::kIo};
}
LOG(ERROR) << __func__ << ": error reading data on bluetooth socket: "
<< std::strerror(errno);
return {Exception::kIo};
}
if (n == 0) {
LOG(INFO) << __func__ << ": socket closed (EOF)";
return {Exception::kIo};
}
buffer.resize(static_cast<size_t>(n));
// Detect truncation: if msg_len > size, we truncated/discarded remainder.
if (want > cap) {
LOG(ERROR) << __func__
<< ": incoming packet (" << want
<< " bytes) exceeds requested size (" << cap
<< "). Packet truncated.";
return {Exception::kIo};
}
return ExceptionOr{ByteArray(std::move(buffer))};
}
}
Exception BleL2capInputStream::Close() {
int fd = fd_.exchange(-1);
if (fd < 0) return {Exception::kSuccess}; // Already closed
::shutdown(fd, SHUT_RDWR);
return {Exception::kSuccess};
}
BleL2capOutputStream::BleL2capOutputStream(int fd) : fd_(fd) {}
BleL2capOutputStream::~BleL2capOutputStream() { Close(); }
Exception BleL2capOutputStream::Write(const ByteArray& data) {
int fd = fd_.load();
if (fd < 0) return Exception{Exception::kIo};
auto poller = Poller::CreateOutputPoller(fd);
size_t total_wrote = 0;
if (data.Empty()) {
return {Exception::kSuccess};
}
size_t max_chunk_size = GetL2capOutputMtu(fd);
if (max_chunk_size == 0) {
max_chunk_size = kDefaultBleL2capMtu;
}
LOG(INFO) << "BleL2capOutputStream::Write bytes=" << data.size()
<< " mtu=" << max_chunk_size << " data=0x"
<< HexPreview(data.data(), data.size());
while (total_wrote < data.size()) {
if (fd_.load() != fd) return {Exception::kIo};
auto result = poller.Ready(); // should wait for POLLOUT/EPOLLOUT
if (result.Raised()) return result;
if (fd_.load() != fd) return {Exception::kIo};
const char *buf = data.data();
size_t remaining = data.size() - total_wrote;
size_t to_write = remaining;
{
// For SEQPACKET/DGRAM, one send() == one packet.
// Cap to discovered “MTU-like” limit to avoid EMSGSIZE.
absl::MutexLock lock(&fd_mutex_);
to_write = std::min(to_write, max_chunk_size);
}
// Prefer send() to avoid SIGPIPE (MSG_NOSIGNAL is Linux).
ssize_t wrote = ::send(fd,
buf + total_wrote,
to_write,
#ifdef MSG_NOSIGNAL
MSG_NOSIGNAL
#else
0
#endif
);
// If send() isnt appropriate in your environment, you can swap back to write().
// ssize_t wrote = ::write(fd_.get(), buf + total_wrote, to_write);
if (wrote < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
if (errno == EMSGSIZE) {
// Our packet is too large; shrink max_chunk_ and retry.
{
absl::MutexLock lock(&fd_mutex_);
if (max_chunk_size > 1) {
max_chunk_size = std::max<size_t>(1, max_chunk_size / 2);
LOG(INFO) << __func__ << ": EMSGSIZE; reducing max_chunk_ to "
<< max_chunk_size;
continue; // retry with smaller chunk
}
}
LOG(ERROR) << __func__ << ": EMSGSIZE even at 1 byte";
return {Exception::kIo};
}
if (errno == EBADF || errno == EPIPE) {
LOG(INFO) << __func__ << ": socket was closed during write";
return {Exception::kIo};
}
LOG(ERROR) << __func__
<< ": error writing data on bluetooth socket: "
<< std::strerror(errno);
return {Exception::kIo};
}
if (wrote == 0) {
// For sockets, 0 usually means peer closed.
LOG(INFO) << __func__ << ": peer closed during write";
return {Exception::kIo};
}
total_wrote += static_cast<size_t>(wrote);
}
return {Exception::kSuccess};
}
Exception BleL2capOutputStream::Close() {
int fd = fd_.exchange(-1);
if (fd < 0) return {Exception::kSuccess}; // Already closed
::shutdown(fd, SHUT_RDWR);
return {Exception::kSuccess};
}
BleL2capSocket::BleL2capSocket(int fd,
api::ble_v2::BlePeripheral::UniqueId peripheral_id)
: peripheral_id_(peripheral_id),
input_stream_(std::make_unique<BleL2capInputStream>(fd)),
output_stream_(std::make_unique<BleL2capOutputStream>(fd))
{
LOG(INFO) << "fd_ " << fd;
LOG(INFO) << "input_stream_ :" << input_stream_.get();
LOG(INFO) << "output_stream_ :" << output_stream_.get();
struct l2cap_options opts;
size_t snd_mtu = GetSocketMtu(fd, BT_SNDMTU);
size_t rcv_mtu = GetSocketMtu(fd, BT_RCVMTU);
LOG(INFO) << "BleL2capSocket MTU fallback snd_mtu=" << snd_mtu
<< " rcv_mtu=" << rcv_mtu;
}
BleL2capSocket::~BleL2capSocket() { Close(); }
Exception BleL2capSocket::Close() {
absl::MutexLock lock(&mutex_);
if (closed_) {
return {Exception::kSuccess};
}
DoClose();
return {Exception::kSuccess};
}
void BleL2capSocket::DoClose() {
closed_ = true;
if (input_stream_) {
input_stream_->Close();
}
if (output_stream_) {
output_stream_->Close();
}
if (close_notifier_) {
auto notifier = std::move(close_notifier_);
mutex_.Unlock();
notifier();
mutex_.Lock();
}
}
void BleL2capSocket::SetCloseNotifier(absl::AnyInvocable<void()> notifier) {
absl::MutexLock lock(&mutex_);
close_notifier_ = std::move(notifier);
}
bool BleL2capSocket::IsClosed() const {
absl::MutexLock lock(&mutex_);
return closed_;
}
} // namespace linux
} // namespace nearby
@@ -1,88 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLE_L2CAP_SOCKET_H_
#define PLATFORM_IMPL_LINUX_BLE_L2CAP_SOCKET_H_
#include <atomic>
#include <memory>
#include "absl/functional/any_invocable.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace linux {
class BleL2capInputStream final : public InputStream {
public:
explicit BleL2capInputStream(int fd);
~BleL2capInputStream() override;
ExceptionOr<ByteArray> Read(std::int64_t size) override;
Exception Close() override;
private:
std::atomic<int> fd_{-1};
std::string pending_; // holds unread bytes from full SDUs
};
class BleL2capOutputStream final : public OutputStream {
public:
explicit BleL2capOutputStream(int fd);
~BleL2capOutputStream() override;
Exception Write(const ByteArray& data) override;
Exception Flush() override { return {Exception::kSuccess}; }
Exception Close() override;
private:
mutable absl::Mutex fd_mutex_;
std::atomic<int> fd_{-1};
};
class BleL2capSocket final : public api::ble_v2::BleL2capSocket {
public:
BleL2capSocket(int fd, api::ble_v2::BlePeripheral::UniqueId peripheral_id);
~BleL2capSocket() override;
InputStream& GetInputStream() override { return *input_stream_; }
OutputStream& GetOutputStream() override { return *output_stream_; }
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
void SetCloseNotifier(absl::AnyInvocable<void()> notifier) override
ABSL_LOCKS_EXCLUDED(mutex_);
api::ble_v2::BlePeripheral::UniqueId GetRemotePeripheralId() override {
return peripheral_id_;
}
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
private:
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable absl::Mutex mutex_;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
std::unique_ptr<BleL2capInputStream> input_stream_;
std::unique_ptr<BleL2capOutputStream> output_stream_;
api::ble_v2::BlePeripheral::UniqueId peripheral_id_;
absl::AnyInvocable<void()> close_notifier_ ABSL_GUARDED_BY(mutex_);
};
} // namespace linux
} // namespace nearby
#endif // PLATFORM_IMPL_LINUX_BLE_L2CAP_SOCKET_H_
@@ -1,117 +0,0 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/ble_l2cap_socket.h"
#include <sys/socket.h>
#include <unistd.h>
#include <string>
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "gtest/gtest.h"
namespace nearby {
namespace linux {
namespace {
class SocketPair final {
public:
SocketPair() {
int fds[2] = {-1, -1};
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
left_ = fds[0];
right_ = fds[1];
}
~SocketPair() {
if (left_ >= 0) close(left_);
if (right_ >= 0) close(right_);
}
int left() const { return left_; }
int right() const { return right_; }
void CloseRight() {
if (right_ >= 0) {
close(right_);
right_ = -1;
}
}
private:
int left_ = -1;
int right_ = -1;
};
TEST(BleL2capSocketTest, OutputStreamWritesData) {
SocketPair pair;
BleL2capSocket socket(pair.left(), /*peripheral_id=*/1);
ByteArray payload("hello");
Exception write_result = socket.GetOutputStream().Write(payload);
EXPECT_TRUE(write_result.Ok());
char buffer[5];
ssize_t bytes_read = recv(pair.right(), buffer, sizeof(buffer), 0);
ASSERT_EQ(bytes_read, sizeof(buffer));
EXPECT_EQ(std::string(buffer, sizeof(buffer)), "hello");
}
TEST(BleL2capSocketTest, InputStreamReadsData) {
SocketPair pair;
BleL2capSocket socket(pair.left(), /*peripheral_id=*/1);
const char* payload = "world";
ASSERT_EQ(send(pair.right(), payload, 5, 0), 5);
ExceptionOr<ByteArray> read_result = socket.GetInputStream().Read(5);
ASSERT_TRUE(read_result.ok());
EXPECT_EQ(read_result.result().string_data(), "world");
}
TEST(BleL2capSocketTest, InputStreamReturnsEmptyOnPeerClose) {
SocketPair pair;
BleL2capSocket socket(pair.left(), /*peripheral_id=*/1);
pair.CloseRight();
ExceptionOr<ByteArray> read_result = socket.GetInputStream().Read(4);
ASSERT_TRUE(read_result.ok());
EXPECT_TRUE(read_result.result().Empty());
}
TEST(BleL2capSocketTest, OutputStreamWriteFailsAfterClose) {
SocketPair pair;
BleL2capSocket socket(pair.left(), /*peripheral_id=*/1);
ASSERT_TRUE(socket.GetOutputStream().Close().Ok());
Exception write_result =
socket.GetOutputStream().Write(ByteArray("data"));
EXPECT_EQ(write_result.value, Exception::kIo);
}
TEST(BleL2capSocketTest, CloseNotifierInvoked) {
SocketPair pair;
BleL2capSocket socket(pair.left(), /*peripheral_id=*/1);
bool notified = false;
socket.SetCloseNotifier([&notified]() { notified = true; });
ASSERT_TRUE(socket.Close().Ok());
EXPECT_TRUE(notified);
}
} // namespace
} // namespace linux
} // namespace nearby
@@ -1,73 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLE_MEDIUM_H_
#define PLATFORM_IMPL_LINUX_API_BLE_MEDIUM_H_
#include "internal/platform/implementation/ble.h"
namespace nearby {
namespace linux {
// Container of operations that can be performed over the BLE medium.
class BleMedium : public api::BleMedium {
public:
BleMedium() {}
~BleMedium() = default;
bool StartAdvertising(
const std::string &service_id, const ByteArray &advertisement_bytes,
const std::string &fast_advertisement_service_uuid) override {
return false;
}
bool StopAdvertising(const std::string &service_id) override { return false; }
// Returns true once the BLE scan has been initiated.
bool StartScanning(const std::string &service_id,
const std::string &fast_advertisement_service_uuid,
DiscoveredPeripheralCallback callback) override {
return false;
}
// Returns true once BLE scanning for service_id is well and truly stopped;
// after this returns, there must be no more invocations of the
// DiscoveredPeripheralCallback passed in to StartScanning() for service_id.
bool StopScanning(const std::string &service_id) override { return false; }
// Callback that is invoked when a new connection is accepted.
using AcceptedConnectionCallback = absl::AnyInvocable<void(
api::BleSocket &socket, const std::string &service_id)>;
// Returns true once BLE socket connection requests to service_id can be
// accepted.
bool StartAcceptingConnections(const std::string &service_id,
AcceptedConnectionCallback callback) override {
return false;
}
bool StopAcceptingConnections(const std::string &service_id) override {
return false;
}
// Connects to a BLE peripheral.
// On success, returns a new BleSocket.
// On error, returns nullptr.
std::unique_ptr<api::BleSocket> Connect(
api::BlePeripheral &peripheral, const std::string &service_id,
CancellationFlag *cancellation_flag) override {
return nullptr;
}
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,611 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <array>
#include <cassert>
#include <cerrno>
#include <cstring>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.h>
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble_v2.h"
// #include "internal/platform/implementation/linux/ble_gatt_client.h"
// #include "internal/platform/implementation/linux/ble_gatt_server.h"
#include "internal/platform/implementation/linux/ble_v2_medium.h"
#include "ble_gatt_client.h"
#include "ble_gatt_server.h"
#include "ble_l2cap_server_socket.h"
#include "ble_l2cap_socket.h"
#include "bluez_le_bearer_client.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/mac_address.h"
#include "internal/platform/prng.h"
#include "absl/types/span.h"
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
#include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h"
#include "internal/platform/implementation/linux/bluez_le_advertisement.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h"
namespace nearby {
namespace linux {
BleV2Medium::BleV2Medium(BluetoothAdapter &adapter)
: system_bus_(adapter.GetConnection()),
adapter_(adapter),
devices_(std::make_unique<BluetoothDevices>(
system_bus_, adapter_.GetObjectPath(), observers_)),
// gatt_discovery_(std::make_shared<BluezGattDiscovery>(system_bus_)),
root_object_manager_(std::make_unique<RootObjectManager>(*system_bus_, "/com/google/nearby/medium/ble/advertisement/monitor")),
adv_monitor_manager_(
bluez::AdvertisementMonitorManager::
DiscoverAdvertisementMonitorManager(*system_bus_, adapter_)),
adv_manager_(std::make_unique<bluez::LEAdvertisementManager>(*system_bus_,
adapter)),
cur_adv_(nullptr) {
if (adv_monitor_manager_) {
LOG(INFO)
<< __func__
<< ": Registering path /com/google/nearby/medium/ble/advertisement/monitor with AdvertisementMonitorManager at "
<< adv_monitor_manager_->getObjectPath();
try {
adv_monitor_manager_->RegisterMonitor(root_object_manager_->getObjectPath());
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(adv_monitor_manager_, "RegisterMonitor", e);
}
}
// if (gatt_discovery_->InitializeKnownServices()) {
// LOG(ERROR) << __func__
// << ": Could not initialize known GATT services";
// }
}
// sync api
// called twice. Once with extended regular advertisement ( when IsExtendedAdvertisementsAvailable() == true )
// and another for GATT-backed header advertisement for legacy devices
bool BleV2Medium::StartAdvertising(
const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters) {
if (!advertising_data.is_extended_advertisement)
{
// can't send two LE advertisements at the same
return true;
}
if (!adapter_.IsEnabled()) {
LOG(WARNING) << "BLE cannot start advertising because the "
"bluetooth adapter is not enabled.";
return false;
}
if (advertising_data.service_data.empty()) {
LOG(WARNING)
<< "BLE cannot start to advertise due to invalid service data.";
return false;
}
absl::MutexLock l (&advs_mutex_);
advs_.push_front(bluez::LEAdvertisement::CreateLEAdvertisement(
*system_bus_, advertising_data, advertise_set_parameters));
auto it = advs_.begin();
LOG(INFO) << __func__ << ": Registering advertisement, is_extended: " << advertising_data.is_extended_advertisement
<< " " << (*it) -> getObjectPath() << " on bluetooth adapter "
<< adapter_.GetObjectPath();
try {
adv_manager_->RegisterAdvertisement((*it)->getObjectPath(), {});
} catch (const sdbus::Error &e) {
advs_.erase(it);
DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "RegisterAdvertisement", e);
return false;
}
return true;
}
bool BleV2Medium::StopAdvertising() {
absl::MutexLock l(&advs_mutex_);
try {
for (auto& adv: advs_)
{
adv_manager_->UnregisterAdvertisement(adv->getObjectPath());
}
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "UnregisterAdvertisement", e);
return false;
}
advs_.clear();
return true;
}
//async api
// this doesn't run. wonder why
std::unique_ptr<api::ble_v2::BleMedium::AdvertisingSession>
BleV2Medium::StartAdvertising(
const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters,
AdvertisingCallback callback) {
if (!adapter_.IsEnabled()) {
LOG(WARNING) << ": BLE cannot start advertising because the "
"bluetooth adapter is not enabled.";
return nullptr;
}
if (advertising_data.service_data.empty()) {
LOG(WARNING)
<< ": BLE cannot start to advertise due to invalid service data.";
return nullptr;
}
std::shared_ptr<sdbus::IProxy> proxy =
sdbus::createProxy(*system_bus_, "org.bluez", adapter_.GetObjectPath());
proxy->finishRegistration();
std::shared_ptr<AdvertisingCallback> shared_cb =
std::make_shared<AdvertisingCallback>(std::move(callback));
absl::MutexLock lock(&advs_mutex_);
advs_.push_front(bluez::LEAdvertisement::CreateLEAdvertisement(
*system_bus_, advertising_data, advertise_set_parameters));
auto adv_it = advs_.begin();
auto pending_call =
proxy->callMethodAsync("RegisterAdvertisement")
.onInterface(org::bluez::LEAdvertisingManager1_proxy::INTERFACE_NAME)
.withArguments((*adv_it)->getObjectPath(),
std::map<std::string, sdbus::Variant>{})
.uponReplyInvoke(
[this, proxy, shared_cb, adv_it](const sdbus::Error *error) {
if (error != nullptr && error->isValid()) {
{
absl::MutexLock lock(&advs_mutex_);
advs_.erase(adv_it);
}
DBUS_LOG_METHOD_CALL_ERROR(adv_manager_,
"RegisterAdvertisement", *error);
auto name = error->getName();
std::string msg = error->getMessage();
absl::Status status;
if (name == "org.bluez.Error.InvalidArguments" ||
name == "org.bluez.Error.InvalidLength") {
status = absl::InvalidArgumentError(msg);
} else if (name == "org.bluez.Error.AlreadyExists") {
status = absl::AlreadyExistsError(msg);
} else if (name == "org.bluez.Error.NotPermitted") {
status = absl::ResourceExhaustedError(msg);
} else {
status = absl::UnknownError(msg);
}
shared_cb->start_advertising_result(std::move(status));
} else {
shared_cb->start_advertising_result(absl::OkStatus());
}
});
absl::AnyInvocable<absl::Status()> stop_adv = [&, adv_it]() {
LOG(INFO) << __func__ << ": Unregistering advertisement object "
<< (*adv_it)->getObjectPath();
absl::MutexLock lock(&advs_mutex_);
try {
adv_manager_->UnregisterAdvertisement((*adv_it)->getObjectPath());
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "UnregisterAdvertisement", e);
return absl::UnknownError(e.getMessage());
}
advs_.erase(adv_it);
return absl::OkStatus();
};
return std::make_unique<api::ble_v2::BleMedium::AdvertisingSession>(
api::ble_v2::BleMedium::AdvertisingSession{std::move(stop_adv)});
}
std::unique_ptr<api::ble_v2::GattServer> BleV2Medium::StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) {
(void)callback;
return nullptr;
return std::make_unique<GattServer>(
*system_bus_, adapter_, devices_,std::move(callback)
);
}
std::unique_ptr<api::ble_v2::GattClient> BleV2Medium::ConnectToGattServer(
api::ble_v2::BlePeripheral::UniqueId peripheral_id,
api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::ClientGattConnectionCallback callback) {
(void)peripheral_id;
(void)tx_power_level;
(void)callback;
LOG(WARNING) << __func__
<< ": GATT client connection is not supported on Linux yet.";
return nullptr;
}
// This is supposed to be for a socket on top of Weave protocol.
std::unique_ptr<api::ble_v2::BleSocket> BleV2Medium::Connect(
const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BlePeripheral::UniqueId peripheral_id,
CancellationFlag *cancellation_flag) {
LOG(INFO) << __func__ << ": Not implemented on linux ";
return nullptr;
}
bool BleV2Medium::IsExtendedAdvertisementsAvailable() {
try {
auto supported_channels = adv_manager_->SupportedSecondaryChannels();
return !supported_channels.empty();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(adv_manager_, "SupportedSecondaryChannels", e);
return false;
}
}
bool BleV2Medium::StartLEDiscovery() {
std::map<std::string, sdbus::Variant> filter;
filter["Transport"] = "auto";
filter["DuplicateData"] = true;
auto &adapter = adapter_.GetBluezAdapterObject();
try {
adapter.SetDiscoveryFilter(filter);
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e);
return false;
}
try {
LOG(INFO) << __func__ << ": Starting LE discovery on "
<< adapter.getObjectPath();
adapter.StartDiscovery();
} catch (const sdbus::Error &e) {
if (e.getName() != "org.bluez.Error.InProgress") {
DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e);
return false;
}
}
return true;
}
bool BleV2Medium::StartScanning(const Uuid &service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
ScanCallback callback) {
if (cur_monitored_service_uuid_.has_value()) {
LOG(ERROR) << __func__
<< ": A sync scanning session is already active for "
<< std::string{*cur_monitored_service_uuid_};
return false;
}
if (adv_monitor_manager_ == nullptr) {
LOG(WARNING) << __func__
<< ": Advertising monitor not supported by BlueZ";
// TODO: Implement manual monitoring.
return false;
}
if (!MonitorManagerSupportsOr()) {
LOG(WARNING)
<< __func__
<< ": \"or_patterns\" not supported by AdvertisementMonitorManager";
// TODO: Implement manual monitoring.
return false;
}
absl::MutexLock lock(&active_adv_monitors_mutex_);
if (active_adv_monitors_.count(service_uuid) == 1) {
LOG(ERROR) << __func__ << ": an advertising session for service "
<< std::string{service_uuid} << " already exists";
return false;
}
auto monitor = std::make_unique<bluez::AdvertisementMonitor>(
*system_bus_, service_uuid, tx_power_level, "or_patterns", devices_,
std::move(callback));
try {
// why is this emitted?
monitor->emitInterfacesAddedSignal(
{org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME});
// adv_monitor_manager_ -> RegisterMonitor(monitor -> getObjectPath());
LOG(INFO)<< __func__ << ": Registered advertisement monitor with path " << monitor -> getObjectPath();
} catch (const sdbus::Error &e) {
LOG(ERROR)
<< __func__
<< ": error emitting InterfacesAdded signal for object path "
<< monitor->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
return false;
}
auto device_watcher = std::make_unique<DeviceWatcher>(
*system_bus_, adapter_.GetObjectPath(), adapter_, devices_);
if (!StartLEDiscovery()) {
LOG(ERROR) << __func__
<< ": Could not start LE discovery on adapter "
<< adapter_.GetObjectPath();
device_watcher = nullptr;
try {
monitor->emitInterfacesRemovedSignal(
{org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME});
} catch (const sdbus::Error &e) {
LOG(ERROR)
<< __func__
<< ": error emitting InterfacesRemoved signal for object path "
<< monitor->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
}
return false;
}
LOG(INFO) << __func__ << " :Started monitoring for service UUID: " << std::string(service_uuid);
active_adv_monitors_[service_uuid] =
std::make_pair(std::move(monitor), std::move(device_watcher));
cur_monitored_service_uuid_ = service_uuid;
return true;
}
bool BleV2Medium::StopScanning() {
if (!cur_monitored_service_uuid_.has_value()) {
LOG(ERROR) << __func__
<< ": No sync scanning session is currently active.";
return false;
}
if (adv_monitor_manager_ == nullptr) {
// TODO: Implement manual monitoring.
return false;
}
auto &adapter = adapter_.GetBluezAdapterObject();
LOG(INFO) << __func__ << ": Stopping discovery for adapter "
<< adapter.getObjectPath();
try {
adapter.StopDiscovery(); // this will stop bluetooth classic discovery as well. do we want this?
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e);
}
absl::MutexLock lock(&active_adv_monitors_mutex_);
auto monitor_it = active_adv_monitors_.find(*cur_monitored_service_uuid_);
assert(monitor_it != active_adv_monitors_.end());
{
auto &[_uuid, session] = *monitor_it;
auto &[adv_monitor, _watcher] = session;
LOG(INFO) << __func__ << ": Removing advertising monitor "
<< adv_monitor->getObjectPath();
adv_monitor->emitInterfacesRemovedSignal(
{org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME});
}
active_adv_monitors_.erase(monitor_it);
cur_monitored_service_uuid_ = std::nullopt;
return true;
}
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession>
BleV2Medium::StartScanning(const Uuid &service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
ScanningCallback callback) {
if (adv_monitor_manager_ == nullptr) {
// TODO: Implement manual monitoring.
return nullptr;
}
absl::MutexLock lock(&active_adv_monitors_mutex_);
if (active_adv_monitors_.count(service_uuid) == 1) {
LOG(ERROR) << __func__ << ": Service " << std::string{service_uuid}
<< " is already being advertised";
return nullptr;
}
auto monitor = std::make_unique<bluez::AdvertisementMonitor>(
*system_bus_, service_uuid, tx_power_level, "or_patterns", devices_,
std::move(callback));
try {
monitor->emitInterfacesAddedSignal(
{org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME});
} catch (const sdbus::Error &e) {
LOG(ERROR)
<< __func__
<< ": error emitting InterfacesAdded signal for object path "
<< monitor->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
return nullptr;
}
auto device_watcher = std::make_unique<DeviceWatcher>(
*system_bus_, adapter_.GetObjectPath(),adapter_, devices_);
if (!StartLEDiscovery()) {
LOG(ERROR) << __func__
<< ": Could not start LE discovery on adapter "
<< adapter_.GetObjectPath();
try {
monitor->emitInterfacesRemovedSignal(
{org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME});
} catch (const sdbus::Error &e) {
LOG(ERROR)
<< __func__
<< ": error emitting InterfacesRemoved signal for object path "
<< monitor->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
}
return nullptr;
}
active_adv_monitors_[service_uuid] =
std::make_pair(std::move(monitor), std::move(device_watcher));
return std::make_unique<ScanningSession>(
ScanningSession{.stop_scanning = [this, service_uuid]() {
absl::MutexLock lock(&active_adv_monitors_mutex_);
if (active_adv_monitors_.count(service_uuid) == 0) {
LOG(ERROR)
<< __func__ << ": Advertising monitor for service "
<< std::string{service_uuid} << " does not exist anymore";
return absl::NotFoundError(
"Advertising monitor for this service does not exist");
}
auto &[monitor, watcher] = active_adv_monitors_[service_uuid];
try {
monitor->emitInterfacesRemovedSignal(
{org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME});
} catch (const sdbus::Error &e) {
LOG(ERROR)
<< __func__
<< ": error emitting InterfacesRemoved signal for object path "
<< monitor->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
}
auto &adapter = adapter_.GetBluezAdapterObject();
absl::Status status;
try {
adapter.StopDiscovery();
status = absl::OkStatus();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e);
status = absl::InternalError(e.getMessage());
}
active_adv_monitors_.erase(service_uuid);
return status;
}});
}
std::unique_ptr<api::ble_v2::BleServerSocket> BleV2Medium::OpenServerSocket(
const std::string &service_id) {
LOG(INFO) << __func__ << ": Opening BLE server socket for service "
<< service_id;
return std::make_unique<BleV2ServerSocket>(service_id);
}
std::unique_ptr<api::ble_v2::BleL2capServerSocket>
BleV2Medium::OpenL2capServerSocket(const std::string &service_id) {
LOG(INFO) << __func__ << ": Opening L2CAP server socket for service "
<< service_id;
Prng prng;
auto psm = 0x80 + (prng.NextUint32() % 0x80);
auto server_socket = std::make_unique<linux::BleL2capServerSocket>(psm);
LOG(INFO) << __func__ << ": L2CAP server socket created with PSM: "
<< server_socket->GetPSM();
return server_socket;
}
// std::unique_ptr<api::ble_v2::BleSocket> BleV2Medium::Connect(
// const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level,
// api::ble_v2::BlePeripheral &peripheral,
// CancellationFlag *cancellation_flag) {
// LOG(WARNING) << __func__ << ": BLE socket connections not implemented on Linux";
// return nullptr;
// }
std::unique_ptr<api::ble_v2::BleL2capSocket> BleV2Medium::ConnectOverL2cap(
int psm, const std::string &service_id,
api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BlePeripheral::UniqueId peripheral_id,
CancellationFlag *cancellation_flag) {
auto device = devices_->get_device_by_unique_id(peripheral_id);
if (!device) {
LOG(ERROR) << __func__ << ": Failed to find device with unique ID "
<< peripheral_id;
return nullptr;
}
LOG(INFO) << __func__ << ": Connecting to L2CAP PSM " << psm
<< " on device " << device->GetMacAddress();
int fd = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (fd < 0) {
LOG(ERROR) << __func__ << ": Failed to create L2CAP socket: "
<< std::strerror(errno);
return nullptr;
}
struct sockaddr_l2 addr;
std::memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(psm);
addr.l2_cid = 0;
addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
std::string mac_addr = device->GetMacAddress();
if (str2ba(mac_addr.c_str(), &addr.l2_bdaddr) < 0) {
LOG(ERROR) << __func__ << ": Invalid Bluetooth address: " << mac_addr;
close(fd);
return nullptr;
}
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
LOG(ERROR) << __func__ << ": Failed to connect to L2CAP socket: "
<< std::strerror(errno);
close(fd);
return nullptr;
}
LOG(INFO) << __func__ << ": Successfully connected to L2CAP socket";
return std::make_unique<BleL2capSocket>(fd, peripheral_id);
}
bool BleV2Medium::StartMultipleServicesScanning(
const std::vector<Uuid> &service_uuids,
api::ble_v2::TxPowerLevel tx_power_level, ScanCallback callback) {
LOG(WARNING) << __func__
<< ": Multiple services scanning not implemented on Linux. "
<< "Use single service scanning instead.";
return false;
}
bool BleV2Medium::PauseMediumScanning() {
LOG(INFO) << __func__ << ": Pause scanning not implemented, returning success";
return true;
}
bool BleV2Medium::ResumeMediumScanning() {
LOG(INFO) << __func__ << ": Resume scanning not implemented, returning success";
return true;
}
void BleV2Medium::AddAlternateUuidForService(uint16_t uuid,
const std::string &service_id) {
LOG(INFO) << __func__ << ": Alternate UUID mapping not implemented. UUID: "
<< uuid << ", service_id: " << service_id;
}
std::optional<api::ble_v2::BlePeripheral::UniqueId>
BleV2Medium::RetrieveBlePeripheralIdFromNativeId(
const std::string &ble_peripheral_native_id) {
LOG(WARNING) << __func__
<< ": Retrieval from native ID not implemented. Native ID: "
<< ble_peripheral_native_id;
return std::nullopt;
}
} // namespace linux
} // namespace nearby
@@ -1,172 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_
#define PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_
#include <memory>
#include <optional>
#include <vector>
#include <sdbus-c++/IConnection.h>
#include "absl/base/attributes.h"
#include "absl/container/flat_hash_map.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble_v2.h"
// #include "internal/platform/implementation/linux/ble_gatt_client.h"
#include "ble_gatt_client.h"
#include "bluez_gatt_manager.h"
#include "internal/platform/implementation/linux/ble_l2cap_server_socket.h"
#include "internal/platform/implementation/linux/ble_l2cap_socket.h"
#include "internal/platform/implementation/linux/ble_v2_server_socket.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_devices.h"
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
#include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h"
#include "internal/platform/implementation/linux/bluez_le_advertisement.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
class BleV2Medium final : public api::ble_v2::BleMedium {
public:
BleV2Medium(const BleV2Medium &) = delete;
BleV2Medium(BleV2Medium &&) = delete;
BleV2Medium &operator=(const BleV2Medium &) = delete;
BleV2Medium &operator=(BleV2Medium &&) = delete;
explicit BleV2Medium(BluetoothAdapter &adapter);
~BleV2Medium() override = default;
bool StartAdvertising(
const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters) override
ABSL_LOCKS_EXCLUDED(cur_adv_mutex_);
std::unique_ptr<AdvertisingSession> StartAdvertising(
const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters,
AdvertisingCallback callback) ABSL_LOCKS_EXCLUDED(advs_mutex_) override;
bool StopAdvertising() override ABSL_LOCKS_EXCLUDED(advs_mutex_);
bool StartScanning(const Uuid &service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
ScanCallback callback) override
ABSL_LOCKS_EXCLUDED(active_adv_monitors_mutex_);
bool StopScanning() override ABSL_LOCKS_EXCLUDED(active_adv_monitors_mutex_);
std::unique_ptr<ScanningSession> StartScanning(
const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
ScanningCallback callback) override;
std::unique_ptr<api::ble_v2::GattServer> StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) override;
std::unique_ptr<api::ble_v2::GattClient> ConnectToGattServer(
api::ble_v2::BlePeripheral::UniqueId peripheral_id,
api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::ClientGattConnectionCallback callback) override;
std::unique_ptr<api::ble_v2::BleServerSocket> OpenServerSocket(
const std::string &service_id) override;
std::unique_ptr<api::ble_v2::BleL2capServerSocket> OpenL2capServerSocket(
const std::string &service_id) override;
std::unique_ptr<api::ble_v2::BleSocket> Connect(
const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BlePeripheral::UniqueId peripheral_id,
CancellationFlag *cancellation_flag) override;
std::unique_ptr<api::ble_v2::BleL2capSocket> ConnectOverL2cap(
int psm, const std::string &service_id,
api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BlePeripheral::UniqueId peripheral_id,
CancellationFlag *cancellation_flag) override;
bool StartMultipleServicesScanning(const std::vector<Uuid> &service_uuids,
api::ble_v2::TxPowerLevel tx_power_level,
ScanCallback callback) override;
bool PauseMediumScanning() override;
bool ResumeMediumScanning() override;
bool IsExtendedAdvertisementsAvailable() override;
void AddAlternateUuidForService(uint16_t uuid,
const std::string &service_id) override;
std::optional<api::ble_v2::BlePeripheral::UniqueId>
RetrieveBlePeripheralIdFromNativeId(
const std::string &ble_peripheral_native_id) override;
// bool GetRemotePeripheral(const std::string &mac_address,
// GetRemotePeripheralCallback callback) override;
// bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id,
// GetRemotePeripheralCallback callback) override;
private:
bool StartLEDiscovery();
bool MonitorManagerSupportsOr() {
std::vector<std::string> supported_types;
try {
supported_types = adv_monitor_manager_->SupportedMonitorTypes();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(adv_monitor_manager_, "SupportedMonitorTypes",
e);
return false;
}
auto is_supported_type = [](std::string pattern) {
return pattern == "or_patterns";
};
auto end = supported_types.cend();
return std::find_if(supported_types.cbegin(), end, is_supported_type) !=
end;
}
std::shared_ptr<sdbus::IConnection> system_bus_;
BluetoothAdapter adapter_;
ObserverList<api::BluetoothClassicMedium::Observer> observers_ = {};
std::shared_ptr<BluetoothDevices> devices_;
std::shared_ptr<BluezGattDiscovery> gatt_discovery_;
std::unique_ptr<RootObjectManager> root_object_manager_;
std::unique_ptr<bluez::AdvertisementMonitorManager> adv_monitor_manager_;
absl::Mutex active_adv_monitors_mutex_;
absl::flat_hash_map<
Uuid,
std::pair<std::unique_ptr<bluez::AdvertisementMonitor>, std::unique_ptr<DeviceWatcher>>>
active_adv_monitors_ ABSL_GUARDED_BY(active_adv_monitors_mutex_);
// Used by the synchronous variant of StartScanning
std::optional<Uuid> cur_monitored_service_uuid_;
std::unique_ptr<bluez::LEAdvertisementManager> adv_manager_;
absl::Mutex cur_adv_mutex_;
std::unique_ptr<bluez::LEAdvertisement> cur_adv_
ABSL_GUARDED_BY(cur_adv_mutex_);
absl::Mutex advs_mutex_;
std::list<std::unique_ptr<bluez::LEAdvertisement>> advs_
ABSL_GUARDED_BY(advs_mutex_);
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,86 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/ble_v2_server_socket.h"
#include <memory>
#include "absl/synchronization/mutex.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/ble_v2_socket.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
std::unique_ptr<api::ble_v2::BleSocket> BleV2ServerSocket::Accept() {
absl::MutexLock lock(&mutex_);
LOG(INFO) << "BleV2ServerSocket::Accept waiting for connection";
while (!closed_ && pending_sockets_.empty()) {
cond_.Wait(&mutex_);
}
if (closed_) {
LOG(INFO) << "BleV2ServerSocket::Accept socket is closed";
return nullptr;
}
std::unique_ptr<BleV2Socket> socket = std::move(pending_sockets_.front());
pending_sockets_.pop_front();
LOG(INFO) << "BleV2ServerSocket::Accept accepted connection";
return socket;
}
Exception BleV2ServerSocket::Close() {
absl::MutexLock lock(&mutex_);
LOG(INFO) << "BleV2ServerSocket::Close for service " << service_id_;
if (closed_) {
return {Exception::kSuccess};
}
closed_ = true;
// Close all pending sockets
for (auto& socket : pending_sockets_) {
if (socket) {
socket->Close();
}
}
pending_sockets_.clear();
cond_.SignalAll();
return {Exception::kSuccess};
}
void BleV2ServerSocket::AddPendingSocket(std::unique_ptr<BleV2Socket> socket) {
absl::MutexLock lock(&mutex_);
if (closed_) {
LOG(WARNING)
<< "BleV2ServerSocket::AddPendingSocket socket is closed";
return;
}
pending_sockets_.push_back(std::move(socket));
cond_.SignalAll();
LOG(INFO) << "BleV2ServerSocket::AddPendingSocket added socket, "
<< "pending count: " << pending_sockets_.size();
}
} // namespace linux
} // namespace nearby
@@ -1,57 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_SERVER_SOCKET_H_
#define PLATFORM_IMPL_LINUX_API_BLE_V2_SERVER_SOCKET_H_
#include <deque>
#include <memory>
#include <string>
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/ble_v2_socket.h"
namespace nearby {
namespace linux {
class BleV2ServerSocket final : public api::ble_v2::BleServerSocket {
public:
explicit BleV2ServerSocket(const std::string& service_id)
: service_id_(service_id) {}
~BleV2ServerSocket() override = default;
std::unique_ptr<api::ble_v2::BleSocket> Accept() override
ABSL_LOCKS_EXCLUDED(mutex_);
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
void AddPendingSocket(std::unique_ptr<BleV2Socket> socket)
ABSL_LOCKS_EXCLUDED(mutex_);
std::string GetServiceId() const { return service_id_; }
private:
std::string service_id_;
absl::Mutex mutex_;
absl::CondVar cond_;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
std::deque<std::unique_ptr<BleV2Socket>> pending_sockets_
ABSL_GUARDED_BY(mutex_);
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,264 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/ble_v2_socket.h"
#include <cstdint>
#include "absl/synchronization/mutex.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
InputStream& BleV2Socket::GetInputStream() { return input_stream_; }
OutputStream& BleV2Socket::GetOutputStream() { return output_stream_; }
Exception BleV2Socket::Close() {
absl::MutexLock lock(&mutex_);
if (closed_) {
return {Exception::kSuccess};
}
closed_ = true;
// Close streams
input_stream_.NotifyClose();
output_stream_.Close();
// Cleanup GATT resources
if (gatt_client_) {
LOG(INFO) << "Disconnecting GATT client for peripheral "
<< peripheral_id_;
gatt_client_->Disconnect();
gatt_client_.reset();
}
if (gatt_server_) {
LOG(INFO) << "Stopping GATT server for peripheral "
<< peripheral_id_;
// Server cleanup is handled by the server itself
gatt_server_.reset();
}
return {Exception::kSuccess};
}
bool BleV2Socket::IsClosed() const {
absl::MutexLock lock(&mutex_);
return closed_;
}
// BleInputStream implementation
ExceptionOr<ByteArray> BleV2Socket::BleInputStream::Read(std::int64_t size) {
absl::MutexLock lock(&mutex_);
while (buffer_.Empty() && !closed_) {
cond_.Wait(&mutex_);
}
if (closed_ && buffer_.Empty()) {
return ExceptionOr<ByteArray>(Exception::kIo);
}
if (size < 0 || static_cast<size_t>(size) >= buffer_.size()) {
ByteArray result = buffer_;
buffer_ = ByteArray();
return ExceptionOr<ByteArray>(result);
}
ByteArray result(buffer_.data(), size);
buffer_ = ByteArray(buffer_.data() + size, buffer_.size() - size);
return ExceptionOr<ByteArray>(result);
}
Exception BleV2Socket::BleInputStream::Close() {
absl::MutexLock lock(&mutex_);
if (closed_) {
return {Exception::kSuccess};
}
closed_ = true;
cond_.SignalAll();
return {Exception::kSuccess};
}
void BleV2Socket::BleInputStream::ReceiveData(const ByteArray& data) {
absl::MutexLock lock(&mutex_);
if (closed_) {
return;
}
if (buffer_.Empty()) {
buffer_ = data;
} else {
ByteArray combined(buffer_.size() + data.size());
std::memcpy(combined.data(), buffer_.data(), buffer_.size());
std::memcpy(combined.data() + buffer_.size(), data.data(), data.size());
buffer_ = std::move(combined);
}
cond_.SignalAll();
}
void BleV2Socket::BleInputStream::NotifyClose() {
absl::MutexLock lock(&mutex_);
closed_ = true;
cond_.SignalAll();
}
// BleOutputStream implementation
Exception BleV2Socket::BleOutputStream::Write(const ByteArray& data) {
absl::MutexLock lock(&mutex_);
if (closed_) {
return {Exception::kIo};
}
if (!write_callback_) {
LOG(WARNING) << "BleOutputStream: No write callback set";
return {Exception::kIo};
}
bool success = write_callback_(data);
return {success ? Exception::kSuccess : Exception::kIo};
}
Exception BleV2Socket::BleOutputStream::Flush() {
return {Exception::kSuccess};
}
Exception BleV2Socket::BleOutputStream::Close() {
absl::MutexLock lock(&mutex_);
if (closed_) {
return {Exception::kSuccess};
}
closed_ = true;
write_callback_ = nullptr;
return {Exception::kSuccess};
}
void BleV2Socket::BleOutputStream::SetWriteCallback(WriteCallback callback) {
absl::MutexLock lock(&mutex_);
write_callback_ = std::move(callback);
}
void BleV2Socket::SetGattServer(
std::unique_ptr<api::ble_v2::GattServer> gatt_server,
const api::ble_v2::GattCharacteristic& rx_char,
const api::ble_v2::GattCharacteristic& tx_char) {
absl::MutexLock lock(&mutex_);
if (closed_) {
LOG(WARNING) << "Cannot set GATT server on closed socket";
return;
}
gatt_server_ = std::move(gatt_server);
rx_char_ = rx_char;
tx_char_ = tx_char;
// Set up write callback to use GATT server notifications
output_stream_.SetWriteCallback(
[this](const ByteArray& data) -> bool {
absl::MutexLock lock(&mutex_);
if (!gatt_server_) {
LOG(ERROR) << "GATT server not available for write";
return false;
}
if (closed_) {
LOG(WARNING) << "Socket is closed, cannot write";
return false;
}
// Notify remote device via TX characteristic
absl::Status status = gatt_server_->NotifyCharacteristicChanged(
tx_char_, /*confirm=*/false, data);
if (!status.ok()) {
LOG(WARNING) << "Failed to notify TX characteristic: "
<< status.message();
return false;
}
return true;
});
LOG(INFO) << "BLE socket configured with GATT server, RX: "
<< std::string(rx_char.uuid)
<< ", TX: " << std::string(tx_char.uuid);
}
void BleV2Socket::SetGattClient(
std::unique_ptr<api::ble_v2::GattClient> gatt_client,
const api::ble_v2::GattCharacteristic& rx_char,
const api::ble_v2::GattCharacteristic& tx_char) {
absl::MutexLock lock(&mutex_);
if (closed_) {
LOG(WARNING) << "Cannot set GATT client on closed socket";
return;
}
gatt_client_ = std::move(gatt_client);
rx_char_ = rx_char;
tx_char_ = tx_char;
// Set up write callback to use GATT client writes
output_stream_.SetWriteCallback(
[this](const ByteArray& data) -> bool {
absl::MutexLock lock(&mutex_);
if (!gatt_client_) {
LOG(ERROR) << "GATT client not available for write";
return false;
}
if (closed_) {
LOG(WARNING) << "Socket is closed, cannot write";
return false;
}
// Write to TX characteristic on remote device
std::string data_str(data.data(), data.size());
bool success = gatt_client_->WriteCharacteristic(
tx_char_, data_str,
api::ble_v2::GattClient::WriteType::kWithoutResponse);
if (!success) {
LOG(WARNING) << "Failed to write to TX characteristic";
return false;
}
return true;
});
// Subscribe to RX characteristic to receive data
bool subscribed = gatt_client_->SetCharacteristicSubscription(
rx_char_, /*enable=*/true,
[this](absl::string_view value) {
if (!IsClosed()) {
ByteArray data(value.data(), value.size());
input_stream_.ReceiveData(data);
}
});
if (!subscribed) {
LOG(ERROR) << "Failed to subscribe to RX characteristic";
}
LOG(INFO) << "BLE socket configured with GATT client, RX: "
<< std::string(rx_char.uuid)
<< ", TX: " << std::string(tx_char.uuid);
}
} // namespace linux
} // namespace nearby
@@ -1,138 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_H_
#define PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_H_
#include <cstdint>
#include <memory>
#include "absl/synchronization/mutex.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace linux {
// BLE v2 Socket implementation using GATT characteristics for data transfer
//
// Data flow:
// - Server side:
// * RX characteristic: Remote writes -> our InputStream reads
// * TX characteristic: Our OutputStream writes -> remote reads via notifications
// - Client side:
// * TX characteristic: Our OutputStream writes -> remote reads
// * RX characteristic: Remote writes (notifications) -> our InputStream reads
class BleV2Socket : public api::ble_v2::BleSocket {
public:
BleV2Socket() = default;
explicit BleV2Socket(api::ble_v2::BlePeripheral::UniqueId peripheral_id)
: peripheral_id_(peripheral_id) {}
~BleV2Socket() override { Close(); }
InputStream& GetInputStream() override;
OutputStream& GetOutputStream() override;
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
api::ble_v2::BlePeripheral::UniqueId GetRemotePeripheralId() override {
return peripheral_id_;
}
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
// GATT integration: Allow external code to feed data to input stream
// Called when remote device writes to RX characteristic
void ReceiveData(const ByteArray& data) { input_stream_.ReceiveData(data); }
// GATT integration: Set callback for output stream writes
// Callback should write to TX characteristic (notify remote)
void SetWriteCallback(
absl::AnyInvocable<bool(const ByteArray& data)> callback) {
output_stream_.SetWriteCallback(std::move(callback));
}
// Set the GATT server and characteristics for server-side socket
void SetGattServer(std::unique_ptr<api::ble_v2::GattServer> gatt_server,
const api::ble_v2::GattCharacteristic& rx_char,
const api::ble_v2::GattCharacteristic& tx_char)
ABSL_LOCKS_EXCLUDED(mutex_);
// Set the GATT client and characteristics for client-side socket
void SetGattClient(std::unique_ptr<api::ble_v2::GattClient> gatt_client,
const api::ble_v2::GattCharacteristic& rx_char,
const api::ble_v2::GattCharacteristic& tx_char)
ABSL_LOCKS_EXCLUDED(mutex_);
private:
class BleInputStream : public InputStream {
public:
BleInputStream() = default;
~BleInputStream() override = default;
ExceptionOr<ByteArray> Read(std::int64_t size) override
ABSL_LOCKS_EXCLUDED(mutex_);
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
void ReceiveData(const ByteArray& data) ABSL_LOCKS_EXCLUDED(mutex_);
void NotifyClose() ABSL_LOCKS_EXCLUDED(mutex_);
private:
absl::Mutex mutex_;
absl::CondVar cond_;
ByteArray buffer_ ABSL_GUARDED_BY(mutex_);
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
class BleOutputStream : public OutputStream {
public:
BleOutputStream() = default;
~BleOutputStream() override = default;
Exception Write(const ByteArray& data) override
ABSL_LOCKS_EXCLUDED(mutex_);
Exception Flush() override;
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
using WriteCallback = absl::AnyInvocable<bool(const ByteArray& data)>;
void SetWriteCallback(WriteCallback callback)
ABSL_LOCKS_EXCLUDED(mutex_);
private:
absl::Mutex mutex_;
WriteCallback write_callback_ ABSL_GUARDED_BY(mutex_);
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
mutable absl::Mutex mutex_;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
BleInputStream input_stream_;
BleOutputStream output_stream_;
api::ble_v2::BlePeripheral::UniqueId peripheral_id_ = 0;
// GATT resources (only one of these will be set)
std::unique_ptr<api::ble_v2::GattServer> gatt_server_ ABSL_GUARDED_BY(mutex_);
std::unique_ptr<api::ble_v2::GattClient> gatt_client_ ABSL_GUARDED_BY(mutex_);
// Characteristics for data transfer
api::ble_v2::GattCharacteristic rx_char_ ABSL_GUARDED_BY(mutex_);
api::ble_v2::GattCharacteristic tx_char_ ABSL_GUARDED_BY(mutex_);
};
} // namespace linux
} // namespace nearby
#endif // PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_H_
@@ -1,130 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/ble_v2_socket_adapter.h"
#include "absl/status/status.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/ble_v2_socket.h"
#include "internal/platform/logging.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
// Standard UUIDs for Nearby Connections GATT socket service
// RX: Remote writes to this, we read from it
constexpr uint64_t kRxCharMsb = 0x0000FE2C00001000ULL;
constexpr uint64_t kRxCharLsb = 0x800000805F9B34FBULL;
// TX: We write to this (notify), remote reads from it
constexpr uint64_t kTxCharMsb = 0x0000FE2C00002000ULL;
constexpr uint64_t kTxCharLsb = 0x800000805F9B34FBULL;
Uuid BleV2SocketAdapter::GetRxCharacteristicUuid() {
return Uuid(kRxCharMsb, kRxCharLsb);
}
Uuid BleV2SocketAdapter::GetTxCharacteristicUuid() {
return Uuid(kTxCharMsb, kTxCharLsb);
}
void BleV2SocketAdapter::RegisterSocket(
api::ble_v2::BlePeripheral::UniqueId device_id, BleV2Socket* socket) {
absl::MutexLock lock(&mutex_);
device_sockets_[device_id] = socket;
LOG(INFO) << "Registered socket for device " << device_id;
}
void BleV2SocketAdapter::UnregisterSocket(
api::ble_v2::BlePeripheral::UniqueId device_id) {
absl::MutexLock lock(&mutex_);
device_sockets_.erase(device_id);
LOG(INFO) << "Unregistered socket for device " << device_id;
}
api::ble_v2::ServerGattConnectionCallback
BleV2SocketAdapter::CreateServerCallbacks() {
api::ble_v2::ServerGattConnectionCallback callbacks;
// Handle subscription to TX characteristic (remote wants to receive data)
callbacks.characteristic_subscription_cb =
[](const api::ble_v2::GattCharacteristic& characteristic) {
LOG(INFO) << "Remote subscribed to characteristic: "
<< std::string(characteristic.uuid);
};
// Handle unsubscription
callbacks.characteristic_unsubscription_cb =
[](const api::ble_v2::GattCharacteristic& characteristic) {
LOG(INFO) << "Remote unsubscribed from characteristic: "
<< std::string(characteristic.uuid);
};
// Handle read requests (not typically used for socket data transfer)
callbacks.on_characteristic_read_cb =
[](api::ble_v2::BlePeripheral::UniqueId remote_device_id,
const api::ble_v2::GattCharacteristic& characteristic, int offset,
api::ble_v2::ServerGattConnectionCallback::ReadValueCallback
callback) {
LOG(INFO) << "Read request from device " << remote_device_id
<< " on characteristic "
<< std::string(characteristic.uuid);
// Return empty data for reads
callback(absl::string_view(""));
};
// Handle write requests - THIS IS WHERE DATA COMES IN
callbacks.on_characteristic_write_cb =
[this](api::ble_v2::BlePeripheral::UniqueId remote_device_id,
const api::ble_v2::GattCharacteristic& characteristic, int offset,
absl::string_view data,
api::ble_v2::ServerGattConnectionCallback::WriteValueCallback
callback) {
LOG(INFO) << "Write request from device " << remote_device_id
<< " on characteristic "
<< std::string(characteristic.uuid) << ", data size: "
<< data.size();
// Find the socket for this device
BleV2Socket* socket = nullptr;
{
absl::MutexLock lock(&mutex_);
auto it = device_sockets_.find(remote_device_id);
if (it != device_sockets_.end()) {
socket = it->second;
}
}
if (socket) {
// Route the data to the socket's input stream
ByteArray byte_data(data.data(), data.size());
socket->ReceiveData(byte_data);
callback(absl::OkStatus());
LOG(INFO) << "Routed " << data.size()
<< " bytes to socket input stream";
} else {
LOG(WARNING) << "No socket registered for device "
<< remote_device_id;
callback(absl::NotFoundError("No socket for device"));
}
};
return callbacks;
}
} // namespace linux
} // namespace nearby
@@ -1,66 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_ADAPTER_H_
#define PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_ADAPTER_H_
#include <memory>
#include <string>
#include "absl/container/flat_hash_map.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/ble_v2_socket.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
// Helper class to adapt GATT server callbacks to socket data streams
// This wires up the ServerGattConnectionCallback to feed data into BleV2Socket
class BleV2SocketAdapter {
public:
BleV2SocketAdapter() = default;
~BleV2SocketAdapter() = default;
// Create GATT server callbacks that will route data to/from sockets
api::ble_v2::ServerGattConnectionCallback CreateServerCallbacks();
// Register a socket for a specific remote device
// When GATT writes come from this device, data is routed to this socket
void RegisterSocket(api::ble_v2::BlePeripheral::UniqueId device_id,
BleV2Socket* socket) ABSL_LOCKS_EXCLUDED(mutex_);
// Unregister a socket
void UnregisterSocket(api::ble_v2::BlePeripheral::UniqueId device_id)
ABSL_LOCKS_EXCLUDED(mutex_);
// Get the RX characteristic UUID (for receiving data from remote)
static Uuid GetRxCharacteristicUuid();
// Get the TX characteristic UUID (for sending data to remote)
static Uuid GetTxCharacteristicUuid();
private:
absl::Mutex mutex_;
// Map of device ID to socket for routing incoming GATT writes
absl::flat_hash_map<api::ble_v2::BlePeripheral::UniqueId, BleV2Socket*>
device_sockets_ ABSL_GUARDED_BY(mutex_);
};
} // namespace linux
} // namespace nearby
#endif // PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_ADAPTER_H_
@@ -1,121 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#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/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
bool BluetoothAdapter::SetStatus(Status status) {
try {
bool val = status == api::BluetoothAdapter::Status::kEnabled;
bluez_adapter_->Powered(val);
return true;
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_SET_ERROR(bluez_adapter_, "Powered", e);
return false;
}
}
bool BluetoothAdapter::IsEnabled() const {
try {
return bluez_adapter_->Powered();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Powered", e);
return false;
}
}
BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const {
bool powered = IsEnabled();
if (!powered) {
return ScanMode::kNone;
}
try {
bool discoverable = bluez_adapter_->Discoverable();
return discoverable ? ScanMode::kConnectableDiscoverable
: ScanMode::kConnectable;
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Discoverable", e);
return ScanMode::kUnknown;
}
}
bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) {
switch (scan_mode) {
case ScanMode::kConnectable:
return SetStatus(Status::kEnabled);
case ScanMode::kConnectableDiscoverable: {
if (!SetStatus(Status::kEnabled)) {
return false;
}
try {
bluez_adapter_->Discoverable(true);
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_SET_ERROR(bluez_adapter_, "Discoverable", e);
return false;
}
return true;
}
case ScanMode::kNone:
return SetStatus(Status::kDisabled);
default:
return false;
}
}
std::string BluetoothAdapter::GetName() const {
try {
return bluez_adapter_->Alias();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Alias", e);
return {};
}
}
bool BluetoothAdapter::SetName(absl::string_view name, bool /*persist*/) {
return SetName(name);
}
bool BluetoothAdapter::SetName(absl::string_view name) {
try {
bluez_adapter_->Alias(std::string(name));
return true;
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_SET_ERROR(bluez_adapter_, "Alias", e);
return false;
}
}
std::string BluetoothAdapter::GetMacAddress() const {
try {
return bluez_adapter_->Address();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Address", e);
return {};
}
}
} // namespace linux
} // namespace nearby
@@ -1,84 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h"
namespace nearby {
namespace linux {
class BluezAdapter : public sdbus::ProxyInterfaces<org::bluez::Adapter1_proxy> {
public:
BluezAdapter(sdbus::IConnection &system_bus,
const sdbus::ObjectPath &adapter_object_path)
: ProxyInterfaces(system_bus, bluez::SERVICE_DEST, adapter_object_path) {
registerProxy();
}
~BluezAdapter() { unregisterProxy(); }
};
class BluetoothAdapter : public api::BluetoothAdapter {
public:
BluetoothAdapter(std::shared_ptr<sdbus::IConnection> system_bus,
const sdbus::ObjectPath &adapter_object_path)
: system_bus_(std::move(system_bus)),
bluez_adapter_(std::make_shared<BluezAdapter>(*system_bus_,
adapter_object_path)) {}
~BluetoothAdapter() override = default;
bool SetStatus(Status status) override;
bool IsEnabled() const override;
ScanMode GetScanMode() const override;
bool SetScanMode(ScanMode scan_mode) override;
std::string GetName() const override;
bool SetName(absl::string_view name) override;
bool SetName(absl::string_view name, bool persist) override;
std::string GetMacAddress() const override;
bool RemoveDeviceByObjectPath(const sdbus::ObjectPath &device_object_path) {
try {
bluez_adapter_->RemoveDevice(device_object_path);
return true;
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(bluez_adapter_, "RemoveDevice", e);
return false;
}
}
sdbus::ObjectPath GetObjectPath() const {
return bluez_adapter_->getObjectPath();
}
BluezAdapter &GetBluezAdapterObject() { return *bluez_adapter_; }
std::shared_ptr<sdbus::IConnection> GetConnection() { return system_bus_; }
private:
std::shared_ptr<sdbus::IConnection> system_bus_;
std::shared_ptr<BluezAdapter> bluez_adapter_;
};
} // namespace linux
} // namespace nearby
#endif // PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_
@@ -1,363 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/Error.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.h>
#include "absl/synchronization/mutex.h"
#include "internal/platform/cancellation_flag_listener.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"
#include "absl/strings/str_cat.h"
namespace nearby {
namespace linux {
bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) {
registered_service_uuids_mutex_.ReaderLock();
bool registered = registered_services_.count(std::string(service_uuid)) == 1;
registered_service_uuids_mutex_.ReaderUnlock();
return registered;
}
void Profile::Release() {
released_ = true;
LOG(INFO) << __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_) {
LOG(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 == nullptr) {
device = devices_.add_new_device(device_object_path);
}
auto alias = device->GetName();
auto mac_addr = device->GetAddress();
LOG(INFO) << __func__ << ": " << getObjectPath()
<< ": Connected to " << mac_addr.ToString();
FDProperties props(fd_props);
LOG(INFO) << "PUSH key(GetAddress.ToString)=" << mac_addr.ToString()
<< " alias=" << alias;
LOG(INFO) << "PUSH_ENTER profile=" << this
<< " mutex=" << &connections_lock_
<< " obj=" << getObjectPath()
<< " path=" << device_object_path;
{
absl::MutexLock l(&connections_lock_);
connections_[mac_addr.ToString()].push_back(std::pair(fd, props));
}
}
void Profile::RequestDisconnection(
const sdbus::ObjectPath &device_object_path) {
auto device = devices_.get_device_by_path(device_object_path);
if (device == nullptr) {
LOG(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->GetMacAddress();
LOG(INFO) << __func__ << ": Disconnection requested for device "
<< device_object_path;
absl::MutexLock l(&connections_lock_);
if (connections_.count(mac_addr) == 0) {
LOG(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) {
absl::MutexLock l(&registered_service_uuids_mutex_);
if (registered_services_.count(std::string(service_uuid)) == 1) {
LOG(WARNING) << __func__ << ": Trying to register profile "
<< service_uuid << " which was already registered.";
return true;
}
auto profile = std::make_shared<Profile>(
getProxy().getConnection(), bluez::profile_object_path(service_uuid),
devices_);
try {
std::map<std::string, sdbus::Variant> options;
if (name.has_value()) {
options["Name"] = std::string(*name);
}
options["RequireAuthorization"] = false;
options["RequireAuthentication"] = false;
options["Channel"] = static_cast<uint16_t>(0);
options["PSM"] = static_cast<uint16_t>(0);
RegisterProfile(profile->getObjectPath(), std::string(service_uuid),
options);
} catch (const sdbus::Error &e) {
BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "RegisterProfile", e);
return false;
}
registered_services_.emplace(service_uuid, profile);
LOG(INFO) << __func__
<< ": Registered profile instance for service uuid "
<< service_uuid;
return true;
}
void ProfileManager::Unregister(absl::string_view service_uuid) {
absl::MutexLock l(&registered_service_uuids_mutex_);
if (registered_services_.count(std::string(service_uuid)) == 0) {
LOG(WARNING)
<< __func__
<< ": attempted to unregister a profile that is not registered";
return;
}
auto profile_object_path = bluez::profile_object_path(service_uuid);
LOG(INFO) << __func__ << ": Unregistering profile "
<< profile_object_path;
try {
UnregisterProfile(profile_object_path);
} catch (const sdbus::Error &e) {
BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "UnregisterProfile", e);
}
registered_services_.erase(std::string(service_uuid));
}
// Get a service record FD for a connected profile (identified by service_uuid)
// to the given device. Only fires when we're requesting a new connection. i.e: we're the client
std::optional<sdbus::UnixFd> ProfileManager::GetServiceRecordFD(
api::BluetoothDevice &remote_device, absl::string_view service_uuid,
CancellationFlag *cancellation_flag) {
std::shared_ptr<Profile> profile;
{
absl::ReaderMutexLock lock(&registered_service_uuids_mutex_);
if (registered_services_.count(std::string(service_uuid)) == 0) {
LOG(ERROR) << __func__ << ": Service " << service_uuid
<< " is not registered";
return std::nullopt;
}
profile = registered_services_[std::string(service_uuid)];
}
auto mac_addr = remote_device.GetMacAddress();
std::unique_ptr<CancellationFlagListener> cancel_listener;
if (cancellation_flag != nullptr)
cancel_listener = std::make_unique<CancellationFlagListener>(
cancellation_flag, [profile]() {
if (profile->connections_lock_.TryLock()) {
profile->connections_lock_.Unlock();
}
}
);
LOG(INFO) << __func__ << ": " << profile->getObjectPath()
<< ": Attempting to get a FD for service "
<< service_uuid << " on device " << mac_addr;
LOG(INFO) << "WAIT profile=" << profile.get()
<< " mutex=" << &profile->connections_lock_
<< " obj=" << profile->getObjectPath()
<< " key=" << mac_addr;
auto cond = [mac_addr, profile, cancellation_flag]() {
profile->connections_lock_.AssertHeld();
LOG(INFO) << "connections_lock_ is held by: " << mac_addr << " with ptr: " << &profile -> connections_lock_;
return profile->connections_.count(mac_addr) != 0 ||
(cancellation_flag != nullptr && cancellation_flag->Cancelled());
};
// BUG: Race condition. Hangs here
LOG(INFO) << "WAIT key(GetMacAddress)=" << mac_addr;
LOG(INFO) << "connections_ size" << profile -> connections_.size();
absl::MutexLock connections_lock(&profile->connections_lock_,
absl::Condition(&cond));
LOG(INFO) << "WAIT_ACQUIRED "
<< " map_size=" << profile->connections_.size();
// Clean up pending tracking
profile->pending_outgoing_.erase(mac_addr);
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
LOG(INFO)
<< __func__ << ": " << profile->getObjectPath() << ": "
<< remote_device.GetMacAddress()
<< ": Cancelled waiting for a new connection on profile "
<< service_uuid;
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);
return std::move(fd);
}
// Listen for a connected profile on any device, returning the connected device
// with its FD. Only fires when another device requests connection from us. i.e. we're the server
std::optional<std::pair<std::shared_ptr<BluetoothDevice>, sdbus::UnixFd>>
ProfileManager::GetServiceRecordFD(absl::string_view service_uuid,
CancellationFlag *cancellation_flag) {
std::shared_ptr<Profile> profile;
{
absl::ReaderMutexLock lock(&registered_service_uuids_mutex_);
if (registered_services_.count(std::string(service_uuid)) == 0) {
return std::nullopt;
}
profile = registered_services_[std::string(service_uuid)];
}
LOG(INFO) << __func__ << ": " << profile->getObjectPath()
<< ": Attempting to get a FD for service "
<< service_uuid;
std::unique_ptr<CancellationFlagListener> cancel_listener;
if (cancellation_flag != nullptr)
cancel_listener = std::make_unique<CancellationFlagListener>(
cancellation_flag, [&profile]() {
profile->connections_lock_.Lock();
profile->connections_lock_.Unlock();
});
profile->connections_lock_.Lock();
auto cond = [profile, &cancellation_flag]() {
profile->connections_lock_.AssertReaderHeld();
// Only accept connections that DON'T have pending outgoing attempts
for (const auto& [mac, fds] : profile->connections_) {
if (profile->pending_outgoing_.count(mac) == 0) {
return true; // Found a connection without pending outgoing
}
}
return cancellation_flag != nullptr && cancellation_flag->Cancelled();
};
profile->connections_lock_.Await(absl::Condition(&cond));
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
LOG(INFO)
<< __func__ << ": Cancelled waiting for new connections on profile "
<< profile->getObjectPath();
profile->connections_lock_.Unlock();
return std::nullopt;
}
// Find first connection without pending outgoing
std::string mac_addr;
sdbus::UnixFd fd;
bool found = false;
for (auto it = profile->connections_.begin(); it != profile->connections_.end(); ++it) {
if (profile->pending_outgoing_.count(it->first) == 0) {
mac_addr = it->first;
auto& fds = it->second;
// Use auto to avoid accessing private FDProperties type
auto [fd_tmp, properties] = fds.back();
fd = std::move(fd_tmp);
fds.pop_back();
if (fds.empty()) {
profile->connections_.erase(it);
}
found = true;
break;
}
}
LOG(INFO) << __func__ << " Cleared connections";
profile->connections_lock_.Unlock();
if (!found) {
LOG(ERROR) << __func__ << ": No eligible connection found";
return std::nullopt;
}
auto device = devices_.get_device_by_address(mac_addr);
if (device == nullptr) {
LOG(ERROR) << __func__ << ": Device " << mac_addr
<< " is no longer available";
return std::nullopt;
}
return std::pair(device, std::move(fd));
}
void ProfileManager::MarkPendingOutgoing(absl::string_view service_uuid,
const std::string& mac_address) {
absl::ReaderMutexLock lock(&registered_service_uuids_mutex_);
if (registered_services_.count(std::string(service_uuid)) == 0) {
return;
}
auto profile = registered_services_[std::string(service_uuid)];
absl::MutexLock l(&profile->connections_lock_);
profile->pending_outgoing_.insert(mac_address);
LOG(INFO) << __func__ << ": Marked " << mac_address
<< " as pending outgoing for " << service_uuid;
}
void ProfileManager::ClearPendingOutgoing(absl::string_view service_uuid,
const std::string& mac_address) {
absl::ReaderMutexLock lock(&registered_service_uuids_mutex_);
if (registered_services_.count(std::string(service_uuid)) == 0) {
return;
}
auto profile = registered_services_[std::string(service_uuid)];
absl::MutexLock l(&profile->connections_lock_);
profile->pending_outgoing_.erase(mac_address);
LOG(INFO) << __func__ << ": Cleared " << mac_address
<< " as pending outgoing for " << service_uuid;
}
} // namespace linux
} // namespace nearby
@@ -1,155 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_
#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 <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/generated/dbus/bluez/profile_manager_client.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/profile_server.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
class ProfileManager;
class Profile final
: public sdbus::AdaptorInterfaces<org::bluez::Profile1_adaptor,
sdbus::ManagedObject_adaptor> {
public:
Profile(const Profile &) = delete;
Profile(Profile &&) = delete;
Profile &operator=(const Profile &) = delete;
Profile &operator=(Profile &&) = delete;
Profile(sdbus::IConnection &system_bus, sdbus::ObjectPath profile_object_path,
BluetoothDevices &devices)
: AdaptorInterfaces(system_bus, std::move(profile_object_path)),
released_(false),
devices_(devices) {
registerAdaptor();
LOG(INFO) << __func__ << ": Created a new BlueZ profile at :"
<< getObjectPath();
}
~Profile() { unregisterAdaptor(); }
private:
friend class ProfileManager;
struct FDProperties {
explicit FDProperties(const std::map<std::string, sdbus::Variant> &fd_props)
: version(std::nullopt), features(std::nullopt) {
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
ABSL_LOCKS_EXCLUDED(connections_lock_);
void RequestDisconnection(const sdbus::ObjectPath &) override
ABSL_LOCKS_EXCLUDED(connections_lock_);
std::atomic_bool released_;
absl::Mutex connections_lock_;
std::map<std::string, std::vector<std::pair<sdbus::UnixFd, FDProperties>>>
connections_ ABSL_GUARDED_BY(connections_lock_);
// Track pending outgoing connection attempts to avoid race with incoming
std::set<std::string> pending_outgoing_ ABSL_GUARDED_BY(connections_lock_);
BluetoothDevices &devices_;
};
class ProfileManager final
: private sdbus::ProxyInterfaces<org::bluez::ProfileManager1_proxy> {
public:
ProfileManager(const ProfileManager &) = delete;
ProfileManager(ProfileManager &&) = delete;
ProfileManager &operator=(const ProfileManager &) = delete;
ProfileManager &operator=(ProfileManager &&) = delete;
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)
ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_);
bool Register(std::optional<absl::string_view> service_name,
absl::string_view service_uuid)
ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_);
bool Register(absl::string_view service_uuid)
ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_) {
return Register(std::nullopt, service_uuid);
}
void Unregister(absl::string_view service_uuid)
ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_);
std::optional<sdbus::UnixFd> GetServiceRecordFD(
api::BluetoothDevice &remote_device, absl::string_view service_uuid,
CancellationFlag *cancellation_flag)
ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_);
std::optional<std::pair<std::shared_ptr<BluetoothDevice>, sdbus::UnixFd>>
GetServiceRecordFD(absl::string_view service_uuid,
CancellationFlag *cancellation_flag)
ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_);
void MarkPendingOutgoing(absl::string_view service_uuid,
const std::string& mac_address)
ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_);
void ClearPendingOutgoing(absl::string_view service_uuid,
const std::string& mac_address)
ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_);
private:
BluetoothDevices &devices_;
// Maps service UUIDs to RegisteredService
absl::Mutex registered_service_uuids_mutex_;
std::map<std::string, std::shared_ptr<Profile>> registered_services_
ABSL_GUARDED_BY(registered_service_uuids_mutex_);
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,176 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include "absl/strings/string_view.h"
#include "internal/platform/bluetooth_utils.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/bluez_device.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
BluetoothDevice::BluetoothDevice(std::shared_ptr<bluez::Device> device)
: lost_(false), device_(device) {
LOG(INFO) << "Created BluetoothDevice for: " << device -> Address();
try {
last_known_name_ = device->Alias();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(device, "Alias", e);
}
try {
MacAddress::FromString(device -> Address(), last_known_address_);
unique_id_ = last_known_address_.address();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(device, "Address", e);
}
}
std::string BluetoothDevice::GetName() const {
auto device = device_;
if (device == nullptr) {
absl::ReaderMutexLock l(&properties_mutex_);
return last_known_name_;
}
try {
std::string alias = device->Alias();
{
absl::MutexLock l(&properties_mutex_);
last_known_name_ = alias;
}
return alias;
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(device, "Alias", e);
return {};
}
}
std::string BluetoothDevice::GetMacAddress() const {
auto device = device_;
if (device == nullptr) {
absl::ReaderMutexLock l(&properties_mutex_);
return last_known_name_;
}
try {
std::string addr = device->Address();
{
absl::MutexLock l(&properties_mutex_);
MacAddress::FromString(addr, last_known_address_);
}
return addr;
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(device, "Address", e);
return std::string();
}
}
std::string BluetoothDevice::GetAddressType() const {
auto device = device_;
if (device == nullptr) return "public";
try {
return device->AddressType();
} catch (const sdbus::Error& e) {
DBUS_LOG_PROPERTY_GET_ERROR(device, "AddressType", e);
return "public";
}
}
bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) {
auto device = device_;
if (device == nullptr) return false;
try {
device->ConnectProfile(std::string(service_uuid));
return true;
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(device, "ConnectProfile", e);
return false;
}
}
bool BluetoothDevice::Connect() {
auto device = device_;
if (device == nullptr) return false;
try {
device->Connect();
return true;
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(device, "Connect", e);
return false;
}
}
MonitoredBluetoothDevice::MonitoredBluetoothDevice(
std::shared_ptr<sdbus::IConnection> system_bus,
std::shared_ptr<bluez::Device> device,
ObserverList<api::BluetoothClassicMedium::Observer> &observers)
: BluetoothDevice(device),
ProxyInterfaces<sdbus::Properties_proxy>(*system_bus, bluez::SERVICE_DEST,
device->getObjectPath()),
system_bus_(std::move(system_bus)),
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;
}
for (auto it = changedProperties.begin(); it != changedProperties.end();
it++)
{
if (it->first == bluez::DEVICE_PROP_ADDRESS) {
LOG(INFO) << __func__ << ": " << getObjectPath()
<< ": Notifying observers about address change";
std::string address = it->second;
for (const auto &observer : observers_.GetObservers()) {
observer->DeviceAddressChanged(*this, address);
}
} else if (it->first == bluez::DEVICE_PROP_PAIRED) {
LOG(INFO) << __func__ << ": " << getObjectPath()
<< "Notifying observers about paired status change.";
for (const auto &observer : observers_.GetObservers()) {
observer->DevicePairedChanged(*this, it->second);
}
} else if (it->first == bluez::DEVICE_PROP_CONNECTED) {
LOG(INFO)
<< __func__ << ": " << getObjectPath()
<< "Notifying observers about connected status change";
for (const auto &observer : observers_.GetObservers()) {
observer->DeviceConnectedStateChanged(*this, it->second);
}
} else if ( it -> first == "ServicesResolved"){
LOG(INFO) << ": ServicesResolved :" << std::string(it->second);
}else if (it->first == bluez::DEVICE_NAME) {
auto callback = GetDiscoveryCallback();
if (callback != nullptr && callback->device_name_changed_cb != nullptr)
callback->device_name_changed_cb(*this);
}
}
}
} // namespace linux
} // namespace nearby
@@ -1,183 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_
#include <atomic>
#include <memory>
#include <sdbus-c++/Error.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 "absl/synchronization/mutex.h"
#include "internal/base/observer_list.h"
// #include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluez_device.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/device_client.h"
namespace nearby {
namespace linux {
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html.
class BluetoothDevice : public api::BluetoothDevice {
public:
using UniqueId = std::uint64_t;
BluetoothDevice(const BluetoothDevice &) = delete;
BluetoothDevice(BluetoothDevice &&) = delete;
BluetoothDevice &operator=(const BluetoothDevice &) = delete;
BluetoothDevice &operator=(BluetoothDevice &&) = delete;
explicit BluetoothDevice(std::shared_ptr<bluez::Device> device);
std::string GetName() const override;
std::string GetMacAddress() const override;
std::string GetAddressType() const;
MacAddress GetAddress() const override { return last_known_address_; }
std::optional<std::map<std::string, sdbus::Variant>> ServiceData() {
auto device = device_;
if (!device) return std::nullopt;
try {
return device->ServiceData();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(device, "ServiceData", e);
return std::nullopt;
}
}
bool Bonded() {
auto device = device_;
if (!device) return false;
try {
return device->Bonded();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(device, "Bonded", e);
return false;
}
}
std::optional<sdbus::PendingAsyncCall> Pair() {
auto device = device_;
if (!device) return std::nullopt;
try {
return device->Pair();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(device, "Pair", e);
return std::nullopt;
}
}
bool CancelPairing() {
auto device = device_;
if (!device) return false;
try {
device->CancelPairing();
return true;
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(device, "CancelPairing", e);
return false;
}
}
void SetPairReplyCallback(absl::AnyInvocable<void(const sdbus::Error *)> cb) {
auto device = device_;
if (device) device->SetPairReplyCallback(std::move(cb));
}
bool ConnectToProfile(absl::string_view service_uuid);
bool Connect();
void MarkLost() { lost_ = true; }
void UnmarkLost() { lost_ = false; }
bool Lost() const { return lost_; }
sdbus::ObjectPath GetObjectPath() {return device_->getObjectPath();}
private:
UniqueId unique_id_;
std::atomic_bool lost_;
mutable absl::Mutex properties_mutex_;
mutable std::string last_known_name_ ABSL_GUARDED_BY(properties_mutex_);
mutable MacAddress last_known_address_ ABSL_GUARDED_BY(properties_mutex_);
std::shared_ptr<bluez::Device> device_;
};
class MonitoredBluetoothDevice final
: 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(const MonitoredBluetoothDevice &) = delete;
MonitoredBluetoothDevice(MonitoredBluetoothDevice &&) = delete;
MonitoredBluetoothDevice &operator=(const MonitoredBluetoothDevice &) =
delete;
MonitoredBluetoothDevice &operator=(MonitoredBluetoothDevice &&) = delete;
MonitoredBluetoothDevice(
std::shared_ptr<sdbus::IConnection> system_bus,
std::shared_ptr<bluez::Device> device,
ObserverList<api::BluetoothClassicMedium::Observer> &observers);
~MonitoredBluetoothDevice() override { unregisterProxy(); }
void SetDiscoveryCallback(
std::shared_ptr<api::BluetoothClassicMedium::DiscoveryCallback> &callback)
ABSL_LOCKS_EXCLUDED(discovery_cb_mutex_) {
absl::MutexLock lock(&discovery_cb_mutex_);
discovery_cb_ = callback;
};
protected:
void onPropertiesChanged(
const std::string &interfaceName,
const std::map<std::string, sdbus::Variant> &changedProperties,
const std::vector<std::string> &invalidatedProperties) override;
private:
std::shared_ptr<sdbus::IConnection> system_bus_;
std::shared_ptr<api::BluetoothClassicMedium::DiscoveryCallback>
GetDiscoveryCallback() ABSL_LOCKS_EXCLUDED(discovery_cb_mutex_) {
discovery_cb_mutex_.ReaderLock();
auto callback = discovery_cb_.lock();
discovery_cb_mutex_.ReaderUnlock();
return callback;
}
ObserverList<api::BluetoothClassicMedium::Observer> &observers_;
absl::Mutex discovery_cb_mutex_;
std::weak_ptr<api::BluetoothClassicMedium::DiscoveryCallback> discovery_cb_
ABSL_GUARDED_BY(discovery_cb_mutex_);
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,179 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstring>
#include <memory>
#include <sdbus-c++/IProxy.h>
#include <sdbus-c++/Types.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/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
#include "internal/platform/implementation/linux/bluetooth_classic_medium.h"
// #include "bluez_agent.h"
#include "internal/platform/implementation/linux/bluetooth_classic_server_socket.h"
#include "internal/platform/implementation/linux/bluetooth_classic_socket.h"
#include "internal/platform/implementation/linux/bluetooth_pairing.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter)
: system_bus_(adapter.GetConnection()),
adapter_(adapter),
observers_(std::make_shared<ObserverList<Observer>>()),
devices_(std::make_shared<BluetoothDevices>(
system_bus_, adapter.GetObjectPath(), *observers_)),
device_watcher_(nullptr),
// agent_manager_(std::make_unique<AgentManager>(*system_bus_)),
profile_manager_(
std::make_unique<ProfileManager>(*system_bus_, *devices_)) {}
bool BluetoothClassicMedium::StartDiscovery(
DiscoveryCallback discovery_callback) {
device_watcher_ = std::make_unique<DeviceWatcher>(
*system_bus_, adapter_.GetObjectPath(), adapter_, devices_,
std::make_unique<DiscoveryCallback>(std::move(discovery_callback)),
observers_);
std::map<std::string, sdbus::Variant> filter;
filter["Transport"] = "auto";
auto &adapter = adapter_.GetBluezAdapterObject();
try {
adapter.SetDiscoveryFilter(filter);
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e);
device_watcher_ = nullptr;
return false;
}
try {
LOG(INFO) << __func__ << ": Starting BR/EDR discovery on "
<< adapter_.GetObjectPath();
adapter.StartDiscovery();
} catch (const sdbus::Error &e) {
if (e.getName() != "org.bluez.Error.InProgress") {
DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e);
device_watcher_ = nullptr;
return false;
}
}
return true;
}
bool BluetoothClassicMedium::StopDiscovery() {
auto &adapter = adapter_.GetBluezAdapterObject();
LOG(INFO) << __func__ << "Stopping discovery on "
<< adapter.getObjectPath();
auto ret = true;
try {
adapter.StopDiscovery();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e);
ret = false;
}
device_watcher_ = nullptr;
return ret;
}
std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
api::BluetoothDevice &remote_device, const std::string &service_uuid,
CancellationFlag *cancellation_flag) {
if (!profile_manager_->ProfileRegistered(service_uuid)) {
if (!profile_manager_->Register(std::nullopt, service_uuid)) {
LOG(ERROR) << __func__ << ": Could not register profile "
<< service_uuid << " with Bluez";
return nullptr;
}
}
auto address = remote_device.GetMacAddress();
auto device = devices_->get_device_by_address(address);
if (device == nullptr) {
LOG(ERROR) << __func__ << ": Device " << address
<< " is no longer known";
return nullptr;
}
if (!device -> Bonded())
{
LOG(ERROR) << __func__ << ": Device " << address
<< " is not Bonded";
}
// Mark as pending BEFORE calling ConnectToProfile to win the race
profile_manager_->MarkPendingOutgoing(service_uuid, address);
if (!device->ConnectToProfile(service_uuid)) {
profile_manager_->ClearPendingOutgoing(service_uuid, address);
return nullptr;
}
auto fd = profile_manager_->GetServiceRecordFD(remote_device, service_uuid,
cancellation_flag);
if (!fd.has_value()) {
LOG(WARNING) << __func__
<< ": Failed to get a new connection for profile "
<< service_uuid << " for device " << address;
return nullptr;
}
return std::unique_ptr<api::BluetoothSocket>(
new BluetoothSocket(device, fd.value()));
}
std::unique_ptr<api::BluetoothServerSocket>
BluetoothClassicMedium::ListenForService(const std::string &service_name,
const std::string &service_uuid) {
LOG(INFO) << __func__ << ": Creating bluez agent on path: " << "/com/example/bluez_agent" ;
if (!profile_manager_->ProfileRegistered(service_uuid)) {
if (!profile_manager_->Register(service_name, service_uuid)) {
LOG(ERROR) << __func__ << ": Could not register profile "
<< service_name << " " << service_uuid
<< " with Bluez";
return nullptr;
}
}
return std::unique_ptr<api::BluetoothServerSocket>(
new BluetoothServerSocket(*profile_manager_, service_uuid));
}
api::BluetoothDevice *BluetoothClassicMedium::GetRemoteDevice(
MacAddress mac_address) {
auto device = devices_->get_device_by_address(mac_address.ToString());
if (device == nullptr) return nullptr;
return device.get();
}
std::unique_ptr<api::BluetoothPairing> BluetoothClassicMedium::CreatePairing(
api::BluetoothDevice &remote_device) {
auto device = devices_->get_device_by_address(remote_device.GetMacAddress());
if (device == nullptr) return nullptr;
return std::unique_ptr<api::BluetoothPairing>(
new BluetoothPairing(adapter_, device));
}
} // namespace linux
} // namespace nearby
@@ -1,117 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#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++/ProxyInterfaces.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
// #include "bluez_agent.h"
#include "internal/base/observer_list.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h"
#include "internal/platform/implementation/linux/bluetooth_devices.h"
namespace nearby {
namespace linux {
// Container of operations that can be performed over the Bluetooth Classic
// medium.
class BluetoothClassicMedium : public api::BluetoothClassicMedium {
public:
explicit BluetoothClassicMedium(BluetoothAdapter &adapter);
// 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(MacAddress mac_address) override;
void AddObserver(Observer *observer) override {
observers_->AddObserver(observer);
};
void RemoveObserver(Observer *observer) override {
observers_->RemoveObserver(observer);
};
private:
std::shared_ptr<sdbus::IConnection> system_bus_;
BluetoothAdapter adapter_;
std::shared_ptr<ObserverList<Observer>> observers_;
std::shared_ptr<BluetoothDevices> devices_;
std::unique_ptr<DeviceWatcher> device_watcher_;
// std::unique_ptr<AgentManager> agent_manager_;
std::unique_ptr<ProfileManager> profile_manager_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,56 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/bluetooth_classic_server_socket.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
#include "internal/platform/implementation/linux/bluetooth_classic_socket.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
std::unique_ptr<api::BluetoothSocket> BluetoothServerSocket::Accept() {
if (stopped_.Cancelled()) {
LOG(ERROR) << __func__ << ": server socket has been stopped";
return nullptr;
}
LOG(INFO) << __func__
<< ": accepting new connections for service uuid "
<< service_uuid_;
auto pair = profile_manager_.GetServiceRecordFD(service_uuid_, &stopped_);
if (!pair.has_value()) {
if (!stopped_.Cancelled())
LOG(ERROR) << __func__
<< ": Failed to get a new connection for profile "
<< service_uuid_;
return nullptr;
}
auto [device, fd] = *pair;
LOG(INFO) << __func__ << ": accepted incoming connection for service uuid " << service_uuid_;
return std::make_unique<BluetoothSocket>(device, std::move(fd));
}
Exception BluetoothServerSocket::Close() {
LOG(ERROR) << __func__ << ": closing bluetooth server socket";
stopped_.Cancel();
profile_manager_.Unregister(service_uuid_);
return {Exception::kSuccess};
}
} // namespace linux
} // namespace nearby
@@ -1,56 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_
#include "absl/strings/string_view.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h"
namespace nearby {
namespace linux {
class BluetoothServerSocket final : public api::BluetoothServerSocket {
public:
BluetoothServerSocket(ProfileManager &profile_manager,
absl::string_view service_uuid)
: profile_manager_(profile_manager), service_uuid_(service_uuid) {}
// 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;
private:
CancellationFlag stopped_;
ProfileManager &profile_manager_;
std::string service_uuid_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,332 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sys/poll.h>
#include <sys/socket.h>
#include <unistd.h>
#include <array>
#include <cerrno>
#include <cstdint>
#include <cstring>
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/linux/bluetooth_classic_socket.h"
#include "internal/platform/logging.h"
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstddef>
#include <algorithm>
struct SocketWriteCaps {
int so_type = 0; // SOCK_STREAM / SOCK_SEQPACKET / SOCK_DGRAM
size_t max_chunk = 0; // 0 => unknown/unlimited
bool packet_based = false;
};
static SocketWriteCaps DetectCapsNoBtHeaders(int fd) {
SocketWriteCaps caps{};
socklen_t len = sizeof(caps.so_type);
if (::getsockopt(fd, SOL_SOCKET, SO_TYPE, &caps.so_type, &len) != 0) {
// If we can't detect, behave conservatively like stream.
caps.so_type = SOCK_STREAM;
}
caps.packet_based = (caps.so_type == SOCK_SEQPACKET || caps.so_type == SOCK_DGRAM);
// Initial guess for packet-based sockets. This will be refined on EMSGSIZE.
if (caps.packet_based) caps.max_chunk = 1024; // start guess
else caps.max_chunk = 0; // unlimited/stream
return caps;
}
namespace nearby {
namespace linux {
Exception Poller::Ready() {
while (true) {
auto ret = poll(fds_, 1, -1);
if (ret < 0) {
if (errno == EAGAIN) continue;
LOG(ERROR) << __func__ << ": error polling socket for I/O: "
<< std::strerror(errno);
return {Exception::kIo};
}
if ((fds_[0].revents & poll_event_) != 0) {
return {Exception::kSuccess};
}
if ((fds_[0].revents & POLLHUP) != 0) {
LOG(ERROR) << __func__ << ": socket disconnected";
return {Exception::kIo};
}
if ((fds_[0].revents & (POLLERR | POLLNVAL)) != 0) {
LOG(ERROR) << __func__ << ": an error occured on the socket";
return {Exception::kIo};
}
}
}
ExceptionOr<ByteArray> BluetoothInputStream::Read(std::int64_t size) {
int fd = fd_raw_.load();
if (fd < 0) return Exception{Exception::kIo};
auto poller = Poller::CreateInputPoller(fd);
int so_type = 0;
socklen_t sl = sizeof(so_type);
if (::getsockopt(fd, SOL_SOCKET, SO_TYPE, &so_type, &sl) != 0) {
// If unknown, default to stream-ish behavior.
so_type = SOCK_STREAM;
}
const bool packet_based = (so_type == SOCK_SEQPACKET || so_type == SOCK_DGRAM);
// Sanity: avoid negative / zero sizes
if (size <= 0) return ExceptionOr{ByteArray(std::string())};
// ---- Packet-based: read ONE message (recommended) ----
if (packet_based) {
// Wait for readability
while (true) {
if (fd_raw_.load() != fd) return {Exception::kIo};
auto result = poller.Ready();
if (result.Raised()) return result;
if (fd_raw_.load() != fd) return {Exception::kIo};
// Peek the next message length without consuming it.
// For seqpacket/dgram, MSG_TRUNC makes recv() return the *full* message length
// even if the buffer is smaller.
ssize_t msg_len = ::recv(fd, nullptr, 0, MSG_PEEK | MSG_TRUNC);
if (msg_len < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
if (errno == EBADF) {
LOG(INFO) << __func__ << ": socket was closed during read";
return {Exception::kIo};
}
LOG(ERROR) << __func__ << ": error peeking message length: "
<< std::strerror(errno);
return {Exception::kIo};
}
if (msg_len == 0) {
LOG(INFO) << __func__ << ": socket closed (EOF)";
return {Exception::kIo};
}
// Decide how much we will actually read/return.
// If caller asked for 'size', cap to that.
size_t want = static_cast<size_t>(msg_len);
size_t cap = static_cast<size_t>(size);
size_t to_read = std::min(want, cap);
std::string buffer;
buffer.resize(to_read);
// Now read/consume the message. If the message is larger than to_read,
// the remainder will be discarded by the kernel for seqpacket/dgram.
// We can detect that and treat it as an error (or choose a different policy).
if (fd_raw_.load() != fd) return {Exception::kIo};
ssize_t n = ::recv(fd, buffer.data(), to_read, 0);
if (n < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
if (errno == EBADF) {
LOG(INFO) << __func__ << ": socket was closed during read";
return {Exception::kIo};
}
LOG(ERROR) << __func__ << ": error reading data on bluetooth socket: "
<< std::strerror(errno);
return {Exception::kIo};
}
if (n == 0) {
LOG(INFO) << __func__ << ": socket closed (EOF)";
return {Exception::kIo};
}
buffer.resize(static_cast<size_t>(n));
// Detect truncation: if msg_len > size, we truncated/discarded remainder.
if (want > cap) {
LOG(ERROR) << __func__
<< ": incoming packet (" << want
<< " bytes) exceeds requested size (" << cap
<< "). Packet truncated.";
return {Exception::kIo};
}
return ExceptionOr{ByteArray(std::move(buffer))};
}
}
// ---- Stream-based: read exactly 'size' bytes (your original behavior) ----
std::string buffer;
buffer.resize(static_cast<size_t>(size));
char* data = buffer.data();
size_t total_read = 0;
while (total_read < static_cast<size_t>(size)) {
if (fd_raw_.load() != fd) return {Exception::kIo};
auto result = poller.Ready();
if (result.Raised()) return result;
if (fd_raw_.load() != fd) return {Exception::kIo};
ssize_t bytes_read = ::read(fd,
data + total_read,
static_cast<size_t>(size) - total_read);
if (bytes_read < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
if (errno == EBADF) {
LOG(INFO) << __func__ << ": socket was closed during read";
return {Exception::kIo};
}
LOG(ERROR) << __func__ << ": error reading data on bluetooth socket: "
<< std::strerror(errno);
return {Exception::kIo};
}
if (bytes_read == 0) {
LOG(INFO) << __func__ << ": socket closed (EOF)";
return {Exception::kIo};
}
total_read += static_cast<size_t>(bytes_read);
}
return ExceptionOr{ByteArray(std::move(buffer))};
}
Exception BluetoothInputStream::Close() {
int fd = fd_raw_.exchange(-1);
if (fd < 0) return {Exception::kSuccess}; // Already closed
::shutdown(fd, SHUT_RDWR);
fd_.reset();
return {Exception::kSuccess};
}
Exception BluetoothOutputStream::Write(const ByteArray &data) {
int fd = fd_raw_.load();
if (fd < 0) return Exception{Exception::kIo};
auto poller = Poller::CreateOutputPoller(fd);
size_t total_wrote = 0;
int so_type = 0;
socklen_t sl = sizeof(so_type);
if (::getsockopt(fd, SOL_SOCKET, SO_TYPE, &so_type, &sl) != 0) {
// If we cant detect, assume stream semantics (no per-message MTU).
so_type = SOCK_STREAM;
}
const bool packet_based = (so_type == SOCK_SEQPACKET || so_type == SOCK_DGRAM);
// Initialize a reasonable starting guess for packet-based sockets.
// This will be refined down on EMSGSIZE.
if (packet_based) {
absl::MutexLock lock(&fd_mutex_);
if (max_chunk_ == 0) max_chunk_ = 1024;
}
size_t max_chunk = 0;
if (packet_based) {
absl::MutexLock lock(&fd_mutex_);
max_chunk = max_chunk_;
}
while (total_wrote < data.size()) {
if (fd_raw_.load() != fd) return {Exception::kIo};
auto result = poller.Ready(); // should wait for POLLOUT/EPOLLOUT
if (result.Raised()) return result;
if (fd_raw_.load() != fd) return {Exception::kIo};
const char *buf = data.data();
size_t remaining = data.size() - total_wrote;
size_t to_write = remaining;
if (packet_based) {
// For SEQPACKET/DGRAM, one send() == one packet.
// Cap to discovered “MTU-like” limit to avoid EMSGSIZE.
absl::MutexLock lock(&fd_mutex_);
to_write = std::min(to_write, max_chunk_);
}
// Prefer send() to avoid SIGPIPE (MSG_NOSIGNAL is Linux).
ssize_t wrote = ::send(fd,
buf + total_wrote,
to_write,
#ifdef MSG_NOSIGNAL
MSG_NOSIGNAL
#else
0
#endif
);
// If send() isnt appropriate in your environment, you can swap back to write().
// ssize_t wrote = ::write(fd_.get(), buf + total_wrote, to_write);
if (wrote < 0) {
if (errno == EINTR) continue;
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
if (errno == EMSGSIZE && packet_based) {
// Our packet is too large; shrink max_chunk_ and retry.
{
absl::MutexLock lock(&fd_mutex_);
if (max_chunk_ > 1) {
max_chunk_ = std::max<size_t>(1, max_chunk_ / 2);
LOG(INFO) << __func__ << ": EMSGSIZE; reducing max_chunk_ to "
<< max_chunk_;
continue; // retry with smaller chunk
}
}
LOG(ERROR) << __func__ << ": EMSGSIZE even at 1 byte";
return {Exception::kIo};
}
if (errno == EBADF || errno == EPIPE) {
LOG(INFO) << __func__ << ": socket was closed during write";
return {Exception::kIo};
}
LOG(ERROR) << __func__
<< ": error writing data on bluetooth socket: "
<< std::strerror(errno);
return {Exception::kIo};
}
if (wrote == 0) {
// For sockets, 0 usually means peer closed.
LOG(INFO) << __func__ << ": peer closed during write";
return {Exception::kIo};
}
total_wrote += static_cast<size_t>(wrote);
}
return {Exception::kSuccess};
}
Exception BluetoothOutputStream::Close() {
int fd = fd_raw_.exchange(-1);
if (fd < 0) return {Exception::kSuccess}; // Already closed
::shutdown(fd, SHUT_RDWR);
fd_.reset();
return {Exception::kSuccess};
}
} // namespace linux
} // namespace nearby
@@ -1,123 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_
#include <atomic>
#include <memory>
#include <optional>
#include <sdbus-c++/Types.h>
#include <sys/poll.h>
#include <systemd/sd-bus.h>
#include "absl/synchronization/mutex.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace linux {
// BlueZ's NewConnection gives us a non-blocking FD, so we need to poll
// it to be able to write/read bytes.
class Poller final {
public:
static Poller CreateInputPoller(const sdbus::UnixFd &fd) {
return Poller(fd, POLLIN);
}
static Poller CreateOutputPoller(const sdbus::UnixFd &fd) {
return Poller(fd, POLLOUT);
}
static Poller CreateInputPoller(int fd) { return Poller(fd, POLLIN); }
static Poller CreateOutputPoller(int fd) { return Poller(fd, POLLOUT); }
Exception Ready();
private:
Poller(const sdbus::UnixFd &fd, short event) : poll_event_(event) {
fds_[0].fd = fd.get();
fds_[0].events = event;
}
Poller(int fd, short event) : poll_event_(event) {
fds_[0].fd = fd;
fds_[0].events = event;
}
short poll_event_;
struct pollfd fds_[1];
};
class BluetoothInputStream final : public nearby::InputStream {
public:
explicit BluetoothInputStream(sdbus::UnixFd fd)
: fd_(std::move(fd)), fd_raw_(fd_.get()) {}
ExceptionOr<ByteArray> Read(std::int64_t size) override;
Exception Close() override;
private:
sdbus::UnixFd fd_;
std::atomic<int> fd_raw_{-1};
};
class BluetoothOutputStream : public nearby::OutputStream {
public:
explicit BluetoothOutputStream(sdbus::UnixFd fd)
: fd_(std::move(fd)), fd_raw_(fd_.get()) {}
Exception Write(const ByteArray &data) override;
Exception Flush() override { return {Exception::kSuccess}; }
Exception Close() override;
private:
mutable absl::Mutex fd_mutex_;
sdbus::UnixFd fd_;
std::atomic<int> fd_raw_{-1};
// For packet sockets, discovered max payload per send/write.
// 0 means "unknown", well initialize on first packet write.
size_t max_chunk_ ABSL_GUARDED_BY(fd_mutex_) = 0;
};
class BluetoothSocket final : public api::BluetoothSocket {
public:
BluetoothSocket(std::shared_ptr<BluetoothDevice> device,
const sdbus::UnixFd &fd)
: device_(std::move(device)), output_stream_(fd), input_stream_(fd) {}
nearby::InputStream &GetInputStream() override { return input_stream_; }
nearby::OutputStream &GetOutputStream() override { return output_stream_; }
Exception Close() override {
input_stream_.Close();
output_stream_.Close();
return Exception{Exception::kSuccess};
}
api::BluetoothDevice *GetRemoteDevice() override { return device_.get(); };
private:
std::shared_ptr<BluetoothDevice> device_;
BluetoothOutputStream output_stream_;
BluetoothInputStream input_stream_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,239 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <chrono>
#include <functional>
#include <optional>
#include <sdbus-c++/Types.h>
#include "absl/strings/substitute.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.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/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/device_client.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
static constexpr std::chrono::minutes kLostPeripheralsCleanupMinFreq(5);
std::shared_ptr<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 nullptr;
}
return devices_by_path_[device_object_path];
}
std::shared_ptr<BluetoothDevice> BluetoothDevices::get_device_by_unique_id(
api::ble_v2::BlePeripheral::UniqueId id)
{
// converting from stoull to mac again
id &= 0x0000FFFFFFFFFFFFULL; // keep 48 bits
std::ostringstream oss;
oss << std::hex << std::setfill('0') << std::setw(12) << id;
std::string hex = oss.str(); // e.g. "aabbccddeeff"
std::string mac;
for (int i = 0; i < 6; ++i) {
if (i) mac.push_back(':');
mac.append(hex.substr(i * 2, 2));
}
return get_device_by_address(mac);
}
std::shared_ptr<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);
}
void BluetoothDevices::mark_peripheral_lost(
const sdbus::ObjectPath &device_object_path) {
absl::ReaderMutexLock lock(&devices_by_path_lock_);
if (devices_by_path_.count(device_object_path) == 0) {
LOG(ERROR) << __func__ << ": Device " << device_object_path
<< " doesn't exist";
return;
}
devices_by_path_[device_object_path]->MarkLost();
}
void BluetoothDevices::cleanup_lost_peripherals() {
auto now = std::chrono::steady_clock::now();
absl::MutexLock lock(&devices_by_path_lock_);
if ((now - last_cleanup_) < kLostPeripheralsCleanupMinFreq) {
return;
}
last_cleanup_ = now;
for (auto it = devices_by_path_.begin(), end = devices_by_path_.end();
it != end;) {
auto copy = it++;
if (copy->second->Lost()) devices_by_path_.erase(copy);
}
}
std::shared_ptr<MonitoredBluetoothDevice> BluetoothDevices::add_new_device(
sdbus::ObjectPath device_object_path) {
absl::MutexLock l(&devices_by_path_lock_);
auto [device_it, inserted] = devices_by_path_.emplace(
std::string(device_object_path),
std::make_shared<MonitoredBluetoothDevice>(
system_bus_,
std::make_shared<bluez::Device>(system_bus_, device_object_path),
observers_));
if (!inserted) device_it->second->UnmarkLost();
return device_it->second;
}
void DeviceWatcher::onInterfacesAdded(
const sdbus::ObjectPath &object,
const std::map<std::string, std::map<std::string, sdbus::Variant>>
&interfaces) {
auto path_prefix = absl::Substitute("$0/dev_", adapter_object_path_);
if (object.find(path_prefix) != 0) {
return;
}
if (interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 0) return;
auto device = devices_->add_new_device(object);
device->SetDiscoveryCallback(discovery_cb_);
if (discovery_cb_ != nullptr &&
discovery_cb_->device_discovered_cb != nullptr) {
discovery_cb_->device_discovered_cb(*device);
}
if (observers_ != nullptr) {
for (const auto &observer : observers_->GetObservers()) {
observer->DeviceAdded(*device);
}
}
}
void DeviceWatcher::onInterfacesRemoved(
const sdbus::ObjectPath &object,
const std::vector<std::string> &interfaces) {
auto path_prefix = absl::Substitute("$0/dev_", adapter_object_path_);
if (object.find(path_prefix) != 0) {
return;
}
auto removed_device_it = std::find(interfaces.begin(), interfaces.end(),
org::bluez::Device1_proxy::INTERFACE_NAME);
if (removed_device_it != interfaces.end()) {
auto device = devices_->get_device_by_path(object);
if (device == nullptr) {
LOG(WARNING) << __func__
<< ": received InterfacesRemoved for a device "
"we don't know about: "
<< object;
return;
}
LOG(INFO) << __func__ << ": Device " << object
<< " has been removed";
if (discovery_cb_ != nullptr && discovery_cb_->device_lost_cb != nullptr) {
discovery_cb_->device_lost_cb(*device);
}
if (observers_ != nullptr) {
for (const auto &observer : observers_->GetObservers()) {
observer->DeviceRemoved(*device);
}
devices_->remove_device_by_path(object);
} else {
devices_->mark_peripheral_lost(object);
}
}
}
void DeviceWatcher::notifyExistingDevices() {
std::map<sdbus::ObjectPath,
std::map<std::string, std::map<std::string, sdbus::Variant>>>
objects;
try {
objects = GetManagedObjects();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e);
return;
}
std::vector<sdbus::ObjectPath> existing_device_paths;
for (const auto& [device_path, interfaces] : objects) {
if (device_path.find(absl::Substitute("$0/dev_", adapter_object_path_)) == 0 &&
interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1) {
// Don't remove bonded, paired, connected, or trusted devices
bool should_skip = false;
auto device_interface_it = interfaces.find(org::bluez::Device1_proxy::INTERFACE_NAME);
if (device_interface_it != interfaces.end()) {
const auto& properties = device_interface_it->second;
auto check_bool_property = [&properties](const std::string& prop_name) -> bool {
auto it = properties.find(prop_name);
if (it != properties.end()) {
try {
return it->second.get<bool>();
} catch (...) {
return false;
}
}
return false;
};
if (check_bool_property("Bonded") ||
check_bool_property("Paired") ||
check_bool_property("Connected") ||
check_bool_property("Trusted")) {
should_skip = true;
LOG(INFO) << __func__ << ": Skipping device " << device_path
<< " (bonded/paired/connected/trusted)";
}
}
if (!should_skip) {
existing_device_paths.push_back(device_path);
}
}
}
// Remove existing devices - they will be immediately re-discovered
// This triggers InterfacesAdded signals which properly invoke discovery callbacks
for (const auto& device_path : existing_device_paths) {
LOG(INFO) << __func__ << ": Refreshing existing device " << device_path;
if (!adapter_.RemoveDeviceByObjectPath(device_path)) {
LOG(WARNING) << __func__ << ": Failed to remove device " << device_path;
}
}
}
} // namespace linux
} // namespace nearby
@@ -1,140 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_
#define PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_
#include <chrono>
#include <memory>
#include <sdbus-c++/AdaptorInterfaces.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/container/flat_hash_map.h"
#include "absl/synchronization/mutex.h"
#include "internal/base/observer_list.h"
#include "internal/platform/bluetooth_utils.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
namespace nearby {
namespace linux {
class BluetoothAdapter;
class BluetoothDevices final {
public:
BluetoothDevices(
std::shared_ptr<sdbus::IConnection> system_bus,
sdbus::ObjectPath adapter_object_path,
ObserverList<api::BluetoothClassicMedium::Observer> &observers)
: system_bus_(std::move(system_bus)),
observers_(observers),
adapter_object_path_(std::move(adapter_object_path)) {}
std::shared_ptr<BluetoothDevice> get_device_by_path(const sdbus::ObjectPath &)
ABSL_LOCKS_EXCLUDED(devices_by_path_lock_);
std::shared_ptr<BluetoothDevice> get_device_by_address(const std::string &);
std::shared_ptr<BluetoothDevice> get_device_by_unique_id(
api::ble_v2::BlePeripheral::UniqueId id);
std::shared_ptr<MonitoredBluetoothDevice> add_new_device(sdbus::ObjectPath)
ABSL_LOCKS_EXCLUDED(devices_by_path_lock_);
void remove_device_by_path(const sdbus::ObjectPath &)
ABSL_LOCKS_EXCLUDED(devices_by_path_lock_);
void mark_peripheral_lost(const sdbus::ObjectPath &)
ABSL_LOCKS_EXCLUDED(devices_by_path_lock_);
void cleanup_lost_peripherals() ABSL_LOCKS_EXCLUDED(devices_by_path_lock_);
// DEBUG
void dump_devices() ABSL_LOCKS_EXCLUDED(devices_by_path_lock_) {
absl::ReaderMutexLock lock(&devices_by_path_lock_);
LOG(INFO) << "Dumping BluetoothDevices:";
for (const auto& [path, device] : devices_by_path_) {
LOG(INFO) << " - Device path: " << path << " , Name: " << device->GetName();
}
}
private:
std::shared_ptr<sdbus::IConnection> system_bus_;
ObserverList<api::BluetoothClassicMedium::Observer> &observers_;
sdbus::ObjectPath adapter_object_path_;
absl::Mutex devices_by_path_lock_;
absl::flat_hash_map<std::string, std::shared_ptr<MonitoredBluetoothDevice>>
devices_by_path_ ABSL_GUARDED_BY(devices_by_path_lock_);
std::chrono::time_point<std::chrono::steady_clock> last_cleanup_
ABSL_GUARDED_BY(devices_by_path_lock_);
};
class DeviceWatcher final : sdbus::ProxyInterfaces<sdbus::ObjectManager_proxy> {
public:
DeviceWatcher(const DeviceWatcher &) = delete;
DeviceWatcher(DeviceWatcher &&) = delete;
DeviceWatcher &operator=(const DeviceWatcher &) = delete;
DeviceWatcher &operator=(DeviceWatcher &&) = delete;
DeviceWatcher(
sdbus::IConnection &system_bus,
const sdbus::ObjectPath &adapter_object_path,
BluetoothAdapter &adapter,
std::shared_ptr<BluetoothDevices> devices,
std::unique_ptr<api::BluetoothClassicMedium::DiscoveryCallback>
discovery_callback,
std::shared_ptr<ObserverList<api::BluetoothClassicMedium::Observer>>
observers)
: ProxyInterfaces(system_bus, "org.bluez", "/"),
adapter_object_path_(adapter_object_path),
adapter_(adapter),
devices_(std::move(devices)),
discovery_cb_(std::move(discovery_callback)),
observers_(std::move(observers)) {
notifyExistingDevices();
registerProxy();
}
DeviceWatcher(sdbus::IConnection &system_bus,
const sdbus::ObjectPath &adapter_object_path,
BluetoothAdapter &adapter,
std::shared_ptr<BluetoothDevices> devices)
: DeviceWatcher(system_bus, adapter_object_path, adapter, std::move(devices),
nullptr, nullptr) {}
~DeviceWatcher() { unregisterProxy(); }
void onInterfacesAdded(
const sdbus::ObjectPath &object,
const std::map<std::string, std::map<std::string, sdbus::Variant>>
&interfaces) override;
void onInterfacesRemoved(const sdbus::ObjectPath &object,
const std::vector<std::string> &interfaces) override;
private:
void notifyExistingDevices();
sdbus::ObjectPath adapter_object_path_;
BluetoothAdapter &adapter_;
std::shared_ptr<BluetoothDevices> devices_;
std::shared_ptr<api::BluetoothClassicMedium::DiscoveryCallback> discovery_cb_;
std::shared_ptr<ObserverList<api::BluetoothClassicMedium::Observer>>
observers_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,105 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <utility>
#include <sdbus-c++/Error.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IProxy.h>
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_pairing.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) {
if (error != nullptr && error->isValid()) {
const auto &name = error->getName();
api::BluetoothPairingCallback::PairingError err =
api::BluetoothPairingCallback::PairingError::kAuthFailed;
LOG(ERROR) << __func__ << ": "
<< "Got error '" << error->getName()
<< "' with message '" << error->getMessage()
<< "' while pairing with device "
<< device_->GetMacAddress();
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;
}
if (pairing_cb_.on_pairing_error_cb != nullptr) {
pairing_cb_.on_pairing_error_cb(err);
}
return;
}
if (pairing_cb_.on_paired_cb != nullptr) {
pairing_cb_.on_paired_cb();
}
}
BluetoothPairing::BluetoothPairing(
BluetoothAdapter &adapter, std::shared_ptr<BluetoothDevice> remote_device)
: device_(std::move(remote_device)),
device_object_path_(bluez::device_object_path(adapter.GetObjectPath(),
device_->GetAddress().ToString())),
adapter_(adapter) {}
bool BluetoothPairing::InitiatePairing(
api::BluetoothPairingCallback pairing_cb) {
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()});
return true;
}
bool BluetoothPairing::FinishPairing(
std::optional<absl::string_view> pin_code) {
device_->SetPairReplyCallback([this](const sdbus::Error *error) {
this->pairing_reply_handler(error);
});
auto call = device_->Pair();
if (!call.has_value()) return false;
pair_async_call_ = *call;
return true;
}
bool BluetoothPairing::CancelPairing() {
if (pair_async_call_.isPending()) {
pair_async_call_.cancel();
}
return device_->CancelPairing();
}
bool BluetoothPairing::Unpair() {
return adapter_.RemoveDeviceByObjectPath(device_object_path_);
}
bool BluetoothPairing::IsPaired() { return device_->Bonded(); }
} // namespace linux
} // namespace nearby
@@ -1,57 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_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/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluetooth_classic_device.h"
namespace nearby {
namespace linux {
class BluetoothPairing final : public api::BluetoothPairing {
public:
BluetoothPairing(BluetoothAdapter &adapter,
std::shared_ptr<BluetoothDevice> remote_device);
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:
void pairing_reply_handler(const sdbus::Error *e);
sdbus::PendingAsyncCall pair_async_call_;
std::shared_ptr<BluetoothDevice> device_;
sdbus::ObjectPath device_object_path_;
linux::BluetoothAdapter adapter_;
api::BluetoothPairingCallback pairing_cb_;
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,85 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#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/linux/bluez.h"
namespace nearby {
namespace linux {
namespace bluez {
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(absl::AsciiStrToUpper(mac_address), {{":", "_"}}));
}
sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) {
return absl::Substitute(
"/com/google/nearby/medium/bluetooth_classic/profiles/$0",
absl::StrReplaceAll(service_uuid, {{"-", "_"}}));
}
sdbus::ObjectPath gatt_profile_object_path(absl::string_view service_uuid) {
return absl::Substitute(
"$0/profile_$1",
NEARBY_BLE_GATT_PROFILE_PATH_ROOT,
absl::StrReplaceAll(service_uuid, {{"-", "_"}}));
}
sdbus::ObjectPath adapter_object_path(absl::string_view name) {
return absl::Substitute("/org/bluez/$0", name);
}
sdbus::ObjectPath gatt_service_path(size_t num) {
return absl::Substitute("$0/service$1", NEARBY_BLE_GATT_PATH_ROOT, num);
}
sdbus::ObjectPath gatt_characteristic_path(
const sdbus::ObjectPath &service_path, size_t num) {
return absl::Substitute("$0/char$1", service_path, num);
}
sdbus::ObjectPath ble_advertisement_path(size_t num) {
return absl::Substitute("/com/google/nearby/medium/ble/advertisement/$0",
num);
}
sdbus::ObjectPath advertisement_monitor_path(absl::string_view uuid) {
return absl::Substitute(
"/com/google/nearby/medium/ble/advertisement/monitor/$0",
absl::StrReplaceAll(uuid, {{"-", "_"}}));
}
int16_t TxPowerLevelDbm(api::ble_v2::TxPowerLevel level) {
switch (level) {
case api::ble_v2::TxPowerLevel::kUnknown:
return 0;
case api::ble_v2::TxPowerLevel::kUltraLow:
return -3;
case api::ble_v2::TxPowerLevel::kLow:
return 0;
case api::ble_v2::TxPowerLevel::kMedium:
return 5;
case api::ble_v2::TxPowerLevel::kHigh:
return 10; // Increased from 6 to 10 dBm (maximum for most adapters)
}
}
} // namespace bluez
} // namespace linux
} // namespace nearby
@@ -1,89 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_H_
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/ble_v2.h"
#include <string>
#define BLUEZ_LOG_METHOD_CALL_ERROR(proxy, method, err) \
do { \
LOG(ERROR) << __func__ << ": Got error '" << (err).getName() \
<< "' with message '" << (err).getMessage() \
<< "' while calling " << method << " on object " \
<< (proxy)->getObjectPath(); \
} while (false)
namespace nearby {
namespace linux {
namespace bluez {
static constexpr const char *SERVICE_DEST = "org.bluez";
static constexpr const char *ADAPTER_INTERFACE = "org.bluez.Adapter1";
static constexpr const char *DEVICE_INTERFACE = "org.bluez.Device1";
static constexpr const char *DEVICE_PROP_ADDRESS = "Address";
static constexpr const char *DEVICE_PROP_ALIAS = "Alias";
static constexpr const char *DEVICE_PROP_PAIRED = "Paired";
static constexpr const char *DEVICE_PROP_CONNECTED = "Connected";
static constexpr const char *DEVICE_NAME = "Name";
static constexpr const char *NEARBY_BLE_GATT_PATH_ROOT =
"/com/google/nearby/medium/ble/gatt";
static constexpr const char *NEARBY_BLE_GATT_PROFILE_PATH_ROOT =
"/com/google/nearby/medium/ble/gatt/profile";
std::string device_object_path(const sdbus::ObjectPath &adapter_object_path,
absl::string_view mac_address);
sdbus::ObjectPath profile_object_path(absl::string_view service_uuid);
sdbus::ObjectPath adapter_object_path(absl::string_view name);
sdbus::ObjectPath gatt_profile_object_path(absl::string_view service_uuid);
sdbus::ObjectPath gatt_service_path(size_t num);
sdbus::ObjectPath gatt_characteristic_path(
const sdbus::ObjectPath &service_path, size_t num);
sdbus::ObjectPath ble_advertisement_path(size_t num);
sdbus::ObjectPath advertisement_monitor_path(absl::string_view uuid);
int16_t TxPowerLevelDbm(api::ble_v2::TxPowerLevel level);
class BluezObjectManager
: public sdbus::ProxyInterfaces<sdbus::ObjectManager_proxy> {
public:
explicit BluezObjectManager(sdbus::IConnection &system_bus)
: ProxyInterfaces(system_bus, "org.bluez", "/") {
registerProxy();
}
virtual ~BluezObjectManager() { unregisterProxy(); }
protected:
void onInterfacesAdded(
const sdbus::ObjectPath &objectPath,
const std::map<std::string, std::map<std::string, sdbus::Variant>>
&interfacesAndProperties) override {}
void onInterfacesRemoved(
const sdbus::ObjectPath &objectPath,
const std::vector<std::string> &interfaces) override {}
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,73 +0,0 @@
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
#include <regex>
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/utils.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
namespace bluez {
AdvertisementMonitor::AdvertisementMonitor(
sdbus::IConnection &system_bus, Uuid service_uuid,
api::ble_v2::TxPowerLevel tx_power_level, absl::string_view type,
std::shared_ptr<BluetoothDevices> devices,
api::ble_v2::BleMedium::ScanCallback scan_callback)
: AdvertisementMonitor(
system_bus, service_uuid, tx_power_level, type, std::move(devices),
api::ble_v2::BleMedium::ScanningCallback{
.start_scanning_result = nullptr,
.advertisement_found_cb =
std::move(scan_callback.advertisement_found_cb)}) {}
AdvertisementMonitor::AdvertisementMonitor(
sdbus::IConnection &system_bus, Uuid service_uuid,
api::ble_v2::TxPowerLevel tx_power_level, absl::string_view type,
std::shared_ptr<BluetoothDevices> devices,
api::ble_v2::BleMedium::ScanningCallback scan_callback)
: AdaptorInterfaces(system_bus, bluez::advertisement_monitor_path(
std::string{service_uuid})),
devices_(std::move(devices)),
scan_callback_{std::move(scan_callback.advertisement_found_cb)},
start_scanning_result_callback_(
std::move(scan_callback.start_scanning_result)),
type_(type),
service_uuid_(service_uuid),
tx_power_level_(tx_power_level) {
registerAdaptor();
}
void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) {
devices_->cleanup_lost_peripherals();
auto peripheral = devices_->add_new_device(device);
auto service_data = peripheral->ServiceData();
if (!service_data.has_value()) return;
struct api::ble_v2::BleAdvertisementData adv_data;
for (const auto &[uuid_str, data] : *service_data) {
auto uuid = UuidFromString(uuid_str);
if (!uuid.has_value()) {
LOG(ERROR)
<< __func__
<< ": Could not parse UUID string in ServiceData for peripheral "
<< peripheral->getObjectPath();
continue;
}
std::vector<uint8_t> bytes = data;
adv_data.service_data.emplace(*uuid,
std::string(bytes.begin(), bytes.end()));
}
auto id = std::stoull(std::regex_replace(peripheral->GetMacAddress(),
std::regex("[:\\-]"), ""), nullptr, 16);
scan_callback_.advertisement_found_cb(id, adv_data);
}
void AdvertisementMonitor::DeviceLost(const sdbus::ObjectPath &device) {
devices_->mark_peripheral_lost(device);
}
} // namespace bluez
} // namespace linux
} // namespace nearby
@@ -1,97 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_ADVERTISEMENT_MONITOR_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_ADVERTISEMENT_MONITOR_H_
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/StandardInterfaces.h>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluetooth_devices.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
namespace bluez {
class AdvertisementMonitor final
: public sdbus::AdaptorInterfaces<org::bluez::AdvertisementMonitor1_adaptor,
sdbus::ManagedObject_adaptor> {
public:
AdvertisementMonitor(const AdvertisementMonitor&) = delete;
AdvertisementMonitor(AdvertisementMonitor&&) = delete;
AdvertisementMonitor& operator=(const AdvertisementMonitor&) = delete;
AdvertisementMonitor& operator=(AdvertisementMonitor&&) = delete;
AdvertisementMonitor(sdbus::IConnection& system_bus, Uuid service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
absl::string_view type,
std::shared_ptr<BluetoothDevices> devices,
api::ble_v2::BleMedium::ScanCallback scan_callback);
AdvertisementMonitor(sdbus::IConnection& system_bus, Uuid service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
absl::string_view type,
std::shared_ptr<BluetoothDevices> devices,
api::ble_v2::BleMedium::ScanningCallback scan_callback);
~AdvertisementMonitor() { unregisterAdaptor(); }
private:
// Methods
void Release() override {}
void Activate() override {
LOG(INFO) <<__func__ << ": bluez advertisement monitor activated at path: " << getObjectPath();
if (start_scanning_result_callback_ != nullptr) {
start_scanning_result_callback_(absl::OkStatus());
}
}
void DeviceFound(const sdbus::ObjectPath& device) override;
void DeviceLost(const sdbus::ObjectPath& device) override;
// Properties
std::string Type() override { return type_; };
int16_t RSSILowThreshold() override { return 127; };
int16_t RSSIHighThreshold() override {
return 127;
}
uint16_t RSSISamplingPeriod() override {
// The Windows implementation uses a sampling interval of 2 seconds.
return 20;
}
std::vector<sdbus::Struct<uint8_t, uint8_t, std::vector<uint8_t>>> Patterns()
override {
std::array<char, 16> service_id_data = service_uuid_.data();
return {{0,
0x16,
{static_cast<uint8_t>(service_id_data[3] & 0xFF),
static_cast<uint8_t>(service_id_data[2] & 0xFF)}
}};
};
std::shared_ptr<BluetoothDevices> devices_;
api::ble_v2::BleMedium::ScanCallback scan_callback_;
absl::AnyInvocable<void(absl::Status)> start_scanning_result_callback_;
std::string type_;
Uuid service_uuid_;
api::ble_v2::TxPowerLevel tx_power_level_;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,89 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_ADVERTISEMENT_MONITOR_MANAGER_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_ADVERTISEMENT_MONITOR_MANAGER_H_
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h"
namespace nearby {
namespace linux {
namespace bluez {
class AdvertisementMonitorManager final
: public sdbus::ProxyInterfaces<
org::bluez::AdvertisementMonitorManager1_proxy> {
private:
friend std::unique_ptr<AdvertisementMonitorManager>
std::make_unique<AdvertisementMonitorManager>(
sdbus::IConnection &, const ::nearby::linux::BluetoothAdapter &);
AdvertisementMonitorManager(
sdbus::IConnection &system_bus,
const ::nearby::linux::BluetoothAdapter &adapter)
: ProxyInterfaces(system_bus, "org.bluez", adapter.GetObjectPath()) {
registerProxy();
}
public:
AdvertisementMonitorManager(const AdvertisementMonitorManager &) = delete;
AdvertisementMonitorManager(AdvertisementMonitorManager &&) = delete;
AdvertisementMonitorManager &operator=(const AdvertisementMonitorManager &) =
delete;
AdvertisementMonitorManager &operator=(AdvertisementMonitorManager &&) =
delete;
~AdvertisementMonitorManager() { unregisterProxy(); }
static std::unique_ptr<AdvertisementMonitorManager>
DiscoverAdvertisementMonitorManager(
sdbus::IConnection &system_bus,
const ::nearby::linux::BluetoothAdapter &adapter) {
bluez::BluezObjectManager manager(system_bus);
std::map<sdbus::ObjectPath,
std::map<std::string, std::map<std::string, sdbus::Variant>>>
objects;
try {
objects = manager.GetManagedObjects();
} catch (const sdbus::Error &e) {
DBUS_LOG_METHOD_CALL_ERROR(&manager, "GetManagedObjects", e);
return nullptr;
}
if (objects.count(adapter.GetObjectPath()) == 0) {
LOG(ERROR) << __func__ << ": Adapter object no longer exists "
<< adapter.GetObjectPath();
return nullptr;
}
if (objects[adapter.GetObjectPath()].count(
org::bluez::AdvertisementMonitorManager1_proxy::INTERFACE_NAME) ==
0) {
LOG(ERROR)
<< __func__ << ": Adapter " << adapter.GetObjectPath()
<< " doesn't provide "
<< org::bluez::AdvertisementMonitorManager1_proxy::INTERFACE_NAME;
return nullptr;
}
return std::make_unique<AdvertisementMonitorManager>(system_bus, adapter);
}
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,65 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_DEVICE_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_DEVICE_H_
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/Types.h>
#include "absl/functional/any_invocable.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/device_client.h"
namespace nearby {
namespace linux {
namespace bluez {
class Device : public sdbus::ProxyInterfaces<org::bluez::Device1_proxy> {
public:
Device(std::shared_ptr<sdbus::IConnection> system_bus,
const sdbus::ObjectPath &device_path)
: ProxyInterfaces(*system_bus, "org.bluez", device_path),
system_bus(std::move(system_bus)) {
registerProxy();
}
~Device() { unregisterProxy(); }
void SetPairReplyCallback(absl::AnyInvocable<void(const sdbus::Error *)> cb)
ABSL_LOCKS_EXCLUDED(pair_callback_lock_) {
absl::MutexLock l(&pair_callback_lock_);
on_pair_reply_cb_ = std::move(cb);
}
void ResetPairReplyCallback() ABSL_LOCKS_EXCLUDED(pair_callback_lock_) {
absl::MutexLock l(&pair_callback_lock_);
on_pair_reply_cb_ = nullptr;
}
protected:
void onPairReply(const sdbus::Error *error) override
ABSL_LOCKS_EXCLUDED(pair_callback_lock_) {
absl::ReaderMutexLock l(&pair_callback_lock_);
if (on_pair_reply_cb_ != nullptr) on_pair_reply_cb_(error);
};
private:
std::shared_ptr<sdbus::IConnection> system_bus;
absl::Mutex pair_callback_lock_;
absl::AnyInvocable<void(const sdbus::Error *)> on_pair_reply_cb_
ABSL_GUARDED_BY(pair_callback_lock_) = nullptr;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,41 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <map>
#include <string>
#include <vector>
#include "internal/platform/implementation/linux/bluez_gatt_characteristic_client.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h"
namespace nearby {
namespace linux {
namespace bluez {
void SubscribedGattCharacteristicClient::onPropertiesChanged(
const std::string& interfaceName,
const std::map<std::string, sdbus::Variant>& changedProperties,
const std::vector<std::string>& invalidatedProperties) {
if (interfaceName != org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME)
return;
if (changedProperties.count("Value") == 1) {
std::vector<uint8_t> value_bytes = changedProperties.at("Value");
if (notify_callback_ != nullptr) {
auto value = std::string(value_bytes.cbegin(), value_bytes.cend());
notify_callback_(value);
}
}
}
} // namespace bluez
} // namespace linux
} // namespace nearby
@@ -1,71 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_CLIENT_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_CLIENT_H_
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/StandardInterfaces.h>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h"
namespace nearby {
namespace linux {
namespace bluez {
class GattCharacteristicClient
: public sdbus::ProxyInterfaces<org::bluez::GattCharacteristic1_proxy,
sdbus::Properties_proxy> {
public:
GattCharacteristicClient(std::shared_ptr<sdbus::IConnection> system_bus,
sdbus::ObjectPath path)
: ProxyInterfaces(*system_bus, "org.bluez", std::move(path)),
system_bus_(std::move(system_bus)) {
registerProxy();
}
virtual ~GattCharacteristicClient() { unregisterProxy(); }
protected:
void onPropertiesChanged(
const std::string& interfaceName,
const std::map<std::string, sdbus::Variant>& changedProperties,
const std::vector<std::string>& invalidatedProperties) override {}
std::shared_ptr<sdbus::IConnection> system_bus_;
};
class SubscribedGattCharacteristicClient : public GattCharacteristicClient {
public:
SubscribedGattCharacteristicClient(
std::shared_ptr<sdbus::IConnection> system_bus, sdbus::ObjectPath path,
absl::AnyInvocable<void(absl::string_view value)> notify_callback)
: GattCharacteristicClient(std::move(system_bus), std::move(path)),
notify_callback_(std::move(notify_callback)) {}
protected:
void onPropertiesChanged(
const std::string& interfaceName,
const std::map<std::string, sdbus::Variant>& changedProperties,
const std::vector<std::string>& invalidatedProperties) override;
private:
absl::AnyInvocable<void(absl::string_view value)> notify_callback_;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,240 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sdbus-c++/Error.h>
#include <sdbus-c++/MethodResult.h>
#include <sdbus-c++/Types.h>
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluez_gatt_characteristic_server.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
namespace bluez {
void GattCharacteristicServer::Update(const nearby::ByteArray &value) {
std::vector<uint8_t> bytes(value.size());
const auto *buf = value.data();
for (auto i = 0; i < value.size(); i++) bytes[i] = buf[i];
absl::MutexLock static_value_lock(&static_value_mutex_);
static_value_ = std::move(bytes);
}
absl::Status GattCharacteristicServer::NotifyChanged(
bool confirm, const ByteArray &new_value) {
std::vector<uint8_t> bytes(new_value.size());
const auto *buf = new_value.data();
for (auto i = 0; i < new_value.size(); i++) bytes[i] = buf[i];
{
absl::MutexLock lock(&cached_value_mutex_);
cached_value_ = bytes;
}
if (confirm) {
auto confirmed = [&]() {
confirmed_mutex_.AssertReaderHeld();
return confirmed_;
};
{
absl::MutexLock lock(&confirmed_mutex_);
confirmed_ = false;
}
absl::ReaderMutexLock lock(&confirmed_mutex_, absl::Condition(&confirmed));
}
try {
emitPropertiesChangedSignal(GattCharacteristic1_adaptor::INTERFACE_NAME,
{"Value"});
return absl::OkStatus();
} catch (const sdbus::Error &e) {
LOG(ERROR) << __func__
<< ": Error emitting PropertiesChanged signal on "
<< getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
return absl::UnknownError(e.getMessage());
}
}
void GattCharacteristicServer::ReadValue(
sdbus::Result<std::vector<uint8_t>> &&result,
std::map<std::string, sdbus::Variant> options) {
{
absl::ReaderMutexLock static_value_lock(&static_value_mutex_);
if (static_value_.has_value()) {
result.returnResults(*static_value_);
absl::MutexLock cached_value_lock(&cached_value_mutex_);
cached_value_ = *static_value_;
return;
}
}
uint16_t offset = options["offset"];
sdbus::ObjectPath device_path = options["device"];
auto device = devices_->get_device_by_path(device_path);
if (device == nullptr) {
result.returnError(
sdbus::Error("org.bluez.Error.NotAuthorized", "device does not exist"));
return;
}
auto characteristic = characteristic_;
// TODO: enable the callback
// server_cb_->on_characteristic_read_cb(
// *device, characteristic, static_cast<int>(offset),
// [result = std::move(result),
// this](absl::StatusOr<absl::string_view> data) {
// const auto &status = data.status();
// if (status.ok()) {
// auto str = data.value();
// std::vector<uint8_t> bytes(str.size());
// for (auto i = 0; i < str.size(); i++) {
// bytes[i] = str[i];
// }
// result.returnResults(bytes);
//
// absl::MutexLock lock(&cached_value_mutex_);
// cached_value_ = bytes;
// } else if (absl::IsPermissionDenied(status)) {
// result.returnError(sdbus::Error("org.bluez.Error.NotPermitted",
// std::string(status.message())));
// } else if (absl::IsUnauthenticated(status)) {
// result.returnError(sdbus::Error("org.bluez.Error.NotAuthorized",
// std::string(status.message())));
// } else if (absl::IsOutOfRange(status)) {
// result.returnError(sdbus::Error("org.bluez.Error.InvalidOffset",
// std::string(status.message())));
// } else if (absl::IsUnimplemented(status)) {
// result.returnError(sdbus::Error("org.bluez.Error.NotSupported",
// std::string(status.message())));
// } else {
// result.returnError(sdbus::Error("org.bluez.Error.Failed",
// std::string(status.message())));
// }
// });
}
void GattCharacteristicServer::WriteValue(
sdbus::Result<> &&result, std::vector<uint8_t> value,
std::map<std::string, sdbus::Variant> options) {
uint16_t offset = options["offset"];
sdbus::ObjectPath device_path = options["device"];
auto device = devices_->get_device_by_path(device_path);
if (device == nullptr) {
result.returnError(
sdbus::Error("org.bluez.Error.NotAuthorized", "device does not exist"));
return;
}
std::string type = options["type"];
std::string data(value.begin(), value.end());
auto characteristic = characteristic_;
// TODO: enable the callback
// TODO: Support writes without response.
// server_cb_->on_characteristic_write_cb(
// *device, characteristic, static_cast<int>(offset), data,
// [result = std::move(result)](absl::Status status) {
// if (status.ok()) {
// result.returnResults();
// } else if (absl::IsPermissionDenied(status)) {
// result.returnError(sdbus::Error("org.bluez.Error.NotPermitted",
// std::string(status.message())));
// } else if (absl::IsUnauthenticated(status)) {
// result.returnError(sdbus::Error("org.bluez.Error.NotAuthorized",
// std::string(status.message())));
// } else if (absl::IsOutOfRange(status)) {
// result.returnError(sdbus::Error("org.bluez.Error.InvalidOffset",
// std::string(status.message())));
// } else if (absl::IsUnimplemented(status)) {
// result.returnError(sdbus::Error("org.bluez.Error.NotSupported",
// std::string(status.message())));
// } else {
// result.returnError(sdbus::Error("org.bluez.Error.Failed",
// std::string(status.message())));
// }
// });
}
void GattCharacteristicServer::StartNotify() {
if ((characteristic_.property |
api::ble_v2::GattCharacteristic::Property::kNotify) ==
api::ble_v2::GattCharacteristic::Property::kNotify) {
if (notify_sessions_.fetch_add(1) == 0) {
if (server_cb_->characteristic_subscription_cb != nullptr) {
server_cb_->characteristic_subscription_cb(characteristic_);
}
notifying_ = true;
}
} else {
throw(sdbus::Error("org.bluez.Error.NotSupported"));
}
}
void GattCharacteristicServer::StopNotify() {
if ((characteristic_.property |
api::ble_v2::GattCharacteristic::Property::kNotify) ==
api::ble_v2::GattCharacteristic::Property::kNotify) {
if (notify_sessions_.fetch_sub(0) == 1) {
if (server_cb_->characteristic_unsubscription_cb != nullptr) {
server_cb_->characteristic_unsubscription_cb(characteristic_);
}
notifying_ = false;
}
} else {
throw(sdbus::Error("org.bluez.Error.Failed"));
}
}
std::vector<std::string> GattCharacteristicServer::Flags() {
auto characteristic = characteristic_;
std::vector<std::string> flags;
if ((characteristic.permission &
api::ble_v2::GattCharacteristic::Permission::kRead) ==
api::ble_v2::GattCharacteristic::Permission::kRead ||
(characteristic.property &
api::ble_v2::GattCharacteristic::Property::kRead) ==
api::ble_v2::GattCharacteristic::Property::kRead)
flags.push_back("read");
if ((characteristic.permission &
api::ble_v2::GattCharacteristic::Permission::kWrite) ==
api::ble_v2::GattCharacteristic::Permission::kWrite ||
(characteristic.property &
api::ble_v2::GattCharacteristic::Property::kWrite) ==
api::ble_v2::GattCharacteristic::Property::kWrite) {
flags.push_back("write");
flags.push_back("write-without-response");
}
if ((characteristic.property &
api::ble_v2::GattCharacteristic::Property::kIndicate) ==
api::ble_v2::GattCharacteristic::Property::kIndicate)
flags.push_back("indicate");
if ((characteristic.property &
api::ble_v2::GattCharacteristic::Property::kNotify) ==
api::ble_v2::GattCharacteristic::Property::kNotify)
flags.push_back("notify");
return flags;
}
} // namespace bluez
} // namespace linux
} // namespace nearby
@@ -1,129 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_SERVER_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_SERVER_H_
#include <atomic>
#include <map>
#include <optional>
#include <string>
#include <vector>
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/MethodResult.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/ble_v2.h"
#include "internal/platform/implementation/linux/bluetooth_devices.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
namespace bluez {
class GattCharacteristicServer final
: public sdbus::AdaptorInterfaces<org::bluez::GattCharacteristic1_adaptor,
sdbus::Properties_adaptor,
sdbus::ManagedObject_adaptor> {
public:
GattCharacteristicServer(const GattCharacteristicServer &) = delete;
GattCharacteristicServer(GattCharacteristicServer &&) = delete;
GattCharacteristicServer &operator=(const GattCharacteristicServer &) =
delete;
GattCharacteristicServer &operator=(GattCharacteristicServer &&) = delete;
GattCharacteristicServer(
sdbus::IConnection &system_bus,
const sdbus::ObjectPath &service_object_path, size_t num,
const api::ble_v2::GattCharacteristic &characteristic,
std::shared_ptr<api::ble_v2::ServerGattConnectionCallback> server_cb,
std::shared_ptr<BluetoothDevices> devices)
: AdaptorInterfaces(system_bus, bluez::gatt_characteristic_path(
service_object_path, num)),
devices_(std::move(devices)),
server_cb_(std::move(server_cb)),
characteristic_(characteristic),
service_object_path_(service_object_path),
notifying_(false),
confirmed_(false),
notify_sessions_(0) {
registerAdaptor();
LOG(INFO)
<< __func__ << "Creating a "
<< org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME
<< " object at " << getObjectPath();
}
~GattCharacteristicServer() { unregisterAdaptor(); }
void Update(const nearby::ByteArray &value)
ABSL_LOCKS_EXCLUDED(static_value_mutex_);
absl::Status NotifyChanged(bool confirm, const ByteArray &new_value)
ABSL_LOCKS_EXCLUDED(confirmed_mutex_);
private:
// Methods
void ReadValue(sdbus::Result<std::vector<uint8_t>> &&result,
std::map<std::string, sdbus::Variant> options) override
ABSL_LOCKS_EXCLUDED(cached_value_mutex_, static_value_mutex_);
void WriteValue(sdbus::Result<> &&result, std::vector<uint8_t> value,
std::map<std::string, sdbus::Variant> options) override;
void StartNotify() override;
void StopNotify() override;
void Confirm() override ABSL_LOCKS_EXCLUDED(confirmed_mutex_) {
absl::MutexLock lock(&confirmed_mutex_);
confirmed_ = true;
};
// Properties
std::string UUID() override { return std::string{characteristic_.uuid}; }
sdbus::ObjectPath Service() override { return service_object_path_; }
bool Notifying() override { return notifying_; }
std::vector<std::string> Flags() override;
std::vector<uint8_t> Value() override
ABSL_LOCKS_EXCLUDED(cached_value_mutex_) {
absl::ReaderMutexLock lock(&cached_value_mutex_);
return cached_value_;
}
std::shared_ptr<BluetoothDevices> devices_;
std::shared_ptr<api::ble_v2::ServerGattConnectionCallback> server_cb_;
api::ble_v2::GattCharacteristic characteristic_;
// Set by `GattServer::UpdateCharacteristic()`
absl::Mutex static_value_mutex_;
std::optional<std::vector<uint8_t>> static_value_
ABSL_GUARDED_BY(static_value_mutex_);
sdbus::ObjectPath service_object_path_;
std::atomic_bool notifying_;
absl::Mutex cached_value_mutex_;
std::vector<uint8_t> cached_value_ ABSL_GUARDED_BY(cached_value_mutex_);
absl::Mutex confirmed_mutex_;
bool confirmed_;
std::atomic_size_t notify_sessions_;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,44 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLUEZ_GATT_MANAGER_H_
#define PLATFORM_IMPL_LINUX_API_BLUEZ_GATT_MANAGER_H_
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/Types.h>
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h"
namespace nearby {
namespace linux {
namespace bluez {
class GattManager
: public sdbus::ProxyInterfaces<org::bluez::GattManager1_proxy> {
public:
GattManager(const GattManager &) = delete;
GattManager(GattManager &&) = delete;
GattManager &operator=(const GattManager &) = delete;
GattManager &operator=(GattManager &&) = delete;
GattManager(sdbus::IConnection &system_bus,
sdbus::ObjectPath adapter_object_path)
: ProxyInterfaces(system_bus, "org.bluez",
std::move(adapter_object_path)) {
registerProxy();
}
~GattManager() { unregisterProxy(); }
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,63 +0,0 @@
//
// Created by root on 1/11/26.
//
#ifndef WORKSPACE_BLUEZ_GATT_PROFILE_H
#define WORKSPACE_BLUEZ_GATT_PROFILE_H
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/Types.h>
#include "generated/dbus/bluez/gatt_profile_server.h"
#include "internal/platform/logging.h"
#include <algorithm>
#include <cctype>
#include <string>
namespace nearby {
namespace linux {
namespace bluez {
class GattProfile
: public sdbus::AdaptorInterfaces<org::bluez::GattProfile1_adaptor, sdbus::ManagedObject_adaptor> {
public:
GattProfile(const GattProfile &) = delete;
GattProfile(GattProfile &&) = delete;
GattProfile &operator=(const GattProfile &) = delete;
GattProfile &operator=(GattProfile &&) = delete;
GattProfile(sdbus::IConnection &system_bus,
sdbus::ObjectPath profile_path, std::string service_uuid)
: AdaptorInterfaces(system_bus, profile_path),
uuids_({service_uuid})
{
registerAdaptor();
}
~GattProfile() { unregisterAdaptor(); }
void Release() override
{
LOG(INFO) << __func__ << ": Gatt profile released";
};
private:
std::string ToLowerAscii(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return s;
}
std::vector<std::string> UUIDs() override
{
LOG(INFO)<< __func__ << ": UUIDs called, returned: " << ToLowerAscii(uuids_[0]);
return uuids_;
};
std::vector<std::string> uuids_;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif //WORKSPACE_BLUEZ_GATT_PROFILE_H
@@ -1,40 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_GATT_SERVICE_CLIENT_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_SERVICE_CLIENT_H_
#include <memory>
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_client.h"
namespace nearby {
namespace linux {
class GattServiceClient final
: public sdbus::ProxyInterfaces<org::bluez::GattService1_proxy> {
public:
GattServiceClient(std::shared_ptr<sdbus::IConnection> system_bus,
sdbus::ObjectPath service_object_path)
: ProxyInterfaces(*system_bus, "org.bluez",
std::move(service_object_path)) {
registerProxy();
}
~GattServiceClient() { unregisterProxy(); }
};
} // namespace linux
} // namespace nearby
#endif
@@ -1,63 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/bluez_gatt_service_server.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluez_gatt_characteristic_server.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
namespace bluez {
bool GattServiceServer::AddCharacteristic(
const Uuid &service_uuid, const Uuid &characteristic_uuid,
api::ble_v2::GattCharacteristic::Permission permission,
api::ble_v2::GattCharacteristic::Property property) {
absl::MutexLock lock(&characterstics_mutex_);
api::ble_v2::GattCharacteristic characteristic{
characteristic_uuid, service_uuid, permission, property};
auto count = characteristics_.size();
std::shared_ptr<GattCharacteristicServer> chr =
std::make_shared<GattCharacteristicServer>(
getObject().getConnection(), getObjectPath(), count, characteristic,
server_cb_, devices_);
try {
chr->emitInterfacesAddedSignal(
{org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME});
} catch (const sdbus::Error &e) {
LOG(ERROR)
<< __func__
<< ": error emitting InterfacesAdded signal for object path "
<< chr->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
return false;
}
characteristics_.insert({characteristic_uuid, std::move(chr)});
return true;
}
std::shared_ptr<GattCharacteristicServer> GattServiceServer::GetCharacteristic(
const Uuid &uuid) {
absl::ReaderMutexLock lock(&characterstics_mutex_);
if (characteristics_.count(uuid) == 0) {
return nullptr;
}
return characteristics_[uuid];
}
} // namespace bluez
} // namespace linux
} // namespace nearby
@@ -1,110 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_BLUEZ_GATT_SERVICE_H_
#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_SERVICE_H_
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/IObject.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/bluez_gatt_characteristic_server.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h"
#include "internal/platform/logging.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
namespace bluez {
class GattServiceServer final
: public sdbus::AdaptorInterfaces<org::bluez::GattService1_adaptor,
sdbus::ManagedObject_adaptor,
sdbus::Properties_adaptor> {
public:
GattServiceServer(const GattServiceServer &) = delete;
GattServiceServer(GattServiceServer &&) = delete;
GattServiceServer &operator=(const GattServiceServer &) = delete;
GattServiceServer &operator=(GattServiceServer &&) = delete;
GattServiceServer(
sdbus::IConnection &system_bus, size_t num, const Uuid &service_uuid,
std::shared_ptr<api::ble_v2::ServerGattConnectionCallback> server_cb,
std::shared_ptr<BluetoothDevices> devices)
: AdaptorInterfaces(system_bus, bluez::gatt_service_path(num)),
devices_(std::move(devices)),
server_cb_(std::move(server_cb)),
uuid_(service_uuid),
primary_(true) {
registerAdaptor();
LOG(INFO) << __func__ << ": Created a "
<< org::bluez::GattService1_adaptor::INTERFACE_NAME
<< " object at " << getObjectPath();
}
~GattServiceServer() {
absl::MutexLock lock(&characterstics_mutex_);
for (auto &[_uuid, characteristic] : characteristics_) {
LOG(INFO) << __func__ << ": Removing characteristic "
<< characteristic->getObjectPath();
try {
characteristic->emitInterfacesRemovedSignal(
{org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME});
} catch (const sdbus::Error &e) {
LOG(ERROR)
<< __func__
<< ": error emitting InterfacesRemoved signal for object path "
<< characteristic->getObjectPath() << " with name '" << e.getName()
<< "' and message '" << e.getMessage() << "'";
}
}
unregisterAdaptor();
}
bool AddCharacteristic(const Uuid &service_uuid,
const Uuid &characteristic_uuid,
api::ble_v2::GattCharacteristic::Permission permission,
api::ble_v2::GattCharacteristic::Property property)
ABSL_LOCKS_EXCLUDED(characterstics_mutex_);
std::shared_ptr<GattCharacteristicServer> GetCharacteristic(const Uuid &uuid)
ABSL_LOCKS_EXCLUDED(characterstics_mutex_);
private:
// Properties
std::string UUID() override { return uuid_; }
bool Primary() override { return primary_; }
sdbus::ObjectPath Device() override { return "/"; }
std::vector<sdbus::ObjectPath> Includes() override { return {}; }
absl::Mutex characterstics_mutex_;
absl::flat_hash_map<Uuid, std::shared_ptr<GattCharacteristicServer>>
characteristics_ ABSL_GUARDED_BY(characterstics_mutex_);
std::shared_ptr<BluetoothDevices> devices_;
std::shared_ptr<api::ble_v2::ServerGattConnectionCallback> server_cb_;
const std::string uuid_;
const bool primary_;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,66 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <vector>
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/bluez_le_advertisement.h"
#include "internal/platform/logging.h"
#include "internal/platform/uuid.h"
namespace nearby {
namespace linux {
namespace bluez {
std::string BytesToHexString(const std::vector<uint8_t>& bytes) {
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (uint8_t b : bytes) {
oss << std::setw(2) << static_cast<int>(b);
}
return oss.str();
}
LEAdvertisement::LEAdvertisement(
sdbus::IConnection& system_bus, sdbus::ObjectPath path,
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters)
: AdaptorInterfaces(system_bus, std::move(path)),
is_extended_advertisement_(advertising_data.is_extended_advertisement),
advertise_set_parameters_(advertise_set_parameters) {
for (const auto& [uuid, data] : advertising_data.service_data) {
std::string uuid_string(uuid);
std::vector<uint8_t> data_bytes(data.size());
const auto* bytes = data.data();
service_uuids_.push_back(uuid_string);
// service_uuids_.push_back("0000FE2C-0000-1000-8000-00805F9B34FB");
// service_uuids_.push_back("0000FE2C-0000-1000-8000-00805F9B34FB");
for (size_t i = 0; i < data.size(); i++) {
data_bytes[i] = bytes[i];
}
// LOG(INFO)<< __func__ << ": " << uuid_string;
// LOG(INFO)<< __func__ << ": " << BytesToHexString(data_bytes);
service_data_.insert({uuid_string, std::move(data_bytes)});
// service_data_.insert({"0000FE2C-0000-1000-8000-00805F9B34FB", std::move(data_bytes)});
}
registerAdaptor();
LOG(INFO) << __func__
<< ": Created a org.bluez.LEAdvertisement1 instance at "
<< getObjectPath();
}
} // namespace bluez
} // namespace linux
} // namespace nearby
@@ -1,117 +0,0 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_API_BLUEZ_BLE_ADVERTISEMENT_H_
#define PLATFORM_IMPL_LINUX_API_BLUEZ_BLE_ADVERTISEMENT_H_
#include <sdbus-c++/AdaptorInterfaces.h>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/StandardInterfaces.h>
#include <sdbus-c++/Types.h>
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/linux/bluetooth_adapter.h"
#include "internal/platform/implementation/linux/bluez.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace linux {
namespace bluez {
class LEAdvertisement final
: public sdbus::AdaptorInterfaces<org::bluez::LEAdvertisement1_adaptor,
sdbus::ObjectManager_adaptor> {
public:
LEAdvertisement(const LEAdvertisement&) = delete;
LEAdvertisement(LEAdvertisement&&) = delete;
LEAdvertisement& operator=(const LEAdvertisement&) = delete;
LEAdvertisement& operator=(LEAdvertisement&&) = delete;
LEAdvertisement(sdbus::IConnection& system_bus, sdbus::ObjectPath path,
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters);
static std::unique_ptr<LEAdvertisement> CreateLEAdvertisement(
sdbus::IConnection& system_bus,
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertising_parameters) {
static std::atomic<size_t> adv_count = 0;
auto object_path = bluez::ble_advertisement_path(adv_count++);
return std::make_unique<LEAdvertisement>(
system_bus, object_path, advertising_data, advertising_parameters);
}
~LEAdvertisement() { unregisterAdaptor(); }
private:
// Methods
void Release() override {
LOG(INFO) << __func__
<< ": LE Advertisement released: " << getObjectPath();
}
// Properties
std::string Type() override { return "peripheral"; }
std::vector<std::string> ServiceUUIDs() override { return service_uuids_; }
std::map<std::string, sdbus::Variant> ManufacturerData() override {
return {};
}
std::vector<std::string> SolicitUUIDs() override { return {}; }
std::map<std::string, sdbus::Variant> ServiceData() override {
return service_data_;
}
std::map<std::string, sdbus::Variant> ScanResponseServiceData() override {
return {};
}
std::vector<std::string> Includes() override {
return {};
}
std::string LocalName() override { return {}; }
uint16_t Duration() override { return 0; }
uint16_t Timeout() override { return 0; }
// Windows seems to hardcode the scan interval to 118.125 milliseconds, so
// lets just replicate that.
uint32_t MinInterval() override { return 118; }
uint32_t MaxInterval() override { return 119; }
int16_t TxPower() override {
return bluez::TxPowerLevelDbm(advertise_set_parameters_.tx_power_level);
};
bool is_extended_advertisement_;
std::vector<std::string> service_uuids_;
std::map<std::string, sdbus::Variant> service_data_;
api::ble_v2::AdvertiseParameters advertise_set_parameters_;
};
class LEAdvertisementManager final
: public sdbus::ProxyInterfaces<org::bluez::LEAdvertisingManager1_proxy> {
public:
LEAdvertisementManager(sdbus::IConnection& system_bus,
BluetoothAdapter& adapter)
: ProxyInterfaces(system_bus, "org.bluez", adapter.GetObjectPath()) {
registerProxy();
}
~LEAdvertisementManager() { unregisterProxy(); }
LEAdvertisementManager(const LEAdvertisementManager&) = delete;
LEAdvertisementManager(LEAdvertisementManager&&) = delete;
LEAdvertisementManager& operator=(const LEAdvertisementManager&) = delete;
LEAdvertisementManager& operator=(LEAdvertisementManager&&) = delete;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif
@@ -1,79 +0,0 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_LE_BEARER_CLIENT_H_
#define PLATFORM_IMPL_LINUX_LE_BEARER_CLIENT_H_
#include <memory>
#include <string>
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/ProxyInterfaces.h>
#include <sdbus-c++/Types.h>
#include "absl/functional/any_invocable.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/linux/generated/dbus/bluez/le_bearer_client.h"
namespace nearby {
namespace linux {
namespace bluez {
class LEBearerClient
: public sdbus::ProxyInterfaces<org::bluez::Bearer::LE1_proxy> {
public:
LEBearerClient(std::shared_ptr<sdbus::IConnection> system_bus,
sdbus::ObjectPath bearer_path)
: ProxyInterfaces(*system_bus, "org.bluez", std::move(bearer_path)),
system_bus_(std::move(system_bus)) {
registerProxy();
}
~LEBearerClient() { unregisterProxy(); }
void SetDisconnectedCallback(
absl::AnyInvocable<void(const std::string& reason,
const std::string& message)> cb)
ABSL_LOCKS_EXCLUDED(disconnect_callback_lock_) {
absl::MutexLock l(&disconnect_callback_lock_);
on_disconnected_cb_ = std::move(cb);
}
void ResetDisconnectedCallback()
ABSL_LOCKS_EXCLUDED(disconnect_callback_lock_) {
absl::MutexLock l(&disconnect_callback_lock_);
on_disconnected_cb_ = nullptr;
}
protected:
void onDisconnected(const std::string& reason,
const std::string& message) override
ABSL_LOCKS_EXCLUDED(disconnect_callback_lock_) {
absl::ReaderMutexLock l(&disconnect_callback_lock_);
if (on_disconnected_cb_ != nullptr) {
on_disconnected_cb_(reason, message);
}
}
private:
std::shared_ptr<sdbus::IConnection> system_bus_;
absl::Mutex disconnect_callback_lock_;
absl::AnyInvocable<void(const std::string&, const std::string&)>
on_disconnected_cb_ ABSL_GUARDED_BY(disconnect_callback_lock_) = nullptr;
};
} // namespace bluez
} // namespace linux
} // namespace nearby
#endif // PLATFORM_IMPL_LINUX_LE_BEARER_CLIENT_H_
@@ -1,100 +0,0 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/condition_variable.h"
#include <future> // NOLINT
#include "absl/time/clock.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/linux/mutex.h"
#include "gtest/gtest.h"
class ConditionVariableTests : public testing::Test {
public:
class ConditionVariableTest {
public:
ConditionVariableTest() {}
std::future<bool> WaitForEvent(bool timedWait, // NOLINT
const absl::Duration* timeout) {
return std::async(
std::launch::async, [this, timedWait, timeout]() mutable -> bool {
if (timedWait == true) {
auto result = this->condition_variable_actual_.Wait(*timeout);
if (result.value == nearby::Exception::kSuccess) {
return true;
} else {
return false;
}
} else {
this->condition_variable_actual_.Wait();
}
return true;
});
}
void PostEvent() {
absl::MutexLock(&mutex_actual_.GetMutex());
condition_variable_actual_.Notify();
}
private:
nearby::linux::Mutex mutex_actual_ =
nearby::linux::Mutex(nearby::linux::Mutex::Mode::kRegular);
nearby::linux::Mutex& mutex_ = mutex_actual_;
nearby::linux::ConditionVariable condition_variable_actual_ =
nearby::linux::ConditionVariable(&mutex_);
nearby::linux::ConditionVariable& condition_variable_ =
condition_variable_actual_;
};
};
TEST_F(ConditionVariableTests, SuccessfulCreation) {
// Arrange
ConditionVariableTest conditionVariableTest;
auto result = conditionVariableTest.WaitForEvent(false, nullptr);
sleep(1);
// Act
conditionVariableTest.PostEvent();
// Assert
ASSERT_TRUE(result.get());
}
TEST_F(ConditionVariableTests, TimedCreation) {
// Arrange
ConditionVariableTest conditionVariableTest;
const absl::Duration duration = absl::Milliseconds(100);
// Act
auto result = conditionVariableTest.WaitForEvent(true, &duration);
// Assert
ASSERT_FALSE(result.get()); // Timed out
// Act
result = conditionVariableTest.WaitForEvent(true, &duration);
sleep(1);
conditionVariableTest.PostEvent();
// Assert
ASSERT_TRUE(result.get()); // Didn't timeout
}
@@ -1,164 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/shared/count_down_latch.h"
#include "gtest/gtest.h"
#include "internal/platform/implementation/platform.h"
#include <atomic>
#include <thread>
#include <vector>
class CountDownLatchTests : public testing::Test {
public:
class TestData {
public:
std::unique_ptr<nearby::api::CountDownLatch>& countDownLatch;
long volatile& count;
};
class CountDownLatchTest {
public:
static unsigned int ThreadProcCountDown(void* lpParam) {
TestData* testData = static_cast<TestData*>(lpParam);
sleep(1);
__sync_fetch_and_add(&testData->count, 1);
testData->countDownLatch->CountDown();
return 0;
}
static unsigned int ThreadProcAwait(void* lpParam) {
TestData* testData = static_cast<TestData*>(lpParam);
sleep(1);
testData->countDownLatch->Await();
__sync_fetch_and_add(&testData->count, 1);
return 0;
}
};
CountDownLatchTests() {}
};
TEST_F(CountDownLatchTests, CountDownLatchAwaitSucceeds) {
// Arrange
long volatile count = 0;
std::unique_ptr<nearby::api::CountDownLatch> countDownLatch =
nearby::api::ImplementationPlatform::CreateCountDownLatch(3);
std::vector<std::thread> threads;
TestData testData{countDownLatch, count};
// Setup 3 threads
for (int i = 0; i < 3; i++) {
// TODO: More complex scenarios may require use of a parameter
// to the thread procedure, such as an event per thread to
// be used for synchronization.
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread
// Could use C++ concurrency for this possibly
threads.emplace_back(CountDownLatchTest::ThreadProcCountDown, &testData);
}
// Act
nearby::Exception result = countDownLatch->Await();
for (auto& thread : threads) {
thread.join();
}
// Assert
EXPECT_EQ(result.value, nearby::Exception::kSuccess);
EXPECT_EQ(count, 3);
}
TEST_F(CountDownLatchTests, CountDownLatchAwaitTimeoutTimesOut) {
// Arrange
std::unique_ptr<nearby::api::CountDownLatch> countDownLatch =
nearby::api::ImplementationPlatform::CreateCountDownLatch(3);
// Act
nearby::ExceptionOr<bool> result =
countDownLatch->Await(absl::Milliseconds(5));
sleep(40);
// Assert
EXPECT_FALSE(result.GetResult());
// TODO(jfcarroll)I think there's a bug in the shared version of this, it's
// not returning a timeout exception, need to look at it some more.
// EXPECT_EQ(result.GetException().value,
// nearby::Exception::kTimeout);
}
TEST_F(CountDownLatchTests, CountDownLatchAwaitNoTimeoutSucceeds) {
// Arrange
long volatile count = 0;
std::unique_ptr<nearby::api::CountDownLatch> countDownLatch =
nearby::api::ImplementationPlatform::CreateCountDownLatch(3);
TestData testData{countDownLatch, count};
std::vector<std::thread> threads;
// Setup 3 threads
for (int i = 0; i < 3; i++) {
// TODO: More complex scenarios may require use of a parameter
// to the thread procedure, such as an event per thread to
// be used for synchronization.
threads.emplace_back(CountDownLatchTest::ThreadProcAwait, &testData);
}
for (auto& thread : threads) {
thread.join();
}
// Act
nearby::ExceptionOr<bool> result =
countDownLatch->Await(absl::Milliseconds(100));
// Assert
EXPECT_TRUE(result.GetResult());
EXPECT_EQ(result.GetException().value, nearby::Exception::kSuccess);
EXPECT_EQ(count, 3);
}
void test(std::string str) {
std::cout << str << std::endl;
return;
}
TEST_F(CountDownLatchTests, CountDownLatchCountDownBeforeAwaitSucceeds) {
// Arrange
long volatile count = 0;
std::unique_ptr<nearby::api::CountDownLatch> countDownLatch =
nearby::api::ImplementationPlatform::CreateCountDownLatch(1);
TestData testData{countDownLatch, count};
std::thread thread(CountDownLatchTest::ThreadProcCountDown, &testData);
// Act
countDownLatch->CountDown(); // This countdown occurs before the thread has a
// chance to run
// Assert
EXPECT_EQ(count, 1);
}
@@ -1,50 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/crypto.h"
#include <string>
#include "gtest/gtest.h"
namespace nearby {
namespace {
TEST(CryptoTest, Md5Hash) {
const std::string input{"Hello Nearby Connection"};
const ByteArray expected_md5(
"\x94\xa3\xbe\xc1\x8d\x30\xe3\x24\x5f\xa1\x4c\xee\xe7\x52\xe9\x36");
ByteArray md5_hash = Crypto::Md5(input);
EXPECT_EQ(md5_hash, expected_md5);
}
TEST(CryptoTest, Md5HashOnEmptyInput) {
EXPECT_EQ(Crypto::Md5(""), ByteArray{});
}
TEST(CryptoTest, Sha256Hash) {
const std::string input("Hello Nearby Connection");
const ByteArray expected_sha256(
"\xb4\x24\xd3\xc0\x58\x12\x9a\x42\xcb\x81\xa0\x4b\x6e\x9d\xfe\x45\x45\x9f"
"\x15\xf7\xc0\xa9\x32\x2f\xfb\x9\x45\xf0\xf9\xbe\x75\xb");
ByteArray sha256_hash = Crypto::Sha256(input);
EXPECT_EQ(sha256_hash, expected_sha256);
}
TEST(CryptoTest, Sha256HashOnEmptyInput) {
EXPECT_EQ(Crypto::Sha256(""), ByteArray{});
}
} // namespace
} // namespace nearby
@@ -24,7 +24,6 @@
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/device_info.h"
#include "internal/platform/implementation/linux/avahi.h"
#include "internal/platform/implementation/linux/dbus.h"
#include "internal/platform/implementation/linux/device_info.h"
#include "internal/platform/logging.h"
@@ -64,11 +63,11 @@ DeviceInfo::DeviceInfo(std::shared_ptr<sdbus::IConnection> system_bus)
login_manager_(std::make_unique<LoginManager>(*system_bus_)) {}
std::optional<std::string> DeviceInfo::GetOsDeviceName() const {
avahi::Server avahi(*system_bus_);
Hostnamed hostnamed(*system_bus_);
try {
return avahi.GetHostNameFqdn();
return hostnamed.Hostname();
} catch (const sdbus::Error &e) {
DBUS_LOG_PROPERTY_GET_ERROR(&avahi, "GetHostNameFqdn", e);
DBUS_LOG_PROPERTY_GET_ERROR(&hostnamed, "GetHostNameFqdn", e);
return std::nullopt;
}
}
@@ -1,129 +0,0 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/device_info.h"
#include <functional>
#include <string>
#include "absl/synchronization/notification.h"
#include "gtest/gtest.h"
#include "internal/platform/implementation/device_info.h"
namespace nearby {
namespace linux {
namespace {
TEST(DeviceInfo, DISABLED_GetComputerName) {
EXPECT_TRUE(DeviceInfo().GetOsDeviceName().has_value());
}
TEST(DeviceInfo, DISABLED_GetDeviceType) {
EXPECT_EQ(DeviceInfo().GetDeviceType(), api::DeviceInfo::DeviceType::kLaptop);
}
TEST(DeviceInfo, GetOsType) {
EXPECT_EQ(DeviceInfo().GetOsType(), api::DeviceInfo::OsType::kLinux);
}
TEST(DeviceInfo, DISABLED_GetFullName) {
EXPECT_TRUE(DeviceInfo().GetFullName().has_value());
}
TEST(DeviceInfo, DISABLED_GetGivenName) {
EXPECT_TRUE(DeviceInfo().GetGivenName().has_value());
}
TEST(DeviceInfo, DISABLED_GetLastName) {
EXPECT_TRUE(DeviceInfo().GetLastName().has_value());
}
TEST(DeviceInfo, DISABLED_GetProfileUserName) {
EXPECT_TRUE(DeviceInfo().GetProfileUserName().has_value());
}
TEST(DeviceInfo, DISABLED_GetLocalAppDataPath) {
EXPECT_TRUE(DeviceInfo().GetLocalAppDataPath().has_value());
}
TEST(DeviceInfo, DISABLED_GetDownloadPath) {
EXPECT_TRUE(DeviceInfo().GetDownloadPath().has_value());
}
TEST(DeviceInfo, DISABLED_GetTemporaryPath) {
EXPECT_TRUE(DeviceInfo().GetTemporaryPath().has_value());
}
TEST(DeviceInfo, DISABLED_IsScreenLocked) {
EXPECT_FALSE(DeviceInfo().IsScreenLocked());
}
TEST(DeviceInfo, DISABLED_RegisterScreenLockedListener) {
std::function<void(api::DeviceInfo::ScreenStatus)> listener_1 =
[](api::DeviceInfo::ScreenStatus) {};
std::function<void(api::DeviceInfo::ScreenStatus)> listener_2 =
[](api::DeviceInfo::ScreenStatus) {};
DeviceInfo device_info;
EXPECT_EQ(device_info.screen_locked_listeners_.size(), 0);
device_info.RegisterScreenLockedListener("listener_1", listener_1);
EXPECT_EQ(device_info.screen_locked_listeners_.size(), 1);
device_info.RegisterScreenLockedListener("listener_2", listener_2);
EXPECT_EQ(device_info.screen_locked_listeners_.size(), 2);
}
TEST(DeviceInfo, DISABLED_UnregisterScreenLockedListener) {
std::function<void(api::DeviceInfo::ScreenStatus)> listener_1 =
[](api::DeviceInfo::ScreenStatus) {};
std::function<void(api::DeviceInfo::ScreenStatus)> listener_2 =
[](api::DeviceInfo::ScreenStatus) {};
DeviceInfo device_info;
EXPECT_EQ(device_info.screen_locked_listeners_.size(), 0);
device_info.RegisterScreenLockedListener("listener_1", listener_1);
device_info.RegisterScreenLockedListener("listener_2", listener_2);
EXPECT_EQ(device_info.screen_locked_listeners_.size(), 2);
device_info.UnregisterScreenLockedListener("listener_1");
EXPECT_EQ(device_info.screen_locked_listeners_.size(), 1);
device_info.UnregisterScreenLockedListener("listener_2");
EXPECT_EQ(device_info.screen_locked_listeners_.size(), 0);
}
TEST(DeviceInfo, DISABLED_UpdateScreenLockedListener) {
absl::Notification notification;
api::DeviceInfo::ScreenStatus screen_locked_tracker =
api::DeviceInfo::ScreenStatus::kUndetermined;
std::function<void(api::DeviceInfo::ScreenStatus)> listener =
[&screen_locked_tracker,
&notification](api::DeviceInfo::ScreenStatus status) {
screen_locked_tracker = api::DeviceInfo::ScreenStatus::kLocked;
notification.Notify();
};
DeviceInfo device_info;
device_info.RegisterScreenLockedListener("listener", listener);
EXPECT_TRUE(notification.WaitForNotificationWithTimeout(absl::Seconds(5)));
EXPECT_EQ(screen_locked_tracker, api::DeviceInfo::ScreenStatus::kLocked);
}
} // namespace
} // namespace linux
} // namespace nearby
@@ -1,4 +1,4 @@
// Copyright 2023 Google LLC
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,19 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_
#define PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_
#include "gtest/gtest.h"
namespace nearby {
namespace api {
class WifiLanSocket {
public:
~WifiLanSocket() = default;
namespace linux {
private:
int fd;
};
} // namespace api
TEST(LinuxStubTests, Placeholder) {
GTEST_SKIP() << "Stub test placeholder to mirror Windows coverage.";
}
} // namespace linux
} // namespace nearby
#endif
@@ -1,323 +0,0 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/executor.h"
#include <algorithm>
#include <thread>
#include <utility>
#include "absl/synchronization/blocking_counter.h"
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
#include "absl/time/time.h"
#include "gtest/gtest.h"
#include "internal/platform/implementation/linux/test_data.h"
namespace nearby {
namespace linux {
namespace {
constexpr absl::Duration kWaitTimeout = absl::Milliseconds(200);
TEST(ExecutorTests, SingleThreadedExecutorSucceeds) {
absl::Notification notification;
// Arrange
std::string expected(RUNNABLE_0_TEXT.c_str());
auto executor = std::make_unique<Executor>();
std::string output = std::string();
// Container to note threads that ran
std::unique_ptr<std::vector<std::thread::id>> threadIds =
std::make_unique<std::vector<std::thread::id>>();
threadIds->push_back(std::this_thread::get_id());
// Act
executor->Execute([&]() {
threadIds->push_back(std::this_thread::get_id());
output.append(RUNNABLE_0_TEXT.c_str());
notification.Notify();
});
ASSERT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
executor->Shutdown();
// Assert
// We should've run 1 time on the main thread, and 5 times on the
// workerThread
ASSERT_EQ(threadIds->size(), 2);
// We should still be on the main thread
ASSERT_EQ(std::this_thread::get_id(), threadIds->at(0));
// We should've run all runnables on the worker thread
ASSERT_EQ(output, expected);
}
TEST(ExecutorTests, SingleThreadedExecutorAfterShutdownFails) {
// Arrange
std::string expected("");
std::unique_ptr<Executor> executor = std::make_unique<Executor>();
std::unique_ptr<std::string> output = std::make_unique<std::string>();
// Container to note threads that ran
std::unique_ptr<std::vector<std::thread::id>> threadIds =
std::make_unique<std::vector<std::thread::id>>();
threadIds->push_back(std::this_thread::get_id());
executor->Shutdown();
// Act
executor->Execute([&output, &threadIds]() {
threadIds->push_back(std::this_thread::get_id());
output->append(RUNNABLE_0_TEXT.c_str());
});
// Assert
// We should've run 1 time on the main thread, and 5 times on the
// workerThread
ASSERT_EQ(threadIds->size(), 1);
// We should still be on the main thread
ASSERT_EQ(std::this_thread::get_id(), threadIds->at(0));
// We should've run all runnables on the worker thread
ASSERT_EQ(*output.get(), expected);
}
TEST(ExecutorTests, SingleThreadedExecutorExecuteNullSucceeds) {
absl::Notification notification;
// Arrange
std::string expected(RUNNABLE_0_TEXT.c_str());
auto executor = std::make_unique<Executor>();
std::string output = std::string();
// Container to note threads that ran
std::unique_ptr<std::vector<std::thread::id>> threadIds =
std::make_unique<std::vector<std::thread::id>>();
threadIds->push_back(std::this_thread::get_id());
// Act
executor->Execute(nullptr);
executor->Execute([&]() {
threadIds->push_back(std::this_thread::get_id());
output.append(RUNNABLE_0_TEXT.c_str());
notification.Notify();
});
executor->Execute(nullptr);
ASSERT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
executor->Shutdown();
// Assert
// We should've run 1 time on the main thread, and 5 times on the
// workerThread
ASSERT_EQ(threadIds->size(), 2);
// We should still be on the main thread
ASSERT_EQ(std::this_thread::get_id(), threadIds->at(0));
// We should've run all runnables on the worker thread
ASSERT_EQ(output, expected);
}
TEST(ExecutorTests, SingleThreadedExecutorMultipleTasksSucceeds) {
absl::BlockingCounter block_count(5);
// Arrange
std::string expected(RUNNABLE_ALL_TEXT.c_str());
auto executor = std::make_unique<Executor>();
std::string output = std::string();
// Container to note threads that ran
std::unique_ptr<std::vector<std::thread::id>> threadIds =
std::make_unique<std::vector<std::thread::id>>();
auto parent_thread = std::this_thread::get_id();
// Act
for (int index = 0; index < 5; index++) {
executor->Execute([&, index]() {
threadIds->push_back(std::this_thread::get_id());
char buffer[128];
snprintf(buffer, sizeof(buffer), "%s%d, ", RUNNABLE_TEXT.c_str(), index);
output.append(std::string(buffer));
block_count.DecrementCount();
});
}
block_count.Wait();
executor->Shutdown();
// Assert
// We should've run 1 time on the main thread, and 5 times on the
// workerThread
ASSERT_EQ(threadIds->size(), 5);
// We should still be on the main thread
ASSERT_EQ(std::this_thread::get_id(), parent_thread);
// We should've run all runnables on the worker thread
auto workerThreadId = threadIds->at(0);
for (int index = 0; index < threadIds->size(); index++) {
ASSERT_EQ(threadIds->at(index), workerThreadId);
}
// We should of run them in the order submitted
ASSERT_EQ(output, expected);
}
TEST(ExecutorTests, MultiThreadedExecutorSingleTaskSucceeds) {
absl::Notification notification;
// Arrange
std::string expected(RUNNABLE_0_TEXT.c_str());
auto executor = std::make_unique<Executor>(2);
// Container to note threads that ran
std::unique_ptr<std::vector<std::thread::id>> threadIds =
std::make_unique<std::vector<std::thread::id>>();
std::shared_ptr<std::string> output = std::make_shared<std::string>();
threadIds->push_back(std::this_thread::get_id());
// Act
executor->Execute([&, output]() {
threadIds->push_back(std::this_thread::get_id());
output->append(RUNNABLE_0_TEXT.c_str());
notification.Notify();
});
ASSERT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
executor->Shutdown();
// Assert
// We should've run 1 time on the main thread, and 5 times on the
// workerThread
ASSERT_EQ(threadIds->size(), 2);
// We should still be on the main thread
ASSERT_EQ(std::this_thread::get_id(), threadIds->at(0));
// We should've run the task
ASSERT_EQ(*output.get(), expected);
}
TEST(ExecutorTests, MultiThreadedExecutorMultipleTasksSucceeds) {
absl::BlockingCounter block_count(5);
// Arrange
auto executor = std::make_unique<Executor>(2);
// Container to note threads that ran
std::unique_ptr<std::vector<std::thread::id>> threadIds =
std::make_unique<std::vector<std::thread::id>>();
std::shared_ptr<std::string> output = std::make_shared<std::string>();
threadIds->push_back(std::this_thread::get_id());
// Act
for (int index = 0; index < 5; index++) {
executor->Execute([&, index]() {
threadIds->push_back(std::this_thread::get_id());
char buffer[128];
snprintf(buffer, sizeof(buffer), "%s %d, ", RUNNABLE_TEXT.c_str(), index);
output->append(std::string(buffer));
block_count.DecrementCount();
});
}
block_count.Wait();
executor->Shutdown();
// Assert
// We should've run 1 time on the main thread, and 5 times on the
// workerThread
ASSERT_EQ(threadIds->size(), 6);
// We should still be on the main thread
ASSERT_EQ(std::this_thread::get_id(), threadIds->at(0));
}
TEST(ExecutorTests, MultiThreadedExecutorSingleTaskAfterShutdownFails) {
// Arrange
std::string expected("");
auto executor = std::make_unique<Executor>(2);
// Container to note threads that ran
std::unique_ptr<std::vector<std::thread::id>> threadIds =
std::make_unique<std::vector<std::thread::id>>();
std::shared_ptr<std::string> output = std::make_shared<std::string>();
threadIds->push_back(std::this_thread::get_id());
executor->Shutdown();
// Act
executor->Execute([output, &threadIds]() {
threadIds->push_back(std::this_thread::get_id());
output->append(RUNNABLE_0_TEXT.c_str());
});
// Assert
// We should've run 1 time on the main thread, and 5 times on the
// workerThread
ASSERT_EQ(threadIds->size(), 1);
// We should still be on the main thread
ASSERT_EQ(std::this_thread::get_id(), threadIds->at(0));
// We should've run the task
ASSERT_EQ(*output.get(), expected);
}
TEST(ExecutorTests,
MultiThreadedExecutorMultipleTasksLargeNumberOfThreadsSucceeds) {
absl::BlockingCounter block_count(250);
// Arrange
auto executor = std::make_unique<Executor>(32);
// Container to note threads that ran
std::vector<std::thread::id> threadIds = std::vector<std::thread::id>();
threadIds.push_back(std::this_thread::get_id());
absl::Mutex mutex;
// Act
for (int index = 0; index < 250; index++) {
executor->Execute([&]() mutable {
std::thread::id id = std::this_thread::get_id();
{
absl::MutexLock lock(&mutex);
threadIds.push_back(id);
}
// Using rand since this is in a critical section
// and windows doesn't have a rand_r anyway
auto sleepTime = (std::rand() % 101) + 1; // NOLINT
sleep(sleepTime);
block_count.DecrementCount();
});
}
block_count.Wait();
executor->Shutdown();
// Assert
// We should still be on the main thread
ASSERT_EQ(std::this_thread::get_id(), threadIds.at(0));
// We should've run 1 time on the main thread, and 200 times on the
// workerThreads
ASSERT_EQ(threadIds.size(), 251);
}
} // namespace
} // namespace linux
} // namespace nearby
@@ -1,779 +0,0 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/file_path.h"
#include <algorithm>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <internal/platform/implementation/linux/device_info.h>
#include <internal/platform/implementation/linux/utils.h>
#include "gtest/gtest.h"
namespace nearby {
namespace linux {
namespace {
const wchar_t* kFileName(L"increment_file_test.txt");
const wchar_t* kFirstIterationFileName(L"/increment_file_test (1).txt");
const wchar_t* kSecondIterationFileName(L"/increment_file_test (2).txt");
const wchar_t* kThirdIterationFileName(L"/increment_file_test (3).txt");
const wchar_t* kNoDotsFileName(L"incrementfiletesttxt");
const wchar_t* kOneIterationNoDotsFileName(L"/incrementfiletesttxt (1)");
const wchar_t* kMultipleDotsFileName(L"increment.file.test.txt");
const wchar_t* kOneIterationMultipleDotsFileName(
L"/increment.file.test (1).txt");
const wchar_t* kImmediateEscape(L"../");
const wchar_t* kLongEscapeBackSlash(L"..\\test\\..\\..\\test");
const wchar_t* kTwoLevelFolder(L"/test/test");
const wchar_t* kLongEscapeSlash(L"../test/../../test");
const wchar_t* kLongEscapeMixedSlash(L"../test\\..\\../test");
const wchar_t* kLongEscapeEndingEscape(L"../test/../../test/..");
const wchar_t* kLongEscapeEndingEscapeWithSlash(
L"../test/../../test/../../../");
} // namespace
// Can't run on google 3, I presume the SHGetKnownFolderPath
// fails.
class FilePathTests : public testing::Test {
protected:
// You can define per-test set-up logic as usual.
FilePathTests() {
default_download_path_ =
string_to_wstring(DeviceInfo().GetDownloadPath().value_or(
std::string(getenv("HOME")).append("/Downloads")));
}
std::wstring default_download_path_;
};
TEST_F(FilePathTests, GetDownloadPathWithEmptyStringArguments\
ShouldReturnBaseDownloadPath) {
std::wstring parent_folder(L"");
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_);
} // NOLINT false lint error here
TEST_F(FilePathTests, GetDownloadPathWithSlashParent\
FolderArgumentsShouldReturnBaseDownloadPath) {
std::wstring parent_folder(L"/");
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_);
} // NOLINT false lint error here
TEST_F(FilePathTests, GetDownloadPathWithBackslashParent\
FolderArgumentsShouldReturnBaseDownloadPath) {
std::wstring parent_folder(L"\\");
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_);
} // NOLINT false lint error here
TEST_F(FilePathTests, GetDownloadPathWithAttemptToEscape\
UsersDownloadFolderShouldReturnDownloadPathNotEscapingUsersDownloadFolder) {
std::wstring parent_folder(kImmediateEscape);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderWithBackslashShouldReturnDownloadPath\
NotEscapingUsersDownloadFolder) {
std::wstring parent_folder(kLongEscapeBackSlash);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderShouldReturnDownloadPathNotEscapingUsers\
DownloadFolder) {
std::wstring parent_folder(kLongEscapeSlash);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderWithMixedSlashShouldReturnDownloadPath\
NotEscapingUsersDownloadFolder) {
std::wstring parent_folder(kLongEscapeMixedSlash);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderWithEndingEscapeShouldReturnDownload\
PathNotEscapingUsersDownloadFolder) {
std::wstring parent_folder(kLongEscapeEndingEscape);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderWithEndingSlashShouldReturnDownloadPathNot\
EscapingUsersDownloadFolder) {
std::wstring parent_folder(kLongEscapeEndingEscapeWithSlash);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithSlashFileName\
ArgumentsShouldReturnBaseDownloadPath) {
std::wstring parent_folder(L"");
std::wstring file_name(L"/");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_);
}
TEST_F(FilePathTests, GetDownloadPathWithBackslashFile\
NameArgumentsShouldReturnBaseDownloadPath) {
std::wstring parent_folder(L"");
std::wstring file_name(L"\\");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
auto result_size = actual.size();
auto default_size = default_download_path_.size();
EXPECT_EQ(actual, default_download_path_);
}
TEST_F(FilePathTests, GetDownloadPathWithParentFolder\
ShouldReturnParentFolderAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"test_parent_folder");
std::wstring file_name(L"");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_parent_folder";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithParentFolder\
StartingWithSlashArgumentsShouldReturnParentFolderAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"/test_parent_folder");
std::wstring file_name(L"");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_parent_folder";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithParentFolder\
StartingWithBackslashArgumentsShouldReturnParentFolderAppendedToBase\
DownloadPath) {
std::wstring parent_folder(L"\\test_parent_folder");
std::wstring file_name(L"");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_parent_folder";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithParentFolder\
EndingWithSlashArgumentsShouldReturnParentFolderAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"test_parent_folder/");
std::wstring file_name(L"");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_parent_folder";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithParentFolder\
EndingWithBackslashArguments\
ShouldReturnParentFolderAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"test_parent_folder\\");
std::wstring file_name(L"");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_parent_folder";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithFileName\
BeginningWithSlashArgumentsShouldReturnFileNameAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"");
std::wstring file_name(L"/test_file_name.name");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_file_name.name";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithFileName\
BeginningWithBackslashArgumentsShouldReturnFileNameAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"");
std::wstring file_name(L"\\test_file_name.name");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_file_name.name";
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, path.str().c_str());
}
TEST_F(FilePathTests, GetDownloadPathWithFileNameEnding\
WithSlashArgumentsShouldReturnFileNameAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"");
std::wstring file_name(L"test_file_name.name/");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_file_name.name";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithFileNameEnding\
WithBackslashArgumentsShouldReturnFileNameAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"");
std::wstring file_name(L"test_file_name.name\\");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_file_name.name";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithParentFolderAnd\
FileNameArgumentsShould\
ReturnParentFolderAndFileNameAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"test_parent_folder");
std::wstring file_name(L"test_file_name.name");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_parent_folder"
<< "/"
<< "test_file_name.name";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithParentFolder\
EndingWithBackslashAndFileNameArgumentsShouldReturnParentFolderAndFileName\
AppendedToBaseDownloadPath) {
std::wstring parent_folder(L"test_parent_folder\\");
std::wstring file_name(L"test_file_name.name");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_parent_folder"
<< "/"
<< "test_file_name.name";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithFileName\
StartingWithBackslashAndParentFolderArgumentsShouldReturnParentFolderAnd\
FileNameAppendedToBaseDownloadPath) {
std::wstring parent_folder(L"test_parent_folder");
std::wstring file_name(L"\\test_file_name.name");
std::wstringstream path(L"");
path << default_download_path_ << L"/" << "test_parent_folder"
<< "/"
<< "test_file_name.name";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_IllegalFileNameCharacters\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x05,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test\x5Test");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_LowestIllegalFileNameCharacter\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x01,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test\x1Test");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_HighestIllegalFileNameCharacter\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x1f,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test\x1fTest");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_IllegalFileNameCharacterQuestionMark\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2f,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test?Test");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_IllegalFileNameCharacterAsterisk\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2f,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test*Test");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_IllegalFileNameCharacterLessThan\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2f,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test<Test");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_IllegalFileNameCharacterGreaterThan\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2f,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test>Test");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_IllegalFileNameCharacterVerticalBar\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2f,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test|Test");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_IllegalFileNameCharacterColon\
ReturnsFileNameWithUnderbarSubstituted) {
// char illegal_character_sequence[]{ 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2f,
// 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0 };
auto illegal_character_sequence(L"Test:Test");
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/Test_Test");
auto actual(FilePath::GetDownloadPath(
parent_folder, std::wstring(illegal_character_sequence)));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_FileDoesntExist\
ReturnsFileWithPassedName) {
std::wstring file_name(kFileName);
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(L"/");
expected.append(file_name);
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_FileExistsReturns\
FileWithIncrementedName) {
std::wstring file_name(kFileName);
std::wstring renamed_file_name(kFirstIterationFileName);
std::wstring parent_folder(L"");
std::wstring output_file_path(default_download_path_);
output_file_path.append(L"/");
output_file_path.append(file_name);
std::wstring expected(default_download_path_);
expected += renamed_file_name;
std::wifstream input_file;
std::wofstream output_file;
output_file.open(wstring_to_string(output_file_path),
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
// Remove the file and check that it is removed
// File 1
std::filesystem::remove(output_file_path.c_str());
input_file.open(wstring_to_string(output_file_path),
std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
}
TEST_F(FilePathTests, GetDownloadPath_MultipleFilesExist\
ReturnsNextIncrementedFileName) {
std::ofstream output_file;
std::ifstream input_file;
std::wstring file_name(kFileName);
std::wstring first_renamed_file_name(kFirstIterationFileName);
std::wstring second_renamed_file_name(kSecondIterationFileName);
std::wstring parent_folder(L"");
std::wstring expected(default_download_path_);
expected.append(second_renamed_file_name.c_str());
std::wstring output_file1_path(default_download_path_);
output_file1_path.append(L"/" + file_name);
std::wstring output_file2_path(default_download_path_);
output_file2_path.append(first_renamed_file_name);
// Create the test files
output_file.open(wstring_to_string(output_file1_path),
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
output_file.clear();
output_file.open(wstring_to_string(output_file2_path),
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(expected, actual);
// Remove the test files and check that it is removed
// File 1
std::filesystem::remove(wstring_to_string(output_file1_path).c_str());
input_file.open(output_file1_path, std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
// File 2
std::filesystem::remove(wstring_to_string(output_file2_path).c_str());
input_file.clear();
input_file.open(wstring_to_string(output_file2_path),
std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
}
TEST_F(FilePathTests, GetDownloadPath_FileNameContains\
MultipleDotsReturnsIncrementBeforeFirstDot) {
std::ifstream input_file;
std::ofstream output_file;
std::wstring file_name(kMultipleDotsFileName);
std::wstring renamed_file_name(kOneIterationMultipleDotsFileName);
std::wstring parent_folder(L"");
std::wstring output_file1_path(default_download_path_);
output_file1_path.append(L"/" + file_name);
std::wstring output_file2_path(default_download_path_);
output_file2_path.append(renamed_file_name);
std::wstring expected(default_download_path_);
expected.append(renamed_file_name);
output_file.open(wstring_to_string(output_file1_path),
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(expected, actual);
std::filesystem::remove(wstring_to_string(output_file1_path).c_str());
input_file.open(wstring_to_string(output_file1_path),
std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
}
TEST_F(FilePathTests, GetDownloadPath_FileNameContainsNo\
DotsReturnsWithIncrementAtEnd) {
std::ifstream input_file;
std::ofstream output_file;
std::wstring file_name(kNoDotsFileName);
std::wstring renamed_file_name(kOneIterationNoDotsFileName);
std::wstring parent_folder(L"");
std::wstring output_file1_path(default_download_path_);
output_file1_path.append(L"/" + file_name);
std::wstring output_file2_path(default_download_path_);
output_file2_path.append(L"/" + renamed_file_name);
std::wstring expected(default_download_path_);
expected.append(renamed_file_name);
output_file.open(wstring_to_string(output_file1_path),
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(expected, actual);
std::filesystem::remove(wstring_to_string(output_file1_path).c_str());
input_file.open(wstring_to_string(output_file1_path),
std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
}
TEST_F(FilePathTests, GetDownloadPath_FileNameExistsWith\
AHoleBetweenRenamedFiles) {
std::ifstream input_file;
std::ofstream output_file;
std::wstring file_name(kFileName);
std::wstring file_name1(kFirstIterationFileName);
std::wstring file_name2(kSecondIterationFileName);
std::wstring file_name3(kThirdIterationFileName);
std::wstring parent_folder(L"");
// Create the path for the original file name
std::wstring output_file_path(default_download_path_);
output_file_path.append(
L"/" +
file_name); // Original file name example: "increment_file_test.txt"
// Create the path for the first iteration of the original file name
std::wstring output_file1_path(default_download_path_);
output_file1_path.append(file_name1); // First iteration on original file
// name example:
// "increment_file_test (1).txt"
// Create the path for the third iteration of the original file name
std::wstring output_file3_path(default_download_path_);
output_file3_path.append(
file_name3); // Third iteration on original file
// name example: "increment_file_test (3).txt"
// Create the expected result which is the second iteration of the original
// file name
std::wstring expected(default_download_path_);
expected.append(file_name2); // Second iteration on original file name
// example: "increment_file_test (2).txt"
// Create the original file
output_file.open(wstring_to_string(output_file_path),
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
// Create the first iteration of the original file
output_file.clear();
output_file.open(wstring_to_string(output_file1_path),
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
// Create the third iteration of the original file
output_file.clear();
output_file.open(wstring_to_string(output_file3_path),
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
// This should return the second iteration of the original file
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(expected, actual);
// Delete the original file
std::filesystem::remove(wstring_to_string(output_file_path).c_str());
input_file.open(wstring_to_string(output_file_path),
std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
// Delete the first iteration of the original file
input_file.clear(); // Reset the input_file state
std::filesystem::remove(wstring_to_string(output_file1_path).c_str());
input_file.open(wstring_to_string(output_file1_path),
std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
// Delete the third iteration of the original file
input_file.clear(); // Reset the input_file state
std::filesystem::remove(wstring_to_string(output_file3_path).c_str());
input_file.open(wstring_to_string(output_file3_path),
std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
}
} // namespace linux
} // namespace nearby
@@ -1,4 +1,4 @@
// Copyright 2020 Google LLC
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,21 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/linux/atomic_boolean.h"
#include "gtest/gtest.h"
TEST(atomic_boolean, SuccessfulCreation) {
// Arrange
nearby::linux::AtomicBoolean atomicBoolean;
bool oldValue = true;
bool result = false;
namespace nearby {
namespace linux {
// Act
oldValue = atomicBoolean.Set(true);
result = atomicBoolean.Get();
TEST(LinuxStubTests, Placeholder) {
GTEST_SKIP() << "Stub test placeholder to mirror Windows coverage.";
}
// Assert
EXPECT_TRUE(result);
EXPECT_FALSE(oldValue);
}
} // namespace linux
} // namespace nearby
@@ -1,94 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__avahi_entrygroup_client_glue_h__proxy__H__
#define __sdbuscpp__avahi_entrygroup_client_glue_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace freedesktop {
namespace Avahi {
class EntryGroup_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.freedesktop.Avahi.EntryGroup";
protected:
EntryGroup_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const int32_t& state, const std::string& error){ this->onStateChanged(state, error); });
}
~EntryGroup_proxy() = default;
virtual void onStateChanged(const int32_t& state, const std::string& error) = 0;
public:
void Free()
{
proxy_.callMethod("Free").onInterface(INTERFACE_NAME);
}
void Commit()
{
proxy_.callMethod("Commit").onInterface(INTERFACE_NAME);
}
void Reset()
{
proxy_.callMethod("Reset").onInterface(INTERFACE_NAME);
}
int32_t GetState()
{
int32_t result;
proxy_.callMethod("GetState").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
bool IsEmpty()
{
bool result;
proxy_.callMethod("IsEmpty").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void AddService(const int32_t& interface, const int32_t& protocol, const uint32_t& flags, const std::string& name, const std::string& type, const std::string& domain, const std::string& host, const uint16_t& port, const std::vector<std::vector<uint8_t>>& txt)
{
proxy_.callMethod("AddService").onInterface(INTERFACE_NAME).withArguments(interface, protocol, flags, name, type, domain, host, port, txt);
}
void AddServiceSubtype(const int32_t& interface, const int32_t& protocol, const uint32_t& flags, const std::string& name, const std::string& type, const std::string& domain, const std::string& subtype)
{
proxy_.callMethod("AddServiceSubtype").onInterface(INTERFACE_NAME).withArguments(interface, protocol, flags, name, type, domain, subtype);
}
void UpdateServiceTxt(const int32_t& interface, const int32_t& protocol, const uint32_t& flags, const std::string& name, const std::string& type, const std::string& domain, const std::vector<std::vector<uint8_t>>& txt)
{
proxy_.callMethod("UpdateServiceTxt").onInterface(INTERFACE_NAME).withArguments(interface, protocol, flags, name, type, domain, txt);
}
void AddAddress(const int32_t& interface, const int32_t& protocol, const uint32_t& flags, const std::string& name, const std::string& address)
{
proxy_.callMethod("AddAddress").onInterface(INTERFACE_NAME).withArguments(interface, protocol, flags, name, address);
}
void AddRecord(const int32_t& interface, const int32_t& protocol, const uint32_t& flags, const std::string& name, const uint16_t& clazz, const uint16_t& type, const uint32_t& ttl, const std::vector<uint8_t>& rdata)
{
proxy_.callMethod("AddRecord").onInterface(INTERFACE_NAME).withArguments(interface, protocol, flags, name, clazz, type, ttl, rdata);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -1,94 +0,0 @@
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<?xml-stylesheet type="text/xsl" href="introspect.xsl"?>
<!DOCTYPE node SYSTEM "introspect.dtd">
<!--
This file is part of avahi.
avahi is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
avahi is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with avahi; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
-->
<node>
<interface name="org.freedesktop.Avahi.EntryGroup">
<method name="Free"/>
<method name="Commit"/>
<method name="Reset"/>
<method name="GetState">
<arg name="state" type="i" direction="out"/>
</method>
<signal name="StateChanged">
<arg name="state" type="i"/>
<arg name="error" type="s"/>
</signal>
<method name="IsEmpty">
<arg name="empty" type="b" direction="out"/>
</method>
<method name="AddService">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="host" type="s" direction="in"/>
<arg name="port" type="q" direction="in"/>
<arg name="txt" type="aay" direction="in"/>
</method>
<method name="AddServiceSubtype">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="subtype" type="s" direction="in"/>
</method>
<method name="UpdateServiceTxt">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="txt" type="aay" direction="in"/>
</method>
<method name="AddAddress">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="address" type="s" direction="in"/>
</method>
<method name="AddRecord">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="clazz" type="q" direction="in"/>
<arg name="type" type="q" direction="in"/>
<arg name="ttl" type="u" direction="in"/>
<arg name="rdata" type="ay" direction="in"/>
</method>
</interface>
</node>
@@ -1,398 +0,0 @@
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<?xml-stylesheet type="text/xsl" href="introspect.xsl"?>
<!DOCTYPE node SYSTEM "introspect.dtd">
<!--
This file is part of avahi.
avahi is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
avahi is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with avahi; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
-->
<node>
<interface name="org.freedesktop.Avahi.Server">
<method name="GetVersionString">
<arg name="version" type="s" direction="out"/>
</method>
<method name="GetAPIVersion">
<arg name="version" type="u" direction="out"/>
</method>
<method name="GetHostName">
<arg name="name" type="s" direction="out"/>
</method>
<method name="SetHostName">
<arg name="name" type="s" direction="in"/>
</method>
<method name="GetHostNameFqdn">
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetDomainName">
<arg name="name" type="s" direction="out"/>
</method>
<method name="IsNSSSupportAvailable">
<arg name="yes" type="b" direction="out"/>
</method>
<method name="GetState">
<arg name="state" type="i" direction="out"/>
</method>
<signal name="StateChanged">
<arg name="state" type="i"/>
<arg name="error" type="s"/>
</signal>
<method name="GetLocalServiceCookie">
<arg name="cookie" type="u" direction="out"/>
</method>
<method name="GetAlternativeHostName">
<arg name="name" type="s" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetAlternativeServiceName">
<arg name="name" type="s" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetNetworkInterfaceNameByIndex">
<arg name="index" type="i" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetNetworkInterfaceIndexByName">
<arg name="name" type="s" direction="in"/>
<arg name="index" type="i" direction="out"/>
</method>
<method name="ResolveHostName">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</method>
<method name="ResolveAddress">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="address" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</method>
<method name="ResolveService">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="type" type="s" direction="out"/>
<arg name="domain" type="s" direction="out"/>
<arg name="host" type="s" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="port" type="q" direction="out"/>
<arg name="txt" type="aay" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</method>
<method name="EntryGroupNew">
<arg name="path" type="o" direction="out"/>
</method>
<method name="DomainBrowserNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="btype" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceTypeBrowserNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceBrowserNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceResolverNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="HostNameResolverNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="AddressResolverNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="address" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="RecordBrowserNew">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="clazz" type="q" direction="in"/>
<arg name="type" type="q" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
</interface>
<interface name="org.freedesktop.Avahi.Server2">
<method name="GetVersionString">
<arg name="version" type="s" direction="out"/>
</method>
<method name="GetAPIVersion">
<arg name="version" type="u" direction="out"/>
</method>
<method name="GetHostName">
<arg name="name" type="s" direction="out"/>
</method>
<method name="SetHostName">
<arg name="name" type="s" direction="in"/>
</method>
<method name="GetHostNameFqdn">
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetDomainName">
<arg name="name" type="s" direction="out"/>
</method>
<method name="IsNSSSupportAvailable">
<arg name="yes" type="b" direction="out"/>
</method>
<method name="GetState">
<arg name="state" type="i" direction="out"/>
</method>
<signal name="StateChanged">
<arg name="state" type="i"/>
<arg name="error" type="s"/>
</signal>
<method name="GetLocalServiceCookie">
<arg name="cookie" type="u" direction="out"/>
</method>
<method name="GetAlternativeHostName">
<arg name="name" type="s" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetAlternativeServiceName">
<arg name="name" type="s" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetNetworkInterfaceNameByIndex">
<arg name="index" type="i" direction="in"/>
<arg name="name" type="s" direction="out"/>
</method>
<method name="GetNetworkInterfaceIndexByName">
<arg name="name" type="s" direction="in"/>
<arg name="index" type="i" direction="out"/>
</method>
<method name="ResolveHostName">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</method>
<method name="ResolveAddress">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="address" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</method>
<method name="ResolveService">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="type" type="s" direction="out"/>
<arg name="domain" type="s" direction="out"/>
<arg name="host" type="s" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="port" type="q" direction="out"/>
<arg name="txt" type="aay" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</method>
<method name="EntryGroupNew">
<arg name="path" type="o" direction="out"/>
</method>
<method name="DomainBrowserPrepare">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="btype" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceTypeBrowserPrepare">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceBrowserPrepare">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="ServiceResolverPrepare">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="type" type="s" direction="in"/>
<arg name="domain" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="HostNameResolverPrepare">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="aprotocol" type="i" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="AddressResolverPrepare">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="address" type="s" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
<method name="RecordBrowserPrepare">
<arg name="interface" type="i" direction="in"/>
<arg name="protocol" type="i" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="clazz" type="q" direction="in"/>
<arg name="type" type="q" direction="in"/>
<arg name="flags" type="u" direction="in"/>
<arg name="path" type="o" direction="out"/>
</method>
</interface>
</node>
@@ -1,58 +0,0 @@
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<?xml-stylesheet type="text/xsl" href="introspect.xsl"?>
<!DOCTYPE node SYSTEM "introspect.dtd">
<!--
This file is part of avahi.
avahi is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
avahi is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with avahi; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
-->
<node>
<interface name="org.freedesktop.Avahi.ServiceBrowser">
<method name="Free"/>
<method name="Start"/>
<signal name="ItemNew">
<arg name="interface" type="i"/>
<arg name="protocol" type="i"/>
<arg name="name" type="s"/>
<arg name="type" type="s"/>
<arg name="domain" type="s"/>
<arg name="flags" type="u"/>
</signal>
<signal name="ItemRemove">
<arg name="interface" type="i"/>
<arg name="protocol" type="i"/>
<arg name="name" type="s"/>
<arg name="type" type="s"/>
<arg name="domain" type="s"/>
<arg name="flags" type="u"/>
</signal>
<signal name="Failure">
<arg name="error" type="s"/>
</signal>
<signal name="AllForNow"/>
<signal name="CacheExhausted"/>
</interface>
</node>
@@ -1,57 +0,0 @@
<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<?xml-stylesheet type="text/xsl" href="introspect.xsl"?>
<!DOCTYPE node SYSTEM "introspect.dtd">
<!--
This file is part of avahi.
avahi is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
avahi is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with avahi; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
-->
<node>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" type="s" direction="out" />
</method>
</interface>
<interface name="org.freedesktop.Avahi.ServiceResolver">
<method name="Free"/>
<method name="Start"/>
<signal name="Found">
<arg name="interface" type="i" direction="out"/>
<arg name="protocol" type="i" direction="out"/>
<arg name="name" type="s" direction="out"/>
<arg name="type" type="s" direction="out"/>
<arg name="domain" type="s" direction="out"/>
<arg name="host" type="s" direction="out"/>
<arg name="aprotocol" type="i" direction="out"/>
<arg name="address" type="s" direction="out"/>
<arg name="port" type="q" direction="out"/>
<arg name="txt" type="aay" direction="out"/>
<arg name="flags" type="u" direction="out"/>
</signal>
<signal name="Failure">
<arg name="error" type="s"/>
</signal>
</interface>
</node>
@@ -1,399 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__avahi_server_client_glue_h__proxy__H__
#define __sdbuscpp__avahi_server_client_glue_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace freedesktop {
namespace Avahi {
class Server_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.freedesktop.Avahi.Server";
protected:
Server_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const int32_t& state, const std::string& error){ this->onStateChanged(state, error); });
}
~Server_proxy() = default;
virtual void onStateChanged(const int32_t& state, const std::string& error) = 0;
public:
std::string GetVersionString()
{
std::string result;
proxy_.callMethod("GetVersionString").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
uint32_t GetAPIVersion()
{
uint32_t result;
proxy_.callMethod("GetAPIVersion").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::string GetHostName()
{
std::string result;
proxy_.callMethod("GetHostName").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void SetHostName(const std::string& name)
{
proxy_.callMethod("SetHostName").onInterface(INTERFACE_NAME).withArguments(name);
}
std::string GetHostNameFqdn()
{
std::string result;
proxy_.callMethod("GetHostNameFqdn").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::string GetDomainName()
{
std::string result;
proxy_.callMethod("GetDomainName").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
bool IsNSSSupportAvailable()
{
bool result;
proxy_.callMethod("IsNSSSupportAvailable").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
int32_t GetState()
{
int32_t result;
proxy_.callMethod("GetState").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
uint32_t GetLocalServiceCookie()
{
uint32_t result;
proxy_.callMethod("GetLocalServiceCookie").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::string GetAlternativeHostName(const std::string& name)
{
std::string result;
proxy_.callMethod("GetAlternativeHostName").onInterface(INTERFACE_NAME).withArguments(name).storeResultsTo(result);
return result;
}
std::string GetAlternativeServiceName(const std::string& name)
{
std::string result;
proxy_.callMethod("GetAlternativeServiceName").onInterface(INTERFACE_NAME).withArguments(name).storeResultsTo(result);
return result;
}
std::string GetNetworkInterfaceNameByIndex(const int32_t& index)
{
std::string result;
proxy_.callMethod("GetNetworkInterfaceNameByIndex").onInterface(INTERFACE_NAME).withArguments(index).storeResultsTo(result);
return result;
}
int32_t GetNetworkInterfaceIndexByName(const std::string& name)
{
int32_t result;
proxy_.callMethod("GetNetworkInterfaceIndexByName").onInterface(INTERFACE_NAME).withArguments(name).storeResultsTo(result);
return result;
}
std::tuple<int32_t, int32_t, std::string, int32_t, std::string, uint32_t> ResolveHostName(const int32_t& interface, const int32_t& protocol, const std::string& name, const int32_t& aprotocol, const uint32_t& flags)
{
std::tuple<int32_t, int32_t, std::string, int32_t, std::string, uint32_t> result;
proxy_.callMethod("ResolveHostName").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, aprotocol, flags).storeResultsTo(result);
return result;
}
std::tuple<int32_t, int32_t, int32_t, std::string, std::string, uint32_t> ResolveAddress(const int32_t& interface, const int32_t& protocol, const std::string& address, const uint32_t& flags)
{
std::tuple<int32_t, int32_t, int32_t, std::string, std::string, uint32_t> result;
proxy_.callMethod("ResolveAddress").onInterface(INTERFACE_NAME).withArguments(interface, protocol, address, flags).storeResultsTo(result);
return result;
}
std::tuple<int32_t, int32_t, std::string, std::string, std::string, std::string, int32_t, std::string, uint16_t, std::vector<std::vector<uint8_t>>, uint32_t> ResolveService(const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain, const int32_t& aprotocol, const uint32_t& flags)
{
std::tuple<int32_t, int32_t, std::string, std::string, std::string, std::string, int32_t, std::string, uint16_t, std::vector<std::vector<uint8_t>>, uint32_t> result;
proxy_.callMethod("ResolveService").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, type, domain, aprotocol, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath EntryGroupNew()
{
sdbus::ObjectPath result;
proxy_.callMethod("EntryGroupNew").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
sdbus::ObjectPath DomainBrowserNew(const int32_t& interface, const int32_t& protocol, const std::string& domain, const int32_t& btype, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("DomainBrowserNew").onInterface(INTERFACE_NAME).withArguments(interface, protocol, domain, btype, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath ServiceTypeBrowserNew(const int32_t& interface, const int32_t& protocol, const std::string& domain, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("ServiceTypeBrowserNew").onInterface(INTERFACE_NAME).withArguments(interface, protocol, domain, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath ServiceBrowserNew(const int32_t& interface, const int32_t& protocol, const std::string& type, const std::string& domain, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("ServiceBrowserNew").onInterface(INTERFACE_NAME).withArguments(interface, protocol, type, domain, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath ServiceResolverNew(const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain, const int32_t& aprotocol, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("ServiceResolverNew").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, type, domain, aprotocol, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath HostNameResolverNew(const int32_t& interface, const int32_t& protocol, const std::string& name, const int32_t& aprotocol, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("HostNameResolverNew").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, aprotocol, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath AddressResolverNew(const int32_t& interface, const int32_t& protocol, const std::string& address, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("AddressResolverNew").onInterface(INTERFACE_NAME).withArguments(interface, protocol, address, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath RecordBrowserNew(const int32_t& interface, const int32_t& protocol, const std::string& name, const uint16_t& clazz, const uint16_t& type, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("RecordBrowserNew").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, clazz, type, flags).storeResultsTo(result);
return result;
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
namespace org {
namespace freedesktop {
namespace Avahi {
class Server2_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.freedesktop.Avahi.Server2";
protected:
Server2_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const int32_t& state, const std::string& error){ this->onStateChanged(state, error); });
}
~Server2_proxy() = default;
virtual void onStateChanged(const int32_t& state, const std::string& error) = 0;
public:
std::string GetVersionString()
{
std::string result;
proxy_.callMethod("GetVersionString").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
uint32_t GetAPIVersion()
{
uint32_t result;
proxy_.callMethod("GetAPIVersion").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::string GetHostName()
{
std::string result;
proxy_.callMethod("GetHostName").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void SetHostName(const std::string& name)
{
proxy_.callMethod("SetHostName").onInterface(INTERFACE_NAME).withArguments(name);
}
std::string GetHostNameFqdn()
{
std::string result;
proxy_.callMethod("GetHostNameFqdn").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::string GetDomainName()
{
std::string result;
proxy_.callMethod("GetDomainName").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
bool IsNSSSupportAvailable()
{
bool result;
proxy_.callMethod("IsNSSSupportAvailable").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
int32_t GetState()
{
int32_t result;
proxy_.callMethod("GetState").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
uint32_t GetLocalServiceCookie()
{
uint32_t result;
proxy_.callMethod("GetLocalServiceCookie").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::string GetAlternativeHostName(const std::string& name)
{
std::string result;
proxy_.callMethod("GetAlternativeHostName").onInterface(INTERFACE_NAME).withArguments(name).storeResultsTo(result);
return result;
}
std::string GetAlternativeServiceName(const std::string& name)
{
std::string result;
proxy_.callMethod("GetAlternativeServiceName").onInterface(INTERFACE_NAME).withArguments(name).storeResultsTo(result);
return result;
}
std::string GetNetworkInterfaceNameByIndex(const int32_t& index)
{
std::string result;
proxy_.callMethod("GetNetworkInterfaceNameByIndex").onInterface(INTERFACE_NAME).withArguments(index).storeResultsTo(result);
return result;
}
int32_t GetNetworkInterfaceIndexByName(const std::string& name)
{
int32_t result;
proxy_.callMethod("GetNetworkInterfaceIndexByName").onInterface(INTERFACE_NAME).withArguments(name).storeResultsTo(result);
return result;
}
std::tuple<int32_t, int32_t, std::string, int32_t, std::string, uint32_t> ResolveHostName(const int32_t& interface, const int32_t& protocol, const std::string& name, const int32_t& aprotocol, const uint32_t& flags)
{
std::tuple<int32_t, int32_t, std::string, int32_t, std::string, uint32_t> result;
proxy_.callMethod("ResolveHostName").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, aprotocol, flags).storeResultsTo(result);
return result;
}
std::tuple<int32_t, int32_t, int32_t, std::string, std::string, uint32_t> ResolveAddress(const int32_t& interface, const int32_t& protocol, const std::string& address, const uint32_t& flags)
{
std::tuple<int32_t, int32_t, int32_t, std::string, std::string, uint32_t> result;
proxy_.callMethod("ResolveAddress").onInterface(INTERFACE_NAME).withArguments(interface, protocol, address, flags).storeResultsTo(result);
return result;
}
std::tuple<int32_t, int32_t, std::string, std::string, std::string, std::string, int32_t, std::string, uint16_t, std::vector<std::vector<uint8_t>>, uint32_t> ResolveService(const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain, const int32_t& aprotocol, const uint32_t& flags)
{
std::tuple<int32_t, int32_t, std::string, std::string, std::string, std::string, int32_t, std::string, uint16_t, std::vector<std::vector<uint8_t>>, uint32_t> result;
proxy_.callMethod("ResolveService").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, type, domain, aprotocol, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath EntryGroupNew()
{
sdbus::ObjectPath result;
proxy_.callMethod("EntryGroupNew").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
sdbus::ObjectPath DomainBrowserPrepare(const int32_t& interface, const int32_t& protocol, const std::string& domain, const int32_t& btype, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("DomainBrowserPrepare").onInterface(INTERFACE_NAME).withArguments(interface, protocol, domain, btype, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath ServiceTypeBrowserPrepare(const int32_t& interface, const int32_t& protocol, const std::string& domain, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("ServiceTypeBrowserPrepare").onInterface(INTERFACE_NAME).withArguments(interface, protocol, domain, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath ServiceBrowserPrepare(const int32_t& interface, const int32_t& protocol, const std::string& type, const std::string& domain, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("ServiceBrowserPrepare").onInterface(INTERFACE_NAME).withArguments(interface, protocol, type, domain, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath ServiceResolverPrepare(const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain, const int32_t& aprotocol, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("ServiceResolverPrepare").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, type, domain, aprotocol, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath HostNameResolverPrepare(const int32_t& interface, const int32_t& protocol, const std::string& name, const int32_t& aprotocol, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("HostNameResolverPrepare").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, aprotocol, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath AddressResolverPrepare(const int32_t& interface, const int32_t& protocol, const std::string& address, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("AddressResolverPrepare").onInterface(INTERFACE_NAME).withArguments(interface, protocol, address, flags).storeResultsTo(result);
return result;
}
sdbus::ObjectPath RecordBrowserPrepare(const int32_t& interface, const int32_t& protocol, const std::string& name, const uint16_t& clazz, const uint16_t& type, const uint32_t& flags)
{
sdbus::ObjectPath result;
proxy_.callMethod("RecordBrowserPrepare").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, clazz, type, flags).storeResultsTo(result);
return result;
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -1,58 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__avahi_servicebrowser_client_glue_h__proxy__H__
#define __sdbuscpp__avahi_servicebrowser_client_glue_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace freedesktop {
namespace Avahi {
class ServiceBrowser_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.freedesktop.Avahi.ServiceBrowser";
protected:
ServiceBrowser_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
proxy_.uponSignal("ItemNew").onInterface(INTERFACE_NAME).call([this](const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain, const uint32_t& flags){ this->onItemNew(interface, protocol, name, type, domain, flags); });
proxy_.uponSignal("ItemRemove").onInterface(INTERFACE_NAME).call([this](const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain, const uint32_t& flags){ this->onItemRemove(interface, protocol, name, type, domain, flags); });
proxy_.uponSignal("Failure").onInterface(INTERFACE_NAME).call([this](const std::string& error){ this->onFailure(error); });
proxy_.uponSignal("AllForNow").onInterface(INTERFACE_NAME).call([this](){ this->onAllForNow(); });
proxy_.uponSignal("CacheExhausted").onInterface(INTERFACE_NAME).call([this](){ this->onCacheExhausted(); });
}
~ServiceBrowser_proxy() = default;
virtual void onItemNew(const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain, const uint32_t& flags) = 0;
virtual void onItemRemove(const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain, const uint32_t& flags) = 0;
virtual void onFailure(const std::string& error) = 0;
virtual void onAllForNow() = 0;
virtual void onCacheExhausted() = 0;
public:
void Free()
{
proxy_.callMethod("Free").onInterface(INTERFACE_NAME);
}
void Start()
{
proxy_.callMethod("Start").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -1,179 +0,0 @@
/*
* 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
@@ -1,57 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__advertisement_monitor_manager_client_h__proxy__H__
#define __sdbuscpp__advertisement_monitor_manager_client_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class AdvertisementMonitorManager1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.AdvertisementMonitorManager1";
protected:
AdvertisementMonitorManager1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~AdvertisementMonitorManager1_proxy() = default;
public:
void RegisterMonitor(const sdbus::ObjectPath& application)
{
proxy_.callMethod("RegisterMonitor").onInterface(INTERFACE_NAME).withArguments(application);
}
void UnregisterMonitor(const sdbus::ObjectPath& application)
{
proxy_.callMethod("UnregisterMonitor").onInterface(INTERFACE_NAME).withArguments(application);
}
public:
std::vector<std::string> SupportedMonitorTypes()
{
return proxy_.getProperty("SupportedMonitorTypes").onInterface(INTERFACE_NAME);
}
std::vector<std::string> SupportedFeatures()
{
return proxy_.getProperty("SupportedFeatures").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -1,57 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__advertisement_monitor_server_h__adaptor__H__
#define __sdbuscpp__advertisement_monitor_server_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class AdvertisementMonitor1_adaptor
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.AdvertisementMonitor1";
protected:
AdvertisementMonitor1_adaptor(sdbus::IObject& object)
: object_(object)
{
object_.registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); });
object_.registerMethod("Activate").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Activate(); });
object_.registerMethod("DeviceFound").onInterface(INTERFACE_NAME).withInputParamNames("device").implementedAs([this](const sdbus::ObjectPath& device){ return this->DeviceFound(device); });
object_.registerMethod("DeviceLost").onInterface(INTERFACE_NAME).withInputParamNames("device").implementedAs([this](const sdbus::ObjectPath& device){ return this->DeviceLost(device); });
object_.registerProperty("Type").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Type(); });
object_.registerProperty("RSSILowThreshold").onInterface(INTERFACE_NAME).withGetter([this](){ return this->RSSILowThreshold(); });
object_.registerProperty("RSSIHighThreshold").onInterface(INTERFACE_NAME).withGetter([this](){ return this->RSSIHighThreshold(); });
object_.registerProperty("RSSISamplingPeriod").onInterface(INTERFACE_NAME).withGetter([this](){ return this->RSSISamplingPeriod(); });
object_.registerProperty("Patterns").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Patterns(); });
}
~AdvertisementMonitor1_adaptor() = default;
private:
virtual void Release() = 0;
virtual void Activate() = 0;
virtual void DeviceFound(const sdbus::ObjectPath& device) = 0;
virtual void DeviceLost(const sdbus::ObjectPath& device) = 0;
private:
virtual std::string Type() = 0;
virtual int16_t RSSILowThreshold() = 0;
virtual int16_t RSSIHighThreshold() = 0;
virtual uint16_t RSSISamplingPeriod() = 0;
virtual std::vector<sdbus::Struct<uint8_t, uint8_t, std::vector<uint8_t>>> Patterns() = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -1,214 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__device_client_h__proxy__H__
#define __sdbuscpp__device_client_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 onPairReply(const sdbus::Error* error) = 0;
public:
void Disconnect()
{
proxy_.callMethod("Disconnect").onInterface(INTERFACE_NAME);
}
void Connect()
{
proxy_.callMethod("Connect").onInterface(INTERFACE_NAME);
}
void ConnectProfile(const std::string& UUID)
{
proxy_.callMethod("ConnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID);
}
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
@@ -1,118 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__gatt_characteristic_client_h__proxy__H__
#define __sdbuscpp__gatt_characteristic_client_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class GattCharacteristic1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.GattCharacteristic1";
protected:
GattCharacteristic1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~GattCharacteristic1_proxy() = default;
public:
std::vector<uint8_t> ReadValue(const std::map<std::string, sdbus::Variant>& options)
{
std::vector<uint8_t> result;
proxy_.callMethod("ReadValue").onInterface(INTERFACE_NAME).withArguments(options).storeResultsTo(result);
return result;
}
void WriteValue(const std::vector<uint8_t>& value, const std::map<std::string, sdbus::Variant>& options)
{
proxy_.callMethod("WriteValue").onInterface(INTERFACE_NAME).withArguments(value, options);
}
std::tuple<sdbus::UnixFd, uint16_t> AcquireWrite(const std::map<std::string, sdbus::Variant>& options)
{
std::tuple<sdbus::UnixFd, uint16_t> result;
proxy_.callMethod("AcquireWrite").onInterface(INTERFACE_NAME).withArguments(options).storeResultsTo(result);
return result;
}
std::tuple<sdbus::UnixFd, uint16_t> AcquireNotify(const std::map<std::string, sdbus::Variant>& options)
{
std::tuple<sdbus::UnixFd, uint16_t> result;
proxy_.callMethod("AcquireNotify").onInterface(INTERFACE_NAME).withArguments(options).storeResultsTo(result);
return result;
}
void StartNotify()
{
proxy_.callMethod("StartNotify").onInterface(INTERFACE_NAME);
}
void StopNotify()
{
proxy_.callMethod("StopNotify").onInterface(INTERFACE_NAME);
}
public:
uint16_t Handle()
{
return proxy_.getProperty("Handle").onInterface(INTERFACE_NAME);
}
std::string UUID()
{
return proxy_.getProperty("UUID").onInterface(INTERFACE_NAME);
}
sdbus::ObjectPath Service()
{
return proxy_.getProperty("Service").onInterface(INTERFACE_NAME);
}
std::vector<uint8_t> Value()
{
return proxy_.getProperty("Value").onInterface(INTERFACE_NAME);
}
bool Notifying()
{
return proxy_.getProperty("Notifying").onInterface(INTERFACE_NAME);
}
std::vector<std::string> Flags()
{
return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME);
}
bool WriteAcquired()
{
return proxy_.getProperty("WriteAcquired").onInterface(INTERFACE_NAME);
}
bool NotifyAcquired()
{
return proxy_.getProperty("NotifyAcquired").onInterface(INTERFACE_NAME);
}
uint16_t MTU()
{
return proxy_.getProperty("MTU").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -1,59 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__generated_dbus_bluez_gatt_characteristic_server_h__adaptor__H__
#define __sdbuscpp__generated_dbus_bluez_gatt_characteristic_server_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class GattCharacteristic1_adaptor
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.GattCharacteristic1";
protected:
GattCharacteristic1_adaptor(sdbus::IObject& object)
: object_(object)
{
object_.registerMethod("ReadValue").onInterface(INTERFACE_NAME).withInputParamNames("options").withOutputParamNames("value").implementedAs([this](sdbus::Result<std::vector<uint8_t>>&& result, std::map<std::string, sdbus::Variant> options){ this->ReadValue(std::move(result), std::move(options)); });
object_.registerMethod("WriteValue").onInterface(INTERFACE_NAME).withInputParamNames("value", "options").implementedAs([this](sdbus::Result<>&& result, std::vector<uint8_t> value, std::map<std::string, sdbus::Variant> options){ this->WriteValue(std::move(result), std::move(value), std::move(options)); });
object_.registerMethod("StartNotify").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->StartNotify(); });
object_.registerMethod("StopNotify").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->StopNotify(); });
object_.registerMethod("Confirm").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Confirm(); });
object_.registerProperty("UUID").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUID(); });
object_.registerProperty("Service").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Service(); });
object_.registerProperty("Value").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Value(); });
object_.registerProperty("Notifying").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Notifying(); });
object_.registerProperty("Flags").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Flags(); });
}
~GattCharacteristic1_adaptor() = default;
private:
virtual void ReadValue(sdbus::Result<std::vector<uint8_t>>&& result, std::map<std::string, sdbus::Variant> options) = 0;
virtual void WriteValue(sdbus::Result<>&& result, std::vector<uint8_t> value, std::map<std::string, sdbus::Variant> options) = 0;
virtual void StartNotify() = 0;
virtual void StopNotify() = 0;
virtual void Confirm() = 0;
private:
virtual std::string UUID() = 0;
virtual sdbus::ObjectPath Service() = 0;
virtual std::vector<uint8_t> Value() = 0;
virtual bool Notifying() = 0;
virtual std::vector<std::string> Flags() = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -1,46 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__gatt_manager_client_h__proxy__H__
#define __sdbuscpp__gatt_manager_client_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class GattManager1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.GattManager1";
protected:
GattManager1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~GattManager1_proxy() = default;
public:
void RegisterApplication(const sdbus::ObjectPath& application, const std::map<std::string, sdbus::Variant>& options)
{
proxy_.callMethod("RegisterApplication").onInterface(INTERFACE_NAME).withArguments(application, options);
}
void UnregisterApplication(const sdbus::ObjectPath& application)
{
proxy_.callMethod("UnregisterApplication").onInterface(INTERFACE_NAME).withArguments(application);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -1,48 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_dbus_bluez_gatt_profile_server_h__adaptor__H__
#define __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_dbus_bluez_gatt_profile_server_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class GattProfile1_adaptor
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.GattProfile1";
protected:
GattProfile1_adaptor(sdbus::IObject& object)
: object_(&object)
{
object_->registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); });
object_->registerProperty("UUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUIDs(); });
}
GattProfile1_adaptor(const GattProfile1_adaptor&) = delete;
GattProfile1_adaptor& operator=(const GattProfile1_adaptor&) = delete;
GattProfile1_adaptor(GattProfile1_adaptor&&) = default;
GattProfile1_adaptor& operator=(GattProfile1_adaptor&&) = default;
~GattProfile1_adaptor() = default;
private:
virtual void Release() = 0;
private:
virtual std::vector<std::string> UUIDs() = 0;
private:
sdbus::IObject* object_;
};
}} // namespaces
#endif
@@ -1,56 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__gatt_service_client_h__proxy__H__
#define __sdbuscpp__gatt_service_client_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class GattService1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.GattService1";
protected:
GattService1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~GattService1_proxy() = default;
public:
std::string UUID()
{
return proxy_.getProperty("UUID").onInterface(INTERFACE_NAME);
}
bool Primary()
{
return proxy_.getProperty("Primary").onInterface(INTERFACE_NAME);
}
sdbus::ObjectPath Device()
{
return proxy_.getProperty("Device").onInterface(INTERFACE_NAME);
}
std::vector<sdbus::ObjectPath> Includes()
{
return proxy_.getProperty("Includes").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -1,45 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__generated_dbus_bluez_gatt_service_server_h__adaptor__H__
#define __sdbuscpp__generated_dbus_bluez_gatt_service_server_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class GattService1_adaptor
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.GattService1";
protected:
GattService1_adaptor(sdbus::IObject& object)
: object_(object)
{
object_.registerProperty("UUID").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUID(); });
object_.registerProperty("Primary").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Primary(); });
object_.registerProperty("Device").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Device(); });
object_.registerProperty("Includes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Includes(); });
}
~GattService1_adaptor() = default;
private:
virtual std::string UUID() = 0;
virtual bool Primary() = 0;
virtual sdbus::ObjectPath Device() = 0;
virtual std::vector<sdbus::ObjectPath> Includes() = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -1,77 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__generated_dbus_bluez_le_advertisement_manager_client_h__proxy__H__
#define __sdbuscpp__generated_dbus_bluez_le_advertisement_manager_client_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class LEAdvertisingManager1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.LEAdvertisingManager1";
protected:
LEAdvertisingManager1_proxy(sdbus::IProxy& proxy)
: proxy_(proxy)
{
}
~LEAdvertisingManager1_proxy() = default;
public:
void RegisterAdvertisement(const sdbus::ObjectPath& advertisement, const std::map<std::string, sdbus::Variant>& options)
{
proxy_.callMethod("RegisterAdvertisement").onInterface(INTERFACE_NAME).withArguments(advertisement, options);
}
void UnregisterAdvertisement(const sdbus::ObjectPath& service)
{
proxy_.callMethod("UnregisterAdvertisement").onInterface(INTERFACE_NAME).withArguments(service);
}
public:
uint8_t ActiveInstances()
{
return proxy_.getProperty("ActiveInstances").onInterface(INTERFACE_NAME);
}
uint8_t SupportedInstances()
{
return proxy_.getProperty("SupportedInstances").onInterface(INTERFACE_NAME);
}
std::vector<std::string> SupportedIncludes()
{
return proxy_.getProperty("SupportedIncludes").onInterface(INTERFACE_NAME);
}
std::vector<std::string> SupportedSecondaryChannels()
{
return proxy_.getProperty("SupportedSecondaryChannels").onInterface(INTERFACE_NAME);
}
std::vector<std::string> SupportedFeatures()
{
return proxy_.getProperty("SupportedFeatures").onInterface(INTERFACE_NAME);
}
std::map<std::string, sdbus::Variant> SupportedCapabilities()
{
return proxy_.getProperty("SupportedCapabilities").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
@@ -1,67 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp__generated_dbus_bluez_le_advertisement_server_h__adaptor__H__
#define __sdbuscpp__generated_dbus_bluez_le_advertisement_server_h__adaptor__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
class LEAdvertisement1_adaptor
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.LEAdvertisement1";
protected:
LEAdvertisement1_adaptor(sdbus::IObject& object)
: object_(object)
{
object_.registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); });
object_.registerProperty("Type").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Type(); });
object_.registerProperty("ServiceUUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ServiceUUIDs(); });
object_.registerProperty("ManufacturerData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ManufacturerData(); });
object_.registerProperty("SolicitUUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SolicitUUIDs(); });
object_.registerProperty("ServiceData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ServiceData(); });
object_.registerProperty("ScanResponseServiceData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ScanResponseServiceData(); });
object_.registerProperty("Includes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Includes(); });
object_.registerProperty("LocalName").onInterface(INTERFACE_NAME).withGetter([this](){ return this->LocalName(); });
object_.registerProperty("Duration").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Duration(); });
object_.registerProperty("Timeout").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Timeout(); });
object_.registerProperty("MinInterval").onInterface(INTERFACE_NAME).withGetter([this](){ return this->MinInterval(); });
object_.registerProperty("MaxInterval").onInterface(INTERFACE_NAME).withGetter([this](){ return this->MaxInterval(); });
object_.registerProperty("TxPower").onInterface(INTERFACE_NAME).withGetter([this](){ return this->TxPower(); });
}
~LEAdvertisement1_adaptor() = default;
private:
virtual void Release() = 0;
private:
virtual std::string Type() = 0;
virtual std::vector<std::string> ServiceUUIDs() = 0;
virtual std::map<std::string, sdbus::Variant> ManufacturerData() = 0;
virtual std::vector<std::string> SolicitUUIDs() = 0;
virtual std::map<std::string, sdbus::Variant> ServiceData() = 0;
virtual std::map<std::string, sdbus::Variant> ScanResponseServiceData() = 0;
virtual std::vector<std::string> Includes() = 0;
virtual std::string LocalName() = 0;
virtual uint16_t Duration() = 0;
virtual uint16_t Timeout() = 0;
virtual uint32_t MinInterval() = 0;
virtual uint32_t MaxInterval() = 0;
virtual int16_t TxPower() = 0;
private:
sdbus::IObject& object_;
};
}} // namespaces
#endif
@@ -1,76 +0,0 @@
/*
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
*/
#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_dbus_bluez_le_bearer_client_h__proxy__H__
#define __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_dbus_bluez_le_bearer_client_h__proxy__H__
#include <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
namespace org {
namespace bluez {
namespace Bearer {
class LE1_proxy
{
public:
static constexpr const char* INTERFACE_NAME = "org.bluez.Bearer.LE1";
protected:
LE1_proxy(sdbus::IProxy& proxy)
: proxy_(&proxy)
{
proxy_->uponSignal("Disconnected").onInterface(INTERFACE_NAME).call([this](const std::string& reason, const std::string& message){ this->onDisconnected(reason, message); });
}
LE1_proxy(const LE1_proxy&) = delete;
LE1_proxy& operator=(const LE1_proxy&) = delete;
LE1_proxy(LE1_proxy&&) = default;
LE1_proxy& operator=(LE1_proxy&&) = default;
~LE1_proxy() = default;
virtual void onDisconnected(const std::string& reason, const std::string& message) = 0;
public:
void Connect()
{
proxy_->callMethod("Connect").onInterface(INTERFACE_NAME);
}
void Disconnect()
{
proxy_->callMethod("Disconnect").onInterface(INTERFACE_NAME);
}
public:
sdbus::ObjectPath Adapter()
{
return proxy_->getProperty("Adapter").onInterface(INTERFACE_NAME);
}
bool Paired()
{
return proxy_->getProperty("Paired").onInterface(INTERFACE_NAME);
}
bool Bonded()
{
return proxy_->getProperty("Bonded").onInterface(INTERFACE_NAME);
}
bool Connected()
{
return proxy_->getProperty("Connected").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy* proxy_;
};
}}} // namespaces
#endif
@@ -1,36 +0,0 @@
<?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>
@@ -1,27 +0,0 @@
<?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.AdvertisementMonitor1">
<method name="Release">
</method>
<method name="Activate">
</method>
<method name="DeviceFound">
<arg type='o' name="device" direction="in"/>
</method>
<method name="DeviceLost">
<arg type='o' name="device" direction="in"/>
</method>
<property name="Type" type="s" access="read">
</property>
<property name="RSSILowThreshold" type="n" access="read">
</property>
<property name="RSSIHighThreshold" type="n" access="read">
</property>
<property name="RSSISamplingPeriod" type="q" access="read">
</property>
<property name="Patterns" type="a(yyay)" access="read">
</property>
</interface>
</node>
@@ -1,14 +0,0 @@
<?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.AdvertisementMonitorManager1">
<method name="RegisterMonitor">
<arg name="application" type="o" direction="in" />
</method>
<method name="UnregisterMonitor">
<arg name="application" type="o" direction="in" />
</method>
<property name="SupportedMonitorTypes" type="as" access="read" />
<property name="SupportedFeatures" type="as" access="read" />
</interface>
</node>
@@ -1,43 +0,0 @@
<?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">
<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>
@@ -1,35 +0,0 @@
<?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.GattCharacteristic1">
<method name="ReadValue">
<arg name="options" type="a{sv}" direction="in" />
<arg name="value" type="ay" direction="out" />
</method>
<method name="WriteValue">
<arg name="value" type="ay" direction="in" />
<arg name="options" type="a{sv}" direction="in" />
</method>
<method name="AcquireWrite">
<arg name="options" type="a{sv}" direction="in" />
<arg name="fd" type="h" direction="out" />
<arg name="mtu" type="q" direction="out" />
</method>
<method name="AcquireNotify">
<arg name="options" type="a{sv}" direction="in" />
<arg name="fd" type="h" direction="out" />
<arg name="mtu" type="q" direction="out" />
</method>
<method name="StartNotify" />
<method name="StopNotify" />
<property name="Handle" type="q" access="read" />
<property name="UUID" type="s" access="read" />
<property name="Service" type="o" access="read" />
<property name="Value" type="ay" access="read" />
<property name="Notifying" type="b" access="read" />
<property name="Flags" type="as" access="read" />
<property name="WriteAcquired" type="b" access="read" />
<property name="NotifyAcquired" type="b" access="read" />
<property name="MTU" type="q" access="read" />
</interface>
</node>
@@ -1,28 +0,0 @@
<!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.GattCharacteristic1">
<method name="ReadValue">
<annotation name="org.freedesktop.DBus.Method.Async" value="server" />
<arg name="options" type="a{sv}" direction="in"/>
<arg name="value" type="ay" direction="out"/>
</method>
<method name="WriteValue">
<annotation name="org.freedesktop.DBus.Method.Async" value="server" />
<arg name="value" type="ay" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
</method>
<method name="StartNotify">
</method>
<method name="StopNotify">
</method>
<method name="Confirm">
</method>
<property name="UUID" type="s" access="read"></property>
<property name="Service" type="o" access="read"></property>
<property name="Value" type="ay" access="read"></property>
<property name="Notifying" type="b" access="read"></property>
<property name="Flags" type="as" access="read"></property>
</interface>
</node>
@@ -1,13 +0,0 @@
<?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.GattManager1">
<method name="RegisterApplication">
<arg name="application" type="o" direction="in" />
<arg name="options" type="a{sv}" direction="in" />
</method>
<method name="UnregisterApplication">
<arg name="application" type="o" direction="in" />
</method>
</interface>
</node>
@@ -1,8 +0,0 @@
<!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.GattProfile1">
<method name="Release"/>
<property name="UUIDs" type="as" access="read"/>
</interface>
</node>
@@ -1,10 +0,0 @@
<!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.GattService1">
<property name="UUID" type="s" access="read"></property>
<property name="Primary" type="b" access="read"></property>
<property name="Device" type="o" access="read"></property>
<property name="Includes" type="ao" access="read"></property>
</interface>
</node>
@@ -1,21 +0,0 @@
<?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.LEAdvertisement1">
<method name="Release"/>
<property name="Type" type="s" access="read"/>
<property name="ServiceUUIDs" type="as" access="read"/>
<property name="ManufacturerData" type="a{sv}" access="read"/>
<property name="SolicitUUIDs" type="as" access="read"/>
<property name="ServiceData" type="a{sv}" access="read"/>
<property name="Includes" type="as" access="read"/>
<property name="LocalName" type="s" access="read"/>
<property name="Duration" type="q" access="read"/>
<property name="Timeout" type="q" access="read"/>
<property name="MinInterval" type="u" access="read"/>
<property name="MaxInterval" type="u" access="read"/>
<property name="TxPower" type="n" access="read"/>
</interface>
</node>
@@ -1,19 +0,0 @@
<?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.LEAdvertisingManager1">
<method name="RegisterAdvertisement">
<arg name="advertisement" type="o" direction="in" />
<arg name="options" type="a{sv}" direction="in" />
</method>
<method name="UnregisterAdvertisement">
<arg name="service" type="o" direction="in" />
</method>
<property name="ActiveInstances" type="y" access="read" />
<property name="SupportedInstances" type="y" access="read" />
<property name="SupportedIncludes" type="as" access="read" />
<property name="SupportedSecondaryChannels" type="as" access="read" />
<property name="SupportedFeatures" type="as" access="read" />
<property name="SupportedCapabilities" type="a{sv}" access="read" />
</interface>
</node>
@@ -1,17 +0,0 @@
<!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>
@@ -1,14 +0,0 @@
<?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>
@@ -1,46 +0,0 @@
/*
* 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,43 +0,0 @@
/*
* 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

Some files were not shown because too many files have changed in this diff Show More