mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
removed non-core files
This commit is contained in:
@@ -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() isn’t 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([¬ified]() { 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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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(®istered_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 can’t 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() isn’t 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", we’ll 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,
|
||||
¬ification](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
|
||||
+8
-13
@@ -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
|
||||
+8
-15
@@ -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
|
||||
-94
@@ -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>
|
||||
-398
@@ -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>
|
||||
-58
@@ -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>
|
||||
-57
@@ -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
|
||||
-57
@@ -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
|
||||
-57
@@ -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
|
||||
-118
@@ -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
|
||||
-59
@@ -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
|
||||
-77
@@ -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>
|
||||
-27
@@ -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>
|
||||
-14
@@ -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>
|
||||
-35
@@ -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>
|
||||
-28
@@ -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>
|
||||
-13
@@ -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>
|
||||
-10
@@ -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>
|
||||
-21
@@ -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>
|
||||
-19
@@ -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>
|
||||
-14
@@ -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
Reference in New Issue
Block a user