mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
merged abandoned linux port
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
# 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.
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
cc_library(
|
||||
name = "types",
|
||||
hdrs = [
|
||||
"atomic_boolean.h",
|
||||
"atomic_reference.h",
|
||||
"atomic_uint32.h",
|
||||
"bluetooth_adapter.h",
|
||||
"condition_variable.h",
|
||||
"device_info.h",
|
||||
"executor.h",
|
||||
"future.h",
|
||||
"mutex.h",
|
||||
"preferences_manager.h",
|
||||
"preferences_repository.h",
|
||||
"scheduled_executor.h",
|
||||
"submittable_executor.h",
|
||||
"timer.h",
|
||||
"thread_pool.h",
|
||||
"log_message.h",
|
||||
"utils.h",
|
||||
],
|
||||
srcs = [
|
||||
"device_info.cc",
|
||||
"log_message.cc",
|
||||
"timer.cc",
|
||||
],
|
||||
copts = ["-lrt"],
|
||||
visibility = ["//third_party/nearby/sharing/internal/impl/linux:__pkg__"],
|
||||
deps = [
|
||||
":comm",
|
||||
"//internal/platform/implementation:types",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@libsystemd//:lib",
|
||||
"@sdbus_cpp//:lib",
|
||||
],
|
||||
)
|
||||
|
||||
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",
|
||||
"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_advertisement_monitor.h",
|
||||
"bluez_advertisement_monitor_manager.h",
|
||||
"bluez_gatt_characteristic_client.h",
|
||||
"bluez_gatt_characteristic_server.h",
|
||||
"bluez_gatt_manager.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 = [
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:comm",
|
||||
"//internal/platform:types",
|
||||
"//internal/platform:uuid",
|
||||
"//internal/platform/implementation:comm",
|
||||
"//internal/platform/implementation:types",
|
||||
"//internal/platform/implementation/linux/generated:types",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
"@com_google_absl//absl/functional:any_invocable",
|
||||
"@com_google_absl//absl/memory",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_absl//absl/types:optional",
|
||||
"@libsystemd//:lib",
|
||||
"@sdbus_cpp//:lib",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "crypto",
|
||||
srcs = [
|
||||
"crypto.cc",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//internal/platform:base",
|
||||
"//internal/platform/implementation:types",
|
||||
"@boringssl//:crypto",
|
||||
"@com_google_absl//absl/strings",
|
||||
])
|
||||
|
||||
cc_library(
|
||||
name = "linux",
|
||||
srcs = [
|
||||
"avahi.cc",
|
||||
"ble_gatt_client.cc",
|
||||
"ble_gatt_server.cc",
|
||||
"ble_v2_medium.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_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",
|
||||
"scheduled_executor.cc",
|
||||
"stream.cc",
|
||||
"submittable_executor.cc",
|
||||
"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",
|
||||
],
|
||||
visibility = [
|
||||
"//connections:__subpackages__",
|
||||
"//fastpair:__subpackages__",
|
||||
"//location/nearby:__subpackages__",
|
||||
"//presence:__subpackages__",
|
||||
"//third_party/nearby/sharing:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":comm",
|
||||
":crypto", # build_cleaner: keep
|
||||
":types",
|
||||
"//internal/flags:nearby_flags",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:cancellation_flag",
|
||||
"//internal/platform:comm",
|
||||
"//internal/platform:types",
|
||||
"//internal/platform:uuid",
|
||||
"//internal/platform/flags:platform_flags",
|
||||
"//internal/platform/implementation:comm",
|
||||
"//internal/platform/implementation:platform",
|
||||
"//internal/platform/implementation:types",
|
||||
"//internal/platform/implementation/shared:count_down_latch",
|
||||
"//internal/platform/implementation/shared:file",
|
||||
"//internal/platform/implementation/linux/generated:types",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/functional:any_invocable",
|
||||
"@com_google_absl//absl/log:check",
|
||||
"@com_google_absl//absl/memory",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_absl//absl/types:optional",
|
||||
"@nlohmann_json//:json",
|
||||
"@libsystemd//:lib",
|
||||
"@sdbus_cpp//:lib",
|
||||
"@libcurl//:lib"
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "test_utils",
|
||||
srcs = [
|
||||
"test_utils.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"test_data.h",
|
||||
"test_utils.h",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:private", # Only private by automation, not intent. Owner may accept CLs adding visibility. See go/scheuklappen#explicit-private.
|
||||
],
|
||||
deps = [
|
||||
"//internal/platform:base",
|
||||
"@nlohmann_json//:json",
|
||||
":types",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "impl_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"atomic_boolean_test.cc",
|
||||
"atomic_reference_test.cc",
|
||||
"mutex_test.cc",
|
||||
"utils_test.cc",
|
||||
# "bluetooth_adapter_test.cc",
|
||||
# "crypto_test.cc",
|
||||
# "device_info_test.cc",
|
||||
# "executor_test.cc",
|
||||
# "file_path_test.cc",
|
||||
# "http_loader_test.cc",
|
||||
# "preferences_manager_test.cc",
|
||||
# "preferences_repository_test.cc",
|
||||
# "scheduled_executor_test.cc",
|
||||
# "submittable_executor_test.cc",
|
||||
# "thread_pool_test.cc",
|
||||
# "timer_test.cc",
|
||||
],
|
||||
tags = ["notap"],
|
||||
deps = [
|
||||
":comm",
|
||||
":crypto",
|
||||
":test_utils",
|
||||
":types",
|
||||
":linux",
|
||||
"//internal/platform:base",
|
||||
"//internal/platform/implementation:comm",
|
||||
"//internal/platform/implementation:platform",
|
||||
"//internal/platform/implementation:types",
|
||||
"//internal/platform/implementation/shared:count_down_latch",
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_absl//absl/types:span",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
"@nlohmann_json//:json",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
// 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_ATOMIC_BOOLEAN_H_
|
||||
#define PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_
|
||||
|
||||
#include <atomic>
|
||||
#include "internal/platform/implementation/atomic_boolean.h"
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
// A boolean value that may be updated atomically.
|
||||
class AtomicBoolean : public api::AtomicBoolean {
|
||||
public:
|
||||
AtomicBoolean(bool initial_value = false) : atomic_boolean_(initial_value) {}
|
||||
~AtomicBoolean() override = default;
|
||||
|
||||
// Atomically read and return current value.
|
||||
bool Get() const override { return atomic_boolean_; };
|
||||
|
||||
// Atomically exchange original value with a new one. Return previous value.
|
||||
bool Set(bool value) override { return atomic_boolean_.exchange(value); };
|
||||
|
||||
private:
|
||||
std::atomic_bool atomic_boolean_ = false;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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_boolean.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(atomic_boolean, SuccessfulCreation) {
|
||||
// Arrange
|
||||
nearby::linux::AtomicBoolean atomicBoolean;
|
||||
bool oldValue = true;
|
||||
bool result = false;
|
||||
|
||||
// Act
|
||||
oldValue = atomicBoolean.Set(true);
|
||||
result = atomicBoolean.Get();
|
||||
|
||||
// Assert
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_FALSE(oldValue);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// 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.
|
||||
|
||||
#ifndef PLATFORM_IMPL_LINUX_ATOMIC_REFERENCE_H_
|
||||
#define PLATFORM_IMPL_LINUX_ATOMIC_REFERENCE_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "internal/platform/implementation/atomic_reference.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
// Type that allows 32-bit atomic reads and writes.
|
||||
class AtomicUint32 : public api::AtomicUint32 {
|
||||
public:
|
||||
~AtomicUint32() override = default;
|
||||
|
||||
// Atomically reads and returns stored value.
|
||||
std::uint32_t Get() const override { return atomic_uint32_; };
|
||||
|
||||
// Atomically stores value.
|
||||
void Set(std::uint32_t value) override { atomic_uint32_ = value; }
|
||||
|
||||
private:
|
||||
std::atomic_int32_t atomic_uint32_ = 0;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPL_LINUX_ATOMIC_REFERENCE_H_
|
||||
@@ -0,0 +1,72 @@
|
||||
// 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);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// 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_ATOMIC_UINT32_H_
|
||||
#define PLATFORM_IMPL_LINUX_ATOMIC_UINT32_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include "internal/platform/implementation/atomic_reference.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
// A boolean value that may be updated atomically.
|
||||
class AtomicUint32 : public api::AtomicUint32 {
|
||||
public:
|
||||
AtomicUint32(std::uint32_t initial_value) : atomic_uint_(initial_value) {}
|
||||
~AtomicUint32() override = default;
|
||||
|
||||
// Atomically read and return current value.
|
||||
std::uint32_t Get() const override { return atomic_uint_; };
|
||||
|
||||
// Atomically exchange original value with a new one. Return previous value.
|
||||
void Set(std::uint32_t value) override { atomic_uint_ = value; };
|
||||
|
||||
private:
|
||||
std::atomic_bool atomic_uint_ = false;
|
||||
};
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
// 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) {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
|
||||
<< ": Found new item through the ServiceBrowser: "
|
||||
<< "interface: " << interface << ", protocol: "
|
||||
<< protocol << ", name: '" << name << "', type: '"
|
||||
<< type << "', domain: '" << domain
|
||||
<< "', flags: " << flags;
|
||||
if (flags & kAvahiLookupResultLocal) {
|
||||
NEARBY_LOGS(VERBOSE) << __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);
|
||||
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) {
|
||||
NEARBY_LOGS(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?
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
|
||||
<< ": Item removed through the ServiceBrowser: "
|
||||
<< "interface: " << interface << ", protocol: "
|
||||
<< protocol << ", name: '" << name << "', type: '"
|
||||
<< type << "', domain: '" << domain
|
||||
<< "', flags: " << flags;
|
||||
if (flags & kAvahiLookupResultLocal) {
|
||||
NEARBY_LOGS(VERBOSE) << __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) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath()
|
||||
<< ": ServiceBrowser reported a failure: " << error;
|
||||
}
|
||||
|
||||
void ServiceBrowser::onAllForNow() {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
|
||||
<< ": notified via ServiceBrowser that all records have "
|
||||
"been added for now";
|
||||
}
|
||||
|
||||
void ServiceBrowser::onCacheExhausted() {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
|
||||
<< ": notified via ServiceBrowser of cache exhaustion";
|
||||
}
|
||||
|
||||
} // namespace avahi
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,127 @@
|
||||
// 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() {
|
||||
NEARBY_LOGS(VERBOSE) << __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() {
|
||||
NEARBY_LOGS(VERBOSE) << __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
|
||||
@@ -0,0 +1,428 @@
|
||||
// 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) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(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;
|
||||
const auto &properties =
|
||||
ifaces.at(org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME);
|
||||
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));
|
||||
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()) {
|
||||
NEARBY_LOGS(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()) {
|
||||
NEARBY_LOGS(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 &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()) {
|
||||
NEARBY_LOGS(ERROR) << ": Couldn't parse UUID '" << chr_uuid_str
|
||||
<< "' in characteristic " << path;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const sdbus::ObjectPath &service_path = properties.at("Service");
|
||||
if (cached_services_.count(service_path) == 0) {
|
||||
cached_services_.emplace(
|
||||
path, std::make_unique<GattServiceClient>(system_bus_, path));
|
||||
}
|
||||
|
||||
auto &service = cached_services_.at(service_path);
|
||||
nearby::Uuid service_uuid;
|
||||
try {
|
||||
const std::string &service_uuid_str = service->UUID();
|
||||
auto service_uuid_maybe = UuidFromString(service_uuid_str);
|
||||
if (!service_uuid_maybe.has_value()) {
|
||||
NEARBY_LOGS(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 &props = characteristics_properties_.at(objectPath);
|
||||
discovered_characteristics_.erase(props);
|
||||
}
|
||||
characteristics_properties_.erase(objectPath);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,210 @@
|
||||
// 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 &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
|
||||
@@ -0,0 +1,147 @@
|
||||
// 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) {
|
||||
NEARBY_LOGS(ERROR)
|
||||
<< __func__
|
||||
<< ": error emitting InterfacesAdded signal for object path "
|
||||
<< service->getObjectPath() << " with name '" << e.getName()
|
||||
<< "' and message '" << e.getMessage() << "'";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (service->AddCharacteristic(service_uuid, characteristic_uuid, permission,
|
||||
property)) {
|
||||
bluez::GattManager manager(system_bus_, adapter_.GetObjectPath());
|
||||
try {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": registering service "
|
||||
<< service->getObjectPath();
|
||||
manager.RegisterApplication("/", {});
|
||||
} catch (const sdbus::Error& e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(&manager, "RegisterApplication", e);
|
||||
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) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(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_) {
|
||||
NEARBY_LOGS(VERBOSE) << __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
|
||||
@@ -0,0 +1,96 @@
|
||||
// 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 <sdbus-c++/IConnection.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) {
|
||||
unique_id_ = BluetoothUtils::ToNumber(adapter_.GetMacAddress());
|
||||
}
|
||||
|
||||
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_),
|
||||
server_cb_(std::make_shared<api::ble_v2::ServerGattConnectionCallback>(
|
||||
std::move(server_cb))) {}
|
||||
~GattServer() override = default;
|
||||
|
||||
api::ble_v2::BlePeripheral& GetBlePeripheral() override {
|
||||
return local_peripheral_;
|
||||
}
|
||||
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::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
|
||||
@@ -0,0 +1,73 @@
|
||||
// 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
|
||||
@@ -0,0 +1,480 @@
|
||||
// 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 <cassert>
|
||||
|
||||
#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 "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/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_)),
|
||||
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_) {
|
||||
NEARBY_LOGS(VERBOSE)
|
||||
<< __func__
|
||||
<< ": Registering path / with AdvertisementMonitorManager at "
|
||||
<< adv_monitor_manager_->getObjectPath();
|
||||
try {
|
||||
adv_monitor_manager_->RegisterMonitor("/");
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(adv_monitor_manager_, "RegisterMonitor", e);
|
||||
}
|
||||
}
|
||||
if (gatt_discovery_->InitializeKnownServices()) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": Could not initialize known GATT services";
|
||||
}
|
||||
}
|
||||
|
||||
bool BleV2Medium::StartAdvertising(
|
||||
const api::ble_v2::BleAdvertisementData &advertising_data,
|
||||
api::ble_v2::AdvertiseParameters advertise_set_parameters) {
|
||||
if (!adapter_.IsEnabled()) {
|
||||
NEARBY_LOGS(WARNING) << "BLE cannot start advertising because the "
|
||||
"bluetooth adapter is not enabled.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (advertising_data.service_data.empty()) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "BLE cannot start to advertise due to invalid service data.";
|
||||
return false;
|
||||
}
|
||||
|
||||
absl::MutexLock lock(&cur_adv_mutex_);
|
||||
if (cur_adv_ != nullptr) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< "Advertising is already enabled for this medium.";
|
||||
return false;
|
||||
}
|
||||
|
||||
cur_adv_ = bluez::LEAdvertisement::CreateLEAdvertisement(
|
||||
*system_bus_, advertising_data, advertise_set_parameters);
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Registering advertisement "
|
||||
<< cur_adv_->getObjectPath() << " on bluetooth adapter "
|
||||
<< adapter_.GetObjectPath();
|
||||
|
||||
try {
|
||||
adv_manager_->RegisterAdvertisement(cur_adv_->getObjectPath(), {});
|
||||
} catch (const sdbus::Error &e) {
|
||||
cur_adv_ = nullptr;
|
||||
DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "RegisterAdvertisement", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BleV2Medium::StopAdvertising() {
|
||||
absl::MutexLock lock(&cur_adv_mutex_);
|
||||
if (cur_adv_ == nullptr) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Advertising is not enabled.";
|
||||
return false;
|
||||
}
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << "Unregistering advertisement object "
|
||||
<< cur_adv_->getObjectPath();
|
||||
|
||||
try {
|
||||
adv_manager_->UnregisterAdvertisement(cur_adv_->getObjectPath());
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "UnregisterAdvertisement", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
cur_adv_ = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
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()) {
|
||||
NEARBY_LOGS(WARNING) << ": BLE cannot start advertising because the "
|
||||
"bluetooth adapter is not enabled.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (advertising_data.service_data.empty()) {
|
||||
NEARBY_LOGS(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]() {
|
||||
NEARBY_LOGS(VERBOSE) << __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) {
|
||||
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 &peripheral,
|
||||
api::ble_v2::TxPowerLevel tx_power_level,
|
||||
api::ble_v2::ClientGattConnectionCallback callback) {
|
||||
auto path = bluez::device_object_path(adapter_.GetObjectPath(),
|
||||
peripheral.GetAddress());
|
||||
|
||||
return std::make_unique<GattClient>(system_bus_, path, gatt_discovery_,
|
||||
std::move(callback.disconnected_cb));
|
||||
}
|
||||
|
||||
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";
|
||||
auto &adapter = adapter_.GetBluezAdapterObject();
|
||||
|
||||
try {
|
||||
adapter.SetDiscoveryFilter(filter);
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
NEARBY_LOGS(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()) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": A sync scanning session is already active for "
|
||||
<< std::string{*cur_monitored_service_uuid_};
|
||||
return false;
|
||||
}
|
||||
|
||||
if (adv_monitor_manager_ == nullptr) {
|
||||
NEARBY_LOGS(WARNING) << __func__
|
||||
<< ": Advertising monitor not supported by BlueZ";
|
||||
// TODO: Implement manual monitoring.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MonitorManagerSupportsOr()) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(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 {
|
||||
monitor->emitInterfacesAddedSignal(
|
||||
{org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME});
|
||||
} catch (const sdbus::Error &e) {
|
||||
NEARBY_LOGS(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(), devices_);
|
||||
if (!StartLEDiscovery()) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(ERROR)
|
||||
<< __func__
|
||||
<< ": error emitting InterfacesRemoved signal for object path "
|
||||
<< monitor->getObjectPath() << " with name '" << e.getName()
|
||||
<< "' and message '" << e.getMessage() << "'";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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()) {
|
||||
NEARBY_LOGS(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();
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": Stopping discovery for adapter "
|
||||
<< adapter.getObjectPath();
|
||||
try {
|
||||
adapter.StopDiscovery();
|
||||
} 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;
|
||||
|
||||
NEARBY_LOGS(VERBOSE) << __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) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(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(), devices_);
|
||||
if (!StartLEDiscovery()) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(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;
|
||||
}});
|
||||
}
|
||||
|
||||
bool BleV2Medium::GetRemotePeripheral(const std::string &mac_address,
|
||||
GetRemotePeripheralCallback callback) {
|
||||
auto device = devices_->get_device_by_address(mac_address);
|
||||
if (device == nullptr) return false;
|
||||
callback(*device);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BleV2Medium::GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id,
|
||||
GetRemotePeripheralCallback callback) {
|
||||
auto device = devices_->get_device_by_unique_id(id);
|
||||
if (device == nullptr) return false;
|
||||
callback(*device);
|
||||
return true;
|
||||
}
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,144 @@
|
||||
// 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 <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 "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 &peripheral,
|
||||
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 {
|
||||
return std::make_unique<BleV2ServerSocket>();
|
||||
}
|
||||
|
||||
std::unique_ptr<api::ble_v2::BleSocket> Connect(
|
||||
const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level,
|
||||
api::ble_v2::BlePeripheral &peripheral,
|
||||
CancellationFlag *cancellation_flag) override {
|
||||
return nullptr;
|
||||
}
|
||||
bool IsExtendedAdvertisementsAvailable() 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
|
||||
@@ -0,0 +1,42 @@
|
||||
// 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 "absl/synchronization/notification.h"
|
||||
#include "internal/platform/implementation/ble_v2.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
class BleV2ServerSocket final : public api::ble_v2::BleServerSocket {
|
||||
public:
|
||||
std::unique_ptr<api::ble_v2::BleSocket> Accept() override {
|
||||
stopped_.WaitForNotification();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Exception Close() override {
|
||||
if (stopped_.HasBeenNotified()) return {Exception::kIo};
|
||||
stopped_.Notify();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
private:
|
||||
absl::Notification stopped_;
|
||||
};
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,121 @@
|
||||
// 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
|
||||
@@ -0,0 +1,84 @@
|
||||
// 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_
|
||||
@@ -0,0 +1,285 @@
|
||||
// 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"
|
||||
|
||||
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;
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": Profile object " << getObjectPath()
|
||||
<< " has been released";
|
||||
}
|
||||
|
||||
void Profile::NewConnection(
|
||||
const sdbus::ObjectPath &device_object_path, const sdbus::UnixFd &fd,
|
||||
const std::map<std::string, sdbus::Variant> &fd_props) {
|
||||
if (released_) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": NewConnection called on released object "
|
||||
<< getObjectPath();
|
||||
throw sdbus::Error("org.bluez.Error.Rejected",
|
||||
"NewConnection called on released object");
|
||||
}
|
||||
|
||||
auto device = devices_.get_device_by_path(device_object_path);
|
||||
|
||||
if (device == nullptr) {
|
||||
device = devices_.add_new_device(device_object_path);
|
||||
}
|
||||
|
||||
auto alias = device->GetName();
|
||||
auto mac_addr = device->GetAddress();
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath()
|
||||
<< ": Connected to " << mac_addr;
|
||||
|
||||
FDProperties props(fd_props);
|
||||
|
||||
absl::MutexLock l(&connections_lock_);
|
||||
connections_[mac_addr].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) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath()
|
||||
<< ": RequestDisconnection called with a device object "
|
||||
"we don't know about: "
|
||||
<< device_object_path;
|
||||
throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object");
|
||||
}
|
||||
|
||||
auto mac_addr = device->GetMacAddress();
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": Disconnection requested for device "
|
||||
<< device_object_path;
|
||||
|
||||
absl::MutexLock l(&connections_lock_);
|
||||
if (connections_.count(mac_addr) == 0) {
|
||||
NEARBY_LOGS(ERROR)
|
||||
<< __func__
|
||||
<< ": Disconnection requested, but we are not connected to this device";
|
||||
return;
|
||||
}
|
||||
|
||||
connections_.erase(mac_addr);
|
||||
}
|
||||
|
||||
bool ProfileManager::Register(std::optional<absl::string_view> name,
|
||||
absl::string_view service_uuid) {
|
||||
absl::MutexLock l(®istered_service_uuids_mutex_);
|
||||
if (registered_services_.count(std::string(service_uuid)) == 1) {
|
||||
NEARBY_LOGS(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);
|
||||
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< __func__
|
||||
<< ": attempted to unregister a profile that is not registered";
|
||||
return;
|
||||
}
|
||||
|
||||
auto profile_object_path = bluez::profile_object_path(service_uuid);
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": Unregistering profile "
|
||||
<< profile_object_path;
|
||||
|
||||
try {
|
||||
UnregisterProfile(profile_object_path);
|
||||
} catch (const sdbus::Error &e) {
|
||||
BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "UnregisterProfile", e);
|
||||
}
|
||||
|
||||
registered_services_.erase(std::string(service_uuid));
|
||||
}
|
||||
|
||||
// Get a service record FD for a connected profile (identified by service_uuid)
|
||||
// to the given device.
|
||||
std::optional<sdbus::UnixFd> ProfileManager::GetServiceRecordFD(
|
||||
api::BluetoothDevice &remote_device, absl::string_view service_uuid,
|
||||
CancellationFlag *cancellation_flag) {
|
||||
std::shared_ptr<Profile> profile;
|
||||
{
|
||||
absl::ReaderMutexLock lock(®istered_service_uuids_mutex_);
|
||||
if (registered_services_.count(std::string(service_uuid)) == 0) {
|
||||
NEARBY_LOGS(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]() {
|
||||
profile->connections_lock_.Lock();
|
||||
profile->connections_lock_.Unlock();
|
||||
});
|
||||
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath()
|
||||
<< ": Attempting to get a FD for service "
|
||||
<< service_uuid << " on device " << mac_addr;
|
||||
|
||||
auto cond = [mac_addr, profile, cancellation_flag]() {
|
||||
profile->connections_lock_.AssertReaderHeld();
|
||||
return profile->connections_.count(mac_addr) != 0 ||
|
||||
(cancellation_flag != nullptr && cancellation_flag->Cancelled());
|
||||
};
|
||||
|
||||
absl::MutexLock connections_lock(&profile->connections_lock_,
|
||||
absl::Condition(&cond));
|
||||
|
||||
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
|
||||
NEARBY_LOGS(VERBOSE)
|
||||
<< __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.
|
||||
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)];
|
||||
}
|
||||
|
||||
NEARBY_LOGS(VERBOSE) << __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();
|
||||
return !profile->connections_.empty() ||
|
||||
(cancellation_flag != nullptr && cancellation_flag->Cancelled());
|
||||
};
|
||||
profile->connections_lock_.Await(absl::Condition(&cond));
|
||||
|
||||
if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) {
|
||||
NEARBY_LOGS(VERBOSE)
|
||||
<< __func__ << ": Cancelled waiting for new connections on profile "
|
||||
<< profile->getObjectPath();
|
||||
profile->connections_lock_.Unlock();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto it = profile->connections_.begin();
|
||||
auto mac_addr = it->first;
|
||||
auto [fd, properties] = it->second.back();
|
||||
it->second.pop_back();
|
||||
if (it->second.empty()) profile->connections_.erase(it);
|
||||
profile->connections_lock_.Unlock();
|
||||
|
||||
auto device = devices_.get_device_by_address(mac_addr);
|
||||
if (device == nullptr) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Device " << mac_addr
|
||||
<< " is no longer available";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::pair(device, std::move(fd));
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,147 @@
|
||||
// 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();
|
||||
NEARBY_LOGS(VERBOSE) << __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_);
|
||||
|
||||
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_);
|
||||
|
||||
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
|
||||
@@ -0,0 +1,148 @@
|
||||
// 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) {
|
||||
try {
|
||||
last_known_name_ = device->Alias();
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(device, "Alias", e);
|
||||
}
|
||||
try {
|
||||
last_known_address_ = device->Address();
|
||||
unique_id_ = BluetoothUtils::ToNumber(last_known_address_);
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(device, "Address", e);
|
||||
}
|
||||
}
|
||||
|
||||
std::string BluetoothDevice::GetName() const {
|
||||
auto device = device_.lock();
|
||||
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_.lock();
|
||||
if (device == nullptr) {
|
||||
absl::ReaderMutexLock l(&properties_mutex_);
|
||||
return last_known_name_;
|
||||
}
|
||||
|
||||
try {
|
||||
std::string addr = device->Address();
|
||||
{
|
||||
absl::MutexLock l(&properties_mutex_);
|
||||
last_known_address_ = addr;
|
||||
}
|
||||
return addr;
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(device, "Address", e);
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) {
|
||||
auto device = device_.lock();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
MonitoredBluetoothDevice::MonitoredBluetoothDevice(
|
||||
std::shared_ptr<sdbus::IConnection> system_bus,
|
||||
std::shared_ptr<bluez::Device> device,
|
||||
ObserverList<api::BluetoothClassicMedium::Observer> &observers)
|
||||
: BluetoothDevice(std::move(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) {
|
||||
NEARBY_LOGS(VERBOSE) << __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) {
|
||||
NEARBY_LOGS(VERBOSE) << __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) {
|
||||
NEARBY_LOGS(VERBOSE)
|
||||
<< __func__ << ": " << getObjectPath()
|
||||
<< "Notifying observers about connected status change";
|
||||
for (const auto &observer : observers_.GetObservers()) {
|
||||
observer->DeviceConnectedStateChanged(*this, 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
|
||||
@@ -0,0 +1,182 @@
|
||||
// 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 api::ble_v2::BlePeripheral {
|
||||
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);
|
||||
|
||||
// BluetoothDevice methods
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName()
|
||||
std::string GetName() const override;
|
||||
// Returns BT MAC address assigned to this device.
|
||||
std::string GetMacAddress() const override;
|
||||
|
||||
// BlePeripheral methods
|
||||
std::string GetAddress() const override { return GetMacAddress(); }
|
||||
UniqueId GetUniqueId() const override { return unique_id_; };
|
||||
|
||||
std::optional<std::map<std::string, sdbus::Variant>> ServiceData() {
|
||||
auto device = device_.lock();
|
||||
if (device == nullptr) 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_.lock();
|
||||
if (device == nullptr) 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_.lock();
|
||||
if (device == nullptr) 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_.lock();
|
||||
if (device == nullptr) 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_.lock();
|
||||
if (device != nullptr) device->SetPairReplyCallback(std::move(cb));
|
||||
}
|
||||
|
||||
bool ConnectToProfile(absl::string_view service_uuid);
|
||||
void MarkLost() { lost_ = true; }
|
||||
void UnmarkLost() { lost_ = false; }
|
||||
bool Lost() const { return lost_; }
|
||||
|
||||
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 std::string last_known_address_ ABSL_GUARDED_BY(properties_mutex_);
|
||||
mutable std::weak_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
|
||||
@@ -0,0 +1,165 @@
|
||||
// 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 "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),
|
||||
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(), 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 {
|
||||
NEARBY_LOGS(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();
|
||||
NEARBY_LOGS(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)) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Device " << address
|
||||
<< " is no longer known";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!device->ConnectToProfile(service_uuid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto fd = profile_manager_->GetServiceRecordFD(remote_device, service_uuid,
|
||||
cancellation_flag);
|
||||
if (!fd.has_value()) {
|
||||
NEARBY_LOGS(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) {
|
||||
if (!profile_manager_->ProfileRegistered(service_uuid)) {
|
||||
if (!profile_manager_->Register(service_name, service_uuid)) {
|
||||
NEARBY_LOGS(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(
|
||||
const std::string &mac_address) {
|
||||
auto device = devices_->get_device_by_address(mac_address);
|
||||
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
|
||||
@@ -0,0 +1,116 @@
|
||||
// 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 "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(
|
||||
const std::string &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<ProfileManager> profile_manager_;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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()) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": server socket has been stopped";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(VERBOSE) << __func__
|
||||
<< ": accepting new connections for service uuid "
|
||||
<< service_uuid_;
|
||||
|
||||
auto pair = profile_manager_.GetServiceRecordFD(service_uuid_, &stopped_);
|
||||
if (!pair.has_value()) {
|
||||
if (!stopped_.Cancelled())
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": Failed to get a new connection for profile "
|
||||
<< service_uuid_;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto [device, fd] = *pair;
|
||||
return std::make_unique<BluetoothSocket>(device, std::move(fd));
|
||||
}
|
||||
|
||||
Exception BluetoothServerSocket::Close() {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": closing bluetooth server socket";
|
||||
stopped_.Cancel();
|
||||
profile_manager_.Unregister(service_uuid_);
|
||||
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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
|
||||
@@ -0,0 +1,123 @@
|
||||
// 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"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
Exception Poller::Ready() {
|
||||
while (true) {
|
||||
auto ret = poll(fds_, 1, -1);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN) continue;
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": socket disconnected";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
if ((fds_[0].revents & (POLLERR | POLLNVAL)) != 0) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": an error occured on the socket";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOr<ByteArray> BluetoothInputStream::Read(std::int64_t size) {
|
||||
if (!fd_.isValid()) return Exception{Exception::kIo};
|
||||
|
||||
auto poller = Poller::CreateInputPoller(fd_);
|
||||
|
||||
std::string buffer;
|
||||
buffer.resize(size);
|
||||
char *data = buffer.data();
|
||||
|
||||
size_t total_read = 0;
|
||||
|
||||
while (total_read < size) {
|
||||
auto result = poller.Ready();
|
||||
if (result.Raised()) return result;
|
||||
|
||||
auto bytes_read = read(fd_.get(), &data[total_read], (size - total_read));
|
||||
if (bytes_read < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": error reading data on bluetooth socket: "
|
||||
<< std::strerror(errno);
|
||||
return {Exception::kIo};
|
||||
}
|
||||
total_read += bytes_read;
|
||||
}
|
||||
|
||||
return ExceptionOr{ByteArray(std::move(buffer))};
|
||||
}
|
||||
|
||||
Exception BluetoothInputStream::Close() {
|
||||
if (!fd_.isValid()) return {Exception::kIo};
|
||||
fd_.reset();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
Exception BluetoothOutputStream::Write(const ByteArray &data) {
|
||||
if (!fd_.isValid()) return Exception{Exception::kIo};
|
||||
|
||||
auto poller = Poller::CreateOutputPoller(fd_);
|
||||
|
||||
size_t total_wrote = 0;
|
||||
|
||||
while (total_wrote < data.size()) {
|
||||
auto result = poller.Ready();
|
||||
if (result.Raised()) return result;
|
||||
|
||||
const char *buf = data.data();
|
||||
auto wrote =
|
||||
write(fd_.get(), &buf[total_wrote], (data.size() - total_wrote));
|
||||
if (wrote < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) continue;
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": error writing data on bluetooth socket: "
|
||||
<< std::strerror(errno);
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
total_wrote += wrote;
|
||||
}
|
||||
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
Exception BluetoothOutputStream::Close() {
|
||||
if (!fd_.isValid()) return {Exception::kIo};
|
||||
fd_.reset();
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,103 @@
|
||||
// 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 <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <sys/poll.h>
|
||||
#include <systemd/sd-bus.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);
|
||||
}
|
||||
|
||||
Exception Ready();
|
||||
|
||||
private:
|
||||
Poller(const sdbus::UnixFd &fd, short event) : poll_event_(event) {
|
||||
fds_[0].fd = fd.get();
|
||||
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)){};
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override;
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
sdbus::UnixFd fd_;
|
||||
};
|
||||
|
||||
class BluetoothOutputStream : public nearby::OutputStream {
|
||||
public:
|
||||
explicit BluetoothOutputStream(sdbus::UnixFd fd) : fd_(std::move(fd)){};
|
||||
|
||||
Exception Write(const ByteArray &data) override;
|
||||
Exception Flush() override { return {Exception::kSuccess}; }
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
sdbus::UnixFd fd_;
|
||||
};
|
||||
|
||||
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
|
||||
@@ -0,0 +1,192 @@
|
||||
// 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 <absl/time/clock.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#include "absl/strings/substitute.h"
|
||||
#include "absl/synchronization/mutex.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_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) {
|
||||
NEARBY_LOGS(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) {
|
||||
NEARBY_LOGS(WARNING) << __func__
|
||||
<< ": received InterfacesRemoved for a device "
|
||||
"we don't know about: "
|
||||
<< object;
|
||||
return;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(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;
|
||||
}
|
||||
auto device_it =
|
||||
std::find_if(objects.begin(), objects.end(), [&](auto entry) {
|
||||
auto &[device_path, interfaces] = entry;
|
||||
|
||||
return device_path.find(
|
||||
absl::Substitute("$0/dev_", adapter_object_path_)) == 0 &&
|
||||
interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1;
|
||||
});
|
||||
|
||||
for (; device_it != objects.end(); device_it++) {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": Adding existing device "
|
||||
<< device_it->first;
|
||||
auto device = devices_->add_new_device(device_it->first);
|
||||
if (discovery_cb_ != nullptr) {
|
||||
device->SetDiscoveryCallback(discovery_cb_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,127 @@
|
||||
// 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 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) {
|
||||
auto addr = BluetoothUtils::FromNumber(id);
|
||||
return get_device_by_address(addr);
|
||||
}
|
||||
|
||||
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_);
|
||||
|
||||
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,
|
||||
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),
|
||||
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,
|
||||
std::shared_ptr<BluetoothDevices> devices)
|
||||
: DeviceWatcher(system_bus, adapter_object_path, 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_;
|
||||
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
|
||||
@@ -0,0 +1,105 @@
|
||||
// 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;
|
||||
|
||||
NEARBY_LOGS(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())),
|
||||
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
|
||||
@@ -0,0 +1,57 @@
|
||||
// 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
|
||||
@@ -0,0 +1,79 @@
|
||||
// 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 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 3;
|
||||
case api::ble_v2::TxPowerLevel::kHigh:
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace bluez
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 { \
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (err).getName() \
|
||||
<< "' with message '" << (err).getMessage() \
|
||||
<< "' while calling " << method << " on object " \
|
||||
<< (proxy)->getObjectPath(); \
|
||||
} while (false)
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
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";
|
||||
|
||||
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_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
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "internal/platform/implementation/linux/bluez_advertisement_monitor.h"
|
||||
#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()) {
|
||||
NEARBY_LOGS(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()));
|
||||
}
|
||||
scan_callback_.advertisement_found_cb(*peripheral, adv_data);
|
||||
}
|
||||
|
||||
void AdvertisementMonitor::DeviceLost(const sdbus::ObjectPath &device) {
|
||||
devices_->mark_peripheral_lost(device);
|
||||
}
|
||||
} // namespace bluez
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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 {
|
||||
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 0; };
|
||||
int16_t RSSIHighThreshold() override {
|
||||
return bluez::TxPowerLevelDbm(tx_power_level_);
|
||||
}
|
||||
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
|
||||
@@ -0,0 +1,87 @@
|
||||
// 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 BluetoothAdapter &);
|
||||
AdvertisementMonitorManager(sdbus::IConnection &system_bus,
|
||||
const 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 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) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Adapter object no longer exists "
|
||||
<< adapter.GetObjectPath();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (objects[adapter.GetObjectPath()].count(
|
||||
org::bluez::AdvertisementMonitorManager1_proxy::INTERFACE_NAME) ==
|
||||
0) {
|
||||
NEARBY_LOGS(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
|
||||
@@ -0,0 +1,65 @@
|
||||
// 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
|
||||
@@ -0,0 +1,41 @@
|
||||
// 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
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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
|
||||
@@ -0,0 +1,238 @@
|
||||
// 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) {
|
||||
NEARBY_LOGS(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_;
|
||||
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: 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
|
||||
@@ -0,0 +1,129 @@
|
||||
// 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();
|
||||
NEARBY_LOGS(VERBOSE)
|
||||
<< __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
|
||||
@@ -0,0 +1,44 @@
|
||||
// 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
|
||||
@@ -0,0 +1,40 @@
|
||||
// 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
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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) {
|
||||
NEARBY_LOGS(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
|
||||
@@ -0,0 +1,110 @@
|
||||
// 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();
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": Created a "
|
||||
<< org::bluez::GattService1_adaptor::INTERFACE_NAME
|
||||
<< " object at " << getObjectPath();
|
||||
}
|
||||
|
||||
~GattServiceServer() {
|
||||
absl::MutexLock lock(&characterstics_mutex_);
|
||||
for (auto &[_uuid, characteristic] : characteristics_) {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << ": Removing characteristic "
|
||||
<< characteristic->getObjectPath();
|
||||
try {
|
||||
characteristic->emitInterfacesRemovedSignal(
|
||||
{org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME});
|
||||
} catch (const sdbus::Error &e) {
|
||||
NEARBY_LOGS(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
|
||||
@@ -0,0 +1,54 @@
|
||||
// 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 {
|
||||
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);
|
||||
for (size_t i = 0; i < data.size(); i++) {
|
||||
data_bytes[i] = bytes[i];
|
||||
}
|
||||
|
||||
service_data_.insert({uuid_string, std::move(data_bytes)});
|
||||
}
|
||||
|
||||
registerAdaptor();
|
||||
|
||||
NEARBY_LOGS(VERBOSE) << __func__
|
||||
<< ": Created a org.bluez.LEAdvertisement1 instance at "
|
||||
<< getObjectPath();
|
||||
}
|
||||
} // namespace bluez
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,112 @@
|
||||
// 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 {
|
||||
NEARBY_LOGS(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::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
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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_CONDITION_VARIABLE_H_
|
||||
#define PLATFORM_IMPL_LINUX_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/condition_variable.h"
|
||||
#include "internal/platform/implementation/linux/mutex.h"
|
||||
#include "internal/platform/implementation/mutex.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
class ConditionVariable : public api::ConditionVariable {
|
||||
public:
|
||||
explicit ConditionVariable(api::Mutex *mutex)
|
||||
: mutex_(&(static_cast<linux::Mutex*>(mutex)->GetMutex())) {}
|
||||
~ConditionVariable() = default;
|
||||
|
||||
Exception Wait() override {
|
||||
cond_var_.Wait(mutex_);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
Exception Wait(absl::Duration timeout) override {
|
||||
cond_var_.WaitWithTimeout(mutex_, timeout);
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
void Notify() override { cond_var_.SignalAll(); }
|
||||
|
||||
private:
|
||||
absl::Mutex *mutex_;
|
||||
absl::CondVar cond_var_;
|
||||
};
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPL_LINUX_CONDITION_VARIABLE_H_
|
||||
@@ -0,0 +1,100 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
// 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);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// 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_CREDENTIAL_STORAGE_H_
|
||||
#define PLATFORM_IMPL_LINUX_CREDENTIAL_STORAGE_H_
|
||||
#include <memory>
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/implementation/credential_storage.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
class CredentialStorage : public api::CredentialStorage {
|
||||
using LocalCredential = ::nearby::internal::LocalCredential;
|
||||
using SharedCredential = ::nearby::internal::SharedCredential;
|
||||
using PublicCredentialType = ::nearby::presence::PublicCredentialType;
|
||||
using SaveCredentialsResultCallback =
|
||||
::nearby::presence::SaveCredentialsResultCallback;
|
||||
using CredentialSelector = ::nearby::presence::CredentialSelector;
|
||||
using GetLocalCredentialsResultCallback =
|
||||
::nearby::presence::GetLocalCredentialsResultCallback;
|
||||
using GetPublicCredentialsResultCallback =
|
||||
::nearby::presence::GetPublicCredentialsResultCallback;
|
||||
|
||||
CredentialStorage(sdbus::IConnection &connection);
|
||||
~CredentialStorage() override = default;
|
||||
|
||||
void SaveCredentials(absl::string_view manager_app_id,
|
||||
absl::string_view account_name,
|
||||
const std::vector<LocalCredential> &Local_credentials,
|
||||
const std::vector<SharedCredential> &Shared_credentials,
|
||||
PublicCredentialType public_credential_type,
|
||||
SaveCredentialsResultCallback callback) override;
|
||||
void UpdateLocalCredential(absl::string_view manager_app_id,
|
||||
absl::string_view account_name,
|
||||
nearby::internal::LocalCredential credential,
|
||||
SaveCredentialsResultCallback callback) override;
|
||||
void GetPublicCredentials(
|
||||
const CredentialSelector &credential_selector,
|
||||
PublicCredentialType public_credential_type,
|
||||
GetPublicCredentialsResultCallback callback) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<sdbus::IProxy> proxy;
|
||||
};
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
// 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 <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/byte_array.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
// Function implementations for platform/implementation/crypto.h.
|
||||
|
||||
namespace nearby {
|
||||
|
||||
// Initialize global crypto state.
|
||||
void Crypto::Init() {}
|
||||
|
||||
static ByteArray Hash(absl::string_view input, const EVP_MD* algo) {
|
||||
unsigned int md_out_size = EVP_MAX_MD_SIZE;
|
||||
uint8_t digest_buffer[EVP_MAX_MD_SIZE];
|
||||
if (input.empty()) return {};
|
||||
|
||||
if (!EVP_Digest(input.data(), input.size(), digest_buffer, &md_out_size, algo,
|
||||
nullptr))
|
||||
return {};
|
||||
|
||||
return ByteArray{reinterpret_cast<char*>(digest_buffer), md_out_size};
|
||||
}
|
||||
|
||||
// Return MD5 hash of input.
|
||||
ByteArray Crypto::Md5(absl::string_view input) {
|
||||
return Hash(input, EVP_md5());
|
||||
}
|
||||
|
||||
// Return SHA256 hash of input.
|
||||
ByteArray Crypto::Sha256(absl::string_view input) {
|
||||
return Hash(input, EVP_sha256());
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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 <cassert>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
|
||||
#include "absl/base/call_once.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/linux/dbus.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
namespace {
|
||||
static absl::Mutex global_system_bus_mutex;
|
||||
static std::weak_ptr<sdbus::IConnection> global_system_bus_connection
|
||||
ABSL_GUARDED_BY(global_system_bus_mutex);
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<sdbus::IConnection> getSystemBusConnection() {
|
||||
absl::MutexLock lock(&global_system_bus_mutex);
|
||||
auto bus = global_system_bus_connection.lock();
|
||||
if (bus == nullptr) {
|
||||
bus =
|
||||
std::shared_ptr<sdbus::IConnection>(sdbus::createSystemBusConnection());
|
||||
bus->enterEventLoopAsync();
|
||||
global_system_bus_connection = bus;
|
||||
}
|
||||
|
||||
return bus;
|
||||
}
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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_DBUS_H_
|
||||
#define PLATFORM_IMPL_LINUX_DBUS_H_
|
||||
|
||||
#include <sdbus-c++/AdaptorInterfaces.h>
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/StandardInterfaces.h>
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
#define DBUS_LOG_METHOD_CALL_ERROR(p, m, e) \
|
||||
do { \
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (e).getName() \
|
||||
<< "' with message '" << (e).getMessage() \
|
||||
<< "' while calling " << (m) << " on object " \
|
||||
<< (p)->getObjectPath(); \
|
||||
} while (false)
|
||||
|
||||
#define DBUS_LOG_PROPERTY_GET_ERROR(p, prop, e) \
|
||||
do { \
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (e).getName() \
|
||||
<< "' with message '" << (e).getMessage() \
|
||||
<< "' while getting property " << (prop) \
|
||||
<< " on object " << (p)->getObjectPath(); \
|
||||
} while (false)
|
||||
|
||||
#define DBUS_LOG_PROPERTY_SET_ERROR(p, prop, e) \
|
||||
do { \
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (e).getName() \
|
||||
<< "' with message '" << (e).getMessage() \
|
||||
<< "' while setting property " << (prop) \
|
||||
<< " on object " << (p)->getObjectPath(); \
|
||||
} while (false)
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
extern std::shared_ptr<sdbus::IConnection> getSystemBusConnection();
|
||||
class RootObjectManager final
|
||||
: public sdbus::AdaptorInterfaces<sdbus::ObjectManager_adaptor,
|
||||
sdbus::Properties_adaptor> {
|
||||
public:
|
||||
explicit RootObjectManager(sdbus::IConnection &system_bus)
|
||||
: AdaptorInterfaces(system_bus, "/") {
|
||||
registerAdaptor();
|
||||
}
|
||||
~RootObjectManager() { unregisterAdaptor(); }
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
#endif
|
||||
@@ -0,0 +1,183 @@
|
||||
// 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 <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
|
||||
#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"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
void CurrentUserSession::RegisterScreenLockedListener(
|
||||
absl::string_view listener_name,
|
||||
std::function<void(api::DeviceInfo::ScreenStatus)> callback) {
|
||||
absl::MutexLock l(&screen_lock_listeners_mutex_);
|
||||
screen_lock_listeners_[listener_name] = std::move(callback);
|
||||
}
|
||||
|
||||
void CurrentUserSession::UnregisterScreenLockedListener(
|
||||
absl::string_view listener_name) {
|
||||
absl::MutexLock l(&screen_lock_listeners_mutex_);
|
||||
screen_lock_listeners_.erase(listener_name);
|
||||
}
|
||||
|
||||
void CurrentUserSession::onLock() {
|
||||
absl::ReaderMutexLock l(&screen_lock_listeners_mutex_);
|
||||
for (auto &[_, callback] : screen_lock_listeners_) {
|
||||
callback(api::DeviceInfo::ScreenStatus::kLocked);
|
||||
}
|
||||
}
|
||||
|
||||
void CurrentUserSession::onUnlock() {
|
||||
absl::ReaderMutexLock l(&screen_lock_listeners_mutex_);
|
||||
for (auto &[_, callback] : screen_lock_listeners_) {
|
||||
callback(api::DeviceInfo::ScreenStatus::kUnlocked);
|
||||
}
|
||||
}
|
||||
|
||||
DeviceInfo::DeviceInfo(std::shared_ptr<sdbus::IConnection> system_bus)
|
||||
: system_bus_(std::move(system_bus)),
|
||||
current_user_session_(std::make_unique<CurrentUserSession>(*system_bus_)),
|
||||
login_manager_(std::make_unique<LoginManager>(*system_bus_)) {}
|
||||
|
||||
std::optional<std::u16string> DeviceInfo::GetOsDeviceName() const {
|
||||
avahi::Server avahi(*system_bus_);
|
||||
try {
|
||||
std::string hostname = avahi.GetHostNameFqdn();
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
return convert.from_bytes(hostname);
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(&avahi, "GetHostNameFqdn", e);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const {
|
||||
Hostnamed hostnamed(*system_bus_);
|
||||
try {
|
||||
std::string chasis = hostnamed.Chassis();
|
||||
api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown;
|
||||
if (chasis == "phone" || chasis == "handset") {
|
||||
device = api::DeviceInfo::DeviceType::kPhone;
|
||||
} else if (chasis == "laptop" || chasis == "desktop") {
|
||||
device = api::DeviceInfo::DeviceType::kLaptop;
|
||||
} else if (chasis == "tablet") {
|
||||
device = api::DeviceInfo::DeviceType::kTablet;
|
||||
}
|
||||
return device;
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(&hostnamed, "Chasis", e);
|
||||
return api::DeviceInfo::DeviceType::kUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::u16string> DeviceInfo::GetFullName() const {
|
||||
struct passwd *pwd = getpwuid(getuid());
|
||||
if (pwd == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
char *name = strtok(pwd->pw_gecos, ",");
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
|
||||
return convert.from_bytes(name != nullptr ? name : pwd->pw_gecos);
|
||||
}
|
||||
|
||||
std::optional<std::string> DeviceInfo::GetProfileUserName() const {
|
||||
char *logname = secure_getenv("LOGNAME");
|
||||
return logname == nullptr ? std::nullopt
|
||||
: std::optional(std::string(logname));
|
||||
}
|
||||
|
||||
std::optional<std::filesystem::path> DeviceInfo::GetDownloadPath() const {
|
||||
char *dir = getenv("XDG_DOWNLOAD_DIR");
|
||||
return std::filesystem::path(std::string(dir));
|
||||
}
|
||||
|
||||
std::optional<std::filesystem::path> DeviceInfo::GetLocalAppDataPath() const {
|
||||
char *dir = getenv("XDG_CONFIG_HOME");
|
||||
if (dir == nullptr) {
|
||||
return std::filesystem::path("/tmp");
|
||||
}
|
||||
return std::filesystem::path(std::string(dir)) / "Google Nearby";
|
||||
}
|
||||
|
||||
std::optional<std::filesystem::path> DeviceInfo::GetTemporaryPath() const {
|
||||
char *dir = getenv("XDG_RUNTIME_PATH");
|
||||
if (dir == nullptr) {
|
||||
return std::filesystem::path("/tmp");
|
||||
}
|
||||
return std::filesystem::path(std::string(dir)) / "Google Nearby";
|
||||
}
|
||||
|
||||
std::optional<std::filesystem::path> DeviceInfo::GetLogPath() const {
|
||||
char *dir = getenv("XDG_STATE_HOME");
|
||||
if (dir == nullptr) {
|
||||
return std::filesystem::path("/tmp");
|
||||
}
|
||||
return std::filesystem::path(std::string(dir)) / "Google Nearby" / "logs";
|
||||
}
|
||||
|
||||
std::optional<std::filesystem::path> DeviceInfo::GetCrashDumpPath() const {
|
||||
char *dir = getenv("XDG_STATE_HOME");
|
||||
if (dir == nullptr) {
|
||||
return std::filesystem::path("/tmp");
|
||||
}
|
||||
return std::filesystem::path(std::string(dir)) / "Google Nearby" / "crashes";
|
||||
}
|
||||
|
||||
bool DeviceInfo::IsScreenLocked() const {
|
||||
try {
|
||||
return current_user_session_->LockedHint();
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(current_user_session_, "LockedHint", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceInfo::PreventSleep() {
|
||||
try {
|
||||
inhibit_fd_ = login_manager_->Inhibit("sleep", "Google Nearby",
|
||||
"Google Nearby", "block");
|
||||
return true;
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(login_manager_, "Inhibit", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceInfo::AllowSleep() {
|
||||
if (!inhibit_fd_.has_value()) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< "No inhibit lock is acquired at the moment";
|
||||
return false;
|
||||
}
|
||||
|
||||
inhibit_fd_.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,171 @@
|
||||
// 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_DEVICE_INFO_H_
|
||||
#define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <sdbus-c++/IConnection.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/ProxyInterfaces.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/device_info.h"
|
||||
#include "internal/platform/implementation/linux/generated/dbus/hostname/hostname_client.h"
|
||||
#include "internal/platform/implementation/linux/generated/dbus/login/login_manager_client.h"
|
||||
#include "internal/platform/implementation/linux/generated/dbus/login/login_session_client.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
class CurrentUserSession final
|
||||
: public sdbus::ProxyInterfaces<org::freedesktop::login1::Session_proxy> {
|
||||
public:
|
||||
CurrentUserSession(const CurrentUserSession &) = delete;
|
||||
CurrentUserSession(CurrentUserSession &&) = delete;
|
||||
CurrentUserSession &operator=(const CurrentUserSession &) = delete;
|
||||
CurrentUserSession &operator=(CurrentUserSession &&) = delete;
|
||||
~CurrentUserSession() { unregisterProxy(); }
|
||||
explicit CurrentUserSession(sdbus::IConnection &system_bus)
|
||||
: ProxyInterfaces(system_bus, "org.freedesktop.login1",
|
||||
"/org/freedesktop/login1/session/auto") {
|
||||
registerProxy();
|
||||
}
|
||||
|
||||
void RegisterScreenLockedListener(
|
||||
absl::string_view listener_name,
|
||||
std::function<void(api::DeviceInfo::ScreenStatus)> callback)
|
||||
ABSL_LOCKS_EXCLUDED(screen_lock_listeners_mutex_);
|
||||
void UnregisterScreenLockedListener(absl::string_view listener_name)
|
||||
ABSL_LOCKS_EXCLUDED(screen_lock_listeners_mutex_);
|
||||
|
||||
protected:
|
||||
void onPauseDevice(const uint32_t &major, const uint32_t &minor,
|
||||
const std::string &type) override {}
|
||||
void onResumeDevice(const uint32_t &major, const uint32_t &minor,
|
||||
const sdbus::UnixFd &fd) override {}
|
||||
|
||||
void onLock() override ABSL_LOCKS_EXCLUDED(screen_lock_listeners_mutex_);
|
||||
void onUnlock() override ABSL_LOCKS_EXCLUDED(screen_lock_listeners_mutex_);
|
||||
|
||||
private:
|
||||
absl::Mutex screen_lock_listeners_mutex_;
|
||||
absl::flat_hash_map<std::string,
|
||||
std::function<void(api::DeviceInfo::ScreenStatus)>>
|
||||
screen_lock_listeners_ ABSL_GUARDED_BY(screen_lock_listeners_mutex_);
|
||||
};
|
||||
|
||||
class Hostnamed
|
||||
: public sdbus::ProxyInterfaces<org::freedesktop::hostname1_proxy> {
|
||||
public:
|
||||
Hostnamed(const Hostnamed &) = delete;
|
||||
Hostnamed(Hostnamed &&) = delete;
|
||||
Hostnamed &operator=(const Hostnamed &) = delete;
|
||||
Hostnamed &operator=(Hostnamed &&) = delete;
|
||||
explicit Hostnamed(sdbus::IConnection &system_bus)
|
||||
: ProxyInterfaces(system_bus, "org.freedesktop.hostname1",
|
||||
"/org/freedesktop/hostname1") {
|
||||
registerProxy();
|
||||
}
|
||||
~Hostnamed() { unregisterProxy(); }
|
||||
};
|
||||
|
||||
class LoginManager final
|
||||
: public sdbus::ProxyInterfaces<org::freedesktop::login1::Manager_proxy> {
|
||||
public:
|
||||
LoginManager(const LoginManager &) = delete;
|
||||
LoginManager(LoginManager &&) = delete;
|
||||
LoginManager &operator=(const LoginManager &) = delete;
|
||||
LoginManager &operator=(LoginManager &&) = delete;
|
||||
explicit LoginManager(sdbus::IConnection &system_bus)
|
||||
: ProxyInterfaces(system_bus, "org.freedesktop.login1",
|
||||
"/org/freedesktop/login1") {
|
||||
registerProxy();
|
||||
}
|
||||
~LoginManager() { unregisterProxy(); }
|
||||
|
||||
protected:
|
||||
void onSessionNew(const std::string &session_id,
|
||||
const sdbus::ObjectPath &object_path) override {}
|
||||
void onSessionRemoved(const std::string &session_id,
|
||||
const sdbus::ObjectPath &object_path) override {}
|
||||
void onUserNew(const uint32_t &uid,
|
||||
const sdbus::ObjectPath &object_path) override {}
|
||||
void onUserRemoved(const uint32_t &uid,
|
||||
const sdbus::ObjectPath &object_path) override {}
|
||||
void onSeatNew(const std::string &seat_id,
|
||||
const sdbus::ObjectPath &object_path) override {}
|
||||
void onSeatRemoved(const std::string &seat_id,
|
||||
const sdbus::ObjectPath &object_path) override {}
|
||||
void onPrepareForShutdown(const bool &start) override {}
|
||||
void onPrepareForSleep(const bool &start) override {}
|
||||
};
|
||||
|
||||
class DeviceInfo final : public api::DeviceInfo {
|
||||
public:
|
||||
explicit DeviceInfo(std::shared_ptr<sdbus::IConnection> system_bus);
|
||||
|
||||
std::optional<std::u16string> GetOsDeviceName() const override;
|
||||
api::DeviceInfo::DeviceType GetDeviceType() const override;
|
||||
api::DeviceInfo::OsType GetOsType() const override {
|
||||
return api::DeviceInfo::OsType::kWindows; // Or ChromeOS?
|
||||
}
|
||||
std::optional<std::u16string> GetFullName() const override;
|
||||
std::optional<std::u16string> GetGivenName() const override {
|
||||
return GetFullName();
|
||||
}
|
||||
std::optional<std::u16string> GetLastName() const override {
|
||||
return GetFullName();
|
||||
}
|
||||
std::optional<std::string> GetProfileUserName() const override;
|
||||
|
||||
std::optional<std::filesystem::path> GetDownloadPath() const override;
|
||||
std::optional<std::filesystem::path> GetLocalAppDataPath() const override;
|
||||
std::optional<std::filesystem::path> GetCommonAppDataPath() const override {
|
||||
return std::nullopt;
|
||||
};
|
||||
std::optional<std::filesystem::path> GetTemporaryPath() const override;
|
||||
std::optional<std::filesystem::path> GetLogPath() const override;
|
||||
std::optional<std::filesystem::path> GetCrashDumpPath() const override;
|
||||
|
||||
bool IsScreenLocked() const override;
|
||||
void RegisterScreenLockedListener(
|
||||
absl::string_view listener_name,
|
||||
std::function<void(api::DeviceInfo::ScreenStatus)> callback) override {
|
||||
current_user_session_->RegisterScreenLockedListener(listener_name,
|
||||
std::move(callback));
|
||||
}
|
||||
void UnregisterScreenLockedListener(
|
||||
absl::string_view listener_name) override {
|
||||
current_user_session_->UnregisterScreenLockedListener(listener_name);
|
||||
}
|
||||
|
||||
bool PreventSleep() override;
|
||||
bool AllowSleep() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<sdbus::IConnection> system_bus_;
|
||||
std::unique_ptr<CurrentUserSession> current_user_session_;
|
||||
std::unique_ptr<LoginManager> login_manager_;
|
||||
std::optional<sdbus::UnixFd> inhibit_fd_;
|
||||
};
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPL_LINUX_DEVICE_INFO_H_
|
||||
@@ -0,0 +1,129 @@
|
||||
// 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
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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/executor.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "internal/platform/implementation/linux/thread_pool.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
Executor::Executor(size_t max_concurrency)
|
||||
: thread_pool_(std::make_unique<ThreadPool>(max_concurrency)) {
|
||||
assert(max_concurrency >= 1);
|
||||
assert(thread_pool_ != nullptr);
|
||||
}
|
||||
|
||||
void Executor::Execute(Runnable &&runnable) {
|
||||
if (shut_down_) {
|
||||
NEARBY_LOGS(VERBOSE) << "Warning: " << __func__
|
||||
<< ": Attempt to execute on a shut down pool.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (runnable == nullptr) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Runnable was null.";
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_->Run(std::move(runnable));
|
||||
}
|
||||
|
||||
void Executor::Shutdown() {
|
||||
shut_down_ = true;
|
||||
thread_pool_->ShutDown();
|
||||
thread_pool_ = nullptr;
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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.
|
||||
|
||||
#ifndef PLATFORM_IMPL_LINUX_EXECUTOR_H_
|
||||
#define PLATFORM_IMPL_LINUX_EXECUTOR_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "internal/platform/implementation/executor.h"
|
||||
#include "internal/platform/implementation/linux/thread_pool.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
// This abstract class is the superclass of all classes representing an
|
||||
// Executor.
|
||||
class Executor : public api::Executor {
|
||||
public:
|
||||
Executor(size_t max_concurrency = 1);
|
||||
|
||||
// Before returning from destructor, executor must wait for all pending
|
||||
// jobs to finish.
|
||||
~Executor() override = default;
|
||||
|
||||
void Execute(Runnable&& runnable) override;
|
||||
void Shutdown() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<linux::ThreadPool> thread_pool_ = nullptr;
|
||||
std::atomic<bool> shut_down_ = false;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPL_LINUX_EXECUTOR_H_
|
||||
@@ -0,0 +1,323 @@
|
||||
// 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
|
||||
@@ -0,0 +1,113 @@
|
||||
// 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/file.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <codecvt>
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <ios>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/linux/utils.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
// InputFile
|
||||
std::unique_ptr<IOFile> IOFile::CreateInputFile(
|
||||
const absl::string_view file_path, size_t size) {
|
||||
return absl::WrapUnique(new IOFile(file_path, size));
|
||||
}
|
||||
|
||||
IOFile::IOFile(const absl::string_view file_path, size_t size)
|
||||
: path_(file_path) {
|
||||
// Always open input file path as wide string on Linux platform.
|
||||
file_.open(std::filesystem::path(linux::string_to_wstring(path_)),
|
||||
std::ios::binary | std::ios::in | std::ios::ate);
|
||||
|
||||
total_size_ = file_.tellg();
|
||||
file_.seekg(0);
|
||||
}
|
||||
|
||||
std::unique_ptr<IOFile> IOFile::CreateOutputFile(const absl::string_view path) {
|
||||
return std::unique_ptr<IOFile>(new IOFile(path));
|
||||
}
|
||||
|
||||
IOFile::IOFile(const absl::string_view file_path)
|
||||
: file_(), path_(file_path), total_size_(0) {
|
||||
// Always open input file path as wide string on Windows platform.
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
file_.open(std::filesystem::path(converter.from_bytes(path_)),
|
||||
std::ios::binary | std::ios::out);
|
||||
}
|
||||
|
||||
ExceptionOr<ByteArray> IOFile::Read(std::int64_t size) {
|
||||
if (!file_.is_open()) {
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
|
||||
if (file_.peek() == EOF) {
|
||||
return ExceptionOr<ByteArray>{ByteArray{}};
|
||||
}
|
||||
|
||||
if (!file_.good()) {
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
|
||||
ByteArray bytes(size);
|
||||
std::unique_ptr<char[]> read_bytes{new char[size]};
|
||||
file_.read(read_bytes.get(), static_cast<ptrdiff_t>(size));
|
||||
auto num_bytes_read = file_.gcount();
|
||||
if (num_bytes_read == 0) {
|
||||
return ExceptionOr<ByteArray>{Exception::kIo};
|
||||
}
|
||||
|
||||
return ExceptionOr<ByteArray>(ByteArray(read_bytes.get(), num_bytes_read));
|
||||
}
|
||||
|
||||
Exception IOFile::Close() {
|
||||
if (file_.is_open()) {
|
||||
file_.close();
|
||||
}
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
Exception IOFile::Write(const ByteArray& data) {
|
||||
if (!file_.is_open()) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
if (!file_.good()) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
file_.write(data.data(), data.size());
|
||||
file_.flush();
|
||||
return {file_.good() ? Exception::kSuccess : Exception::kIo};
|
||||
}
|
||||
|
||||
Exception IOFile::Flush() {
|
||||
file_.flush();
|
||||
return {file_.good() ? Exception::kSuccess : Exception::kIo};
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,60 @@
|
||||
// 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.
|
||||
|
||||
#ifndef PLATFORM_IMPL_LINUX_FILE_H_
|
||||
#define PLATFORM_IMPL_LINUX_FILE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/input_file.h"
|
||||
#include "internal/platform/implementation/output_file.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
class IOFile final : public api::InputFile, public api::OutputFile {
|
||||
public:
|
||||
static std::unique_ptr<IOFile> CreateInputFile(
|
||||
const absl::string_view file_path, size_t size);
|
||||
|
||||
static std::unique_ptr<IOFile> CreateOutputFile(const absl::string_view path);
|
||||
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override;
|
||||
|
||||
std::string GetFilePath() const override { return path_; }
|
||||
|
||||
std::int64_t GetTotalSize() const override { return total_size_; }
|
||||
Exception Close() override;
|
||||
|
||||
Exception Write(const ByteArray& data) override;
|
||||
Exception Flush() override;
|
||||
|
||||
private:
|
||||
explicit IOFile(const absl::string_view file_path, size_t size);
|
||||
explicit IOFile(const absl::string_view file_path);
|
||||
|
||||
std::fstream file_;
|
||||
std::string path_;
|
||||
std::int64_t total_size_;
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPL_LINUX_FILE_H_
|
||||
@@ -0,0 +1,209 @@
|
||||
// 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 <cctype>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "internal/platform/implementation/linux/dbus.h"
|
||||
#include "internal/platform/implementation/linux/device_info.h"
|
||||
#include "internal/platform/implementation/linux/utils.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
const wchar_t* kUpOneLevel = L"/..";
|
||||
constexpr wchar_t kPathDelimiter = L'/';
|
||||
constexpr wchar_t kReplacementChar = L'_';
|
||||
constexpr wchar_t kForwardSlash = L'/';
|
||||
constexpr wchar_t kBackSlash = L'\\';
|
||||
|
||||
std::wstring FilePath::GetCustomSavePath(std::wstring parent_folder,
|
||||
std::wstring file_name) {
|
||||
std::wstring path;
|
||||
path += parent_folder + kPathDelimiter + file_name;
|
||||
return CreateOutputFileWithRename(path);
|
||||
}
|
||||
|
||||
std::wstring FilePath::GetDownloadPath(std::wstring parent_folder,
|
||||
std::wstring file_name) {
|
||||
return CreateOutputFileWithRename(
|
||||
GetDownloadPathInternal(parent_folder, file_name));
|
||||
}
|
||||
|
||||
std::wstring FilePath::GetDownloadPathInternal(std::wstring parent_folder,
|
||||
std::wstring file_name) {
|
||||
DeviceInfo info = DeviceInfo(linux::getSystemBusConnection());
|
||||
|
||||
std::optional<std::filesystem::path> download_path = info.GetDownloadPath();
|
||||
|
||||
std::string base_path;
|
||||
|
||||
std::wstring wide_path(string_to_wstring(base_path));
|
||||
|
||||
if (!download_path) {
|
||||
// If grabbing the download path fails then we make a custom one
|
||||
base_path = getenv("HOME");
|
||||
base_path.append("/Downloads");
|
||||
} else {
|
||||
base_path = download_path.value();
|
||||
}
|
||||
|
||||
// If parent_folder starts with a \\ or /, then strip it
|
||||
while (!parent_folder.empty() && (*parent_folder.begin() == kBackSlash ||
|
||||
*parent_folder.begin() == kForwardSlash)) {
|
||||
parent_folder.erase(0, 1);
|
||||
}
|
||||
|
||||
// If parent_folder ends with a \\ or /, then strip it
|
||||
while (!parent_folder.empty() && (*parent_folder.rbegin() == kBackSlash ||
|
||||
*parent_folder.rbegin() == kForwardSlash)) {
|
||||
parent_folder.erase(parent_folder.size() - 1, 1);
|
||||
}
|
||||
|
||||
// If file_name starts with a \\, then strip it
|
||||
while (!file_name.empty() && (*file_name.begin() == kBackSlash ||
|
||||
*file_name.begin() == kForwardSlash)) {
|
||||
file_name.erase(0, 1);
|
||||
}
|
||||
|
||||
// If file_name ends with a \\, then strip it
|
||||
while (!file_name.empty() && (*file_name.rbegin() == kBackSlash ||
|
||||
*file_name.rbegin() == kForwardSlash)) {
|
||||
file_name.erase(file_name.size() - 1, 1);
|
||||
}
|
||||
|
||||
std::wstring path;
|
||||
|
||||
if (parent_folder.empty()) {
|
||||
path =
|
||||
file_name.empty() ? wide_path : wide_path + kForwardSlash + file_name;
|
||||
} else {
|
||||
path = file_name.empty() ? wide_path + kForwardSlash + parent_folder
|
||||
: wide_path + kForwardSlash + parent_folder +
|
||||
kForwardSlash + file_name;
|
||||
}
|
||||
|
||||
// Convert to UTF8 format.
|
||||
return path;
|
||||
}
|
||||
|
||||
// If the file already exists we add " (x)", where x is an incrementing number,
|
||||
// starting at 1, using the next non-existing number, to the file name, just
|
||||
// before the first dot, or at the end if no dot. The absolute path is returned.
|
||||
std::wstring FilePath::CreateOutputFileWithRename(std::wstring path) {
|
||||
std::wstring sanitized_path(path);
|
||||
|
||||
// Replace any \\ with /
|
||||
std::replace(sanitized_path.begin(), sanitized_path.end(), kBackSlash,
|
||||
kForwardSlash);
|
||||
|
||||
// Remove any /..'s
|
||||
SanitizePath(sanitized_path);
|
||||
|
||||
auto last_delimiter = sanitized_path.find_last_of(kPathDelimiter);
|
||||
std::wstring folder(sanitized_path.substr(0, last_delimiter));
|
||||
std::wstring file_name(sanitized_path.substr(last_delimiter));
|
||||
|
||||
// Locate the last dot
|
||||
auto first = file_name.find_last_of('.');
|
||||
|
||||
if (first == std::string::npos) {
|
||||
first = file_name.size();
|
||||
}
|
||||
|
||||
// Break the string at the dot.
|
||||
auto file_name1 = file_name.substr(0, first);
|
||||
auto file_name2 = file_name.substr(first);
|
||||
|
||||
// Construct the target file name
|
||||
std::wstring target(sanitized_path);
|
||||
|
||||
std::fstream file;
|
||||
|
||||
// Open file as std::wstring
|
||||
file.open(wstring_to_string(target), std::fstream::binary | std::fstream::in);
|
||||
|
||||
// While we successfully open the file, keep incrementing the count.
|
||||
int count = 0;
|
||||
while (!(file.rdstate() & std::ifstream::failbit)) {
|
||||
file.close();
|
||||
|
||||
target = (folder + file_name1 + L" (" + std::to_wstring(++count) + L")" +
|
||||
file_name2);
|
||||
|
||||
file.clear();
|
||||
file.open(wstring_to_string(target),
|
||||
std::fstream::binary | std::fstream::in);
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
NEARBY_LOGS(INFO) << "Renamed " << wstring_to_string(path) << " to "
|
||||
<< wstring_to_string(target);
|
||||
}
|
||||
|
||||
// The above leaves the file open, so close it.
|
||||
file.close();
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
std::wstring FilePath::MutateForbiddenPathElements(std::wstring& str) {
|
||||
// There are no forbidden paths in Linux
|
||||
return str;
|
||||
}
|
||||
|
||||
void FilePath::SanitizePath(std::wstring& path) {
|
||||
size_t pos = std::wstring::npos;
|
||||
// Search for the substring in string in a loop until nothing is found
|
||||
while ((pos = path.find(kUpOneLevel)) != std::string::npos) {
|
||||
// If found then erase it from string
|
||||
path.erase(pos, wcslen(kUpOneLevel));
|
||||
}
|
||||
|
||||
ReplaceInvalidCharacters(path);
|
||||
}
|
||||
|
||||
// Legit the only illegal character in Linux
|
||||
char kIllegalFileCharacters[] = {'/'};
|
||||
|
||||
void FilePath::ReplaceInvalidCharacters(std::wstring& path) {
|
||||
for (auto& character : path) {
|
||||
// If 0 < character < 32, it's illegal, replace it
|
||||
if (character > 0 && character < 32) {
|
||||
NEARBY_LOGS(INFO) << "In path " << wstring_to_string(path)
|
||||
<< " replaced \'" << std::string(1, character)
|
||||
<< "\' with \'" << std::string(1, kReplacementChar);
|
||||
character = kReplacementChar;
|
||||
}
|
||||
for (auto illegal_character : kIllegalFileCharacters) {
|
||||
if (character == illegal_character) {
|
||||
NEARBY_LOGS(INFO) << "In path " << wstring_to_string(path)
|
||||
<< " replaced \'" << std::string(1, character)
|
||||
<< "\' with \'" << std::string(1, kReplacementChar);
|
||||
character = kReplacementChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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.
|
||||
|
||||
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_LINUX_FILE_PATH_H_
|
||||
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_LINUX_FILE_PATH_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
class FilePath {
|
||||
public:
|
||||
static std::wstring GetCustomSavePath(std::wstring parent_folder,
|
||||
std::wstring file_name);
|
||||
static std::wstring GetDownloadPath(std::wstring parent_folder,
|
||||
std::wstring file_name);
|
||||
|
||||
private:
|
||||
// If the file already exists we add " (x)", where x is an incrementing
|
||||
// number, starting at 1, using the next non-existing number, to the
|
||||
// file name, just before the first dot, or at the end if no dot. The
|
||||
// absolute path is returned.
|
||||
static std::wstring CreateOutputFileWithRename(std::wstring path);
|
||||
|
||||
static void ReplaceInvalidCharacters(std::wstring& path);
|
||||
static void SanitizePath(std::wstring& path);
|
||||
static std::wstring MutateForbiddenPathElements(std::wstring& str);
|
||||
static std::wstring GetDownloadPathInternal(std::wstring parent_folder,
|
||||
std::wstring file_name);
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_LINUX_FILE_PATH_H_
|
||||
@@ -0,0 +1,779 @@
|
||||
// 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
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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.
|
||||
|
||||
#ifndef PLATFORM_IMPL_LINUX_FUTURE_H_
|
||||
#define PLATFORM_IMPL_LINUX_FUTURE_H_
|
||||
|
||||
#include "internal/platform/implementation/future.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
// A Future represents the result of an asynchronous computation.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html
|
||||
template <typename T>
|
||||
class Future : public api::Future<T> {
|
||||
public:
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
~Future() override = default;
|
||||
|
||||
// throws Exception::kInterrupted, Exception::kExecution
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
ExceptionOr<T> Get() override { return ExceptionOr<T>{Exception::kFailed}; }
|
||||
|
||||
// throws Exception::kInterrupted, Exception::kExecution
|
||||
// throws Exception::kTimeout if timeout is exceeded while waiting for
|
||||
// result.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
ExceptionOr<T> Get(absl::Duration timeout) override {
|
||||
return ExceptionOr<T>{Exception::kFailed};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace linux
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPL_LINUX_FUTURE_H_
|
||||
@@ -0,0 +1,22 @@
|
||||
# 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.
|
||||
licenses(["notice"])
|
||||
|
||||
cc_library(
|
||||
name = "types",
|
||||
textual_hdrs = glob(["**/*.h"]),
|
||||
visibility = [
|
||||
"//internal/platform/implementation/linux:__subpackages__",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,94 @@
|
||||
|
||||
/*
|
||||
* 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
@@ -0,0 +1,94 @@
|
||||
<?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
@@ -0,0 +1,398 @@
|
||||
<?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
@@ -0,0 +1,58 @@
|
||||
<?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
@@ -0,0 +1,57 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,399 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,179 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__bluez_adapter_client_glue_h__proxy__H__
|
||||
#define __sdbuscpp__bluez_adapter_client_glue_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class Adapter1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.Adapter1";
|
||||
|
||||
protected:
|
||||
Adapter1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~Adapter1_proxy() = default;
|
||||
|
||||
public:
|
||||
void StartDiscovery()
|
||||
{
|
||||
proxy_.callMethod("StartDiscovery").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void SetDiscoveryFilter(const std::map<std::string, sdbus::Variant>& properties)
|
||||
{
|
||||
proxy_.callMethod("SetDiscoveryFilter").onInterface(INTERFACE_NAME).withArguments(properties);
|
||||
}
|
||||
|
||||
void StopDiscovery()
|
||||
{
|
||||
proxy_.callMethod("StopDiscovery").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void RemoveDevice(const sdbus::ObjectPath& device)
|
||||
{
|
||||
proxy_.callMethod("RemoveDevice").onInterface(INTERFACE_NAME).withArguments(device);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetDiscoveryFilters()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
proxy_.callMethod("GetDiscoveryFilters").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ConnectDevice(const std::map<std::string, sdbus::Variant>& properties)
|
||||
{
|
||||
proxy_.callMethod("ConnectDevice").onInterface(INTERFACE_NAME).withArguments(properties);
|
||||
}
|
||||
|
||||
public:
|
||||
std::string Address()
|
||||
{
|
||||
return proxy_.getProperty("Address").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string AddressType()
|
||||
{
|
||||
return proxy_.getProperty("AddressType").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string Name()
|
||||
{
|
||||
return proxy_.getProperty("Name").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string Alias()
|
||||
{
|
||||
return proxy_.getProperty("Alias").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void Alias(const std::string& value)
|
||||
{
|
||||
proxy_.setProperty("Alias").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
uint32_t Class()
|
||||
{
|
||||
return proxy_.getProperty("Class").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
bool Powered()
|
||||
{
|
||||
return proxy_.getProperty("Powered").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void Powered(const bool& value)
|
||||
{
|
||||
proxy_.setProperty("Powered").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
std::string PowerState()
|
||||
{
|
||||
return proxy_.getProperty("PowerState").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
bool Discoverable()
|
||||
{
|
||||
return proxy_.getProperty("Discoverable").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void Discoverable(const bool& value)
|
||||
{
|
||||
proxy_.setProperty("Discoverable").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
uint32_t DiscoverableTimeout()
|
||||
{
|
||||
return proxy_.getProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void DiscoverableTimeout(const uint32_t& value)
|
||||
{
|
||||
proxy_.setProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
bool Pairable()
|
||||
{
|
||||
return proxy_.getProperty("Pairable").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void Pairable(const bool& value)
|
||||
{
|
||||
proxy_.setProperty("Pairable").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
uint32_t PairableTimeout()
|
||||
{
|
||||
return proxy_.getProperty("PairableTimeout").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void PairableTimeout(const uint32_t& value)
|
||||
{
|
||||
proxy_.setProperty("PairableTimeout").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
bool Discovering()
|
||||
{
|
||||
return proxy_.getProperty("Discovering").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> UUIDs()
|
||||
{
|
||||
return proxy_.getProperty("UUIDs").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string Modalias()
|
||||
{
|
||||
return proxy_.getProperty("Modalias").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> Roles()
|
||||
{
|
||||
return proxy_.getProperty("Roles").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> ExperimentalFeatures()
|
||||
{
|
||||
return proxy_.getProperty("ExperimentalFeatures").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
|
||||
/*
|
||||
* 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
@@ -0,0 +1,57 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,214 @@
|
||||
|
||||
/*
|
||||
* 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
@@ -0,0 +1,118 @@
|
||||
|
||||
/*
|
||||
* 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
@@ -0,0 +1,59 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
/*
|
||||
* 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
@@ -0,0 +1,77 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
/*
|
||||
* 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("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::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
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.bluez.Adapter1">
|
||||
<method name="StartDiscovery" />
|
||||
<method name="SetDiscoveryFilter">
|
||||
<arg name="properties" type="a{sv}" direction="in" />
|
||||
</method>
|
||||
<method name="StopDiscovery" />
|
||||
<method name="RemoveDevice">
|
||||
<arg name="device" type="o" direction="in" />
|
||||
</method>
|
||||
<method name="GetDiscoveryFilters">
|
||||
<arg name="filters" type="as" direction="out" />
|
||||
</method>
|
||||
<method name="ConnectDevice">
|
||||
<arg name="properties" type="a{sv}" direction="in" />
|
||||
</method>
|
||||
<property name="Address" type="s" access="read" />
|
||||
<property name="AddressType" type="s" access="read" />
|
||||
<property name="Name" type="s" access="read" />
|
||||
<property name="Alias" type="s" access="readwrite" />
|
||||
<property name="Class" type="u" access="read" />
|
||||
<property name="Powered" type="b" access="readwrite" />
|
||||
<property name="PowerState" type="s" access="read" />
|
||||
<property name="Discoverable" type="b" access="readwrite" />
|
||||
<property name="DiscoverableTimeout" type="u" access="readwrite" />
|
||||
<property name="Pairable" type="b" access="readwrite" />
|
||||
<property name="PairableTimeout" type="u" access="readwrite" />
|
||||
<property name="Discovering" type="b" access="read" />
|
||||
<property name="UUIDs" type="as" access="read" />
|
||||
<property name="Modalias" type="s" access="read" />
|
||||
<property name="Roles" type="as" access="read" />
|
||||
<property name="ExperimentalFeatures" type="as" access="read" />
|
||||
</interface>
|
||||
</node>
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?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
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.bluez.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>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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
@@ -0,0 +1,35 @@
|
||||
<?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
@@ -0,0 +1,28 @@
|
||||
<!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
@@ -0,0 +1,13 @@
|
||||
<?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>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<!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
@@ -0,0 +1,21 @@
|
||||
<?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
@@ -0,0 +1,19 @@
|
||||
<?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>
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<node>
|
||||
<interface name="org.bluez.Profile1">
|
||||
<method name='Release'>
|
||||
</method>
|
||||
<method name='NewConnection'>
|
||||
<arg type='o' name='device' direction='in'/>
|
||||
<arg type='h' name='fd' direction='in'/>
|
||||
<arg type='a{sv}' name='fd_properties' direction='in'/>
|
||||
</method>
|
||||
<method name='RequestDisconnection'>
|
||||
<arg type='o' name='device' direction='in'/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.bluez.ProfileManager1">
|
||||
<method name="RegisterProfile">
|
||||
<arg name="profile" type="o" direction="in" />
|
||||
<arg name="UUID" type="s" direction="in" />
|
||||
<arg name="options" type="a{sv}" direction="in" />
|
||||
</method>
|
||||
<method name="UnregisterProfile">
|
||||
<arg name="profile" type="o" direction="in" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp__bluez_profile_manager_client_glue_h__proxy__H__
|
||||
#define __sdbuscpp__bluez_profile_manager_client_glue_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class ProfileManager1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.ProfileManager1";
|
||||
|
||||
protected:
|
||||
ProfileManager1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~ProfileManager1_proxy() = default;
|
||||
|
||||
public:
|
||||
void RegisterProfile(const sdbus::ObjectPath& profile, const std::string& UUID, const std::map<std::string, sdbus::Variant>& options)
|
||||
{
|
||||
proxy_.callMethod("RegisterProfile").onInterface(INTERFACE_NAME).withArguments(profile, UUID, options);
|
||||
}
|
||||
|
||||
void UnregisterProfile(const sdbus::ObjectPath& profile)
|
||||
{
|
||||
proxy_.callMethod("UnregisterProfile").onInterface(INTERFACE_NAME).withArguments(profile);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user