From ff9438a3ed04cbc1c0f45869ba1da7705ac1757f Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Fri, 19 May 2023 19:19:15 -0500 Subject: [PATCH 001/201] Started implementing Linux specific platform This is the start of the implementing for the Linux platform. I aim to make this as similar to the Windows platform as possible, although due to the fundamental difference in the two OS's, there will be things that need to be different. As such, I will be using the Windows platform files as a base, and reimplementing the functions with Linux equivalents. I am sure this will have bugs, which by my best attempt will be fixed when found. --- internal/platform/implementation/linux/BUILD | 290 ++++++++++++++ .../implementation/linux/atomic_boolean.h | 43 +++ .../linux/atomic_boolean_test.cc | 32 ++ .../implementation/linux/atomic_reference.h | 43 +++ .../linux/atomic_reference_test.cc | 72 ++++ .../implementation/linux/condition_variable.h | 51 +++ .../linux/condition_variable_test.cc | 102 +++++ .../platform/implementation/linux/crypto.cc | 54 +++ .../implementation/linux/crypto_test.cc | 50 +++ .../implementation/linux/device_info.cc | 264 +++++++++++++ .../implementation/linux/device_info.h | 62 +++ .../platform/implementation/linux/executor.cc | 55 +++ .../platform/implementation/linux/executor.h | 50 +++ .../implementation/linux/executor_test.cc | 323 ++++++++++++++++ .../platform/implementation/linux/file.cc | 111 ++++++ internal/platform/implementation/linux/file.h | 60 +++ .../platform/implementation/linux/mutex.h | 69 ++++ .../implementation/linux/mutext_test.cc | 105 +++++ .../platform/implementation/linux/test_data.h | 34 ++ .../implementation/linux/thread_pool.cc | 128 +++++++ .../implementation/linux/thread_pool.h | 72 ++++ .../platform/implementation/linux/utils.cc | 362 ++++++++++++++++++ .../platform/implementation/linux/utils.h | 85 ++++ 23 files changed, 2517 insertions(+) create mode 100644 internal/platform/implementation/linux/BUILD create mode 100644 internal/platform/implementation/linux/atomic_boolean.h create mode 100644 internal/platform/implementation/linux/atomic_boolean_test.cc create mode 100644 internal/platform/implementation/linux/atomic_reference.h create mode 100644 internal/platform/implementation/linux/atomic_reference_test.cc create mode 100644 internal/platform/implementation/linux/condition_variable.h create mode 100644 internal/platform/implementation/linux/condition_variable_test.cc create mode 100644 internal/platform/implementation/linux/crypto.cc create mode 100644 internal/platform/implementation/linux/crypto_test.cc create mode 100644 internal/platform/implementation/linux/device_info.cc create mode 100644 internal/platform/implementation/linux/device_info.h create mode 100644 internal/platform/implementation/linux/executor.cc create mode 100644 internal/platform/implementation/linux/executor.h create mode 100644 internal/platform/implementation/linux/executor_test.cc create mode 100644 internal/platform/implementation/linux/file.cc create mode 100644 internal/platform/implementation/linux/file.h create mode 100644 internal/platform/implementation/linux/mutex.h create mode 100644 internal/platform/implementation/linux/mutext_test.cc create mode 100644 internal/platform/implementation/linux/test_data.h create mode 100644 internal/platform/implementation/linux/thread_pool.cc create mode 100644 internal/platform/implementation/linux/thread_pool.h create mode 100644 internal/platform/implementation/linux/utils.cc create mode 100644 internal/platform/implementation/linux/utils.h diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD new file mode 100644 index 00000000..801ab31f --- /dev/null +++ b/internal/platform/implementation/linux/BUILD @@ -0,0 +1,290 @@ +# 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. +licenses(["notice"]) + +cc_library( + name = "types", + srcs = [ + "device_info.cc", + "log_message.cc", + "timer.cc", + ], + hdrs = [ + "atomic_boolean.h", + "atomic_reference.h", + "bluetooth_adapter.h", + "condition_variable.h", + "device_info.h", + "executor.h", + "future.h", + "input_file.h", + "listenable_future.h", + "log_message.h", + "mutex.h", + "output_file.h", + "preferences_manager.h", + "scheduled_executor.h", + "settable_future.h", + "submittable_executor.h", + "timer.h", + "utils.h", + ], + defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"], + visibility = ["//visibility:public"], + deps = [ + ":comm", + "//base", + "//base:stringprintf", + "//internal/base:bluetooth_address", + "//internal/platform:base", + "//internal/platform:logging", + "//internal/platform:types", + "//internal/platform:uuid", + "//internal/platform/implementation:types", + "//strings:strappendv", + "@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/memory", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + "@nlohmann_json//:json", + ], +) + +cc_library( + name = "comm", + hdrs = [ + "ble.h", + "ble_gatt_client.h", + "ble_gatt_server.h", + "ble_medium.h", + "ble_peripheral.h", + "ble_socket.h", + "ble_v2.h", + "ble_v2_peripheral.h", + "ble_v2_server_socket.h", + "ble_v2_socket.h", + "bluetooth_adapter.h", + "bluetooth_classic.h", + "bluetooth_classic_device.h", + "bluetooth_classic_medium.h", + "bluetooth_classic_server_socket.h", + "bluetooth_classic_socket.h", + "bluetooth_pairing.h", + "condition_variable.h", + "executor.h", + "file.h", + "file_path.h", + "http_loader.h", + "mutex.h", + "scheduled_executor.h", + "server_sync.h", + "submittable_executor.h", + "thread_pool.h", + "webrtc.h", + "wifi.h", + "wifi_direct.h", + "wifi_hotspot.h", + "wifi_lan.h", + ], + visibility = ["//visibility:private"], + deps = [ + "//internal/platform:base", + "//internal/platform:comm", + "//internal/platform:types", + "//internal/platform:uuid", + "//internal/platform/implementation:comm", + "//internal/platform/implementation: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", + ], +) + +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 = [ + "ble_gatt_client.cc", + "ble_gatt_server.cc", + "ble_medium.cc", + "ble_socket.cc", + "ble_v2.cc", + "ble_v2_peripheral.cc", + "ble_v2_server_socket.cc", + "ble_v2_socket.cc", + "bluetooth_adapter.cc", + "bluetooth_classic_device.cc", + "bluetooth_classic_medium.cc", + "bluetooth_classic_server_socket.cc", + "bluetooth_classic_socket.cc", + "bluetooth_pairing.cc", + "executor.cc", + "file.cc", + "file_path.cc", + "http_loader.cc", + "platform.cc", + "preferences_manager.cc", + "preferences_repository.cc", + "preferences_repository.h", + "scheduled_executor.cc", + "submittable_executor.cc", + "system_clock.cc", + "thread_pool.cc", + "utils.cc", + "webrtc.cc", + "wifi_direct_medium.cc", + "wifi_direct_server_socket.cc", + "wifi_direct_socket.cc", + "wifi_hotspot_medium.cc", + "wifi_hotspot_server_socket.cc", + "wifi_hotspot_socket.cc", + "wifi_lan_medium.cc", + "wifi_lan_server_socket.cc", + "wifi_lan_socket.cc", + "wifi_medium.cc", + ], + defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"], + visibility = [ + "//connections:__subpackages__", + "//fastpair:__subpackages__", + "//location/nearby:__subpackages__", + "//presence:__subpackages__", + ], + deps = [ + ":comm", + ":crypto", # build_cleaner: keep + ":types", + "//internal/flags:nearby_flags", + "//internal/platform:base", + "//internal/platform:cancellation_flag", + "//internal/platform:comm", + "//internal/platform:logging", + "//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", + "//third_party/webrtc/files/stable/webrtc/api/task_queue:default_task_queue_factory", + "//third_party/webrtc/files/stable/webrtc/rtc_base:checks", + "@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", + ], +) + +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", + ], +) + +cc_test( + name = "impl_test", + size = "small", + srcs = [ + "atomic_boolean_test.cc", + "atomic_reference_test.cc", + "ble_gatt_server_test.cc", + "ble_medium_test.cc", + "ble_v2_peripheral_test.cc", + "ble_v2_test.cc", + "bluetooth_adapter_test.cc", + "count_down_latch_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", + "utils_test.cc", + "webrtc_test.cc", + ], + tags = ["notap"], + deps = [ + ":comm", + ":crypto", + ":test_utils", + ":types", + ":windows", + "//internal/platform:base", + "//internal/platform:logging", + "//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", + ], +) diff --git a/internal/platform/implementation/linux/atomic_boolean.h b/internal/platform/implementation/linux/atomic_boolean.h new file mode 100644 index 00000000..8147dabb --- /dev/null +++ b/internal/platform/implementation/linux/atomic_boolean.h @@ -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_BOOLEAN_H_ +#define PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_ + +#include + +#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() 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_ \ No newline at end of file diff --git a/internal/platform/implementation/linux/atomic_boolean_test.cc b/internal/platform/implementation/linux/atomic_boolean_test.cc new file mode 100644 index 00000000..ecd5e41a --- /dev/null +++ b/internal/platform/implementation/linux/atomic_boolean_test.cc @@ -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); +} \ No newline at end of file diff --git a/internal/platform/implementation/linux/atomic_reference.h b/internal/platform/implementation/linux/atomic_reference.h new file mode 100644 index 00000000..ec7793dd --- /dev/null +++ b/internal/platform/implementation/linux/atomic_reference.h @@ -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 + +#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_ \ No newline at end of file diff --git a/internal/platform/implementation/linux/atomic_reference_test.cc b/internal/platform/implementation/linux/atomic_reference_test.cc new file mode 100644 index 00000000..8e69a64a --- /dev/null +++ b/internal/platform/implementation/linux/atomic_reference_test.cc @@ -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); +} \ No newline at end of file diff --git a/internal/platform/implementation/linux/condition_variable.h b/internal/platform/implementation/linux/condition_variable.h new file mode 100644 index 00000000..3661b3a7 --- /dev/null +++ b/internal/platform/implementation/linux/condition_variable.h @@ -0,0 +1,51 @@ +// 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. +#ifndef PLATFORM_IMPL_LINUX_CONDITION_VARIABLE_H_ +#define PLATFORM_IMPL_LINUX_CONDITION_VARIABLE_H_ + +#include // NOLINT + +#include "internal/platform/implementation/condition_variable.h" +#include "internal/platform/implementation/linux/mutex.h" +#include "internal/platform/mutex.h" + +namespace nearby { +namespace linux { + +class ConditionVariable : public api::ConditionVariable { + public: + explicit ConditionVariable(api::Mutex* mutex) + : mutex_(&(static_cast(mutex))->mutex_) {} + ~ConditionVariable() override = 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_ diff --git a/internal/platform/implementation/linux/condition_variable_test.cc b/internal/platform/implementation/linux/condition_variable_test.cc new file mode 100644 index 00000000..a45aae8e --- /dev/null +++ b/internal/platform/implementation/linux/condition_variable_test.cc @@ -0,0 +1,102 @@ +// 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 // 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 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 +} diff --git a/internal/platform/implementation/linux/crypto.cc b/internal/platform/implementation/linux/crypto.cc new file mode 100644 index 00000000..bdd1d926 --- /dev/null +++ b/internal/platform/implementation/linux/crypto.cc @@ -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 +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/byte_array.h" + +#include + +// 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(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 diff --git a/internal/platform/implementation/linux/crypto_test.cc b/internal/platform/implementation/linux/crypto_test.cc new file mode 100644 index 00000000..551616ee --- /dev/null +++ b/internal/platform/implementation/linux/crypto_test.cc @@ -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 + +#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 \ No newline at end of file diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc new file mode 100644 index 00000000..b05aeda8 --- /dev/null +++ b/internal/platform/implementation/linux/device_info.cc @@ -0,0 +1,264 @@ +// 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" + +// For Linux device specific stuff +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "internal/base/bluetooth_address.h" +#include "internal/platform/implementation/device_info.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +std::optional DeviceInfo::GetOsDeviceName() const { + // As I know of, there is no way to fully determine the length of the Hostname (device nickname) + + // https://stackoverflow.com/a/18851841 Max Host name length is limited to 64 bytes + char *device_name = new char[HOST_NAME_MAX]; + + // Linux hostnames are limited to UTF-8, 8-bit wide characters, so we need to convert + // that to the return type for a UTF-16 string, 16-bits wide. + if (gethostname(device_name, HOST_NAME_MAX) == 0) { + std::string name(device_name); + delete[] device_name; + return std::wstring_convert, char16_t>().from_bytes(name); + } + + NEARBY_LOGS(ERROR) << ": Failed to get device name, error:" + << strerror(errno); + delete[] device_name; + return std::nullopt; +} + +api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { + // While there is no *official* way to detect if a Linux system is a laptop or not, we can try to + // find its chassis type and make a very educated guess as to what the user is using. + // See https://superuser.com/a/1107191 + std::fstream chassis_type("/sys/class/dmi/id/chassis_type", std::ios::binary | std::ios::in); + + char chartype = 0; + + chassis_type.get(chartype); + + // The code is stored as text in the file, in order to get a correct + // representation in decimal, we can subtract 48 from it. + int type = chartype - 48; + + switch (type) { + case 3: + case 4: + // Type 3 and 4 are both types of desktops + return api::DeviceInfo::DeviceType::kDesktop; + case 6: + case 7: + // Type 6 and 7 are both Towers + return api::DeviceInfo::DeviceType::kDesktop; + case 9: + case 10: + // Type 9 and 10 are laptop esc, laptop and notebook + return api::DeviceInfo::DeviceType::kLaptop; + case 11: + case 30: + // Type 11 is labled as "Hand Held" + return api::DeviceInfo::DeviceType::kTablet; + case 31: + case 32: + // Type 31 and 32 are Convertable / Detatchable + return api::DeviceInfo::DeviceType::kLaptop; + default: + return api::DeviceInfo::DeviceType::kUnknown; + } +} + +api::DeviceInfo::OsType DeviceInfo::GetOsType() const { + return api::DeviceInfo::OsType::kLinux; +} + +std::optional DeviceInfo::GetFullName() const { + // We can use the C function getpwnam() to get information in a passwd database. + // The users full name is optionally in the passwd->pw_gecos member of the passwd struct. + + struct passwd *full_user_data = getpwnam(getlogin()); + std::u16string u16str; + + if (full_user_data == nullptr) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error retrieving locally authenticated user."; + return std::nullopt; + } + + // The GECOS field is optional and used for information purposes only. + // Usually it would contain the full name of the user. + // See https://man7.org/linux/man-pages/man5/passwd.5.html + u16str = *full_user_data->pw_gecos; + + if (u16str.empty()) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error retrieving full name of user. (GECOS field empty)"; + return std::nullopt; + } + + return u16str; +} + +std::optional DeviceInfo::GetGivenName() const { + std::optional user_full_name = GetFullName(); + + if (user_full_name == std::nullopt) { + NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving first name of user."; + return std::nullopt; + } + + if (user_full_name->empty()) { + NEARBY_LOGS(ERROR) + << __func__ << ": Error unboxing string value for first name of user."; + return std::nullopt; + } + + std::u16string::size_type seperator = user_full_name->find_first_of(u" "); + + // If the Full Name doesn't contain a space, then we assume the whole thing is a first name + if (seperator == std::u16string::npos) { + return user_full_name.value(); + } + + return user_full_name->substr(*user_full_name->begin(), seperator); +} + +std::optional DeviceInfo::GetLastName() const { + std::optional user_full_name = GetFullName(); + + if (user_full_name == std::nullopt) { + NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving last name of user."; + return std::nullopt; + } + + if (user_full_name->empty()) { + NEARBY_LOGS(ERROR) + << __func__ << ": Error unboxing string value for last name of user."; + return std::nullopt; + } + std::u16string::size_type seperator = user_full_name->find_first_of(u" "); + + // If the Full Name doesn't contain a space, then we assume there is no last name + if (seperator == std::u16string::npos) { + return std::nullopt; + } + + return user_full_name->substr(*user_full_name->begin(), seperator); +} + +std::optional DeviceInfo::GetProfileUserName() const { + + std::string user_name = getlogin(); + + + if (user_name.empty()) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error retrieving account name of user." + << strerror(errno); + return std::nullopt; + } + + return user_name; +} + +std::optional DeviceInfo::GetDownloadPath() const { + // This assumes xdg-user-dir is installed on the target system, which is better + // than guessing completely. This is 99.9% of the time going to be installed + // automatically by the Distro/DE + FILE *fp = popen("xdg-user-dir DOWNLOAD", "r"); + char *path = new char[512]; + if (fp == nullptr) { + pclose(fp); + delete fp; + delete[] path; + return std::nullopt; + } + + while (fgets(path, sizeof(path), fp) != nullptr) { + + } + int exit_status = WEXITSTATUS(fclose(fp)); + if (exit_status != 0) { + delete fp; + delete[] path; + return std::nullopt; + } + delete fp; + std::filesystem::path fpath = std::filesystem::path(path); + delete[] path; + return fpath; +} + +std::optional DeviceInfo::GetLocalAppDataPath() const { + //TODO: Figure out how to get cross distro path + + return std::nullopt; +} + +std::optional DeviceInfo::GetCommonAppDataPath() const { + //TODO: Figure out how to get cross distro path + + return std::nullopt; +} + +std::optional DeviceInfo::GetTemporaryPath() const { + return std::filesystem::temp_directory_path(); +} + +std::optional DeviceInfo::GetLogPath() const { + //TODO: Figure out how to get cross distro path + + return std::nullopt; +} + +std::optional DeviceInfo::GetCrashDumpPath() const { + //TODO: Figure out how to get cross distro path + + return std::nullopt; +} + +bool DeviceInfo::IsScreenLocked() const { + // TODO: Determine if it's actually possible to detect Linux screen lock cross DE, WM, WE, etc. + return false; +} + +void DeviceInfo::RegisterScreenLockedListener(absl::string_view listener_name, + std::function callback) { + //TODO: Figure out what this does + // Assuming it has to do with detecting if the screen is locked, that may not be possible. +} + +void DeviceInfo::UnregisterScreenLockedListener(absl::string_view listener_name) { + //TODO: Figure out what this does too + // Assuming it has to do with detecting if the screen is locked, that may not be possible. +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h new file mode 100644 index 00000000..55e80eda --- /dev/null +++ b/internal/platform/implementation/linux/device_info.h @@ -0,0 +1,62 @@ +// 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. + +#ifndef PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ +#define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ + +#include +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/device_info.h" + +namespace nearby { +namespace linux { + +class DeviceInfo : public api::DeviceInfo { + public: + ~DeviceInfo() override = default; + + std::optional GetOsDeviceName() const override; + api::DeviceInfo::DeviceType GetDeviceType() const override; + api::DeviceInfo::OsType GetOsType() const override; + std::optional GetFullName() const override; + std::optional GetGivenName() const override; + std::optional GetLastName() const override; + std::optional GetProfileUserName() const override; + + std::optional GetDownloadPath() const override; + std::optional GetLocalAppDataPath() const override; + std::optional GetCommonAppDataPath() const override; + std::optional GetTemporaryPath() const override; + std::optional GetLogPath() const override; + std::optional GetCrashDumpPath() const override; + + bool IsScreenLocked() const override; + void RegisterScreenLockedListener( + absl::string_view listener_name, + std::function callback) override; + void UnregisterScreenLockedListener(absl::string_view listener_name) override; + absl::flat_hash_map> + screen_locked_listeners_; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ \ No newline at end of file diff --git a/internal/platform/implementation/linux/executor.cc b/internal/platform/implementation/linux/executor.cc new file mode 100644 index 00000000..37dfcd9c --- /dev/null +++ b/internal/platform/implementation/linux/executor.cc @@ -0,0 +1,55 @@ +// 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 + +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +Executor::Executor() : Executor(1) {} + +Executor::Executor(int32_t max_concurrency) + : max_concurrency_(max_concurrency) { + assert(max_concurrency_ >= 1); + thread_pool_ = linux::ThreadPool::Create(max_concurrency); + 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 diff --git a/internal/platform/implementation/linux/executor.h b/internal/platform/implementation/linux/executor.h new file mode 100644 index 00000000..bd96ef06 --- /dev/null +++ b/internal/platform/implementation/linux/executor.h @@ -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. + +#ifndef PLATFORM_IMPL_LINUX_EXECUTOR_H_ +#define PLATFORM_IMPL_LINUX_EXECUTOR_H_ + +#include +#include + +#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(); + explicit Executor(int max_concurrency); + + // 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 thread_pool_ = nullptr; + std::atomic shut_down_ = false; + int32_t max_concurrency_; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_EXECUTOR_H_ diff --git a/internal/platform/implementation/linux/executor_test.cc b/internal/platform/implementation/linux/executor_test.cc new file mode 100644 index 00000000..858c7fc2 --- /dev/null +++ b/internal/platform/implementation/linux/executor_test.cc @@ -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 +#include +#include + +#include "gtest/gtest.h" +#include "absl/synchronization/blocking_counter.h" +#include "absl/synchronization/mutex.h" +#include "absl/synchronization/notification.h" +#include "absl/time/time.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(); + std::string output = std::string(); + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + 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 = std::make_unique(); + std::unique_ptr output = std::make_unique(); + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + 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(); + std::string output = std::string(); + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + 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(); + std::string output = std::string(); + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + 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(2); + + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + std::shared_ptr output = std::make_shared(); + + 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(2); + + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + std::shared_ptr output = std::make_shared(); + + 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(2); + + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + std::shared_ptr output = std::make_shared(); + + 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(32); + + // Container to note threads that ran + std::vector threadIds = std::vector(); + + 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 diff --git a/internal/platform/implementation/linux/file.cc b/internal/platform/implementation/linux/file.cc new file mode 100644 index 00000000..acb5fd0c --- /dev/null +++ b/internal/platform/implementation/linux/file.cc @@ -0,0 +1,111 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +#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::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::CreateOutputFile(const absl::string_view path) { + return std::unique_ptr(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> converter; + file_.open(std::filesystem::path(converter.from_bytes(path_)), std::ios::binary | std::ios::out); +} + +ExceptionOr IOFile::Read(std::int64_t size) { + if (!file_.is_open()) { + return ExceptionOr{Exception::kIo}; + } + + if (file_.peek() == EOF) { + return ExceptionOr{ByteArray{}}; + } + + if (!file_.good()) { + return ExceptionOr{Exception::kIo}; + } + + ByteArray bytes(size); + std::unique_ptr read_bytes{new char[size]}; + file_.read(read_bytes.get(), static_cast(size)); + auto num_bytes_read = file_.gcount(); + if (num_bytes_read == 0) { + return ExceptionOr{Exception::kIo}; + } + + return ExceptionOr(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 diff --git a/internal/platform/implementation/linux/file.h b/internal/platform/implementation/linux/file.h new file mode 100644 index 00000000..5176f33c --- /dev/null +++ b/internal/platform/implementation/linux/file.h @@ -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 +#include +#include +#include + +#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 CreateInputFile( + const absl::string_view file_path, size_t size); + + static std::unique_ptr CreateOutputFile(const absl::string_view path); + + ExceptionOr 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_ diff --git a/internal/platform/implementation/linux/mutex.h b/internal/platform/implementation/linux/mutex.h new file mode 100644 index 00000000..f9235a16 --- /dev/null +++ b/internal/platform/implementation/linux/mutex.h @@ -0,0 +1,69 @@ +// 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. +#ifndef PLATFORM_IMPL_LINUX_MUTEX_H_ +#define PLATFORM_IMPL_LINUX_MUTEX_H_ + +#include +#include // NOLINT + +#include "absl/memory/memory.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/mutex.h" + +namespace nearby { +namespace linux { + +// A lock is a tool for controlling access to a shared resource by multiple +// threads. +// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html +class ABSL_LOCKABLE Mutex : public api::Mutex { + public: + explicit Mutex(Mode mode) : mode_(mode) {} + ~Mutex() override = default; + Mutex(Mutex&&) = delete; + Mutex& operator=(Mutex&&) = delete; + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + + void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override { + if (mode_ == Mode::kRegularNoCheck) mutex_.ForgetDeadlockInfo(); + if (mode_ == Mode::kRegular || mode_ == Mode::kRegularNoCheck) { + mutex_.Lock(); + } else { + recursive_mutex_.lock(); + } + } + + void Unlock() ABSL_UNLOCK_FUNCTION() override { + if (mode_ == Mode::kRegular || mode_ == Mode::kRegularNoCheck) { + mutex_.Unlock(); + } else { + recursive_mutex_.unlock(); + } + } + + absl::Mutex& GetMutex() { return mutex_; } + std::recursive_mutex& GetRecursiveMutex() { return recursive_mutex_; } + + private: + friend class ConditionVariable; + absl::Mutex mutex_; + std::recursive_mutex recursive_mutex_; // The actual mutex allocation + Mode mode_; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_MUTEX_H_ \ No newline at end of file diff --git a/internal/platform/implementation/linux/mutext_test.cc b/internal/platform/implementation/linux/mutext_test.cc new file mode 100644 index 00000000..466575d2 --- /dev/null +++ b/internal/platform/implementation/linux/mutext_test.cc @@ -0,0 +1,105 @@ +// 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/mutex.h" + +#include // NOLINT + +#include "gtest/gtest.h" + +class MutexTests : public testing::Test { + public: + class MutexTest { + public: + MutexTest(nearby::linux::Mutex& mutex) : mutex_(mutex) {} + + std::future WaitForLock() { // NOLINT + return std::async(std::launch::async, + // for this lambda you need C++14 + [this]() mutable { + absl::MutexLock(&mutex_.GetMutex()); + return true; + }); + } + + void PostEvent() { + absl::MutexLock(&mutex_.GetMutex()); + mutex_.Unlock(); + } + + private: + nearby::linux::Mutex& mutex_; + }; +}; + +TEST_F(MutexTests, SuccessfulRecursiveCreation) { + // Arrange + nearby::linux::Mutex mutex = + nearby::linux::Mutex(nearby::linux::Mutex::Mode::kRecursive); + + // Act + std::recursive_mutex& actual = mutex.GetRecursiveMutex(); + + // Assert + ASSERT_TRUE(actual.native_handle() != nullptr); +} + +TEST_F(MutexTests, SuccessfulCreation) { + // Arrange + nearby::linux::Mutex mutex(nearby::linux::Mutex::Mode::kRegular); + + // Act + absl::Mutex& actual = mutex.GetMutex(); + + // Assert + ASSERT_TRUE(&actual != nullptr); +} + +TEST_F(MutexTests, SuccessfulSignal) { + // Arrange + nearby::linux::Mutex mutex(nearby::linux::Mutex::Mode::kRegular); + + nearby::linux::Mutex& mutexRef = mutex; + MutexTest mutexTest(mutexRef); + + mutex.Lock(); + + // Act + auto result = mutexTest.WaitForLock(); + mutex.Unlock(); + + // Assert + ASSERT_TRUE(result.get()); +} + +TEST_F(MutexTests, SuccessfulRecursiveSignal) { + // Arrange + nearby::linux::Mutex mutex(nearby::linux::Mutex::Mode::kRecursive); + + nearby::linux::Mutex& mutexRef = mutex; + MutexTest mutexTest(mutexRef); + + mutex.Lock(); + mutex.Lock(); + mutex.Lock(); + + // Act + auto result = mutexTest.WaitForLock(); + mutex.Unlock(); + mutex.Unlock(); + mutex.Unlock(); + + // Assert + ASSERT_TRUE(result.get()); +} diff --git a/internal/platform/implementation/linux/test_data.h b/internal/platform/implementation/linux/test_data.h new file mode 100644 index 00000000..7cdddf9b --- /dev/null +++ b/internal/platform/implementation/linux/test_data.h @@ -0,0 +1,34 @@ +// 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. + +#ifndef PLATFORM_IMPL_LINUX_TEST_DATA_H_ +#define PLATFORM_IMPL_LINUX_TEST_DATA_H_ + +#define INVALID_ARGUMENT_TEXT "max_concurrency" +#define THREADPOOL_MAX_SIZE_TEXT "Thread pool max size exceeded." +#define RUNNABLE_TEXT std::string("runnable ") +#define RUNNABLE_0_TEXT RUNNABLE_TEXT + std::string("0") +#define RUNNABLE_1_TEXT RUNNABLE_TEXT + std::string("1") +#define RUNNABLE_2_TEXT RUNNABLE_TEXT + std::string("2") +#define RUNNABLE_3_TEXT RUNNABLE_TEXT + std::string("3") +#define RUNNABLE_4_TEXT RUNNABLE_TEXT + std::string("4") +#define RUNNABLE_SEPARATOR_TEXT std::string(", ") +#define RUNNABLE_ALL_TEXT \ + (RUNNABLE_0_TEXT + RUNNABLE_SEPARATOR_TEXT + RUNNABLE_1_TEXT + \ + RUNNABLE_SEPARATOR_TEXT + RUNNABLE_2_TEXT + RUNNABLE_SEPARATOR_TEXT + \ + RUNNABLE_3_TEXT + RUNNABLE_SEPARATOR_TEXT + RUNNABLE_4_TEXT + \ + RUNNABLE_SEPARATOR_TEXT) + +#endif // PLATFORM_IMPL_LINUX_TEST_DATA_H_ + diff --git a/internal/platform/implementation/linux/thread_pool.cc b/internal/platform/implementation/linux/thread_pool.cc new file mode 100644 index 00000000..40dec614 --- /dev/null +++ b/internal/platform/implementation/linux/thread_pool.cc @@ -0,0 +1,128 @@ +// Copyright 2021-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/thread_pool.h" + +#include +#include + +#include "absl/memory/memory.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/logging.h" +#include "internal/platform/runnable.h" + +namespace nearby { +namespace linux { + +std::unique_ptr ThreadPool::Create(int max_pool_size) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Create thread pool with maximum size(" + << max_pool_size << ")."; + + if (max_pool_size <= 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Maximum pool size must be positive integer value."; + return nullptr; + } + + std::unique_ptr> thread_pool = std::make_unique>(); + + // Sets thread pool maximum value. + thread_pool->resize(max_pool_size); + + return absl::WrapUnique( + new ThreadPool(thread_pool, max_pool_size)); +} + +ThreadPool::ThreadPool(std::unique_ptr> &thread_pool, int max_pool_size) + : thread_pool_(std::move(thread_pool)), + max_pool_size_(max_pool_size) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Thread pool(" << this + << ") is created with size:" << max_pool_size_; + + for (int size = 0; size < max_pool_size_; size++) { + thread_pool_->at(size) = std::thread([this]() { + while (!tasks_.empty()) { + RunNextTask(); + // Possibly don't need but here to prevent 100% usage for loop + sleep(300); + } + }); + } +} + +ThreadPool::~ThreadPool() { + NEARBY_LOGS(VERBOSE) << __func__ << ": Thread pool(" << this + << ") is released."; + + ShutDown(); +} + +bool ThreadPool::Run(Runnable task) { + absl::MutexLock lock(&mutex_); + + if (thread_pool_->size() == max_pool_size_) { + return false; + } + + tasks_.push(std::move(task)); + NEARBY_LOGS(VERBOSE) << __func__ << ": Scheduled to run task(" + << &tasks_.back() << ")."; + return true; +} + +void ThreadPool::ShutDown() { + absl::MutexLock lock(&mutex_); + + if (!thread_pool_->empty()) { + NEARBY_LOGS(WARNING) << __func__ << ": Request to shutdown thread pool with " << thread_pool_->size() << " tasks not finished(" << this << ")."; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": Shutdown thread pool(" << this << ")."; + if (thread_pool_ == nullptr) { + NEARBY_LOGS(WARNING) << __func__ << ": Shutdown on closed thread pool(" + << this << ")."; + return; + } + + thread_pool_.reset(); +} + +void ThreadPool::RunNextTask() { + Runnable task = nullptr; + + { + absl::MutexLock lock(&mutex_); + + if (!thread_pool_) { + return; + } + if (!tasks_.empty()) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Run task(" << &tasks_.front() + << ")."; + + task = std::move(tasks_.front()); + tasks_.pop(); + } + } + if (task == nullptr) { + NEARBY_LOGS(WARNING) << __func__ + << ": Tried to run task in an empty thread pool."; + return; + } + + task(); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/thread_pool.h b/internal/platform/implementation/linux/thread_pool.h new file mode 100644 index 00000000..889fe8b6 --- /dev/null +++ b/internal/platform/implementation/linux/thread_pool.h @@ -0,0 +1,72 @@ +// Copyright 2020-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_THREAD_POOL_H_ +#define PLATFORM_IMPL_LINUX_THREAD_POOL_H_ + +#include +#include +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/runnable.h" + +namespace nearby { +namespace linux { + +class ThreadPool { + public: + virtual ~ThreadPool(); + static std::unique_ptr Create(int max_pool_size); + + // Runs a task on thread pool. The result indicates whether the task is put + // into the thread pool. + bool Run(Runnable task) ABSL_LOCKS_EXCLUDED(mutex_); + + // The thread pool is closed immediately if there is no outstanding work, + // I/O, timer, or wait objects that are bound to the pool; otherwise, the + // thread pool is released asynchronously after the outstanding objects are + // freed. + void ShutDown() ABSL_LOCKS_EXCLUDED(mutex_); + + private: + ThreadPool(std::unique_ptr> &thread_pool, int max_pool_size); + + void RunNextTask(); + + // Starts each task and injects a function that removes the task when it is finished + std::thread tasks_runner_; + + // Protects the access to tasks of the thread pool. + mutable absl::Mutex mutex_; + + // The task queue of the thread pool. Thread pool will pick up task to run + // when it is idle. + std::queue tasks_ ABSL_GUARDED_BY(mutex_); + + // All the threads run in the pool + std::unique_ptr> thread_pool_ ABSL_GUARDED_BY(mutex_); + + // The maximum thread count in the thread pool + int max_pool_size_ ABSL_GUARDED_BY(mutex_) = 0; + +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_THREAD_POOL_H_ diff --git a/internal/platform/implementation/linux/utils.cc b/internal/platform/implementation/linux/utils.cc new file mode 100644 index 00000000..1d22b21b --- /dev/null +++ b/internal/platform/implementation/linux/utils.cc @@ -0,0 +1,362 @@ +// 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/utils.h" + +// Standard C/C++ headers +#include +#include +#include +#include +#include +#include +#include + +// Third party headers +#include "absl/strings/ascii.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" + +// Nearby connections headers +#include "absl/strings/string_view.h" +#include "internal/platform/bluetooth_utils.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/implementation/crypto.h" +#include "internal/platform/logging.h" +#include "internal/platform/uuid.h" + +// Linux headers +#include +#include +#include +#include + +namespace nearby { +namespace linux { +namespace { + +std::string uint64_to_mac_address_string(uint64_t bluetoothAddress) { + std::string buffer = absl::StrFormat( + "%02llx:%02llx:%02llx:%02llx:%02llx:%02llx", bluetoothAddress >> 40, + (bluetoothAddress >> 32) & 0xff, (bluetoothAddress >> 24) & 0xff, + (bluetoothAddress >> 16) & 0xff, (bluetoothAddress >> 8) & 0xff, + bluetoothAddress & 0xff); + + return absl::AsciiStrToUpper(buffer); +} + +uint64_t mac_address_string_to_uint64(absl::string_view mac_address) { + ByteArray mac_address_array = BluetoothUtils::FromString(mac_address); + uint64_t mac_address_uint64 = 0; + for (int i = 0; i < mac_address_array.size(); i++) { + mac_address_uint64 <<= 8; + mac_address_uint64 |= static_cast( + static_cast(*(mac_address_array.data() + i))); + } + return mac_address_uint64; +} + +std::string ipaddr_4bytes_to_dotdecimal_string( + absl::string_view ipaddr_4bytes) { + + union addrs { + in_addr_t addr; + uint8_t bits[4]; + } address; + + address.bits[0] = ipaddr_4bytes[0]; + address.bits[1] = ipaddr_4bytes[1]; + address.bits[2] = ipaddr_4bytes[2]; + address.bits[3] = ipaddr_4bytes[3]; + + struct in_addr addr; + + addr.s_addr = address.addr; + char* ipv4_address = inet_ntoa(addr); + if (ipv4_address == nullptr) { + return {}; + } + + return std::string(ipv4_address); +} + +std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s) { + if (ipv4_s.empty()) { + return {}; + } + + struct in_addr addr; + + if (inet_aton(ipv4_s.c_str(), &addr) != 0) { + return {}; + } + + std::string ipv4_b = std::to_string(addr.s_addr); + + return std::string(); +} + +std::wstring string_to_wstring(std::string str) { + std::wstring_convert> converter; + return converter.from_bytes(str); +} + +std::string wstring_to_string(std::wstring wstr) { + std::wstring_convert> converter; + return converter.to_bytes(wstr); +} + +std::vector GetIpv4Addresses() { + std::vector result; + + struct ifaddrs *interface = nullptr; + char host[NI_MAXHOST]; + + if (getifaddrs(&interface) != 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to get interfaces. Error: " + << strerror(errno); + freeifaddrs(interface); + return {}; + } + int status = 0; + for (struct ifaddrs *ifa = interface; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_INET) { + status = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST); + } + switch (status) { + case EAI_AGAIN: + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get IP for interface: " + << ifa->ifa_name + << " : The name could not be resolved at this time. " + << "Try again later."; + break; + case EAI_BADFLAGS: + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get IP for interface: " + << ifa->ifa_name + << " : The flags argument has an invalid value."; + break; + case EAI_FAIL: + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get IP for interface: " + << ifa->ifa_name + << " : A nonrecoverable error occured."; + break; + case EAI_FAMILY: + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get IP for interface: " + << ifa->ifa_name + << " : The address family was not recognized, " + << "or the address length was invalid for the " + << "specified family."; + break; + case EAI_MEMORY: + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get IP for interface: " + << ifa->ifa_name + << " : Out of memory."; + break; + case EAI_NONAME: + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get IP for interface: " + << ifa->ifa_name + << " : The name does not resolve for the suplied arguments." + << " NI_NAMEREQD is set and the host's name cannot be located, " + << "or neither hostname nor service name were requsted."; + break; + case EAI_OVERFLOW: + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get IP for interface: " + << ifa->ifa_name + << " : The bugger pointed to by `host` or `serv` was too small."; + break; + case EAI_SYSTEM: + NEARBY_LOGS(ERROR) << __func__ + << "A system error occured. Error code: " + << errno + << ": " << strerror(errno); + break; + } + } + return result; +} + +std::vector Get4BytesIpv4Addresses() { + std::vector result; + std::vector ipv4_addresses = GetIpv4Addresses(); + for (const auto& ipv4_address : ipv4_addresses) { + // Converts IP address from x.x.x.x to 4 bytes format using utils function + result.push_back(ipaddr_dotdecimal_to_4bytes_string(ipv4_address)); + } + + return result; +} + +/* +Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid) { + int64_t data1 = guid.Data1; + int64_t data2 = guid.Data2; + int64_t data3 = guid.Data3; + + int64_t msb = ((data1 >> 24) & 0xff) << 56 | ((data1 >> 16) & 0xff) << 48 | + ((data1 >> 8) & 0xff) << 40 | ((data1)&0xff) << 32 | + ((data2 >> 8) & 0xff) << 24 | ((data2)&0xff) << 16 | + ((data3 >> 8) & 0xff) << 8 | (data3 & 0xff); + + int64_t lsb = + ((int64_t)guid.Data4[0]) << 56 | ((int64_t)guid.Data4[1]) << 48 | + ((int64_t)guid.Data4[2]) << 40 | ((int64_t)guid.Data4[3]) << 32 | + ((int64_t)guid.Data4[4]) << 24 | ((int64_t)guid.Data4[5]) << 16 | + ((int64_t)guid.Data4[6]) << 8 | (int64_t)guid.Data4[7]; + + return Uuid(msb, lsb); +} +*/ + +/* +winrt::guid nearby_uuid_to_winrt_guid(Uuid uuid) { + winrt::guid guid; + uint64_t msb = uuid.GetMostSigBits(); + guid.Data1 = ((msb >> 56) & 0xff) << 24 | ((msb >> 48) & 0xff) << 16 | + ((msb >> 40) & 0xff) << 8 | ((msb >> 32) & 0xff); + guid.Data2 = ((msb >> 24) & 0xff) << 8 | ((msb >> 16) & 0xff); + guid.Data3 = ((msb >> 8) & 0xff) << 8 | (msb & 0xff); + uint64_t lsb = uuid.GetLeastSigBits(); + guid.Data4[0] = (lsb >> 56) & 0xff; + guid.Data4[1] = (lsb >> 48) & 0xff; + guid.Data4[2] = (lsb >> 40) & 0xff; + guid.Data4[3] = (lsb >> 32) & 0xff; + guid.Data4[4] = (lsb >> 24) & 0xff; + guid.Data4[5] = (lsb >> 16) & 0xff; + guid.Data4[6] = (lsb >> 8) & 0xff; + guid.Data4[7] = lsb & 0xff; + return guid; +} +*/ + +/* +bool is_nearby_uuid_equal_to_winrt_guid(const Uuid& uuid, + const ::winrt::guid& guid) { + return uuid == winrt_guid_to_nearby_uuid(guid); +} +*/ + +ByteArray Sha256(absl::string_view input, size_t size) { + ByteArray hash = nearby::Crypto::Sha256(input); + return ByteArray{hash.data(), size}; +} +/* +bool InspectableReader::ReadBoolean(IInspectable inspectable) { + if (inspectable == nullptr) { + return false; + } + + auto property_value = + inspectable.try_as(); + if (property_value == nullptr) { + throw std::invalid_argument("no property value interface."); + } + if (property_value.Type() != + winrt::Windows::Foundation::PropertyType::Boolean) { + throw std::invalid_argument("not uin16 data type."); + } + + return property_value.GetBoolean(); +} + +uint16 InspectableReader::ReadUint16(IInspectable inspectable) { + if (inspectable == nullptr) { + return 0; + } + + auto property_value = + inspectable.try_as(); + if (property_value == nullptr) { + throw std::invalid_argument("no property value interface."); + } + if (property_value.Type() != + winrt::Windows::Foundation::PropertyType::UInt16) { + throw std::invalid_argument("not uin16 data type."); + } + + return property_value.GetUInt16(); +} + +uint32 InspectableReader::ReadUint32(IInspectable inspectable) { + if (inspectable == nullptr) { + return 0; + } + + auto property_value = + inspectable.try_as(); + if (property_value == nullptr) { + throw std::invalid_argument("no property value interface."); + } + if (property_value.Type() != + winrt::Windows::Foundation::PropertyType::UInt32) { + throw std::invalid_argument("not uin32 data type."); + } + + return property_value.GetUInt32(); +} + +std::string InspectableReader::ReadString(IInspectable inspectable) { + if (inspectable == nullptr) { + return ""; + } + + auto property_value = + inspectable.try_as(); + if (property_value == nullptr) { + throw std::invalid_argument("no property value interface."); + } + if (property_value.Type() != + winrt::Windows::Foundation::PropertyType::String) { + throw std::invalid_argument("not string data type."); + } + + return wstring_to_string(property_value.GetString().c_str()); +} + +std::vector InspectableReader::ReadStringArray( + IInspectable inspectable) { + std::vector result; + if (inspectable == nullptr) { + return result; + } + + auto property_value = + inspectable.try_as(); + if (property_value == nullptr) { + throw std::invalid_argument("no property value interface."); + } + if (property_value.Type() != + winrt::Windows::Foundation::PropertyType::StringArray) { + throw std::invalid_argument("not string array data type."); + } + + winrt::com_array strings; + property_value.GetStringArray(strings); + + for (winrt::hstring str : strings) { + result.push_back(winrt::to_string(str)); + } + return result; +} +*/ +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/utils.h b/internal/platform/implementation/linux/utils.h new file mode 100644 index 00000000..ef43e77e --- /dev/null +++ b/internal/platform/implementation/linux/utils.h @@ -0,0 +1,85 @@ +// 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_UTILS_H_ +#define PLATFORM_IMPL_LINUX_UTILS_H_ + +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { + +std::string uint64_to_mac_address_string(uint64_t bluetoothAddress); +uint64_t mac_address_string_to_uint64(absl::string_view mac_address); + +std::string ipaddr_4bytes_to_dotdecimal_string(absl::string_view ipaddr_4bytes); +std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s); + +// Helpers to linux platform +std::wstring string_to_wstring(std::string str); +std::string wstring_to_string(std::wstring wstr); +ByteArray Sha256(absl::string_view input, size_t size); + +// Reads the IPv4 addresses +std::vector GetIpv4Addresses(); +std::vector Get4BytesIpv4Addresses(); + +/* +// Help methods to convert between Uuid and winrt::guid +Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid); +winrt::guid nearby_uuid_to_winrt_guid(Uuid uuid); + +// Check whether Uuid and guid is the same value. +bool is_nearby_uuid_equal_to_winrt_guid(const Uuid& uuid, + const ::winrt::guid& guid); +*/ + +namespace Constants { +// The Id of the Service Name SDP attribute +const uint16_t SdpServiceNameAttributeId = 0x100; + +// The SDP Type of the Service Name SDP attribute. +// The first byte in the SDP Attribute encodes the SDP Attribute Type as +// follows: +// - the Attribute Type size in the least significant 3 bits, +// - the SDP Attribute Type value in the most significant 5 bits. +const char SdpServiceNameAttributeType = (4 << 3) | 5; + +// Possible values for the adapter type. Refer to: +// https://learn.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_info +const uint16_t kInterfaceTypeEthernet = 6; +const uint16_t kInterfaceTypeWifi = 71; +} // namespace Constants + +/* +class InspectableReader { + public: + static bool ReadBoolean(IInspectable inspectable); + static uint16_t ReadUint16(IInspectable inspectable); + static uint32_t ReadUint32(IInspectable inspectable); + static std::string ReadString(IInspectable inspectable); + static std::vector ReadStringArray(IInspectable inspectable); +}; +*/ + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_UTILS_H_ From d387a441593f7d4399bcf5b6b2b4790db45ffb54 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Fri, 19 May 2023 19:51:04 -0500 Subject: [PATCH 002/201] Fix memory leak with getting interfaces There was no free after we were finished with the interface pointer --- internal/platform/implementation/linux/utils.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/platform/implementation/linux/utils.cc b/internal/platform/implementation/linux/utils.cc index 1d22b21b..0660b9b8 100644 --- a/internal/platform/implementation/linux/utils.cc +++ b/internal/platform/implementation/linux/utils.cc @@ -191,6 +191,7 @@ std::vector GetIpv4Addresses() { break; } } + freeifaddrs(interface); return result; } From cbef0de68dd916ba61e80b80f87b805730425610 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Sun, 21 May 2023 17:07:15 -0500 Subject: [PATCH 003/201] Added program data directories to Linux platform device_info There are a couple of places where apps can store data in Linux, one is in the HOME directory, which is being phased out, the second, is in HOME/.config, and the other is HOME/.local/share. This uses HOME/.local/share, and since there isn't a common appdata path on Linux that function will just return the local appdata path. --- .../implementation/linux/device_info.cc | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index b05aeda8..5ee10822 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -49,7 +49,7 @@ std::optional DeviceInfo::GetOsDeviceName() const { return std::wstring_convert, char16_t>().from_bytes(name); } - NEARBY_LOGS(ERROR) << ": Failed to get device name, error:" + NEARBY_LOGS(ERROR) << ": Failed to get device name, error: " << strerror(errno); delete[] device_name; return std::nullopt; @@ -210,6 +210,7 @@ std::optional DeviceInfo::GetDownloadPath() const { delete[] path; return std::nullopt; } + delete fp; std::filesystem::path fpath = std::filesystem::path(path); delete[] path; @@ -217,15 +218,32 @@ std::optional DeviceInfo::GetDownloadPath() const { } std::optional DeviceInfo::GetLocalAppDataPath() const { - //TODO: Figure out how to get cross distro path + // From lots of research I have done, it seems there is no way to get a path + // for this cross distro wise, some distros might implement this path in + // a different way. Because of that, this will have to be hard-coded and in + // the future may be able to detect which distro and if the path is different + // deal with that. + + std::string app_data_dir(getenv("HOME")); + app_data_dir.append("/.local/share"); + + if (std::filesystem::is_directory(app_data_dir)) { + return app_data_dir; + } return std::nullopt; } std::optional DeviceInfo::GetCommonAppDataPath() const { - //TODO: Figure out how to get cross distro path + // From lots of research I have done, it seems there is no way to get a path + // for this cross distro wise, some distros might implement this path in + // a different way. Because of that, this will have to be hard-coded and in + // the future may be able to detect which distro and if the path is different + // deal with that. + + // Also there is no common appdata path on Linux - return std::nullopt; + return GetLocalAppDataPath(); } std::optional DeviceInfo::GetTemporaryPath() const { @@ -233,14 +251,13 @@ std::optional DeviceInfo::GetTemporaryPath() const { } std::optional DeviceInfo::GetLogPath() const { - //TODO: Figure out how to get cross distro path - - return std::nullopt; + return std::nullopt; } std::optional DeviceInfo::GetCrashDumpPath() const { - //TODO: Figure out how to get cross distro path - + // Crash dumps are handled by the system, it will generate a core (crash) dump + // and put it in a directory. + // E.g. "Segmentation fault (core dumped)" return std::nullopt; } From 46928a3347303d23ac08956cf6049025ab56bdab Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Sun, 21 May 2023 18:58:33 -0500 Subject: [PATCH 004/201] Implemented Linux equivalent to Windows file_path* This adds a Linux equivalent to file path operations done in the Windows headers and source files. Some differences that will occur are the invalid path names and contents, as there are no invalid path names, and only one invalid path content (excluding non-printable characters) on Linux. --- .../implementation/linux/file_path.cc | 209 +++++ .../platform/implementation/linux/file_path.h | 49 ++ .../implementation/linux/file_path_test.cc | 770 ++++++++++++++++++ 3 files changed, 1028 insertions(+) create mode 100644 internal/platform/implementation/linux/file_path.cc create mode 100644 internal/platform/implementation/linux/file_path.h create mode 100644 internal/platform/implementation/linux/file_path_test.cc diff --git a/internal/platform/implementation/linux/file_path.cc b/internal/platform/implementation/linux/file_path.cc new file mode 100644 index 00000000..f66fe6a4 --- /dev/null +++ b/internal/platform/implementation/linux/file_path.cc @@ -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 +#include +#include +#include +#include +#include + +#include "absl/strings/str_cat.h" +#include "internal/platform/implementation/linux/utils.h" +#include "internal/platform/implementation/linux/device_info.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(); + + std::optional 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 diff --git a/internal/platform/implementation/linux/file_path.h b/internal/platform/implementation/linux/file_path.h new file mode 100644 index 00000000..6053b2f4 --- /dev/null +++ b/internal/platform/implementation/linux/file_path.h @@ -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 + +#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_ diff --git a/internal/platform/implementation/linux/file_path_test.cc b/internal/platform/implementation/linux/file_path_test.cc new file mode 100644 index 00000000..a9c7e878 --- /dev/null +++ b/internal/platform/implementation/linux/file_path_test.cc @@ -0,0 +1,770 @@ +// 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 +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include +#include + +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"TestTest"); + + 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 From af5bea6a3d707f57e789bbc8edf41e693a6b8afe Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 22 Jul 2023 15:28:32 +0530 Subject: [PATCH 005/201] Initial sketch. --- internal/platform/implementation/linux/BUILD | 18 +++ .../implementation/linux/device_info.cc | 121 ++++++++++++++++++ .../implementation/linux/device_info.h | 51 ++++++++ .../platform/implementation/linux/platform.cc | 12 ++ 4 files changed, 202 insertions(+) create mode 100644 internal/platform/implementation/linux/BUILD create mode 100644 internal/platform/implementation/linux/device_info.cc create mode 100644 internal/platform/implementation/linux/device_info.h create mode 100644 internal/platform/implementation/linux/platform.cc diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD new file mode 100644 index 00000000..5eb73e71 --- /dev/null +++ b/internal/platform/implementation/linux/BUILD @@ -0,0 +1,18 @@ +licenses(["notice"]) + +cc_library( + name = "types", + hdrs = [ + "device_info.h", + ], + srcs = [ + "device_info.cc", + ], + deps = [ + "//internal/platform/implementation:types", + "//internal/platform:logging", + "@com_google_absl//absl/strings", + "@libsystemd//:lib", + ], +) + diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc new file mode 100644 index 00000000..80fa2c30 --- /dev/null +++ b/internal/platform/implementation/linux/device_info.cc @@ -0,0 +1,121 @@ +#include +#include +#include + +#include +#include +#include + +#include "internal/platform/implementation/device_info.h" +#include "internal/platform/implementation/linux/device_info.h" +#include "internal/platform/logging.h" + +namespace nearby { + +namespace linux { + +const char *HOSTNAME_DEST = "org.freedesktop.hostname1"; +const char *HOSTNAME_PATH = "/org/freedesktop/hostname1"; +const char *HOSTNAME_INTERFACE = "org.freedesktop.hostname1"; + +std::optional DeviceInfo::GetOsDeviceName() const { + sd_bus *bus = nullptr; + if (sd_bus_default_system(&bus) < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; + return std::nullopt; + } + + sd_bus_error err = SD_BUS_ERROR_NULL; + + char *hostname = nullptr; + if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, + HOSTNAME_INTERFACE, "PrettyHostname", &err, + &hostname) < 0) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Error getting PrettyHostname from org.freedesktop.hostname1: " + << err.message; + } + if (!hostname || hostname[0] == '\0') { + int ret = sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, + HOSTNAME_INTERFACE, "Hostname", &err, + &hostname); + if (ret < 0) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Error getting Hostname from org.freedesktop.hostname1: " + << err.message; + sd_bus_error_free(&err); + sd_bus_unref(bus); + return std::nullopt; + } + } + + sd_bus_error_free(&err); + sd_bus_unref(bus); + + std::wstring_convert, char16_t> convert; + + std::u16string name = convert.from_bytes(hostname); + free(hostname); + return name; +} + +api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { + sd_bus *bus; + if (sd_bus_default_system(&bus) < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; + return api::DeviceInfo::DeviceType::kUnknown; + } + sd_bus_error err = SD_BUS_ERROR_NULL; + char *chasis = nullptr; + + if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, + HOSTNAME_INTERFACE, "Chasis", &err, + &chasis) < 0) { + NEARBY_LOGS(ERROR) + << __func__ << ": Error getting Chasis from org.freedesktop.hostname1: " + << err.message; + sd_bus_error_free(&err); + sd_bus_unref(bus); + return api::DeviceInfo::DeviceType::kUnknown; + } + + sd_bus_unref(bus); + + api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; + + if (strcmp(chasis, "phone") == 0) { + device = api::DeviceInfo::DeviceType::kPhone; + } else if (strcmp(chasis, "laptop") == 0 || strcmp(chasis, "desktop") == 0) { + device = api::DeviceInfo::DeviceType::kLaptop; + } else if (strcmp(chasis, "tablet") == 0) { + device = api::DeviceInfo::DeviceType::kTablet; + } else if (strcmp(chasis, "handset") == 0) { + device = api::DeviceInfo::DeviceType::kPhone; + } + free(chasis); + return device; +} + +std::optional DeviceInfo::GetFullName() const { + struct passwd *pwd = getpwuid(getuid()); + if (!pwd) { + return std::nullopt; + } + char *name = strtok(pwd->pw_gecos, ","); + + std::wstring_convert, char16_t> convert; + return convert.from_bytes(name ? name : pwd->pw_gecos); +} + +std::optional DeviceInfo::GetProfileUserName() const { + struct passwd *pwd = getpwuid(getuid()); + if (!pwd) { + return std::nullopt; + } + char *name = strtok(pwd->pw_gecos, ","); + return std::string(name); +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h new file mode 100644 index 00000000..43cef077 --- /dev/null +++ b/internal/platform/implementation/linux/device_info.h @@ -0,0 +1,51 @@ +#ifndef PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ +#define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ + +#include + +#include +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/device_info.h" + +namespace nearby { +namespace linux { + +class DeviceInfo : public api::DeviceInfo { +public: + ~DeviceInfo() override; + + std::optional GetOsDeviceName() const override; + api::DeviceInfo::DeviceType GetDeviceType() const override; + api::DeviceInfo::OsType GetOsType() const override { + return api::DeviceInfo::OsType::kWindows; // Or ChromeOS? + } + std::optional GetFullName() const override; + std::optional GetGivenName() const override { + return GetFullName(); + } + std::optional GetLastName() const override { + return GetFullName(); + } + std::optional GetProfileUserName() const override; + + std::optional GetDownloadPath() const override; + std::optional GetLocalAppDataPath() const override; + std::optional GetCommonAppDataPath() const override; + std::optional GetTemporaryPath() const override; + std::optional GetLogPath() const override; + std::optional GetCrashDumpPath() const override; + + bool IsScreenLocked() const override; + void RegisterScreenLockedListener( + absl::string_view listener_name, + std::function callback) override; + void UnregisterScreenLockedListener(absl::string_view listener_name) override; + + sd_bus *system_bus; +}; +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc new file mode 100644 index 00000000..11b37bcf --- /dev/null +++ b/internal/platform/implementation/linux/platform.cc @@ -0,0 +1,12 @@ +#include "internal/platform/implementation/platform.h" + +#include +#include + +namespace nearby { +namespace api { +namespace { + std::string ImplementationPlatform::GetCustomSavePath() +} +} // namespace api +} // namespace nearby From 112072dbadfc046ac0f66d35b485ab595acdc864 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 22 Jul 2023 20:16:26 +0530 Subject: [PATCH 006/201] Add additional methods for DeviceInfo. --- .../implementation/linux/device_info.cc | 90 +++++++++++++++++++ .../implementation/linux/device_info.h | 10 ++- 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 80fa2c30..6c398448 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -1,10 +1,13 @@ +#include #include #include #include #include #include + #include +#include #include "internal/platform/implementation/device_info.h" #include "internal/platform/implementation/linux/device_info.h" @@ -18,6 +21,10 @@ const char *HOSTNAME_DEST = "org.freedesktop.hostname1"; const char *HOSTNAME_PATH = "/org/freedesktop/hostname1"; const char *HOSTNAME_INTERFACE = "org.freedesktop.hostname1"; +const char *LOGIN_DEST = "org.freedesktop.login1"; +const char *LOGIN_PATH = "/org/freedesktop/login1/session/_"; +const char *LOGIN_INTERFACE = "org.freedesktop.login1.Session"; + std::optional DeviceInfo::GetOsDeviceName() const { sd_bus *bus = nullptr; if (sd_bus_default_system(&bus) < 0) { @@ -117,5 +124,88 @@ std::optional DeviceInfo::GetProfileUserName() const { char *name = strtok(pwd->pw_gecos, ","); return std::string(name); } + +std::optional DeviceInfo::GetDownloadPath() const { + char *dir = getenv("XDG_DOWNLOAD_DIR"); + if (dir == NULL) { + std::filesystem::path home_path(std::string(getenv("HOME"))); + return home_path / "Desktop"; + } + return std::filesystem::path(std::string(dir)); +} + +std::optional DeviceInfo::GetLocalAppDataPath() const { + char *dir = getenv("XDG_STATE_HOME"); + if (dir == NULL) { + return std::filesystem::path("/tmp"); + } + return std::filesystem::path(std::string(dir)) / "com.github.google.nearby"; +} + +std::optional DeviceInfo::GetTemporaryPath() const { + char *dir = getenv("XDG_CACHE_HOME"); + if (dir == NULL) { + return std::filesystem::path("/tmp"); + } + return std::filesystem::path(std::string(dir)) / "com.github.google.nearby"; +} + +std::optional DeviceInfo::GetLogPath() const { + char *dir = getenv("XDG_STATE_HOME"); + if (dir == NULL) { + return std::filesystem::path("/tmp"); + } + return std::filesystem::path(std::string(dir)) / "com.github.google.nearby" / + "logs"; +} + +std::optional DeviceInfo::GetCrashDumpPath() const { + char *dir = getenv("XDG_STATE_HOME"); + if (dir == NULL) { + return std::filesystem::path("/tmp"); + } + return std::filesystem::path(std::string(dir)) / "com.github.google.nearby" / + "crash"; +} + +bool DeviceInfo::IsScreenLocked() const { + char *session = nullptr; + if (sd_pid_get_session(getpid(), &session) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error getting session for current user"; + return false; + } + + sd_bus *bus; + if (sd_bus_default_system(&bus) < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; + free(session); + return false; + } + + std::string session_path(LOGIN_PATH); + session_path += session; + + free(session); + + sd_bus_error err = SD_BUS_ERROR_NULL; + bool locked; + + if (sd_bus_get_property_trivial(bus, LOGIN_DEST, session_path.c_str(), + LOGIN_INTERFACE, "LockedHint", &err, 'b', + &locked) < 0) { + + NEARBY_LOGS(ERROR) + << __func__ + << ": Error getting LockedState from org.freedesktop.login1: " + << err.message; + locked = false; + } + + sd_bus_error_free(&err); + sd_bus_unref(bus); + + return locked; +} } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 43cef077..3d001486 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -32,16 +32,20 @@ public: std::optional GetDownloadPath() const override; std::optional GetLocalAppDataPath() const override; - std::optional GetCommonAppDataPath() const override; + std::optional GetCommonAppDataPath() const override { + return std::nullopt; + }; std::optional GetTemporaryPath() const override; std::optional GetLogPath() const override; std::optional GetCrashDumpPath() const override; bool IsScreenLocked() const override; + // TODO: Implement listening to logind for changes to LockedState. void RegisterScreenLockedListener( absl::string_view listener_name, - std::function callback) override; - void UnregisterScreenLockedListener(absl::string_view listener_name) override; + std::function callback) override{}; + void + UnregisterScreenLockedListener(absl::string_view listener_name) override{}; sd_bus *system_bus; }; From 545646f63e8f9c3997948f2aac6702aee0314304 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 23 Jul 2023 19:01:14 +0530 Subject: [PATCH 007/201] Use cleanup attribute for freeing libsystemd resources. --- .../implementation/linux/device_info.cc | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 6c398448..c45bf230 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -26,13 +26,14 @@ const char *LOGIN_PATH = "/org/freedesktop/login1/session/_"; const char *LOGIN_INTERFACE = "org.freedesktop.login1.Session"; std::optional DeviceInfo::GetOsDeviceName() const { - sd_bus *bus = nullptr; + __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus = nullptr; if (sd_bus_default_system(&bus) < 0) { NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; return std::nullopt; } - sd_bus_error err = SD_BUS_ERROR_NULL; + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; char *hostname = nullptr; if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, @@ -52,15 +53,10 @@ std::optional DeviceInfo::GetOsDeviceName() const { << __func__ << ": Error getting Hostname from org.freedesktop.hostname1: " << err.message; - sd_bus_error_free(&err); - sd_bus_unref(bus); return std::nullopt; } } - sd_bus_error_free(&err); - sd_bus_unref(bus); - std::wstring_convert, char16_t> convert; std::u16string name = convert.from_bytes(hostname); @@ -69,12 +65,14 @@ std::optional DeviceInfo::GetOsDeviceName() const { } api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { - sd_bus *bus; + __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus; if (sd_bus_default_system(&bus) < 0) { NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; return api::DeviceInfo::DeviceType::kUnknown; } - sd_bus_error err = SD_BUS_ERROR_NULL; + + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; char *chasis = nullptr; if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, @@ -83,13 +81,9 @@ api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { NEARBY_LOGS(ERROR) << __func__ << ": Error getting Chasis from org.freedesktop.hostname1: " << err.message; - sd_bus_error_free(&err); - sd_bus_unref(bus); return api::DeviceInfo::DeviceType::kUnknown; } - sd_bus_unref(bus); - api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; if (strcmp(chasis, "phone") == 0) { @@ -165,7 +159,7 @@ std::optional DeviceInfo::GetCrashDumpPath() const { return std::filesystem::path("/tmp"); } return std::filesystem::path(std::string(dir)) / "com.github.google.nearby" / - "crash"; + "crashes"; } bool DeviceInfo::IsScreenLocked() const { @@ -176,7 +170,7 @@ bool DeviceInfo::IsScreenLocked() const { return false; } - sd_bus *bus; + __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus; if (sd_bus_default_system(&bus) < 0) { NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; free(session); @@ -188,7 +182,8 @@ bool DeviceInfo::IsScreenLocked() const { free(session); - sd_bus_error err = SD_BUS_ERROR_NULL; + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; bool locked; if (sd_bus_get_property_trivial(bus, LOGIN_DEST, session_path.c_str(), @@ -202,9 +197,6 @@ bool DeviceInfo::IsScreenLocked() const { locked = false; } - sd_bus_error_free(&err); - sd_bus_unref(bus); - return locked; } } // namespace linux From f9a62a24dca4ec5e9a1877f4fec4e72710738d4d Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 23 Jul 2023 19:01:50 +0530 Subject: [PATCH 008/201] Add bluetooth_adapter implementation. --- internal/platform/implementation/linux/BUILD | 14 ++ .../implementation/linux/bluetooth_adapter.cc | 161 ++++++++++++++++++ .../implementation/linux/bluetooth_adapter.h | 38 +++++ .../platform/implementation/linux/bluez.h | 13 ++ 4 files changed, 226 insertions(+) create mode 100644 internal/platform/implementation/linux/bluetooth_adapter.cc create mode 100644 internal/platform/implementation/linux/bluetooth_adapter.h create mode 100644 internal/platform/implementation/linux/bluez.h diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 5eb73e71..c57cff94 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -16,3 +16,17 @@ cc_library( ], ) +cc_library( + name = "linux", + hdrs = [ + "bluetooth_adapter.h", + "bluez.h" + ], + srcs = ["bluetooth_adapter.cc"], + deps = [ + "//internal/platform/implementation:types", + "//internal/platform:logging", + "@com_google_absl//absl/strings", + "@libsystemd//:lib", + ] +) diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc new file mode 100644 index 00000000..cc734974 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -0,0 +1,161 @@ +#include + +#include "internal/platform/implementation/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +using namespace api; + +bool BluetoothAdapter::SetStatus(Status status) { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + + if (sd_bus_set_property( + system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, + "Powered", &err, "b", + status == api::BluetoothAdapter::Status::kEnabled ? 1 : 0) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error setting adaptor status: " << err.message; + return false; + } + return true; +} + +bool BluetoothAdapter::IsEnabled() const { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + int enabled = 0; + + if (sd_bus_get_property_trivial(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b', + &enabled) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error getting adaptor status: " << err.message; + } + return enabled; +} + +BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + int powered = 0; + int discoverable = 0; + + if (sd_bus_get_property_trivial(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b', + &powered) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error getting adaptor status: " << err.message; + return ScanMode::kUnknown; + } + if (!powered) { + return ScanMode::kNone; + } + + if (sd_bus_get_property_trivial(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, + 'b', &powered) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error getting adaptor's discoverable status: " + << err.message; + return ScanMode::kUnknown; + } + return discoverable ? ScanMode::kConnectableDiscoverable + : ScanMode::kConnectable; +} + +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; + } + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + if (sd_bus_set_property(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, "b", + 1) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error setting adapter's discoverable status: " + << err.message; + return false; + } + return true; + } + case ScanMode::kNone: + return SetStatus(Status::kDisabled); + default: + return false; + } +} + +std::string BluetoothAdapter::GetName() const { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + char *cname = nullptr; + if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "Alias", &err, + &cname) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error getting adapter's name: " << err.message; + return std::string(); + } + std::string name(cname); + free(cname); + return name; +} + +bool BluetoothAdapter::SetName(absl::string_view name, bool persist) { + if (persist) { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + std::string pretty_hostname(name); + if (sd_bus_set_property(system_bus, "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", "PrettyHostname", &err, + "s", pretty_hostname.c_str()) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error setting PrettyHostname: " << err.message; + } + } + return SetName(name); +} + +bool BluetoothAdapter::SetName(absl::string_view name) { + std::string alias(name); + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + if (sd_bus_set_property(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "Alias", &err, "s", + alias.c_str()) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error setting adapter's name: " << err.message; + return false; + } + return true; +} + +std::string BluetoothAdapter::GetMacAddress() const { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + char *caddr = nullptr; + if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "Address", &err, + &caddr) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error getting adapter's name: " << err.message; + return std::string(); + } + std::string addr(caddr); + free(caddr); + return addr; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h new file mode 100644 index 00000000..0ca0facf --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -0,0 +1,38 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ + +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/bluetooth_adapter.h" +#include + +namespace nearby { +namespace linux { +class BluetoothAdapter : public api::BluetoothAdapter { +public: + ~BluetoothAdapter() override { + if (system_bus) { + sd_bus_unrefp(&system_bus); + } + }; + + 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; + +private: + sd_bus *system_bus; +}; +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h new file mode 100644 index 00000000..472885a1 --- /dev/null +++ b/internal/platform/implementation/linux/bluez.h @@ -0,0 +1,13 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUEZ_H_ +#define PLATFORM_IMPL_LINUX_BLUEZ_H_ + +namespace nearby { +namespace linux { +const char *BLUEZ_SERVICE = "org.bluez"; + +const char *BLUEZ_ADAPTER_INTERFACE = "org.bluez.Adapter1"; + +} // namespace linux +} // namespace nearby + +#endif From b66e7ff7350025165b8f57f7f7a708a974ace4d9 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 30 Jul 2023 02:10:58 +0530 Subject: [PATCH 009/201] More bluetooth medium code. --- .../linux/bluetooth_bluez_profile.cc | 107 +++++++++++ .../linux/bluetooth_bluez_profile.h | 58 ++++++ .../linux/bluetooth_classic_device.cc | 78 ++++++++ .../linux/bluetooth_classic_device.h | 34 ++++ .../linux/bluetooth_classic_medium.cc | 171 ++++++++++++++++++ .../linux/bluetooth_classic_medium.h | 99 ++++++++++ .../linux/bluetooth_classic_server_socket.h | 32 ++++ .../linux/bluetooth_classic_socket.cc | 68 +++++++ .../linux/bluetooth_classic_socket.h | 61 +++++++ .../implementation/linux/bluetooth_pairing.cc | 132 ++++++++++++++ .../implementation/linux/bluetooth_pairing.h | 33 ++++ .../platform/implementation/linux/bluez.h | 1 - 12 files changed, 873 insertions(+), 1 deletion(-) create mode 100644 internal/platform/implementation/linux/bluetooth_bluez_profile.cc create mode 100644 internal/platform/implementation/linux/bluetooth_bluez_profile.h create mode 100644 internal/platform/implementation/linux/bluetooth_classic_device.cc create mode 100644 internal/platform/implementation/linux/bluetooth_classic_device.h create mode 100644 internal/platform/implementation/linux/bluetooth_classic_medium.cc create mode 100644 internal/platform/implementation/linux/bluetooth_classic_medium.h create mode 100644 internal/platform/implementation/linux/bluetooth_classic_server_socket.h create mode 100644 internal/platform/implementation/linux/bluetooth_classic_socket.cc create mode 100644 internal/platform/implementation/linux/bluetooth_classic_socket.h create mode 100644 internal/platform/implementation/linux/bluetooth_pairing.cc create mode 100644 internal/platform/implementation/linux/bluetooth_pairing.h diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc new file mode 100644 index 00000000..a2b2c8cc --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -0,0 +1,107 @@ +#include +#include + +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" + +const char *BLUEZ_PROFILEMANAGER_INTERFACE = "org.bluez.ProfileManager1"; +static int profile_release(sd_bus_message *m, void *userdata, + sd_bus_error *error) { + // TODO +} +static int profile_new_connection(sd_bus_message *m, void *userdata, + sd_bus_error *error) { + // TODO +} +static int profile_new(sd_bus_message *m, void *userdata, sd_bus_error *error) { + // TODO +} + +static const sd_bus_vtable vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD_WITH_ARGS("Release", SD_BUS_NO_ARGS, SD_BUS_NO_RESULT, + profile_release, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS( + "NewConnection", SD_BUS_ARGS("o", path, "h", fd, "a{sq}", properties), + SD_BUS_NO_RESULT, profile_new_connection, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("RequestDisconnection", SD_BUS_ARGS("o", object), + SD_BUS_NO_RESULT, profile_new, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END}; + +namespace nearby { +namespace linux { +std::unique_ptr NewProfileManager() { + sd_bus *system_bus; + if (auto ret = sd_bus_default_system(&system_bus); ret < 0) { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + sd_bus_error_set_errno(&err, ret); + + NEARBY_LOGS(ERROR) << __func__ + << "Error connecting to system bus: " << err.name << ": " + << err.message; + return nullptr; + } + + sd_bus_slot *slot = nullptr; + auto manager = new ProfileManager(system_bus, slot); + + if (auto ret = sd_bus_add_object_vtable( + system_bus, &slot, "/com/github/google/nearby", "org.bluez.Profile1", + vtable, manager->GetMethodData()); + ret < 0) { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + sd_bus_error_set_errno(&err, ret); + + NEARBY_LOGS(ERROR) << __func__ + << "Error adding object /com/github/google/nearby: " + << err.name << ": " << err.message; + return nullptr; + } + + return std::unique_ptr(manager); +} + +bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { + registered_service_uuids_lock_.ReaderLock(); + bool registered = + registered_service_uuids_.count(std::string(service_uuid)) == 1; + registered_service_uuids_lock_.ReaderUnlock(); + return registered; +} + +bool ProfileManager::RegisterProfile(absl::string_view service_uuid) { + if (ProfileRegistered(service_uuid)) { + return true; + } + + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + std::string uuid(service_uuid); + + registered_service_uuids_lock_.Lock(); + if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez", + BLUEZ_PROFILEMANAGER_INTERFACE, "RegisterProfile", &err, + nullptr, "osa{sq}", "/com/github/google/nearby", + uuid.c_str(), 0, nullptr) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << "Error calling RegisterProfile: " << err.name << ": " + << err.message; + registered_service_uuids_lock_.Unlock(); + return false; + } + registered_service_uuids_.insert(uuid); + registered_service_uuids_lock_.Unlock(); + return true; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h new file mode 100644 index 00000000..ba7e6e3a --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -0,0 +1,58 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ + +#include +#include +#include +#include +#include + +#include + +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/bluetooth_classic.h" + +namespace nearby { +namespace linux { + +class ProfileManager { +public: + ProfileManager(sd_bus *system_bus, sd_bus_slot *slot) { + system_bus_ = system_bus; + slot_ = slot; + } + ~ProfileManager() { sd_bus_unref(system_bus_); } + + bool ProfileRegistered(absl::string_view service_uuid); + bool RegisterProfile(absl::string_view sevice_uuid); + + std::optional GetServiceRecordFD(api::BluetoothDevice &remote_device, + absl::string_view service_uuid); + +struct MethodData { + std::map>, int> &connections_; + absl::Mutex &connections_lock_; + }; + struct MethodData *GetMethodData() { return &data_; } + +private: + bool InitManagerObj(); + + // Maps (mac address, service uuid) tuples to FDs. Probably + // an awful way to do this, but whatever. + std::map>, int> connections_; + absl::Mutex connections_lock_; + + MethodData data_{connections_, connections_lock_}; + + std::set registered_service_uuids_; + absl::Mutex registered_service_uuids_lock_; + + sd_bus *system_bus_; + sd_bus_slot *slot_; +}; + +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc new file mode 100644 index 00000000..8f64ee2c --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -0,0 +1,78 @@ +#include + +#include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +BluetoothDevice::BluetoothDevice(absl::string_view adapter, + absl::string_view address) { + mac_addr_ = std::string(address); + object_path_ = absl::Substitute("/org/bluez/$0/dev_$1", adapter, + absl::StrReplaceAll(address, {{":", "_"}})); + if (sd_bus_default_system(&system_bus) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; + } +} + +BluetoothDevice::BluetoothDevice(absl::string_view device_object_path) { + if (sd_bus_default_system(&system_bus) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; + return; + } + + object_path_ = device_object_path; +} + +std::string BluetoothDevice::GetName() const { + if (!system_bus) { + return std::string(); + } + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + char *cname = nullptr; + if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE, + object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, + "Alias", &err, &cname) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error getting alias for device " + << object_path_ << " :" << err.message; + return std::string(); + } + + std::string name(cname); + free(cname); + return name; +} + +std::string BluetoothDevice::GetMacAddress() const { + if (!system_bus) { + return std::string(); + } + + if (!mac_addr_.empty()) { + return mac_addr_; + } + + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + char *c_addr = nullptr; + if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE, + object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, + "Address", &err, &c_addr) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error getting address for device " + << object_path_ << " :" << err.message; + return std::string(); + } + + std::string addr(c_addr); + free(c_addr); + return addr; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h new file mode 100644 index 00000000..fcdb1d5f --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -0,0 +1,34 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ + +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/bluetooth_classic.h" + +namespace nearby { +namespace linux { +const char *BLUEZ_DEVICE_INTERFACE = "org.bluez.Device1"; +// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. +class BluetoothDevice : public api::BluetoothDevice { +public: + BluetoothDevice(absl::string_view adapter, absl::string_view address); + BluetoothDevice(absl::string_view device_object_path); + + virtual ~BluetoothDevice() override { sd_bus_unref(system_bus); }; + + // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() + std::string GetName() const override; + + // Returns BT MAC address assigned to this device. + std::string GetMacAddress() const override; + +private: + sd_bus *system_bus; + std::string object_path_; + std::string mac_addr_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc new file mode 100644 index 00000000..713aa8cb --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -0,0 +1,171 @@ +#include + +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "absl/strings/str_replace.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_classic_medium.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, + sd_bus_error *ret_error) { + const sd_bus_error *reply_err = sd_bus_message_get_error(m); + if (reply_err) { + NEARBY_LOGS(ERROR) << __func__ + << "Received error while listening for InterfacesAdded: " + << reply_err->message; + return 0; + } + + struct BluetoothClassicMedium::DiscoveryParams *params = + static_cast(userdata); + char *c_object_path = nullptr; + int ret = sd_bus_message_read(m, "o", &c_object_path); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << "Error reading object path from message: " << ret; + return ret; + } + + std::string object_path(c_object_path); + + if (!absl::StrContains(object_path, absl::StrCat(params->adapter_object_path, + "/", "dev_"))) { + // Interface added for an object we dont care about. + return 0; + } + + if (params->devices_by_path.count(object_path) != 0) { + // Object already exists + return 0; + } + + ret = sd_bus_message_enter_container(m, 'a', "{sa{sv}}"); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error entering container: " << ret; + return 0; + } + + while (true) { + const char *interface_name = nullptr; + ret = sd_bus_message_read(m, "s", &interface_name); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error reading dict entry: " << ret; + } + if (ret == 0) + break; + + if (strcmp(interface_name, "org.bluez.Device1") == 0) { + NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " + << c_object_path; + auto bluetoothDevice = + std::make_unique(BluetoothDevice(object_path)); + params->devices_by_path[object_path] = std::move(bluetoothDevice); + + if (params->cb.device_discovered_cb != nullptr) { + params->cb.device_discovered_cb(*params->devices_by_path[object_path]); + } + for (auto &observer : params->observers_.GetObservers()) { + observer->DeviceAdded(*params->devices_by_path[object_path]); + } + return 0; + } + } + + return 0; +} + +BluetoothClassicMedium::BluetoothClassicMedium(absl::string_view adapter) { + if (sd_bus_default_system(&system_bus_) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; + } + adapter_object_path_ = absl::Substitute("/org/bluez/$0/", adapter); +} + +BluetoothClassicMedium::~BluetoothClassicMedium() { + if (system_bus_) + sd_bus_unref(system_bus_); + if (system_bus_slot_) + sd_bus_slot_unref(system_bus_slot_); +} + +bool BluetoothClassicMedium::StartDiscovery( + DiscoveryCallback discovery_callback) { + if (!system_bus_) + return false; + + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = + nullptr; + + discovery_params_.cb = std::move(discovery_callback); + discovery_params_.adapter_object_path = adapter_object_path_; + + sd_bus_match_signal(system_bus_, &system_bus_slot_, BLUEZ_SERVICE, "/", + "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", + bluez_interfaces_added_signal_handler, + &discovery_params_); + + if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, + adapter_object_path_.c_str(), BLUEZ_ADAPTER_INTERFACE, + "StartDiscovery", &err, &reply, nullptr) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error calling StartDiscovery on adapter " + << adapter_object_path_ << ": " << err.message; + return false; + } + + return true; +} + +bool BluetoothClassicMedium::StopDiscovery() { + if (!system_bus_) + return false; + + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = + nullptr; + + int ret = sd_bus_call_method( + system_bus_, BLUEZ_SERVICE, adapter_object_path_.c_str(), + BLUEZ_ADAPTER_INTERFACE, "StopDiscovery", &err, &reply, nullptr); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error calling StopDiscovery on " + << adapter_object_path_ << ": " << err.message; + return false; + } + const sd_bus_error *m_err = sd_bus_message_get_error(reply); + + if (m_err) { + NEARBY_LOGS(ERROR) << __func__ << "Error calling StopDiscovery on " + << adapter_object_path_ << ": " << err.message; + return false; + } + + return true; +} + +std::unique_ptr +BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, + const std::string &service_uuid, + CancellationFlag *cancellation_flag) { + auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress()); + +} + +std::string +BluetoothClassicMedium::GetDeviceObjectPath(absl::string_view mac_address) { + return absl::Substitute("$0/dev_$1", adapter_object_path_, absl::StrReplaceAll(mac_address, {{":", "_"}})); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h new file mode 100644 index 00000000..84b3cca2 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -0,0 +1,99 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_ + +#include +#include + +#include + +#include "internal/base/observer_list.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" + +namespace nearby { +namespace linux { +// Container of operations that can be performed over the Bluetooth Classic +// medium. +class BluetoothClassicMedium : public api::BluetoothClassicMedium { +public: + BluetoothClassicMedium(absl::string_view adapter); + ~BluetoothClassicMedium(); + + // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() + // + // Returns true once the process of discovery has been initiated. + bool StartDiscovery(DiscoveryCallback discovery_callback) override; + // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#cancelDiscovery() + // + // Returns true once discovery is well and truly stopped; after this returns, + // there must be no more invocations of the DiscoveryCallback passed in to + // StartDiscovery(). + bool StopDiscovery() override; + + // A combination of + // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createInsecureRfcommSocketToServiceRecord + // followed by + // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#connect(). + // + // service_uuid is the canonical textual representation + // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Format) of a + // type 3 name-based + // (https://en.wikipedia.org/wiki/Universally_unique_identifier#Versions_3_and_5_(namespace_name-based)) + // UUID. + // + // On success, returns a new BluetoothSocket. + // On error, returns nullptr. + std::unique_ptr + 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 + 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 + CreatePairing(api::BluetoothDevice &remote_device) override; + + api::BluetoothDevice * + GetRemoteDevice(const std::string &mac_address) override; + + void AddObserver(Observer *observer) override; + void RemoveObserver(Observer *observer) override; + + struct DiscoveryParams { + std::string &adapter_object_path; + std::map> &devices_by_path; + ObserverList &observers_; + BluetoothClassicMedium::DiscoveryCallback cb; + }; + +private: + std::string GetDeviceObjectPath(absl::string_view mac_address); + + sd_bus *system_bus_ = nullptr; + sd_bus_slot *system_bus_slot_ = nullptr; + std::string adapter_object_path_ = std::string(); + std::map> devices_by_id_; + ObserverList observers_; + + DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_id_, observers_}; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h new file mode 100644 index 00000000..1361557c --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -0,0 +1,32 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_ + +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/exception.h" + +namespace nearby { +namespace linux { +class BluetoothServerSocket : api::BluetoothServerSocket { +public: + ~BluetoothServerSocket() = default; + + // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept() + // + // Blocks until either: + // - at least one incoming connection request is available, or + // - ServerSocket is closed. + // On success, returns connected socket, ready to exchange data. + // Returns nullptr on error. + // Once error is reported, it is permanent, and ServerSocket has to be + // closed. + std::unique_ptr Accept() override; + + // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close() + // + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + Exception Close() override; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc new file mode 100644 index 00000000..c1552ea0 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/bluetooth_classic_socket.h" + +namespace nearby { +namespace linux { + +ExceptionOr BluetoothInputStream::Read(std::int64_t size) { + char *data = new char[size]; + ssize_t ret = read(fd_, data, size); + if (ret == 0) { + delete[] data; + return ExceptionOr(ByteArray()); + } else if (ret < 0) { + delete[] data; + return Exception::kIo; + } + + return ExceptionOr(ByteArray(data, size)); +} + +ExceptionOr BluetoothInputStream::Skip(std::size_t offset) { + auto off = lseek(fd_, offset, SEEK_CUR); + if (off != offset) { + auto end = lseek(fd_, 0, SEEK_END); + return off == end ? ExceptionOr((std::size_t)off) : Exception::kIo; + } + return ExceptionOr((std::size_t)(off)); +} + +ExceptionOr BluetoothInputStream::ReadExactly(std::size_t size) { + char *data = new char[size]; + ssize_t ret = read(fd_, data, size); + if (ret < 0) { + delete[] data; + return Exception::kIo; + } + + return ExceptionOr(ByteArray(data, size)); +} + +Exception BluetoothOutputStream::Write(const ByteArray &data) { + ssize_t written = 0; + while (written < data.size()) { + ssize_t ret = write(fd_, data.data(), data.size()); + if (ret < 1) { + return Exception{Exception::kIo}; + } + written += ret; + } + return Exception{Exception::kSuccess}; +} + +Exception BluetoothOutputStream::Flush() { + return Exception{Exception::kSuccess}; +} + +Exception BluetoothOutputStream::Close() { + return close(fd_) < 0 ? Exception{Exception::kIo} + : Exception{Exception::kSuccess}; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h new file mode 100644 index 00000000..d7384b80 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -0,0 +1,61 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_ + +#include + +#include + +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/bluetooth_classic.h" + +namespace nearby { +namespace linux { + +class BluetoothInputStream : public InputStream { +public: + BluetoothInputStream(int fd) { fd_ = fd; }; + + ExceptionOr Read(std::int64_t size) override; + ExceptionOr Skip(size_t offset) override; + ExceptionOr ReadExactly(std::size_t size); + + Exception Close() override; + +private: + int fd_; +}; + +class BluetoothOutputStream : public OutputStream { +public: + BluetoothOutputStream(int fd) { fd_ = fd; }; + + Exception Write(const ByteArray &data) override; + Exception Flush() override; + Exception Close() override; + +private: + int fd_; +}; + +class BluetoothSocket : public api::BluetoothSocket { +public: + BluetoothSocket(std::string object, int fd) { + fd_ = fd; + object_ = object; + input_stream_ = BluetoothInputStream(fd_); + output_stream_ = BluetoothOutputStream(fd_); + } + + InputStream &GetInputStream() override { return input_stream_; } + OutputStream &GetOutputStream() override { return output_stream_; } + +private: + int fd_; + std::string object_; + BluetoothInputStream input_stream_ = {-1}; + BluetoothOutputStream output_stream_ = {-1}; +}; +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc new file mode 100644 index 00000000..e2007b4e --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -0,0 +1,132 @@ +#include +#include + +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_pairing.h" +#include "internal/platform/implementation/linux/bluez.h" + +namespace nearby { +namespace linux { + +int pairing_reply_handler(sd_bus_message *m, void *userdata, + sd_bus_error *err) { + auto pairing_cb = static_cast(userdata); + if (sd_bus_message_is_method_error(m, nullptr)) { + if (sd_bus_message_is_method_error( + m, "org.bluez.Error.AuthenticationCanceled")) { + pairing_cb->on_pairing_error_cb( + api::BluetoothPairingCallback::PairingError::kAuthCanceled); + } else if (sd_bus_message_is_method_error( + m, "org.bluez.Error.AuthenticationFailed")) { + pairing_cb->on_pairing_error_cb( + api::BluetoothPairingCallback::PairingError::kAuthFailed); + } else if (sd_bus_message_is_method_error( + m, "org.bluez.Error.AuthenticationRejected")) { + pairing_cb->on_pairing_error_cb( + api::BluetoothPairingCallback::PairingError::kAuthRejected); + } else if (sd_bus_message_is_method_error( + m, "org.bluez.Error.AuthenticationTimeout")) { + pairing_cb->on_pairing_error_cb( + api::BluetoothPairingCallback::PairingError::kAuthTimeout); + } else { + pairing_cb->on_pairing_error_cb( + api::BluetoothPairingCallback::PairingError::kAuthFailed); + } + return 0; + } + if (err) { + NEARBY_LOGS(ERROR) << __func__ + << "Error pairing with device: " << err->message; + pairing_cb->on_pairing_error_cb( + api::BluetoothPairingCallback::PairingError::kUnknown); + } else { + pairing_cb->on_paired_cb(); + } + return 0; +} + +BluetoothPairing::BluetoothPairing(absl::string_view object_path) { + object_path_ = object_path; + if (sd_bus_default_system(&system_bus_) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; + } +} + +bool BluetoothPairing::InitiatePairing( + api::BluetoothPairingCallback pairing_cb) { + if (!system_bus_) + return false; + + pairing_cb_ = std::move(pairing_cb); + + if (sd_bus_call_method_async(system_bus_, nullptr, BLUEZ_SERVICE, + object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, + "Pair", &pairing_reply_handler, &pairing_cb_, + nullptr) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error calling method Pair on device " + << object_path_; + return false; + } + pairing_cb.on_pairing_initiated_cb(api::PairingParams{ + api::PairingParams::PairingType::kConsent, std::string()}); + return true; +} + +bool BluetoothPairing::FinishPairing( + std::optional pin_code) { + return true; +} + +bool BluetoothPairing::CancelPairing() { + if (!system_bus_) + return false; + + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, object_path_.c_str(), + BLUEZ_DEVICE_INTERFACE, "CancelPairing", &err, nullptr, + nullptr)) { + NEARBY_LOGS(ERROR) << __func__ + << "Error calling method CancelPairing on device " + << object_path_ << ": " << err.message; + return false; + } + return true; +} + +bool BluetoothPairing::Unpair() { + if (!system_bus_) + return false; + + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "RemoveDevice", &err, nullptr, + "o", object_path_.c_str())) { + NEARBY_LOGS(ERROR) << __func__ + << "Error calling method CancelPairing on device " + << object_path_ << ": " << err.message; + return false; + } + return true; +} + +bool BluetoothPairing::IsPaired() { + if (!system_bus_) + return false; + + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + int paired = 0; + if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, + object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, + "Bonded", &err, 'b', &paired) < 0) { + NEARBY_LOGS(ERROR) << __func__ + << "Error getting Bonded property for device " + << object_path_ << ": " << err.message; + } + return paired; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h new file mode 100644 index 00000000..3e5ee4e4 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -0,0 +1,33 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PROFILE_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_ + +#include + +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +class BluetoothPairing : public api::BluetoothPairing { +public: + BluetoothPairing(absl::string_view object_path); + ~BluetoothPairing() { sd_bus_unref(system_bus_); } + + bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; + bool FinishPairing(std::optional pin_code) override; + bool CancelPairing() override; + bool Unpair() override; + bool IsPaired() override; + +private: + std::string object_path_; + sd_bus *system_bus_; + api::BluetoothPairingCallback pairing_cb_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 472885a1..50316c95 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -4,7 +4,6 @@ namespace nearby { namespace linux { const char *BLUEZ_SERVICE = "org.bluez"; - const char *BLUEZ_ADAPTER_INTERFACE = "org.bluez.Adapter1"; } // namespace linux From b5552e268cdeed6a8fa066bb13e862c5af1ae31e Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 1 Aug 2023 18:22:46 +0530 Subject: [PATCH 010/201] Add BluetoothServerSocket implementation. --- .../linux/bluetoth_classic_server_socket.cc | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 internal/platform/implementation/linux/bluetoth_classic_server_socket.cc diff --git a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc new file mode 100644 index 00000000..efe5dcac --- /dev/null +++ b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc @@ -0,0 +1,47 @@ +#include "absl/strings/str_replace.h" +#include "absl/strings/substitute.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_server_socket.h" +#include "internal/platform/implementation/linux/bluetooth_classic_socket.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" +#include + +namespace nearby { +namespace linux { +std::unique_ptr BluetoothServerSocket::Accept() { + auto pair = profile_manager_.GetServiceRecordFD(service_uuid_); + if (!pair.has_value()) { + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get a new connection for profile " + << service_uuid_ << " for device "; + return nullptr; + } + auto device_object_path = + absl::Substitute("$0/dev_$1", adapter_object_path_, + absl::StrReplaceAll(pair->first, {{":", "_"}})); + auto device = BluetoothDevice(sd_bus_ref(system_bus_), device_object_path); + return std::unique_ptr(new BluetoothSocket( + device, device_object_path, service_uuid_, pair->second)); +} + +Exception BluetoothServerSocket::Close() { + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + auto profile_object_path = + absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid_); + + if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez", + "org.bluez.ProfileManager1", "UnregisterProfile", &err, + nullptr, "o", profile_object_path.c_str()) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error unregistering profile object " + << profile_object_path << ": " << err.message; + return {Exception::kFailed}; + } + + return {Exception::kSuccess}; +} +} // namespace linux +} // namespace nearby From b5ba24bc0605e069f5a450fe949c7bd3478a2ffb Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 1 Aug 2023 18:27:05 +0530 Subject: [PATCH 011/201] Add additional code for implementing BluetoothClassicMedium. --- .../linux/bluetooth_bluez_profile.cc | 169 +++++++++++++----- .../linux/bluetooth_bluez_profile.h | 45 ++--- .../linux/bluetooth_classic_device.cc | 34 ++-- .../linux/bluetooth_classic_device.h | 13 +- .../linux/bluetooth_classic_medium.cc | 88 +++++++-- .../linux/bluetooth_classic_medium.h | 18 +- .../linux/bluetooth_classic_server_socket.h | 19 +- .../linux/bluetooth_classic_socket.cc | 32 ++++ .../linux/bluetooth_classic_socket.h | 14 +- .../implementation/linux/bluetooth_pairing.cc | 37 ++-- .../implementation/linux/bluetooth_pairing.h | 7 +- 11 files changed, 332 insertions(+), 144 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index a2b2c8cc..afb7d1a9 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -1,26 +1,67 @@ +#include #include #include +#include +#include +#include +#include #include #include +#include "absl/strings/substitute.h" #include "absl/synchronization/mutex.h" -#include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" const char *BLUEZ_PROFILEMANAGER_INTERFACE = "org.bluez.ProfileManager1"; + +namespace nearby { +namespace linux { static int profile_release(sd_bus_message *m, void *userdata, sd_bus_error *error) { - // TODO + return 0; } static int profile_new_connection(sd_bus_message *m, void *userdata, sd_bus_error *error) { - // TODO + char *c_device_object = nullptr; + int fd = 0, ret; + + ret = sd_bus_message_read(m, "oh", &c_device_object, &fd); + if (ret < 0) { + return ret; + } + + std::string device_object(c_device_object); + fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (fd < 0) { + return sd_bus_error_set_errno(error, errno); + } + + sd_bus *bus; + sd_bus_default_system(&bus); + + BluetoothDevice device(bus, device_object); + auto mac_addr = device.GetMacAddress(); + if (mac_addr.empty()) { + return -1; + } + + struct RegisteredService *service = + static_cast(userdata); + service->connections_lock.Lock(); + service->connections[mac_addr] = fd; + service->connections_lock.Unlock(); + + return 0; } -static int profile_new(sd_bus_message *m, void *userdata, sd_bus_error *error) { + +static int profile_request_disconnection(sd_bus_message *m, void *userdata, + sd_bus_error *error) { // TODO + return 0; } static const sd_bus_vtable vtable[] = { @@ -31,54 +72,19 @@ static const sd_bus_vtable vtable[] = { "NewConnection", SD_BUS_ARGS("o", path, "h", fd, "a{sq}", properties), SD_BUS_NO_RESULT, profile_new_connection, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_ARGS("RequestDisconnection", SD_BUS_ARGS("o", object), - SD_BUS_NO_RESULT, profile_new, + SD_BUS_NO_RESULT, profile_request_disconnection, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END}; -namespace nearby { -namespace linux { -std::unique_ptr NewProfileManager() { - sd_bus *system_bus; - if (auto ret = sd_bus_default_system(&system_bus); ret < 0) { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - sd_bus_error_set_errno(&err, ret); - - NEARBY_LOGS(ERROR) << __func__ - << "Error connecting to system bus: " << err.name << ": " - << err.message; - return nullptr; - } - - sd_bus_slot *slot = nullptr; - auto manager = new ProfileManager(system_bus, slot); - - if (auto ret = sd_bus_add_object_vtable( - system_bus, &slot, "/com/github/google/nearby", "org.bluez.Profile1", - vtable, manager->GetMethodData()); - ret < 0) { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - sd_bus_error_set_errno(&err, ret); - - NEARBY_LOGS(ERROR) << __func__ - << "Error adding object /com/github/google/nearby: " - << err.name << ": " << err.message; - return nullptr; - } - - return std::unique_ptr(manager); -} - bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { registered_service_uuids_lock_.ReaderLock(); - bool registered = - registered_service_uuids_.count(std::string(service_uuid)) == 1; + bool registered = registered_services_.count(std::string(service_uuid)) == 1; registered_service_uuids_lock_.ReaderUnlock(); return registered; } -bool ProfileManager::RegisterProfile(absl::string_view service_uuid) { +bool ProfileManager::RegisterProfile(absl::string_view name, + absl::string_view service_uuid) { if (ProfileRegistered(service_uuid)) { return true; } @@ -87,21 +93,90 @@ bool ProfileManager::RegisterProfile(absl::string_view service_uuid) { SD_BUS_ERROR_NULL; std::string uuid(service_uuid); + auto profile_object_path = + absl::Substitute("/com/github/google/nearby/profiles/$0", uuid); + struct RegisteredService *service = new struct RegisteredService(uuid); + service->slot = nullptr; + registered_service_uuids_lock_.Lock(); + auto ret = sd_bus_add_object_vtable(system_bus_, &service->slot, + profile_object_path.c_str(), + "org.bluez.Profile1", vtable, service); + if (ret < 0) { + sd_bus_error_set_errno(&err, ret); + + NEARBY_LOGS(ERROR) << __func__ << "Error adding object " + << profile_object_path << ": " << err.message; + registered_service_uuids_lock_.Unlock(); + return false; + } + + NEARBY_LOGS(VERBOSE) << __func__ + << "Registered a ProfileManager for service UUID " + << uuid << " at " << profile_object_path; + if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez", - BLUEZ_PROFILEMANAGER_INTERFACE, "RegisterProfile", &err, - nullptr, "osa{sq}", "/com/github/google/nearby", - uuid.c_str(), 0, nullptr) < 0) { + BLUEZ_PROFILEMANAGER_INTERFACE, "RegisterProfile", + &err, nullptr, "osa{sq}", "/com/github/google/nearby", + uuid.c_str(), 1, "Name", + std::string(name).c_str()) < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error calling RegisterProfile: " << err.name << ": " << err.message; registered_service_uuids_lock_.Unlock(); return false; } - registered_service_uuids_.insert(uuid); + + registered_services_[uuid] = service; registered_service_uuids_lock_.Unlock(); return true; } +std::optional +ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device, + absl::string_view service_uuid) { + if (!ProfileRegistered(service_uuid)) { + return std::nullopt; + } + + auto mac_addr = remote_device.GetMacAddress(); + + registered_service_uuids_lock_.ReaderLock(); + auto service = registered_services_[std::string(service_uuid)]; + registered_service_uuids_lock_.ReaderUnlock(); + + service->connections_lock.Lock(); + auto cond = [mac_addr, service]() { + return service->connections.count(mac_addr) == 1; + }; + service->connections_lock.Await(absl::Condition(&cond)); + int fd = service->connections[mac_addr]; + service->connections.erase(mac_addr); + service->connections_lock.Unlock(); + + return fd; +} + +std::optional> +ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { + if (!ProfileRegistered(service_uuid)) { + return std::nullopt; + } + + registered_service_uuids_lock_.ReaderLock(); + auto service = registered_services_[std::string(service_uuid)]; + registered_service_uuids_lock_.ReaderUnlock(); + service->connections_lock.Lock(); + auto cond = [service]() { return !service->connections.empty(); }; + service->connections_lock.Await(absl::Condition(&cond)); + auto it = service->connections.begin(); + auto mac_addr = it->first; + auto fd = it->second; + service->connections.erase(it); + service->connections_lock.Unlock(); + + return std::pair(mac_addr, fd); +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index ba7e6e3a..b579ddbc 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -1,11 +1,13 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ +#include #include #include #include #include #include +#include #include @@ -16,41 +18,40 @@ namespace nearby { namespace linux { +struct RegisteredService { +public: + sd_bus_slot *slot; + absl::Mutex connections_lock; + // Maps mac addresses to unclaimed FDs. Probably an awful way to do this, but + // whatever. + std::map connections; + std::string &uuid; + RegisteredService(std::string &uuid) : uuid(uuid) {} +}; + class ProfileManager { public: - ProfileManager(sd_bus *system_bus, sd_bus_slot *slot) { - system_bus_ = system_bus; - slot_ = slot; - } + ProfileManager(sd_bus *system_bus) { system_bus_ = system_bus; } ~ProfileManager() { sd_bus_unref(system_bus_); } bool ProfileRegistered(absl::string_view service_uuid); - bool RegisterProfile(absl::string_view sevice_uuid); + bool RegisterProfile(absl::string_view service_name, + absl::string_view service_uuid); + bool RegisterProfile(absl::string_view service_uuid) { + return RegisterProfile("", service_uuid); + } std::optional GetServiceRecordFD(api::BluetoothDevice &remote_device, absl::string_view service_uuid); - -struct MethodData { - std::map>, int> &connections_; - absl::Mutex &connections_lock_; - }; - struct MethodData *GetMethodData() { return &data_; } + std::optional> + GetServiceRecordFD(absl::string_view service_uuid); private: - bool InitManagerObj(); - - // Maps (mac address, service uuid) tuples to FDs. Probably - // an awful way to do this, but whatever. - std::map>, int> connections_; - absl::Mutex connections_lock_; - - MethodData data_{connections_, connections_lock_}; - - std::set registered_service_uuids_; + // Maps service UUIDs to RegisteredService + std::map registered_services_; absl::Mutex registered_service_uuids_lock_; sd_bus *system_bus_; - sd_bus_slot *slot_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 8f64ee2c..cda7e74a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -10,33 +10,25 @@ namespace nearby { namespace linux { -BluetoothDevice::BluetoothDevice(absl::string_view adapter, +BluetoothDevice::BluetoothDevice(sd_bus *system_bus, absl::string_view adapter, absl::string_view address) { mac_addr_ = std::string(address); object_path_ = absl::Substitute("/org/bluez/$0/dev_$1", adapter, absl::StrReplaceAll(address, {{":", "_"}})); - if (sd_bus_default_system(&system_bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; - } + system_bus_ = system_bus; } -BluetoothDevice::BluetoothDevice(absl::string_view device_object_path) { - if (sd_bus_default_system(&system_bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; - return; - } - - object_path_ = device_object_path; +BluetoothDevice::BluetoothDevice(sd_bus *system_bus, + absl::string_view device_object_path) { + system_bus_ = system_bus; + object_path_ = device_object_path; } std::string BluetoothDevice::GetName() const { - if (!system_bus) { - return std::string(); - } __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; char *cname = nullptr; - if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE, + if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, "Alias", &err, &cname) < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error getting alias for device " @@ -50,29 +42,25 @@ std::string BluetoothDevice::GetName() const { } std::string BluetoothDevice::GetMacAddress() const { - if (!system_bus) { - return std::string(); - } - if (!mac_addr_.empty()) { return mac_addr_; } - + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; char *c_addr = nullptr; - if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE, + if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, "Address", &err, &c_addr) < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error getting address for device " << object_path_ << " :" << err.message; return std::string(); } - + std::string addr(c_addr); free(c_addr); return addr; } - + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index fcdb1d5f..098abc03 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -12,19 +12,20 @@ const char *BLUEZ_DEVICE_INTERFACE = "org.bluez.Device1"; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. class BluetoothDevice : public api::BluetoothDevice { public: - BluetoothDevice(absl::string_view adapter, absl::string_view address); - BluetoothDevice(absl::string_view device_object_path); - - virtual ~BluetoothDevice() override { sd_bus_unref(system_bus); }; + BluetoothDevice(sd_bus *system_bus, absl::string_view adapter, + absl::string_view address); + BluetoothDevice(sd_bus *system_bus, absl::string_view device_object_path); + + ~BluetoothDevice() override { sd_bus_unref(system_bus_); }; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() std::string GetName() const override; // Returns BT MAC address assigned to this device. std::string GetMacAddress() const override; - + private: - sd_bus *system_bus; + sd_bus *system_bus_; std::string object_path_; std::string mac_addr_; }; diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 713aa8cb..e53fa850 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -3,12 +3,16 @@ #include #include +#include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" -#include "absl/strings/str_replace.h" #include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_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/implementation/linux/bluez.h" #include "internal/platform/logging.h" @@ -65,9 +69,12 @@ int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, if (strcmp(interface_name, "org.bluez.Device1") == 0) { NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " - << c_object_path; - auto bluetoothDevice = - std::make_unique(BluetoothDevice(object_path)); + << object_path; + sd_bus *system_bus = nullptr; + sd_bus_default_system(&system_bus); + + auto bluetoothDevice = std::make_unique( + BluetoothDevice(system_bus, object_path)); params->devices_by_path[object_path] = std::move(bluetoothDevice); if (params->cb.device_discovered_cb != nullptr) { @@ -83,16 +90,15 @@ int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, return 0; } -BluetoothClassicMedium::BluetoothClassicMedium(absl::string_view adapter) { - if (sd_bus_default_system(&system_bus_) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; - } +BluetoothClassicMedium::BluetoothClassicMedium(sd_bus *system_bus, + absl::string_view adapter) + : profile_manager_(sd_bus_ref(system_bus)) { + system_bus_ = system_bus; adapter_object_path_ = absl::Substitute("/org/bluez/$0/", adapter); } BluetoothClassicMedium::~BluetoothClassicMedium() { - if (system_bus_) - sd_bus_unref(system_bus_); + sd_bus_unref(system_bus_); if (system_bus_slot_) sd_bus_slot_unref(system_bus_slot_); } @@ -159,12 +165,70 @@ BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, const std::string &service_uuid, CancellationFlag *cancellation_flag) { auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress()); - + if (!profile_manager_.ProfileRegistered(service_uuid)) { + if (!profile_manager_.RegisterProfile(service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << "Could not register profile " + << service_uuid << " with Bluez"; + return nullptr; + } + } + auto fd = profile_manager_.GetServiceRecordFD(remote_device, service_uuid); + if (!fd.has_value()) { + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get a new connection for profile " + << service_uuid << " for device " << device_object_path; + return nullptr; + } + + return std::unique_ptr(new BluetoothSocket( + remote_device, device_object_path, service_uuid, fd.value())); +} + +std::unique_ptr +BluetoothClassicMedium::ListenForService(const std::string &service_name, + const std::string &service_uuid) { + if (!profile_manager_.ProfileRegistered(service_uuid)) { + if (!profile_manager_.RegisterProfile(service_name, service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << "Could not register profile " + << service_name << " " << service_uuid + << " with Bluez"; + return nullptr; + } + } + + auto pair = profile_manager_.GetServiceRecordFD(service_uuid); + if (!pair.has_value()) { + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get a new connection for profile " + << service_uuid << " for device "; + return nullptr; + } + + auto device_object_path = GetDeviceObjectPath(pair->first); + auto device = BluetoothDevice(sd_bus_ref(system_bus_), device_object_path); + + return std::unique_ptr( + new BluetoothServerSocket(sd_bus_ref(system_bus_), profile_manager_, + adapter_object_path_, service_uuid)); +} + +api::BluetoothDevice * +BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { + return new BluetoothDevice(sd_bus_ref(system_bus_), + GetDeviceObjectPath(mac_address)); +} + +std::unique_ptr +BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) { + auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress()); + return std::unique_ptr( + new BluetoothPairing(sd_bus_ref(system_bus_), device_object_path)); } std::string BluetoothClassicMedium::GetDeviceObjectPath(absl::string_view mac_address) { - return absl::Substitute("$0/dev_$1", adapter_object_path_, absl::StrReplaceAll(mac_address, {{":", "_"}})); + return absl::Substitute("$0/dev_$1", adapter_object_path_, + absl::StrReplaceAll(mac_address, {{":", "_"}})); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 84b3cca2..1fd6886c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -8,6 +8,7 @@ #include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" namespace nearby { @@ -16,7 +17,7 @@ namespace linux { // medium. class BluetoothClassicMedium : public api::BluetoothClassicMedium { public: - BluetoothClassicMedium(absl::string_view adapter); + BluetoothClassicMedium(sd_bus *system_bus, absl::string_view adapter); ~BluetoothClassicMedium(); // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() @@ -72,8 +73,12 @@ public: api::BluetoothDevice * GetRemoteDevice(const std::string &mac_address) override; - void AddObserver(Observer *observer) override; - void RemoveObserver(Observer *observer) override; + void AddObserver(Observer *observer) override { + observers_.AddObserver(observer); + }; + void RemoveObserver(Observer *observer) override { + observers_.RemoveObserver(observer); + }; struct DiscoveryParams { std::string &adapter_object_path; @@ -83,15 +88,18 @@ public: }; private: + ProfileManager profile_manager_; + std::string GetDeviceObjectPath(absl::string_view mac_address); - + sd_bus *system_bus_ = nullptr; sd_bus_slot *system_bus_slot_ = nullptr; std::string adapter_object_path_ = std::string(); std::map> devices_by_id_; ObserverList observers_; - DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_id_, observers_}; + DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_id_, + observers_}; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h index 1361557c..ce0f2e7d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -1,13 +1,22 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_SERVER_SOCKET_H_ -#include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/exception.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" namespace nearby { namespace linux { -class BluetoothServerSocket : api::BluetoothServerSocket { +class BluetoothServerSocket : public api::BluetoothServerSocket { public: + BluetoothServerSocket(sd_bus *system_bus, ProfileManager &profile_manager, + absl::string_view adapter_object_path, + absl::string_view service_uuid) + : profile_manager_(profile_manager) { + system_bus_ = system_bus; + adapter_object_path_ = adapter_object_path; + service_uuid_ = service_uuid; + } ~BluetoothServerSocket() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept() @@ -25,6 +34,12 @@ public: // // Returns Exception::kIo on error, Exception::kSuccess otherwise. Exception Close() override; + +private: + sd_bus *system_bus_; + ProfileManager &profile_manager_; + std::string adapter_object_path_; + std::string service_uuid_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index c1552ea0..4ef2bade 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -3,9 +3,14 @@ #include #include +#include + #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" namespace nearby { namespace linux { @@ -64,5 +69,32 @@ Exception BluetoothOutputStream::Close() { return close(fd_) < 0 ? Exception{Exception::kIo} : Exception{Exception::kSuccess}; } + +Exception BluetoothSocket::Close() { + __attribute__((cleanup(sd_bus_unrefp))) sd_bus *system_bus = NULL; + __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = + SD_BUS_ERROR_NULL; + + if (auto ret = sd_bus_default_system(&system_bus); ret < 0) { + sd_bus_error_set_errno(&err, ret); + NEARBY_LOGS(ERROR) << __func__ + << "Error connecting to system bus: " << err.name << ": " + << err.message; + return Exception{Exception::kFailed}; + } + + if (sd_bus_call_method(system_bus, BLUEZ_SERVICE, device_object_path_.c_str(), + BLUEZ_DEVICE_INTERFACE, "DisconnectProfile", &err, + nullptr, "s", connected_profile_uuid_.c_str()) < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error disconnecting from profile " + << connected_profile_uuid_ << " on device " + << device_object_path_ << ": " << err.name << ": " + << err.message; + return Exception{Exception::kFailed}; + } + + return Exception{Exception::kSuccess}; +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index d7384b80..7a40fc0a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -40,19 +40,27 @@ private: class BluetoothSocket : public api::BluetoothSocket { public: - BluetoothSocket(std::string object, int fd) { + BluetoothSocket(api::BluetoothDevice &device, + absl::string_view device_object_path, + absl::string_view connected_profile_uuid, int fd) + : device_(device) { fd_ = fd; - object_ = object; + device_object_path_ = device_object_path; + connected_profile_uuid_ = connected_profile_uuid; input_stream_ = BluetoothInputStream(fd_); output_stream_ = BluetoothOutputStream(fd_); } InputStream &GetInputStream() override { return input_stream_; } OutputStream &GetOutputStream() override { return output_stream_; } + Exception Close() override; + api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; private: int fd_; - std::string object_; + std::string device_object_path_; + api::BluetoothDevice &device_; + std::string connected_profile_uuid_; BluetoothInputStream input_stream_ = {-1}; BluetoothOutputStream output_stream_ = {-1}; }; diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index e2007b4e..814a0162 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -46,13 +46,6 @@ int pairing_reply_handler(sd_bus_message *m, void *userdata, return 0; } -BluetoothPairing::BluetoothPairing(absl::string_view object_path) { - object_path_ = object_path; - if (sd_bus_default_system(&system_bus_) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error connecting to system bus"; - } -} - bool BluetoothPairing::InitiatePairing( api::BluetoothPairingCallback pairing_cb) { if (!system_bus_) @@ -60,12 +53,12 @@ bool BluetoothPairing::InitiatePairing( pairing_cb_ = std::move(pairing_cb); - if (sd_bus_call_method_async(system_bus_, nullptr, BLUEZ_SERVICE, - object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "Pair", &pairing_reply_handler, &pairing_cb_, - nullptr) < 0) { + if (sd_bus_call_method_async( + system_bus_, nullptr, BLUEZ_SERVICE, device_object_path_.c_str(), + BLUEZ_DEVICE_INTERFACE, "Pair", &pairing_reply_handler, &pairing_cb_, + nullptr) < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error calling method Pair on device " - << object_path_; + << device_object_path_; return false; } pairing_cb.on_pairing_initiated_cb(api::PairingParams{ @@ -84,12 +77,12 @@ bool BluetoothPairing::CancelPairing() { __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, object_path_.c_str(), - BLUEZ_DEVICE_INTERFACE, "CancelPairing", &err, nullptr, - nullptr)) { + if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, + device_object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, + "CancelPairing", &err, nullptr, nullptr)) { NEARBY_LOGS(ERROR) << __func__ << "Error calling method CancelPairing on device " - << object_path_ << ": " << err.message; + << device_object_path_ << ": " << err.message; return false; } return true; @@ -103,10 +96,10 @@ bool BluetoothPairing::Unpair() { SD_BUS_ERROR_NULL; if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "RemoveDevice", &err, nullptr, - "o", object_path_.c_str())) { + "o", device_object_path_.c_str())) { NEARBY_LOGS(ERROR) << __func__ << "Error calling method CancelPairing on device " - << object_path_ << ": " << err.message; + << device_object_path_ << ": " << err.message; return false; } return true; @@ -119,12 +112,12 @@ bool BluetoothPairing::IsPaired() { __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; int paired = 0; - if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, - object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "Bonded", &err, 'b', &paired) < 0) { + if (sd_bus_get_property_trivial( + system_bus_, BLUEZ_SERVICE, device_object_path_.c_str(), + BLUEZ_DEVICE_INTERFACE, "Bonded", &err, 'b', &paired) < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error getting Bonded property for device " - << object_path_ << ": " << err.message; + << device_object_path_ << ": " << err.message; } return paired; } diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 3e5ee4e4..1b1084f9 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -13,7 +13,10 @@ namespace nearby { namespace linux { class BluetoothPairing : public api::BluetoothPairing { public: - BluetoothPairing(absl::string_view object_path); + BluetoothPairing(sd_bus *system_bus, absl::string_view device_object_path) { + system_bus_ = system_bus; + device_object_path_ = device_object_path; + } ~BluetoothPairing() { sd_bus_unref(system_bus_); } bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; @@ -23,7 +26,7 @@ public: bool IsPaired() override; private: - std::string object_path_; + std::string device_object_path_; sd_bus *system_bus_; api::BluetoothPairingCallback pairing_cb_; }; From 2539ec16100fe0e4370cbb17f2867ee1a38519f1 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Wed, 2 Aug 2023 18:24:19 -0500 Subject: [PATCH 012/201] Implemented some more Linux equivalents --- .../linux/count_down_latch_test.cc | 161 ++++++++++++++++++ .../platform/implementation/linux/future.h | 48 ++++++ .../implementation/linux/log_message.cc | 71 ++++++++ .../implementation/linux/log_message.h | 43 +++++ .../implementation/linux/thread_pool.cc | 2 +- 5 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 internal/platform/implementation/linux/count_down_latch_test.cc create mode 100644 internal/platform/implementation/linux/future.h create mode 100644 internal/platform/implementation/linux/log_message.cc create mode 100644 internal/platform/implementation/linux/log_message.h diff --git a/internal/platform/implementation/linux/count_down_latch_test.cc b/internal/platform/implementation/linux/count_down_latch_test.cc new file mode 100644 index 00000000..6f4caccd --- /dev/null +++ b/internal/platform/implementation/linux/count_down_latch_test.cc @@ -0,0 +1,161 @@ +// 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 +#include +#include + +class CountDownLatchTests : public testing::Test { + public: + class TestData { + public: + std::unique_ptr& countDownLatch; + long volatile& count; + }; + + class CountDownLatchTest { + public: + static unsigned int ThreadProcCountDown(void *lpParam) { + TestData* testData = static_cast(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(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 countDownLatch = + nearby::api::ImplementationPlatform::CreateCountDownLatch(3); + + std::vector 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(); + + // Assert + EXPECT_EQ(result.value, nearby::Exception::kSuccess); + EXPECT_EQ(count, 3); +} + +TEST_F(CountDownLatchTests, CountDownLatchAwaitTimeoutTimesOut) { + // Arrange + + std::unique_ptr countDownLatch = + nearby::api::ImplementationPlatform::CreateCountDownLatch(3); + + // Act + nearby::ExceptionOr 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 countDownLatch = + nearby::api::ImplementationPlatform::CreateCountDownLatch(3); + + TestData testData{countDownLatch, count}; + + std::vector 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 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 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); +} + diff --git a/internal/platform/implementation/linux/future.h b/internal/platform/implementation/linux/future.h new file mode 100644 index 00000000..2f0bcab9 --- /dev/null +++ b/internal/platform/implementation/linux/future.h @@ -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 +class Future : public api::Future { + public: + // TODO(b/184975123): replace with real implementation. + ~Future() override = default; + + // throws Exception::kInterrupted, Exception::kExecution + // TODO(b/184975123): replace with real implementation. + ExceptionOr Get() override { return ExceptionOr{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 Get(absl::Duration timeout) override { + return ExceptionOr{Exception::kFailed}; + } +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_FUTURE_H_ diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc new file mode 100644 index 00000000..53d16a47 --- /dev/null +++ b/internal/platform/implementation/linux/log_message.cc @@ -0,0 +1,71 @@ +// 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/log_message.h" + +#include + +#include "strings/strappendv.h" + +namespace nearby { +namespace linux { + +api::LogMessage::Severity min_log_severity_ = api::LogMessage::Severity::kInfo; + +inline absl::LogSeverity ConvertSeverity(api::LogMessage::Severity severity) { + switch (severity) { + // api::LogMessage::Severity kVerbose and kInfo is mapped to + // absl::LogSeverity kInfo since absl::LogSeverity doesn't have kVerbose + // level. + case api::LogMessage::Severity::kVerbose: + case api::LogMessage::Severity::kInfo: + return absl::LogSeverity::kInfo; + case api::LogMessage::Severity::kWarning: + return absl::LogSeverity::kWarning; + case api::LogMessage::Severity::kError: + return absl::LogSeverity::kError; + case api::LogMessage::Severity::kFatal: + return absl::LogSeverity::kFatal; + } +} + +LogMessage::LogMessage(const char* file, int line, Severity severity) + : log_streamer_(ConvertSeverity(severity), file, line) {} + +LogMessage::~LogMessage() = default; + +void LogMessage::Print(const char* format, ...) { + va_list ap; + va_start(ap, format); + std::string result; + strings::StrAppendV(&result, format, ap); + log_streamer_.stream() << result; + va_end(ap); +} + +std::ostream& LogMessage::Stream() { return log_streamer_.stream(); } + +} // namespace linux + +namespace api { + +void LogMessage::SetMinLogSeverity(Severity severity) { + windows::min_log_severity_ = severity; +} + +bool LogMessage::ShouldCreateLogMessage(Severity severity) { + return severity >= windows::min_log_severity_; +} +} // namespace api +} // namespace nearby diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h new file mode 100644 index 00000000..bd06ab79 --- /dev/null +++ b/internal/platform/implementation/linux/log_message.h @@ -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_LOG_MESSAGE_H_ +#define PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ + +#include "glog/logging.h" +#include "internal/platform/implementation/log_message.h" + +namespace nearby { +namespace linux { + +// See documentation in +// cpp/platform/api/log_message.h +class LogMessage : public api::LogMessage { + public: + LogMessage(const char* file, int line, Severity severity); + ~LogMessage() override; + + void Print(const char* format, ...) override; + + std::ostream& Stream() override; + + private: + google::LogMessage log_streamer_; + static api::LogMessage::Severity min_log_severity_; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ diff --git a/internal/platform/implementation/linux/thread_pool.cc b/internal/platform/implementation/linux/thread_pool.cc index 40dec614..2eb1fa12 100644 --- a/internal/platform/implementation/linux/thread_pool.cc +++ b/internal/platform/implementation/linux/thread_pool.cc @@ -56,7 +56,7 @@ ThreadPool::ThreadPool(std::unique_ptr> &thread_pool, i RunNextTask(); // Possibly don't need but here to prevent 100% usage for loop sleep(300); - } + } }); } } From 622451436b650671179fbb46d92a70134c5eb693 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 3 Aug 2023 17:14:03 +0530 Subject: [PATCH 013/201] Refactor --- .../implementation/linux/bluetooth_adapter.cc | 20 +++++++++---------- .../implementation/linux/bluetooth_adapter.h | 9 +++------ .../linux/bluetooth_classic_device.cc | 8 ++++++++ .../linux/bluetooth_classic_device.h | 1 + .../linux/bluetooth_classic_medium.cc | 17 +++++++--------- .../linux/bluetooth_classic_medium.h | 4 ++-- .../implementation/linux/bluetooth_pairing.cc | 5 +++-- .../implementation/linux/bluetooth_pairing.h | 1 - 8 files changed, 34 insertions(+), 31 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index cc734974..b24c5395 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -15,8 +15,8 @@ bool BluetoothAdapter::SetStatus(Status status) { SD_BUS_ERROR_NULL; if (sd_bus_set_property( - system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, - "Powered", &err, "b", + system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", + BLUEZ_ADAPTER_INTERFACE, "Powered", &err, "b", status == api::BluetoothAdapter::Status::kEnabled ? 1 : 0) < 0) { NEARBY_LOGS(ERROR) << __func__ << ": Error setting adaptor status: " << err.message; @@ -30,7 +30,7 @@ bool BluetoothAdapter::IsEnabled() const { SD_BUS_ERROR_NULL; int enabled = 0; - if (sd_bus_get_property_trivial(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b', &enabled) < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -45,7 +45,7 @@ BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const { int powered = 0; int discoverable = 0; - if (sd_bus_get_property_trivial(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b', &powered) < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -56,7 +56,7 @@ BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const { return ScanMode::kNone; } - if (sd_bus_get_property_trivial(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, 'b', &powered) < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -78,7 +78,7 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { } __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; - if (sd_bus_set_property(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + if (sd_bus_set_property(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, "b", 1) < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -99,7 +99,7 @@ std::string BluetoothAdapter::GetName() const { __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; char *cname = nullptr; - if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "Alias", &err, &cname) < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -116,7 +116,7 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) { __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; std::string pretty_hostname(name); - if (sd_bus_set_property(system_bus, "org.freedesktop.hostname1", + if (sd_bus_set_property(system_bus_, "org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "PrettyHostname", &err, "s", pretty_hostname.c_str()) < 0) { @@ -131,7 +131,7 @@ bool BluetoothAdapter::SetName(absl::string_view name) { std::string alias(name); __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; - if (sd_bus_set_property(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + if (sd_bus_set_property(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "Alias", &err, "s", alias.c_str()) < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -145,7 +145,7 @@ std::string BluetoothAdapter::GetMacAddress() const { __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; char *caddr = nullptr; - if (sd_bus_get_property_string(system_bus, BLUEZ_SERVICE, "/org/bluez/hci0", + if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "Address", &err, &caddr) < 0) { NEARBY_LOGS(ERROR) << __func__ diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index 0ca0facf..b9c4b2c2 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -11,11 +11,8 @@ namespace nearby { namespace linux { class BluetoothAdapter : public api::BluetoothAdapter { public: - ~BluetoothAdapter() override { - if (system_bus) { - sd_bus_unrefp(&system_bus); - } - }; + BluetoothAdapter(sd_bus *bus) { system_bus_ = bus; } + ~BluetoothAdapter() override { sd_bus_unref(system_bus_); }; bool SetStatus(Status status) override; bool IsEnabled() const override; @@ -30,7 +27,7 @@ public: std::string GetMacAddress() const override; private: - sd_bus *system_bus; + sd_bus *system_bus_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index cda7e74a..ad325e71 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -24,6 +24,14 @@ BluetoothDevice::BluetoothDevice(sd_bus *system_bus, object_path_ = device_object_path; } +BluetoothDevice::BluetoothDevice(const BluetoothDevice &device) { + if (!device.mac_addr_.empty()) { + mac_addr_ = device.mac_addr_; + } + object_path_ = device.object_path_; + system_bus_ = sd_bus_ref(device.system_bus_); +} + std::string BluetoothDevice::GetName() const { __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL; diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 098abc03..18e93795 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -15,6 +15,7 @@ public: BluetoothDevice(sd_bus *system_bus, absl::string_view adapter, absl::string_view address); BluetoothDevice(sd_bus *system_bus, absl::string_view device_object_path); + BluetoothDevice(const BluetoothDevice &device); ~BluetoothDevice() override { sd_bus_unref(system_bus_); }; diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index e53fa850..e298d6c0 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -55,7 +55,7 @@ int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, ret = sd_bus_message_enter_container(m, 'a', "{sa{sv}}"); if (ret < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error entering container: " << ret; - return 0; + return ret; } while (true) { @@ -63,6 +63,7 @@ int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, ret = sd_bus_message_read(m, "s", &interface_name); if (ret < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error reading dict entry: " << ret; + return ret; } if (ret == 0) break; @@ -149,13 +150,6 @@ bool BluetoothClassicMedium::StopDiscovery() { << adapter_object_path_ << ": " << err.message; return false; } - const sd_bus_error *m_err = sd_bus_message_get_error(reply); - - if (m_err) { - NEARBY_LOGS(ERROR) << __func__ << "Error calling StopDiscovery on " - << adapter_object_path_ << ": " << err.message; - return false; - } return true; } @@ -214,8 +208,11 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, api::BluetoothDevice * BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { - return new BluetoothDevice(sd_bus_ref(system_bus_), - GetDeviceObjectPath(mac_address)); + if (devices_by_path_.count(mac_address) == 1) { + return devices_by_path_[mac_address].get(); + } + + return nullptr; } std::unique_ptr diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 1fd6886c..c4d5217d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -95,10 +95,10 @@ private: sd_bus *system_bus_ = nullptr; sd_bus_slot *system_bus_slot_ = nullptr; std::string adapter_object_path_ = std::string(); - std::map> devices_by_id_; + std::map> devices_by_path_; ObserverList observers_; - DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_id_, + DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_path_, observers_}; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 814a0162..3d82511f 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -5,6 +5,7 @@ #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_pairing.h" #include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" namespace nearby { namespace linux { @@ -79,7 +80,7 @@ bool BluetoothPairing::CancelPairing() { SD_BUS_ERROR_NULL; if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, device_object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "CancelPairing", &err, nullptr, nullptr)) { + "CancelPairing", &err, nullptr, nullptr) < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error calling method CancelPairing on device " << device_object_path_ << ": " << err.message; @@ -96,7 +97,7 @@ bool BluetoothPairing::Unpair() { SD_BUS_ERROR_NULL; if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", BLUEZ_ADAPTER_INTERFACE, "RemoveDevice", &err, nullptr, - "o", device_object_path_.c_str())) { + "o", device_object_path_.c_str()) < 0) { NEARBY_LOGS(ERROR) << __func__ << "Error calling method CancelPairing on device " << device_object_path_ << ": " << err.message; diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 1b1084f9..fa0f321d 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -7,7 +7,6 @@ #include "absl/strings/string_view.h" #include "internal/platform/implementation/bluetooth_classic.h" -#include "internal/platform/logging.h" namespace nearby { namespace linux { From 037d8c6f3849a04daf658c83e97e43d5f4096e0d Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 3 Aug 2023 17:17:59 +0530 Subject: [PATCH 014/201] Add additional libraries. --- internal/platform/implementation/linux/BUILD | 56 ++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index c57cff94..3006bf08 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -7,8 +7,11 @@ cc_library( ], srcs = [ "device_info.cc", + "bluetooth_adapter.h", ], + visibility = ["//third_party/nearby/sharing/internal/impl/linux:__pkg__"], deps = [ + ":comm", "//internal/platform/implementation:types", "//internal/platform:logging", "@com_google_absl//absl/strings", @@ -17,16 +20,63 @@ cc_library( ) cc_library( - name = "linux", + name = "comm", hdrs = [ "bluetooth_adapter.h", - "bluez.h" + "bluetooth_bluez_profile.h", + "bluetooth_classic_device.h", + "bluetooth_classic_medium.h", + "bluetooth_classic_server_socket.h", + "bluetooth_classic_socket.h", + "bluetooth_pairing.h", + "bluez.h", ], - srcs = ["bluetooth_adapter.cc"], deps = [ + "//internal/platform:base", + "//internal/platform:comm", + "//internal/platform:types", + "//internal/platform:uuid", + "//internal/platform/implementation:comm", + "//internal/platform/implementation: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", + ], + visibility = ["//visibility:private"], +) + +cc_library( + name = "linux", + srcs = [ + "bluetooth_adapter.cc", + "bluetooth_bluez_profile.cc", + "bluetooth_classic_device.cc", + "bluetooth_classic_medium.cc", + "bluetooth_classic_socket.cc", + "bluetooth_pairing.cc", + ], + visibility = [ + "//connections:__subpackages__", + "//fastpair:__subpackages__", + "//location/nearby:__subpackages__", + "//presence:__subpackages__", + "//third_party/nearby/sharing:__subpackages__", + ], + deps = [ + ":comm", "//internal/platform/implementation:types", "//internal/platform:logging", "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", "@libsystemd//:lib", ] ) From ea13cbc23711c99167d6cae806414ca3c9f3db76 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Fri, 4 Aug 2023 18:13:05 -0500 Subject: [PATCH 015/201] Implemented Windows implementation compliant Linux `http_loader` The `http_loader` class takes a `WebRequest` with information to send a web request, and sends it. This uses `libcurl`, which is present from installation on most major Linux distrobutions (e.g. Fedora, Ubuntu, PopOS...). If libcurl is not present on the target system, it will need to be installed. --- .../implementation/linux/http_loader.cc | 547 ++++++++++++++++++ .../implementation/linux/http_loader.h | 90 +++ .../implementation/linux/http_loader_test.cc | 51 ++ 3 files changed, 688 insertions(+) create mode 100644 internal/platform/implementation/linux/http_loader.cc create mode 100644 internal/platform/implementation/linux/http_loader.h create mode 100644 internal/platform/implementation/linux/http_loader_test.cc diff --git a/internal/platform/implementation/linux/http_loader.cc b/internal/platform/implementation/linux/http_loader.cc new file mode 100644 index 00000000..8cc4abcb --- /dev/null +++ b/internal/platform/implementation/linux/http_loader.cc @@ -0,0 +1,547 @@ +// 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/http_loader.h" + +#include +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/ascii.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +namespace { + +constexpr int32_t kSchemaMaximumLength = 10; +constexpr int32_t kHostNameMaximumLength = 256; + +using ::nearby::api::WebResponse; + +} // namespace + +HttpLoader::HttpLoader(const nearby::api::WebRequest &request) : + request_(request), + header_data_(open_memstream(&header_strings_, &header_sizeloc_)), + our_header_data_(nullptr), + response_data_(open_memstream(&response_strings_, &response_sizeloc_)), + curl_(curl_easy_init()) {} + +HttpLoader::~HttpLoader() { + DisconnectWebServer(); +} + +absl::StatusOr HttpLoader::GetResponse() { + absl::Status status; + + status = ParseUrl(); + if (!status.ok()) { + return status; + } + + status = ConnectWebServer(); + if (!status.ok()) { + return status; + } + + // Sends request to web server. + status = SendRequest(); + if (!status.ok()) { + return status; + } + + // Processes response from web server + absl::StatusOr result = ProcessResponse(); + if (!result.ok()) { + return result; + } + + DisconnectWebServer(); + return result; +} + +absl::StatusOr HttpLoader::QueryStatusCode(CURL *file_handle) { + long status_code; + absl::Status status; + status = QueryResponseInfo(file_handle, CURLINFO_RESPONSE_CODE, &status_code); + if (!status.ok()) { + return status; + } + + if (status_code < 0) { + return absl::InternalError("Invalid status code."); + } + + return status_code; +} + +absl::StatusOr HttpLoader::QueryStatusText( + CURL *request_handle) { + absl::StatusOr status; + std::string status_text; + + status = QueryStatusCode(request_handle); + if (!status.ok()) { + return status.status(); + } + + switch (status.value()) { + case 100: + return "Continue"; + case 101: + return "Switching Protocols"; + case 102: + return "Processing"; + case 103: + return "Early Hints"; + case 200: + return "OK"; + case 201: + return "Created"; + case 202: + return "Accepted"; + case 203: + return "Non-Authoritative Information"; + case 204: + return "No Content"; + case 205: + return "Reset Content"; + case 206: + return "Partial Content"; + case 207: + return "Multi-Status"; + case 208: + return "Already Reported"; + case 226: + return "IM Used"; + case 300: + return "Multiple Choices"; + case 301: + return "Moved Permanently"; + case 302: + return "Found"; + case 303: + return "See Other"; + case 304: + return "Not Modified"; + case 305: + return "Use Proxy"; + case 307: + return "Temporary Redirect"; + case 308: + return "Permanent Redirect"; + case 400: + return "Bad Request"; + case 401: + return "Unauthorized"; + case 402: + return "Payment Required"; + case 403: + return "Forbidden"; + case 404: + return "Not Found"; + case 405: + return "Method Not Allowed"; + case 406: + return "Not Acceptable"; + case 407: + return "Proxy Authentication Required"; + case 408: + return "Request Timeout"; + case 409: + return "Conflict"; + case 410: + return "Gone"; + case 411: + return "Lenth Required"; + case 412: + return "Precondition Failed"; + case 413: + return "Payload Too Large"; + case 414: + return "URI Too Long"; + case 415: + return "Unsupported Media Type"; + case 416: + return "Range Not Satisfiable"; + case 417: + return "Expectation Failed"; + case 418: + return "I'm a teapot!"; + case 421: + return "Misdirected Request"; + case 422: + return "Unprocessable Content"; + case 423: + return "Locked"; + case 424: + return "Failed Dependency"; + case 425: + return "Too Early"; + case 426: + return "Upgrade Required"; + case 428: + return "Precondition Required"; + case 429: + return "Too Many Requests"; + case 431: + return "Request Header Fields Too Large"; + case 451: + return "Unavailable For Legal Reasons"; + case 500: + return "Internal Server Error"; + case 501: + return "Not Implemented"; + case 502: + return "Bad Gateway"; + case 503: + return "Service Unavailable"; + case 504: + return "Gateway Timeout"; + case 505: + return "HTTP Version Not Supported"; + case 506: + return "Variant Also Negotiates"; + case 507: + return "Insufficient Storage"; + case 508: + return "Loop Detected"; + case 509: + return "Network Authentication Required"; + default: + return absl::InternalError("Invalid status code."); + } +} + +absl::StatusOr> +HttpLoader::QueryResponseHeaders(CURL *request_handle) { + absl::Status status; + long header_size; + + status = QueryResponseInfo(curl_, CURLINFO_HEADER_SIZE, &header_size); + + if (!status.ok()) { + return status; + } + + std::string headers_string(header_strings_, header_size); + + std::multimap headers; + // Parse headers in response + size_t start = 0; + size_t pos = 0; + while ((pos = headers_string.find("\r\n", start)) != std::string::npos) { + std::string header = headers_string.substr(start, pos - start); + // Get key and value in header + size_t split_pos = 0; + if ((split_pos = header.find(": ")) != std::string::npos) { + std::string key = header.substr(0, split_pos); + std::string value = header.substr(split_pos + 2); + headers.emplace(key, value); + } + + start = pos + 2; + } + + return headers; +} + +const nearby::api::WebRequest& HttpLoader::GetRequest() { + return request_; +} + +size_t HttpLoader::CurlReadCallback(char *buffer, size_t size, size_t nitems, void *userdata) { + size_t write_size_max = size * nitems; + size_t write_amount = 0; + for (const auto &str : reinterpret_cast(userdata)->GetRequest().body) { + if (write_amount == write_size_max) { + break; + } + *(buffer + write_amount) = str; + write_amount++; + } + + return write_amount; +} + +// This function uses the CURL getinfo function to grab info. Each info_level has a different +// type it can return. It would not be feasable to determine the type and return it. +// IT IS UP TO THE CALLER OF THE FUNCTION TO USE THE void* CORRECTLY. +absl::Status HttpLoader::QueryResponseInfo(CURL *request_handle, + CURLINFO info_level, + void *info) { + CURLcode query_result = curl_easy_getinfo(request_handle, info_level, &info); + + if (query_result == CURLE_OK) { + return absl::OkStatus(); + } + + return absl::InvalidArgumentError("Failed to query HTTP information: " + std::string(curl_easy_strerror(query_result))); +} + +absl::Status HttpLoader::ParseUrl() { + CURLU *url_components = curl_url(); + char *schema; + char *host_name; + char *path; + + CURLUcode ret = curl_url_set(url_components, CURLUPART_URL, request_.url.c_str(), CURLU_NON_SUPPORT_SCHEME); + if (ret) { + curl_url_cleanup(url_components); + curl_free(schema); + curl_free(host_name); + curl_free(path); + url_components = nullptr; + schema = nullptr; + host_name = nullptr; + path = nullptr; + return absl::InvalidArgumentError("Invalid URL format: " + std::string(curl_url_strerror(ret))); + } + + ret = curl_url_get(url_components, CURLUPART_SCHEME, &schema, CURLU_URLDECODE | CURLU_URLENCODE | CURLU_DEFAULT_PORT | CURLU_DEFAULT_SCHEME); + if (ret) { + curl_url_cleanup(url_components); + curl_free(schema); + curl_free(host_name); + curl_free(path); + url_components = nullptr; + schema = nullptr; + host_name = nullptr; + path = nullptr; + return absl::InvalidArgumentError("Could not parse URL schema: " + std::string(curl_url_strerror(ret))); + } + + ret = curl_url_get(url_components, CURLUPART_PATH, &path, CURLU_URLDECODE | CURLU_URLENCODE | CURLU_DEFAULT_PORT | CURLU_DEFAULT_SCHEME); + if (ret) { + curl_url_cleanup(url_components); + curl_free(schema); + curl_free(host_name); + curl_free(path); + url_components = nullptr; + schema = nullptr; + host_name = nullptr; + path = nullptr; + return absl::InvalidArgumentError("Could not parse URL path: " + std::string(curl_url_strerror(ret))); + } + + if (!(schema_ == "http" || schema_ == "https")) { + curl_url_cleanup(url_components); + curl_free(schema); + curl_free(host_name); + curl_free(path); + url_components = nullptr; + schema = nullptr; + host_name = nullptr; + path = nullptr; + return absl::InvalidArgumentError("URL supports HTTP and HTTPS only."); + } + + host_ = host_name; + schema_ = schema; + path_ = path; + + if (schema_ == "https") { + is_secure_ = true; + } + + curl_url_cleanup(url_components); + curl_free(schema); + curl_free(host_name); + curl_free(path); + url_components = nullptr; + schema = nullptr; + host_name = nullptr; + path = nullptr; + return absl::OkStatus(); +} + +absl::Status HttpLoader::ConnectWebServer() { + std::vector option_return_codes; + if (curl_) { + curl_ = curl_easy_init(); + header_data_ = open_memstream(&header_strings_, &header_sizeloc_); + response_data_ = open_memstream(&response_strings_, &response_sizeloc_); + } + + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L)); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_URL, request_.url.c_str())); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_PORT, port_)); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_AUTOREFERER, 1L)); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L)); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_USERAGENT, "Mozilla/5.0")); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_HEADERDATA, header_data_)); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_WRITEDATA, response_data_)); + + // Prepare headers + std::string request_headers; + for (const auto& header : request_.headers) { + struct curl_slist *list = curl_slist_append(our_header_data_, std::string(header.first + ": " + header.second).c_str()); + if (list) { + our_header_data_ = list; + } + } + + if (!request_headers.empty()) { + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, our_header_data_)); + } + + if (request_.method == "GET") { + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L)); + } + else if (request_.method == "POST") { + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, static_cast(request_.body.size()))); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, request_.body.c_str())); + } + else if (request_.method == "PUT") { + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_UPLOAD, 1L)); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_READFUNCTION, CurlReadCallback)); + option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_READDATA, this)); + option_return_codes.push_back(curl_easy_setopt(curl_, (request_.body.size() < std::numeric_limits::max() ? CURLOPT_INFILESIZE : CURLOPT_INFILESIZE_LARGE), request_.body.size())); + + } + else { + NEARBY_LOGS(ERROR) << "Failed to open internet with error " + << "Invalid request method: " << request_.method << "."; + return absl::FailedPreconditionError("Failed to open internet: Invalid request method."); + } + + for (const auto &ret : option_return_codes) { + if (ret) { + NEARBY_LOGS(ERROR) << "Failed to open internet with error " + << curl_easy_strerror(ret) << "."; + return absl::FailedPreconditionError(absl::StrCat(curl_easy_strerror(ret))); + } + } + + return absl::OkStatus(); +} + +absl::Status HttpLoader::SendRequest() { + + CURLcode ret = curl_easy_perform(curl_); + + if (ret != CURLE_OK) { + NEARBY_LOGS(ERROR) + << "Failed to send request to remote web server with error " + << curl_easy_strerror(ret) << "."; + return absl::FailedPreconditionError(absl::StrCat(curl_easy_strerror(ret))); + } + + return absl::OkStatus(); +} + +absl::StatusOr HttpLoader::ProcessResponse() { + absl::Status status; + WebResponse web_response; + auto status_code = QueryStatusCode(curl_); + if (!status_code.ok()) { + return absl::InternalError("Failed to read HTTP status"); + } + + web_response.status_code = status_code.value(); + auto status_text = QueryStatusText(curl_); + if (!status_text.ok()) { + return absl::InternalError("Failed to read HTTP status"); + } + + web_response.status_text = status_text.value(); + auto headers = QueryResponseHeaders(curl_); + if (!headers.ok()) { + headers.status(); + } + web_response.headers = *headers; + + curl_off_t download_size; + + CURLcode ret = curl_easy_getinfo(curl_, CURLINFO_SIZE_DOWNLOAD_T, &download_size); + + if (ret) { + if (download_size != 0) { + // Append data to response + web_response.body.assign(response_strings_, download_size); + } else { + NEARBY_LOGS(ERROR) + << "Failed to read response from remote web server with error " + << curl_easy_strerror(ret) << "."; + return absl::FailedPreconditionError(absl::StrCat(curl_easy_strerror(ret))); + } + } + + status = HTTPCodeToStatus(web_response.status_code, web_response.status_text); + if (!status.ok()) { + return status; + } + + return web_response; +} + +void HttpLoader::DisconnectWebServer() { + fclose(header_data_); + header_data_ = nullptr; + delete header_strings_; + header_strings_ = nullptr; + curl_easy_cleanup(curl_); + curl_ = nullptr; + curl_slist_free_all(our_header_data_); + our_header_data_ = nullptr; + fclose(response_data_); + response_data_ = nullptr; + delete response_strings_; + response_strings_ = nullptr; +} + +absl::Status HttpLoader::HTTPCodeToStatus(int status_code, + absl::string_view status_message) { + switch (status_code) { + case 400: + return absl::InvalidArgumentError(status_message); + case 401: + return absl::UnauthenticatedError(status_message); + case 403: + return absl::PermissionDeniedError(status_message); + case 404: + return absl::NotFoundError(status_message); + case 409: + return absl::AbortedError(status_message); + case 416: + return absl::OutOfRangeError(status_message); + case 429: + return absl::ResourceExhaustedError(status_message); + case 499: + return absl::CancelledError(status_message); + case 504: + return absl::DeadlineExceededError(status_message); + case 501: + return absl::UnimplementedError(status_message); + case 503: + return absl::UnavailableError(status_message); + default: + break; + } + if (status_code >= 200 && status_code < 300) { + return absl::OkStatus(); + } else if (status_code >= 400 && status_code < 500) { + return absl::FailedPreconditionError(status_message); + } else if (status_code >= 500 && status_code < 600) { + return absl::InternalError(status_message); + } + return absl::UnknownError(status_message); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/http_loader.h b/internal/platform/implementation/linux/http_loader.h new file mode 100644 index 00000000..97ca5507 --- /dev/null +++ b/internal/platform/implementation/linux/http_loader.h @@ -0,0 +1,90 @@ +// 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_HTTP_LOADER_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_LINUX_HTTP_LOADER_H_ + +#include +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/http_loader.h" + +namespace nearby { +namespace linux { + +// HttpLoader is used to get HTTP response from remote server. +// +// HttpLoader gets HTTP request information from caller, and calling Windows +// WinInet APIs to get HTTP response. The platform handles HTTP/HTTPS sessions. +class HttpLoader { + public: + explicit HttpLoader(const nearby::api::WebRequest& request); + ~HttpLoader(); + + absl::StatusOr GetResponse(); + + const nearby::api::WebRequest& GetRequest(); + + private: + // Defines the buffer size. It is used to init a buffer for receiving HTTP + // response. The unit is byte. + static constexpr int kReceiveBufferSize = 8 * 1024; + static size_t CurlReadCallback(char *buffer, size_t size, size_t nitems, void *userdata); + + absl::Status ConnectWebServer(); + absl::Status SendRequest(); + absl::StatusOr ProcessResponse(); + void DisconnectWebServer(); + + absl::StatusOr QueryStatusCode(CURL *file_handle); + absl::StatusOr QueryStatusText(CURL *request_handle); + absl::StatusOr> QueryResponseHeaders( + CURL *request_handle); + absl::Status QueryResponseInfo(CURL *request_handle, CURLINFO info_level, + void *info); + + absl::Status ParseUrl(); + + // Converts HTTP status code to absl Status. + // + // @param status_code HTTP status code, such 200, 404 etc. + // @param status_message short description of the status code. + // @return converted absl status. + absl::Status HTTPCodeToStatus(int status_code, + absl::string_view status_message); + + nearby::api::WebRequest request_; + std::string host_; + std::string path_; + std::string schema_; + bool is_secure_ = false; + int port_ = 80; + + FILE *header_data_; + char *header_strings_; + size_t header_sizeloc_; + struct curl_slist *our_header_data_; + FILE *response_data_; + char *response_strings_; + size_t response_sizeloc_; + CURL *curl_; +}; + +} // namespace linux +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_LINUX_HTTP_LOADER_H_ diff --git a/internal/platform/implementation/linux/http_loader_test.cc b/internal/platform/implementation/linux/http_loader_test.cc new file mode 100644 index 00000000..800ed6a9 --- /dev/null +++ b/internal/platform/implementation/linux/http_loader_test.cc @@ -0,0 +1,51 @@ +// 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/http_loader.h" + +#include + +#include "gtest/gtest.h" + +namespace nearby { +namespace linux { +namespace { +using ::nearby::api::WebRequest; + +TEST(HttpLoader, DISABLED_TestGetUrl) { + WebRequest request; + request.url = "https://www.google.com?id=456#fragment"; + request.method = "GET"; + auto response = HttpLoader(request).GetResponse(); + ASSERT_TRUE(response.ok()); + EXPECT_EQ(response->status_code, 200); +} + +TEST(HttpLoader, DISABLED_TestGetNotExistingUrl) { + WebRequest request; + request.url = "https://www.abcdefgabcdefg.com"; + request.method = "GET"; + EXPECT_FALSE(HttpLoader(request).GetResponse().ok()); +} + +TEST(HttpLoader, DISABLED_TestInvalidUrl) { + WebRequest request; + request.url = "https:/www.abcdefgabcdefg.com/name?id=456"; + request.method = "GET"; + EXPECT_FALSE(HttpLoader(request).GetResponse().ok()); +} + +} // namespace +} // namespace linux +} // namespace nearby From 1230cbb5d33235394b917b2d995e1dd4010e49e2 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Sun, 6 Aug 2023 16:39:57 -0500 Subject: [PATCH 016/201] Added implementation for test_utils --- .../implementation/linux/test_utils.cc | 37 ++++++++++++++++ .../implementation/linux/test_utils.h | 43 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 internal/platform/implementation/linux/test_utils.cc create mode 100644 internal/platform/implementation/linux/test_utils.h diff --git a/internal/platform/implementation/linux/test_utils.cc b/internal/platform/implementation/linux/test_utils.cc new file mode 100644 index 00000000..209a8904 --- /dev/null +++ b/internal/platform/implementation/linux/test_utils.cc @@ -0,0 +1,37 @@ +// 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/test_utils.h" +#include "internal/platform/implementation/linux/device_info.h" + +#include +#include +#include + +#include "absl/strings/str_format.h" +#include "absl/strings/str_replace.h" + +namespace test_utils { +std::wstring StringToWideString(const std::string& s) { + std::wstring_convert> converter; + return converter.from_bytes(s); +} + +std::string GetPayloadPath(nearby::PayloadId payload_id) { + std::filesystem::path path = nearby::linux::DeviceInfo().GetDownloadPath().value_or(std::string(getenv("HOME")).append("Downloads")); + + return path.string(); +} + +} // namespace test_utils diff --git a/internal/platform/implementation/linux/test_utils.h b/internal/platform/implementation/linux/test_utils.h new file mode 100644 index 00000000..5abfb07f --- /dev/null +++ b/internal/platform/implementation/linux/test_utils.h @@ -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_TEST_UTILS_H_ +#define PLATFORM_IMPL_LINUX_TEST_UTILS_H_ + +#include + +#include "internal/platform/payload_id.h" + +#define TEST_BUFFER_SIZE 256 +#define TEST_PAYLOAD_ID 64l +#define TEST_STRING \ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas " \ + "eleifend nisl at magna maximus, id finibus mauris ultrices. Mauris " \ + "interdum efficitur turpis eget auctor. Nullam commodo metus et ante " \ + "bibendum molestie. Donec iaculis ante nec diam rutrum egestas. Proin " \ + "maximus metus luctus rutrum congue. Integer et eros nunc. Etiam purus " \ + "neque, tincidunt eu elementum in, pharetra sit amet magna. Quisque " \ + "consequat aliquam aliquam. Vestibulum ante ipsum primis in faucibus orci " \ + "luctus et ultrices posuere cubilia curae; Maecenas a semper eros, a " \ + "auctor mi. In luctus diam sem, eu pretium nisi porttitor ac. Sed cursus, " \ + "arcu in bibendum feugiat, leo erat finibus massa, ut tincidunt magna nunc " \ + "eu tellus. Cras feugiat ornare vestibulum. Nullam at ipsum vestibulum " \ + "sapien luctus dictum ac vel ligula." + +namespace test_utils { +std::wstring StringToWideString(const std::string& s); +std::string GetPayloadPath(nearby::PayloadId payload_id); +} // namespace test_utils + +#endif // PLATFORM_IMPL_LINUX_TEST_UTILS_H_ From 21d3dfca4e47c211aa3bac197dda906e6f35fda5 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Sun, 6 Aug 2023 18:28:46 -0500 Subject: [PATCH 017/201] Implemented scheduled_executor --- .../linux/scheduled_executor.cc | 82 ++++++++++++++ .../implementation/linux/scheduled_executor.h | 100 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 internal/platform/implementation/linux/scheduled_executor.cc create mode 100644 internal/platform/implementation/linux/scheduled_executor.h diff --git a/internal/platform/implementation/linux/scheduled_executor.cc b/internal/platform/implementation/linux/scheduled_executor.cc new file mode 100644 index 00000000..ff8b3a1d --- /dev/null +++ b/internal/platform/implementation/linux/scheduled_executor.cc @@ -0,0 +1,82 @@ +// 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/scheduled_executor.h" + +#include +#include +#include + +#include "absl/time/time.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +ScheduledExecutor::ScheduledExecutor() + : executor_(std::make_unique()), + shut_down_(false) {} + +// Cancelable is kept both in the executor context, and in the caller context. +// We want Cancelable to live until both caller and executor are done with it. +// Exclusive ownership model does not work for this case; +// using std:shared_ptr<> instead of std::unique_ptr<>. +std::shared_ptr ScheduledExecutor::Schedule( + Runnable&& runnable, absl::Duration duration) { + if (shut_down_) { + NEARBY_LOGS(ERROR) << __func__ + << ": Attempt to Schedule on a shut down executor."; + + return nullptr; + } + + // Cleans completed tasks + std::remove_if( + scheduled_tasks_.begin(), scheduled_tasks_.end(), + [](std::shared_ptr& task) { return task->IsDone(); }); + + std::shared_ptr task = + std::make_shared(std::move(runnable), duration); + + scheduled_tasks_.push_back(task); + executor_->Execute([task]() { task->Start(); }); + return task; +} + +void ScheduledExecutor::Execute(Runnable&& runnable) { + if (shut_down_) { + NEARBY_LOGS(ERROR) << __func__ + << ": Attempt to Execute on a shut down executor."; + return; + } + + executor_->Execute(std::move(runnable)); +} + +void ScheduledExecutor::Shutdown() { + if (!shut_down_) { + shut_down_ = true; + for (auto& task : scheduled_tasks_) { + task->Cancel(); + } + + scheduled_tasks_.clear(); + executor_->Shutdown(); + return; + } + NEARBY_LOGS(ERROR) << __func__ + << ": Attempt to Shutdown on a shut down executor."; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/scheduled_executor.h b/internal/platform/implementation/linux/scheduled_executor.h new file mode 100644 index 00000000..4dffef8b --- /dev/null +++ b/internal/platform/implementation/linux/scheduled_executor.h @@ -0,0 +1,100 @@ +// 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_SCHEDULED_EXECUTOR_H_ +#define PLATFORM_IMPL_LINUX_SCHEDULED_EXECUTOR_H_ + +#include +#include +#include + +#include "absl/synchronization/notification.h" +#include "absl/time/time.h" +#include "internal/platform/implementation/cancelable.h" +#include "internal/platform/implementation/scheduled_executor.h" +#include "internal/platform/implementation/linux/executor.h" + +namespace nearby { +namespace linux { + +#define TIMER_NAME_BUFFER_SIZE 64 + +// An Executor that can schedule commands to run after a given delay, or to +// execute periodically. +// +// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html +class ScheduledExecutor : public api::ScheduledExecutor { + public: + ScheduledExecutor(); + + ~ScheduledExecutor() override = default; + + // Cancelable is kept both in the executor context, and in the caller context. + // We want Cancelable to live until both caller and executor are done with it. + // Exclusive ownership model does not work for this case; + // using std:shared_ptr<> instead if std::unique_ptr<>. + std::shared_ptr Schedule(Runnable&& runnable, + absl::Duration duration) override; + + // Executes the runnable task immedately. + void Execute(Runnable&& runnable) override; + + // Shutdowns the executor, all scheduled task will be cancelled. + void Shutdown() override; + + private: + class ScheduledTask : public api::Cancelable { + public: + explicit ScheduledTask(Runnable&& task, absl::Duration duration) + : task_(std::move(task)), duration_(duration) {} + + bool Cancel() override { + if (is_executed_ || is_cancelled_) { + return false; + } + + is_cancelled_ = true; + notification_.Notify(); + return true; + }; + + void Start() { + if (is_executed_ || + notification_.WaitForNotificationWithTimeout(duration_)) { + return; + } + + is_executed_ = true; + task_(); + } + + bool IsDone() const { return is_cancelled_ || is_executed_; } + + private: + Runnable task_; + absl::Duration duration_; + absl::Notification notification_; + bool is_cancelled_ = false; + bool is_executed_ = false; + }; + + std::unique_ptr executor_ = nullptr; + std::vector> scheduled_tasks_; + std::atomic_bool shut_down_ = false; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_SCHEDULED_EXECUTOR_H_ From e6f52fba982b196625f5e226611fab5d628072b8 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Mon, 7 Aug 2023 13:58:39 -0500 Subject: [PATCH 018/201] Implemented preferences_manager and helpers --- .../linux/preferences_manager.cc | 282 ++++++++++++++++++ .../linux/preferences_manager.h | 141 +++++++++ .../linux/preferences_manager_test.cc | 189 ++++++++++++ .../linux/preferences_repository.cc | 153 ++++++++++ .../linux/preferences_repository.h | 48 +++ .../linux/preferences_repository_test.cc | 161 ++++++++++ 6 files changed, 974 insertions(+) create mode 100644 internal/platform/implementation/linux/preferences_manager.cc create mode 100644 internal/platform/implementation/linux/preferences_manager.h create mode 100644 internal/platform/implementation/linux/preferences_manager_test.cc create mode 100644 internal/platform/implementation/linux/preferences_repository.cc create mode 100644 internal/platform/implementation/linux/preferences_repository.h create mode 100644 internal/platform/implementation/linux/preferences_repository_test.cc diff --git a/internal/platform/implementation/linux/preferences_manager.cc b/internal/platform/implementation/linux/preferences_manager.cc new file mode 100644 index 00000000..9d174c09 --- /dev/null +++ b/internal/platform/implementation/linux/preferences_manager.cc @@ -0,0 +1,282 @@ +// Copyright 2021-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/preferences_manager.h" + +#include // NOLINT(build/c++17) +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/linux/preferences_repository.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +namespace { +using json = ::nlohmann::json; +} // namespace + +PreferencesManager::PreferencesManager(absl::string_view file_path) + : api::PreferencesManager(file_path) { + std::optional path = + nearby::api::ImplementationPlatform::CreateDeviceInfo() + ->GetLocalAppDataPath(); + if (!path.has_value()) { + path = std::filesystem::temp_directory_path(); + } + + std::filesystem::path full_path = *path / std::string(file_path); + preferences_repository_ = + std::make_unique(full_path.string()); + value_ = preferences_repository_->LoadPreferences(); +} + +bool PreferencesManager::Set(absl::string_view key, const json& value) { + absl::MutexLock lock(&mutex_); + return SetValue(key, value); +} + +bool PreferencesManager::SetBoolean(absl::string_view key, bool value) { + absl::MutexLock lock(&mutex_); + return SetValue(key, value); +} + +bool PreferencesManager::SetInteger(absl::string_view key, int value) { + absl::MutexLock lock(&mutex_); + return SetValue(key, value); +} + +bool PreferencesManager::SetInt64(absl::string_view key, int64_t value) { + absl::MutexLock lock(&mutex_); + return SetValue(key, value); +} + +bool PreferencesManager::SetString(absl::string_view key, + absl::string_view value) { + absl::MutexLock lock(&mutex_); + return SetValue(key, absl::StrCat(value)); +} + +bool PreferencesManager::SetBooleanArray(absl::string_view key, + absl::Span value) { + absl::MutexLock lock(&mutex_); + return SetArrayValue(key, value); +} + +bool PreferencesManager::SetIntegerArray(absl::string_view key, + absl::Span value) { + absl::MutexLock lock(&mutex_); + return SetArrayValue(key, value); +} + +bool PreferencesManager::SetInt64Array(absl::string_view key, + absl::Span value) { + absl::MutexLock lock(&mutex_); + return SetArrayValue(key, value); +} + +bool PreferencesManager::SetStringArray(absl::string_view key, + absl::Span value) { + absl::MutexLock lock(&mutex_); + return SetArrayValue(key, value); +} + +bool PreferencesManager::SetTime(absl::string_view key, absl::Time value) { + // Save time as nanos + absl::MutexLock lock(&mutex_); + int64_t tt = absl::ToUnixNanos(value); + if (value_[absl::StrCat(key)] == tt) { + return false; + } + + value_[absl::StrCat(key)] = tt; + return Commit(); +} + +// Get JSON value. +json PreferencesManager::Get(absl::string_view key, + const json& default_value) const { + absl::MutexLock lock(&mutex_); + return GetValue(key, default_value); +} + +bool PreferencesManager::GetBoolean(absl::string_view key, + bool default_value) const { + absl::MutexLock lock(&mutex_); + return GetValue(key, default_value); +} + +int PreferencesManager::GetInteger(absl::string_view key, + int default_value) const { + absl::MutexLock lock(&mutex_); + return GetValue(key, default_value); +} + +int64_t PreferencesManager::GetInt64(absl::string_view key, + int64_t default_value) const { + absl::MutexLock lock(&mutex_); + return GetValue(key, default_value); +} + +std::string PreferencesManager::GetString( + absl::string_view key, const std::string& default_value) const { + absl::MutexLock lock(&mutex_); + return GetValue(key, default_value); +} + +std::vector PreferencesManager::GetBooleanArray( + absl::string_view key, absl::Span default_value) const { + absl::MutexLock lock(&mutex_); + return GetArrayValue(key, default_value); +} + +std::vector PreferencesManager::GetIntegerArray( + absl::string_view key, absl::Span default_value) const { + absl::MutexLock lock(&mutex_); + return GetArrayValue(key, default_value); +} + +std::vector PreferencesManager::GetInt64Array( + absl::string_view key, absl::Span default_value) const { + absl::MutexLock lock(&mutex_); + return GetArrayValue(key, default_value); +} + +std::vector PreferencesManager::GetStringArray( + absl::string_view key, absl::Span default_value) const { + absl::MutexLock lock(&mutex_); + return GetArrayValue(key, default_value); +} + +absl::Time PreferencesManager::GetTime(absl::string_view key, + absl::Time default_value) const { + absl::MutexLock lock(&mutex_); + auto result = value_.find(absl::StrCat(key)); + if (result == value_.end()) { + return default_value; + } + + return absl::FromUnixNanos(result->get()); +} + +// Removes preferences +void PreferencesManager::Remove(absl::string_view key) { + absl::MutexLock lock(&mutex_); + value_.erase(absl::StrCat(key)); +} + +// Private methods + +// Writes data to storage. +bool PreferencesManager::Commit() { + if (!preferences_repository_->SavePreferences(value_)) { + NEARBY_LOGS(ERROR) << "Failed to save preference." << std::endl; + return false; + } + return true; +} + +bool PreferencesManager::SetValue(absl::string_view key, const json& value) { + if (!value_.is_object()) { + NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_=" + << value_.dump(4); + value_ = json::object(); + } + + if (value_[absl::StrCat(key)] == value) { + return false; + } + + value_[absl::StrCat(key)] = value; + return Commit(); +} + +template +T PreferencesManager::GetValue(absl::string_view key, + const T& default_value) const { + if (!value_.is_object()) { + NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_=" + << value_.dump(4); + return default_value; + } + + auto it = value_.find(absl::StrCat(key)); + if (it == value_.end()) { + return default_value; + } + return it->get(); +} + +template +bool PreferencesManager::SetArrayValue(absl::string_view key, + absl::Span value) { + if (!value_.is_object()) { + NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_=" + << value_.dump(4); + value_ = json::object(); + } + + json array_value = json::array(); + for (const T& item_value : value) { + array_value.push_back(item_value); + } + + if (value_[absl::StrCat(key)] == array_value) { + return false; + } + + value_[absl::StrCat(key)] = array_value; + return Commit(); +} + +template +std::vector PreferencesManager::GetArrayValue( + absl::string_view key, absl::Span default_value) const { + std::vector result; + + if (!value_.is_object()) { + NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_=" + << value_.dump(4); + + for (const T& value : default_value) { + result.push_back(value); + } + return result; + } + + auto array_value = value_.find(absl::StrCat(key)); + if (array_value == value_.end() || !array_value->is_array()) { + for (const T& value : default_value) { + result.push_back(value); + } + return result; + } + + auto it = array_value->begin(); + while (it != array_value->end()) { + result.push_back(it->get()); + ++it; + } + + return result; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/preferences_manager.h b/internal/platform/implementation/linux/preferences_manager.h new file mode 100644 index 00000000..9aaa3006 --- /dev/null +++ b/internal/platform/implementation/linux/preferences_manager.h @@ -0,0 +1,141 @@ +// Copyright 2021-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_IMPLEMENTATION_LINUX_PREFERENCES_MANAGER_H_ +#define PLATFORM_IMPLEMENTATION_LINUX_PREFERENCES_MANAGER_H_ + +#include + +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/preferences_manager.h" +#include "internal/platform/implementation/linux/preferences_repository.h" + +namespace nearby { +namespace linux { + +// Sets and gets preference settings from the application. +// Preferences are persistent storage for application settings, it is key/value +// based settings. Application components can observe the interested preference +// change by the observer. +class PreferencesManager : public api::PreferencesManager { + public: + explicit PreferencesManager(absl::string_view path); + + // Sets values + + bool Set(absl::string_view key, const nlohmann::json& value) override + ABSL_LOCKS_EXCLUDED(mutex_); + + bool SetBoolean(absl::string_view key, bool value) override + ABSL_LOCKS_EXCLUDED(mutex_); + bool SetInteger(absl::string_view key, int value) override + ABSL_LOCKS_EXCLUDED(mutex_); + bool SetInt64(absl::string_view key, int64_t value) override + ABSL_LOCKS_EXCLUDED(mutex_); + bool SetString(absl::string_view key, absl::string_view value) override + ABSL_LOCKS_EXCLUDED(mutex_); + + bool SetBooleanArray(absl::string_view key, + absl::Span value) override + ABSL_LOCKS_EXCLUDED(mutex_); + bool SetIntegerArray(absl::string_view key, + absl::Span value) override + ABSL_LOCKS_EXCLUDED(mutex_); + bool SetInt64Array(absl::string_view key, + absl::Span value) override + ABSL_LOCKS_EXCLUDED(mutex_); + bool SetStringArray(absl::string_view key, + absl::Span value) override + ABSL_LOCKS_EXCLUDED(mutex_); + + bool SetTime(absl::string_view key, absl::Time value) override + ABSL_LOCKS_EXCLUDED(mutex_); + + // Gets values + nlohmann::json Get(absl::string_view key, + const nlohmann::json& default_value) const override + ABSL_LOCKS_EXCLUDED(mutex_); + + bool GetBoolean(absl::string_view key, bool default_value) const override + ABSL_LOCKS_EXCLUDED(mutex_); + int GetInteger(absl::string_view key, int default_value) const override + ABSL_LOCKS_EXCLUDED(mutex_); + int64_t GetInt64(absl::string_view key, int64_t default_value) const override + ABSL_LOCKS_EXCLUDED(mutex_); + std::string GetString(absl::string_view key, + const std::string& default_value) const override + ABSL_LOCKS_EXCLUDED(mutex_); + + std::vector GetBooleanArray(absl::string_view key, + absl::Span default_value) + const override ABSL_LOCKS_EXCLUDED(mutex_); + std::vector GetIntegerArray( + absl::string_view key, absl::Span default_value) const override + ABSL_LOCKS_EXCLUDED(mutex_); + std::vector GetInt64Array(absl::string_view key, + absl::Span default_value) + const override ABSL_LOCKS_EXCLUDED(mutex_); + std::vector GetStringArray( + absl::string_view key, + absl::Span default_value) const override + ABSL_LOCKS_EXCLUDED(mutex_); + + absl::Time GetTime(absl::string_view key, + absl::Time default_value) const override + ABSL_LOCKS_EXCLUDED(mutex_); + + // Removes preferences + void Remove(absl::string_view key) override ABSL_LOCKS_EXCLUDED(mutex_); + + private: + // Writes data to storage. + bool Commit() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + bool SetValue(absl::string_view key, const nlohmann::json& value) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + template + T GetValue(absl::string_view key, const T& default_value) const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + template + bool SetArrayValue(absl::string_view key, absl::Span value) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + template + std::vector GetArrayValue(absl::string_view key, + absl::Span default_value) const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + nlohmann::json value_ ABSL_GUARDED_BY(mutex_); + std::unique_ptr preferences_repository_ + ABSL_GUARDED_BY(mutex_); + + mutable absl::Mutex mutex_; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPLEMENTATION_LINUX_PREFERENCES_MANAGER_H_ diff --git a/internal/platform/implementation/linux/preferences_manager_test.cc b/internal/platform/implementation/linux/preferences_manager_test.cc new file mode 100644 index 00000000..064e4acf --- /dev/null +++ b/internal/platform/implementation/linux/preferences_manager_test.cc @@ -0,0 +1,189 @@ +// Copyright 2021-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/preferences_manager.h" + +#include + +#include +#include // NOLINT(build/c++17) +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +namespace { +using json = ::nlohmann::json; +constexpr absl::Duration kTimeOut = absl::Milliseconds(200); +constexpr char kPreferencesFilePath[] = "Google/Nearby/Sharing"; +} // namespace + + +TEST(PreferencesManager, CorruptedConfigFile) { + std::filesystem::path settingsPath = + std::filesystem::temp_directory_path(); + std::ofstream output_stream{settingsPath / "preferences.json"}; + output_stream << "CORRUPTED" << std::endl; + + NEARBY_LOGS(INFO) << "Loading preferences from: " << settingsPath.string(); + EXPECT_EQ(PreferencesManager(settingsPath.string()).GetInteger("data", 100), + 100); +} + +TEST(PreferencesManager, ValidConfigFile) { + std::filesystem::path settingsPath = + std::filesystem::temp_directory_path(); + std::ofstream output_stream{settingsPath / "preferences.json"}; + output_stream << "{\"data\":8, \"name\": \"Valid\"}" << std::endl; + output_stream.close(); + + NEARBY_LOGS(INFO) << "Loading preferences from: " << settingsPath.string(); + EXPECT_EQ(PreferencesManager(settingsPath.string()).GetInteger("data", 100), + 8); +} + +TEST(PreferencesManager, SetAndGetBoolean) { + std::string bool_key = "bool_key"; + PreferencesManager pm(kPreferencesFilePath); + EXPECT_TRUE(pm.GetBoolean(bool_key, true)); + pm.SetBoolean(bool_key, true); + EXPECT_TRUE(pm.GetBoolean(bool_key, false)); +} + +TEST(PreferencesManager, SetAndGetInt) { + std::string int_key = "int_key"; + PreferencesManager pm(kPreferencesFilePath); + EXPECT_EQ(pm.GetInteger(int_key, 1234), 1234); + pm.SetInteger(int_key, 6789); + EXPECT_EQ(pm.GetInteger(int_key, 0), 6789); +} + +TEST(PreferencesManager, SetAndGetInt64) { + std::string int64_key = "int64_key"; + PreferencesManager pm(kPreferencesFilePath); + EXPECT_EQ(pm.GetInt64(int64_key, 1234), 1234); + pm.SetInt64(int64_key, 56789); + EXPECT_EQ(pm.GetInt64(int64_key, 0), 56789); +} + +TEST(PreferencesManager, SetAndGetString) { + std::string string_key = "string_key"; + PreferencesManager pm(kPreferencesFilePath); + EXPECT_EQ(pm.GetString(string_key, "abcd"), "abcd"); + pm.SetString(string_key, "this is a test string"); + EXPECT_EQ(pm.GetString(string_key, ""), "this is a test string"); +} + +TEST(PreferencesManager, SetAndGetTime) { + std::string time_key = "time_key"; + PreferencesManager pm(kPreferencesFilePath); + absl::Time time = absl::Now(); + EXPECT_EQ(pm.GetTime(time_key, time), time); + pm.SetTime(time_key, time); + absl::Time ret = pm.GetTime(time_key, absl::Now()); + EXPECT_EQ(absl::ToUnixNanos(ret), absl::ToUnixNanos(time)); +} + +TEST(PreferencesManager, MultipleSetAndGetString) { + std::string string1_key = "string1_key"; + PreferencesManager pm(kPreferencesFilePath); + pm.SetString(string1_key, "this is first string"); + pm.SetString(string1_key, "this is second string"); + EXPECT_EQ(pm.GetString(string1_key, ""), "this is second string"); +} + +TEST(PreferencesManager, SetAndGetValue) { + std::string value_key = "value_key"; + PreferencesManager pm(kPreferencesFilePath); + json value = {{"key1", "value1"}, {"key2", "value2"}}; + EXPECT_TRUE(pm.Get(value_key, json()).empty()); + pm.Set(value_key, value); + auto result = pm.Get(value_key, json()); + ASSERT_FALSE(result.empty()); + auto val = result["key2"]; + EXPECT_EQ(val.get(), "value2"); +} + +TEST(PreferencesManager, SetAndGetBooleanArray) { + std::string bool_array_key = "bool_array_key"; + auto pm = PreferencesManager(kPreferencesFilePath); + auto default_result = + pm.GetBooleanArray(bool_array_key, absl::Span({true})); + EXPECT_EQ(default_result[0], true); + pm.SetBooleanArray(bool_array_key, + absl::Span({true, false, false, true, true})); + auto result = + pm.GetBooleanArray(bool_array_key, absl::Span({true})); + EXPECT_EQ(result[2], false); + EXPECT_EQ(result[3], true); +} + +TEST(PreferencesManager, SetAndGetIntArray) { + std::string int_array_key = "int_array_key"; + auto pm = PreferencesManager(kPreferencesFilePath); + auto result = pm.GetIntegerArray(int_array_key, std::vector{5, 6}); + EXPECT_EQ(result[1], 6); + pm.SetIntegerArray(int_array_key, std::vector{1, 7, 4, 10, 12}); + result = pm.GetIntegerArray(int_array_key, std::vector{11, 17, 14, 110}); + EXPECT_EQ(result[3], 10); +} + +TEST(PreferencesManager, SetAndGetInt64Array) { + std::string int64_array_key = "int64_array_key"; + auto pm = PreferencesManager(kPreferencesFilePath); + auto result = pm.GetInt64Array(int64_array_key, std::vector{99}); + EXPECT_EQ(result[0], 99); + pm.SetInt64Array(int64_array_key, std::vector{16, 7, 64, 100, 12}); + result = pm.GetInt64Array(int64_array_key, std::vector{1, 5, 6, 12}); + EXPECT_EQ(result[3], 100); + EXPECT_EQ(result[4], 12); +} + +TEST(PreferencesManager, SetAndGetStringArray) { + std::string string_array_key = "string_array_key"; + auto pm = PreferencesManager(kPreferencesFilePath); + auto result = pm.GetStringArray(string_array_key, + std::vector{"value", "morning"}); + EXPECT_EQ(result[1], "morning"); + pm.SetStringArray( + string_array_key, + std::vector{"one", "two", "three", "four", "five"}); + result = pm.GetStringArray(string_array_key, + std::vector{"good", "morning"}); + EXPECT_EQ(result[3], "four"); +} + +TEST(PreferencesManager, RemoveKey) { + std::string string_key = "string_key"; + auto pm = PreferencesManager(kPreferencesFilePath); + pm.SetString(string_key, "remove key"); + pm.Remove(string_key); + auto result = pm.GetString(string_key, "default key"); + EXPECT_EQ(result, "default key"); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/preferences_repository.cc b/internal/platform/implementation/linux/preferences_repository.cc new file mode 100644 index 00000000..c6e3d2f3 --- /dev/null +++ b/internal/platform/implementation/linux/preferences_repository.cc @@ -0,0 +1,153 @@ +// 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/preferences_repository.h" + +#include +#include // NOLINT(build/c++17) +#include +#include + +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +namespace { +using json = ::nlohmann::json; + +constexpr char kPreferencesFileName[] = "preferences.json"; +constexpr char kPreferencesBackupFileName[] = "preferences_bak.json"; + +} // namespace + +json PreferencesRepository::LoadPreferences() { + absl::MutexLock lock(&mutex_); + std::optional preferences = AttemptLoad(); + if (preferences.has_value()) { + // The top level root should be an object, if it's not then something went + // wrong or the file was corrupted. + if (!preferences.value().is_object()) { + NEARBY_LOGS(ERROR) << "Preferences loaded was not a valid object: " + << preferences.value().dump(4); + + return json::object(); + } + + return preferences.value(); + } + + NEARBY_LOGS(ERROR) << "Could not load preferences file, trying backup."; + + // In the future we should switch to using a transaction log or another + // stable method which doesn't pose a risk of losing settings + preferences = RestoreFromBackup(); + if (preferences.has_value()) { + NEARBY_LOGS(ERROR) << "Successfully recovered from backup."; + return preferences.value(); + } + + NEARBY_LOGS(ERROR) << "Failed to load preferences file from back up."; + + return json::object(); +} + +bool PreferencesRepository::SavePreferences(json preferences) { + absl::MutexLock lock(&mutex_); + try { + std::filesystem::path path = path_; + if (!std::filesystem::exists(path) && + !std::filesystem::create_directories(path)) { + NEARBY_LOGS(ERROR) << "Failed to create preferences path."; + return false; + } + + std::filesystem::path full_name = path / kPreferencesFileName; + std::filesystem::path full_name_backup = path / kPreferencesBackupFileName; + + // Create a backup without moving the bytes on disk + if (std::filesystem::exists(full_name)) { + NEARBY_LOGS(INFO) << "Making backup of preferences file."; + std::filesystem::rename(full_name, full_name_backup); + } + + std::ofstream preferences_file(full_name.c_str()); + preferences_file << preferences; + preferences_file.close(); + + // Make sure the file wasn't saved in a corrupted state + if (!AttemptLoad().has_value()) { + NEARBY_LOGS(ERROR) << "Preferences saved to disk in corrupted state. " + "Restoring from backup."; + + if (!RestoreFromBackup().has_value()) { + NEARBY_LOGS(ERROR) << "Failed to restore preferences file."; + return false; + } + } + } catch (const std::exception& e) { + NEARBY_LOGS(ERROR) << "Failed to save preferences file: " << e.what(); + return false; + } + + return true; +} + +std::optional PreferencesRepository::AttemptLoad() { + std::filesystem::path path = path_; + std::filesystem::path full_name = path / kPreferencesFileName; + if (!std::filesystem::exists(path) || !std::filesystem::exists(full_name)) { + return std::nullopt; + } + + try { + std::ifstream preferences_file(full_name.c_str()); + if (!preferences_file.good()) { + return std::nullopt; + } + + json preferences = json::parse(preferences_file, nullptr, false); + preferences_file.close(); + + if (preferences.is_discarded()) { + NEARBY_LOGS(ERROR) << "Preferences file corrupted."; + return std::nullopt; + } + + return preferences; + } catch (const std::exception& e) { + NEARBY_LOGS(ERROR) << "Exception while loading preferences: " << e.what(); + return std::nullopt; + } +} + +std::optional PreferencesRepository::RestoreFromBackup() { + std::filesystem::path path = path_; + std::filesystem::path full_name = path / kPreferencesFileName; + std::filesystem::path full_name_backup = path / kPreferencesBackupFileName; + + if (!std::filesystem::exists(full_name_backup)) { + NEARBY_LOGS(WARNING) + << "Backup requested but no backup preferences file found."; + return std::nullopt; + } + + std::filesystem::rename(full_name_backup, full_name); + + NEARBY_LOGS(INFO) << "Attempting load from backup preferences."; + return AttemptLoad(); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/preferences_repository.h b/internal/platform/implementation/linux/preferences_repository.h new file mode 100644 index 00000000..b0b23345 --- /dev/null +++ b/internal/platform/implementation/linux/preferences_repository.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef PLATFORM_IMPLEMENTATION_LINUX_PREFERENCES_REPOSITORY_H_ +#define PLATFORM_IMPLEMENTATION_LINUX_PREFERENCES_REPOSITORY_H_ + +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" + +namespace nearby { +namespace linux { + +class PreferencesRepository { + public: + explicit PreferencesRepository(absl::string_view path) : path_(path) {} + + nlohmann::json LoadPreferences() ABSL_LOCKS_EXCLUDED(&mutex_); + bool SavePreferences(nlohmann::json preferences) ABSL_LOCKS_EXCLUDED(&mutex_); + + std::optional AttemptLoad(); + std::optional RestoreFromBackup(); + + private: + absl::Mutex mutex_; + const std::string path_; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPLEMENTATION_LINUX_PREFERENCES_REPOSITORY_H_ diff --git a/internal/platform/implementation/linux/preferences_repository_test.cc b/internal/platform/implementation/linux/preferences_repository_test.cc new file mode 100644 index 00000000..3e380bb9 --- /dev/null +++ b/internal/platform/implementation/linux/preferences_repository_test.cc @@ -0,0 +1,161 @@ +// 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/preferences_repository.h" + +#include // NOLINT(build/c++17) +#include +#include + +#include "gtest/gtest.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/device_info.h" +#include "internal/platform/implementation/platform.h" + +namespace nearby { +namespace linux { +namespace { + +using json = ::nlohmann::json; + +constexpr char kPreferencesFileName[] = "preferences.json"; +constexpr char kPreferencesBackupFileName[] = "preferences_bak.json"; +constexpr char kPreferencesPath[] = "Google/Nearby/Sharing"; + +TEST(PreferencesRepository, LoadWithBadPath) { + PreferencesRepository preferences_repository{"c:\\users\\a\\b\\c\\d\\e\\f"}; + json result = preferences_repository.LoadPreferences(); + EXPECT_TRUE(result.empty()); +} + +TEST(PreferencesRepository, RecoverFromBadPreferences) { + std::optional app_data_path = + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + ASSERT_TRUE(app_data_path.has_value()); + std::filesystem::path full_path = *app_data_path / kPreferencesPath; + std::filesystem::path full_name = full_path / kPreferencesFileName; + + if (std::filesystem::exists(full_name)) { + std::filesystem::remove(full_name); + } + + std::ofstream pref_file(full_name.c_str()); + pref_file << "\"Bad top level object\""; + pref_file.close(); + + PreferencesRepository preferences_repository{full_path.string()}; + EXPECT_EQ(preferences_repository.LoadPreferences(), json::object()); +} + +TEST(PreferencesRepository, SaveAndLoadPreferences) { + std::optional app_data_path = + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + ASSERT_TRUE(app_data_path.has_value()); + std::filesystem::path full_path = *app_data_path / kPreferencesPath; + std::filesystem::path full_name = full_path / kPreferencesFileName; + + if (std::filesystem::exists(full_name)) { + std::filesystem::remove(full_name); + } + + PreferencesRepository preferences_repository{full_path.string()}; + json data; + data["key1"] = "value1"; + data["key2"] = "value2"; + EXPECT_TRUE(preferences_repository.SavePreferences(data)); + json result = preferences_repository.LoadPreferences(); + EXPECT_EQ(result.size(), 2); + EXPECT_EQ(result["key1"], "value1"); + EXPECT_EQ(result["key2"], "value2"); + std::filesystem::remove(full_name); +} + +TEST(PreferencesRepository, LoadFromBackup) { + std::optional app_data_path = + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + ASSERT_TRUE(app_data_path.has_value()); + std::filesystem::path full_path = *app_data_path / kPreferencesPath; + std::filesystem::path full_name = full_path / kPreferencesFileName; + std::filesystem::path full_name_backup = + full_path / kPreferencesBackupFileName; + + if (std::filesystem::exists(full_name)) { + std::filesystem::remove(full_name); + } + + if (std::filesystem::exists(full_name_backup)) { + std::filesystem::remove(full_name_backup); + } + + PreferencesRepository preferences_repository{full_path.string()}; + json data; + data["key1"] = "value1"; + data["key2"] = "value2"; + + std::ofstream backup_file(full_name_backup.c_str()); + backup_file << data; + backup_file.close(); + + std::optional result; + result = preferences_repository.AttemptLoad(); + EXPECT_FALSE(result.has_value()); + result = preferences_repository.RestoreFromBackup(); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(result.value()["key1"], "value1"); + EXPECT_EQ(result.value()["key2"], "value2"); + std::filesystem::remove(full_name); + EXPECT_FALSE(std::filesystem::exists(full_name_backup)); +} + +TEST(PreferencesRepository, RecoverFromCorruption) { + std::optional app_data_path = + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + ASSERT_TRUE(app_data_path.has_value()); + std::filesystem::path full_path = *app_data_path / kPreferencesPath; + std::filesystem::path full_name = full_path / kPreferencesFileName; + std::filesystem::path full_name_backup = + full_path / kPreferencesBackupFileName; + + if (std::filesystem::exists(full_name)) { + std::filesystem::remove(full_name); + } + + if (std::filesystem::exists(full_name_backup)) { + std::filesystem::remove(full_name_backup); + } + + PreferencesRepository preferences_repository{full_path.string()}; + json data; + data["key1"] = "value1"; + data["key2"] = "value2"; + + std::ofstream preferences_file(full_name_backup.c_str()); + preferences_file << data; + preferences_file.close(); + + std::ofstream backup_file(full_name.c_str()); + backup_file << "[BAD JSON FILE]"; + backup_file.close(); + + std::optional result = preferences_repository.LoadPreferences(); + EXPECT_EQ(result.value()["key1"], "value1"); + EXPECT_EQ(result.value()["key2"], "value2"); + std::filesystem::remove(full_name); + EXPECT_FALSE(std::filesystem::exists(full_name_backup)); +} + +} // namespace +} // namespace linux +} // namespace nearby From fa197d2036614301ff79d6816ebbd4d65e19f28a Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Mon, 7 Aug 2023 15:16:43 -0500 Subject: [PATCH 019/201] Implemented submittable_executor and some other missed files A file was named wrong. It was changed. --- .../implementation/linux/device_info_test.cc | 129 +++++++++ .../linux/{mutext_test.cc => mutex_test.cc} | 0 .../linux/scheduled_executor_test.cc | 179 +++++++++++++ .../linux/submittable_executor.cc | 63 +++++ .../linux/submittable_executor.h | 53 ++++ .../linux/submittable_executor_test.cc | 250 ++++++++++++++++++ .../implementation/linux/thread_pool_test.cc | 71 +++++ 7 files changed, 745 insertions(+) create mode 100644 internal/platform/implementation/linux/device_info_test.cc rename internal/platform/implementation/linux/{mutext_test.cc => mutex_test.cc} (100%) create mode 100644 internal/platform/implementation/linux/scheduled_executor_test.cc create mode 100644 internal/platform/implementation/linux/submittable_executor.cc create mode 100644 internal/platform/implementation/linux/submittable_executor.h create mode 100644 internal/platform/implementation/linux/submittable_executor_test.cc create mode 100644 internal/platform/implementation/linux/thread_pool_test.cc diff --git a/internal/platform/implementation/linux/device_info_test.cc b/internal/platform/implementation/linux/device_info_test.cc new file mode 100644 index 00000000..9168a7b4 --- /dev/null +++ b/internal/platform/implementation/linux/device_info_test.cc @@ -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 +#include + +#include "gtest/gtest.h" +#include "absl/synchronization/notification.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 listener_1 = + [](api::DeviceInfo::ScreenStatus) {}; + std::function 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 listener_1 = + [](api::DeviceInfo::ScreenStatus) {}; + std::function 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 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 diff --git a/internal/platform/implementation/linux/mutext_test.cc b/internal/platform/implementation/linux/mutex_test.cc similarity index 100% rename from internal/platform/implementation/linux/mutext_test.cc rename to internal/platform/implementation/linux/mutex_test.cc diff --git a/internal/platform/implementation/linux/scheduled_executor_test.cc b/internal/platform/implementation/linux/scheduled_executor_test.cc new file mode 100644 index 00000000..2c9e804f --- /dev/null +++ b/internal/platform/implementation/linux/scheduled_executor_test.cc @@ -0,0 +1,179 @@ +// 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/scheduled_executor.h" + +#include +#include + +#include "gtest/gtest.h" +#include "absl/synchronization/notification.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "internal/platform/implementation/linux/test_data.h" + +namespace nearby { +namespace linux { +namespace { + +TEST(ScheduledExecutorTests, ExecuteSucceeds) { + absl::Notification notification; + // Arrange + std::string expected(RUNNABLE_0_TEXT.c_str()); + + auto submittableExecutor = std::make_unique(); + std::string output = std::string(); + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + // Act + submittableExecutor->Execute([&]() { + threadIds->push_back(std::this_thread::get_id()); + output.append(RUNNABLE_0_TEXT.c_str()); + notification.Notify(); + }); + + ASSERT_TRUE( + notification.WaitForNotificationWithTimeout(absl::Milliseconds(200))); + submittableExecutor->Shutdown(); + + // Assert + // We should've run 1 time on the main thread, and 1 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(ScheduledExecutorTests, ScheduleSucceeds) { + absl::Notification notification; + // Arrange + std::string expected(RUNNABLE_0_TEXT.c_str()); + + auto submittableExecutor = std::make_unique(); + std::string output = std::string(); + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + std::chrono::system_clock::time_point timeNow = + std::chrono::system_clock::now(); + std::chrono::system_clock::time_point timeExecuted; + + // Act + submittableExecutor->Schedule( + [&]() { + timeExecuted = std::chrono::system_clock::now(); + threadIds->push_back(std::this_thread::get_id()); + output.append(RUNNABLE_0_TEXT.c_str()); + notification.Notify(); + }, + absl::Milliseconds(50)); + + ASSERT_TRUE( + notification.WaitForNotificationWithTimeout(absl::Milliseconds(200))); + submittableExecutor->Shutdown(); + + 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(ScheduledExecutorTests, CancelSucceeds) { + absl::Notification notification; + // Arrange + std::string expected(""); + + auto submittableExecutor = std::make_unique(); + std::string output = std::string(); + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + // Act + auto cancelable = submittableExecutor->Schedule( + [&]() { + threadIds->push_back(std::this_thread::get_id()); + output.append(RUNNABLE_0_TEXT.c_str()); + notification.Notify(); + }, + absl::Milliseconds(1000)); + + auto actual = cancelable->Cancel(); + + EXPECT_FALSE( + notification.WaitForNotificationWithTimeout(absl::Milliseconds(2000))); + submittableExecutor->Shutdown(); + + // Assert + ASSERT_TRUE(actual); + 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, expected); +} + +TEST(ScheduledExecutorTests, CancelAfterStartedFails) { + absl::Notification notification; + // Arrange + std::string expected(RUNNABLE_0_TEXT.c_str()); + + auto submittableExecutor = std::make_unique(); + std::string output = std::string(); + // Container to note threads that ran + std::unique_ptr> threadIds = + std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + // Act + auto cancelable = submittableExecutor->Schedule( + [&]() { + threadIds->push_back(std::this_thread::get_id()); + output.append(RUNNABLE_0_TEXT.c_str()); + notification.Notify(); + }, + absl::Milliseconds(100)); + + absl::SleepFor(absl::Milliseconds(200)); + auto actual = cancelable->Cancel(); + + ASSERT_TRUE( + notification.WaitForNotificationWithTimeout(absl::Milliseconds(2000))); + submittableExecutor->Shutdown(); + + // Assert + ASSERT_FALSE(actual); + 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); +} + +} // namespace +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/submittable_executor.cc b/internal/platform/implementation/linux/submittable_executor.cc new file mode 100644 index 00000000..3b721522 --- /dev/null +++ b/internal/platform/implementation/linux/submittable_executor.cc @@ -0,0 +1,63 @@ +// 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/submittable_executor.h" + +#include "internal/platform/implementation/linux/executor.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +SubmittableExecutor::SubmittableExecutor() : SubmittableExecutor(1) {} + +SubmittableExecutor::SubmittableExecutor(int32_t max_concurrancy) + : executor_(std::make_unique(max_concurrancy)), + shut_down_(false) {} + +bool SubmittableExecutor::DoSubmit(Runnable&& wrapped_callable) { + if (!shut_down_) { + executor_->Execute(std::move(wrapped_callable)); + return true; + } + + NEARBY_LOGS(ERROR) << "Error: " << __func__ + << ": Attempt to DoSubmit on a shutdown executor."; + + return false; +} + +// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable- +void SubmittableExecutor::Execute(Runnable&& runnable) { + if (!shut_down_) { + executor_->Execute(std::move(runnable)); + } else { + NEARBY_LOGS(ERROR) << "Error: " << __func__ + << ": Attempt to Execute on a shutdown executor."; + } +} + +// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#shutdown-- +void SubmittableExecutor::Shutdown() { + if (!shut_down_) { + executor_->Shutdown(); + shut_down_ = true; + } + + NEARBY_LOGS(ERROR) << "Error: " << __func__ + << ": Attempt to Shutdown on a shutdown executor."; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/submittable_executor.h b/internal/platform/implementation/linux/submittable_executor.h new file mode 100644 index 00000000..63b1ef0b --- /dev/null +++ b/internal/platform/implementation/linux/submittable_executor.h @@ -0,0 +1,53 @@ +// 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_SUBMITTABLE_EXECUTOR_H_ +#define PLATFORM_IMPL_LINUX_SUBMITTABLE_EXECUTOR_H_ + +#include "internal/platform/implementation/submittable_executor.h" +#include "internal/platform/implementation/linux/executor.h" + +namespace nearby { +namespace linux { + +// Main interface to be used by platform as a base class for +// - MultiThreadExecutorWrapper +// - SingleThreadExecutorWrapper +// Platform must override bool submit(absl::AnyInvocable) method. +class SubmittableExecutor : public api::SubmittableExecutor { + public: + SubmittableExecutor(); + SubmittableExecutor(int32_t maxConcurrancy); + ~SubmittableExecutor() override = default; + + // Submit a callable (with no delay). + // Returns true, if callable was submitted, false otherwise. + // Callable is not submitted if shutdown is in progress. + bool DoSubmit(Runnable&& wrapped_callable) override; + + // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable- + void Execute(Runnable&& runnable) override; + + // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html#shutdown-- + void Shutdown() override; + + private: + std::unique_ptr executor_; + std::atomic_bool shut_down_ = false; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_SUBMITTABLE_EXECUTOR_H_ diff --git a/internal/platform/implementation/linux/submittable_executor_test.cc b/internal/platform/implementation/linux/submittable_executor_test.cc new file mode 100644 index 00000000..b3cf11d6 --- /dev/null +++ b/internal/platform/implementation/linux/submittable_executor_test.cc @@ -0,0 +1,250 @@ +// 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/submittable_executor.h" + +#include +#include + +#include "gtest/gtest.h" +#include "absl/synchronization/blocking_counter.h" +#include "absl/synchronization/notification.h" +#include "absl/time/time.h" +#include "internal/platform/implementation/linux/test_data.h" + +namespace nearby { +namespace linux { +namespace { + +constexpr absl::Duration kWaitTimeout = absl::Milliseconds(200); + +TEST(SubmittableExecutorTests, SingleThreadedExecuteSucceeds) { + absl::Notification notification; + // Arrange + std::string expected(RUNNABLE_0_TEXT.c_str()); + + auto submittableExecutor = std::make_unique(); + std::string output = std::string(); + // Container to note threads that ran + auto threadIds = std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + // Act + submittableExecutor->Execute([&]() { + threadIds->push_back(std::this_thread::get_id()); + output.append(RUNNABLE_0_TEXT.c_str()); + notification.Notify(); + }); + + ASSERT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout)); + submittableExecutor->Shutdown(); + + // Assert + // We should've run 1 time on the main thread, and 1 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(SubmittableExecutorTests, SingleThreadedExecuteAfterShutdownFails) { + // Arrange + std::string expected(""); + + auto submittableExecutor = std::make_unique(); + std::string output = std::string(); + // Container to note threads that ran + auto threadIds = std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + submittableExecutor->Shutdown(); + + // Act + submittableExecutor->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 0 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, expected); +} + +TEST(SubmittableExecutorTests, SingleThreadedDoSubmitSucceeds) { + absl::Notification notification; + // Arrange + std::string expected(RUNNABLE_0_TEXT.c_str()); + + auto submittableExecutor = std::make_unique(); + std::string output = std::string(); + // Container to note threads that ran + auto threadIds = std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + // Act + auto result = submittableExecutor->DoSubmit([&]() { + threadIds->push_back(std::this_thread::get_id()); + output.append(RUNNABLE_0_TEXT.c_str()); + notification.Notify(); + }); + + ASSERT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout)); + submittableExecutor->Shutdown(); + + // Assert + // We should've said we were going to run this one + ASSERT_TRUE(result); + // We should've run 1 time on the main thread, and 1 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(SubmittableExecutorTests, + SingleThreadedDoSubmitAfterShutdownReturnsFalse) { + // Arrange + std::string expected(""); + + auto submittableExecutor = std::make_unique(); + std::unique_ptr output = std::make_unique(); + // Container to note threads that ran + auto threadIds = std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + submittableExecutor->Shutdown(); + + // Act + auto result = submittableExecutor->DoSubmit([&output, &threadIds]() { + threadIds->push_back(std::this_thread::get_id()); + output->append(RUNNABLE_0_TEXT.c_str()); + }); + + // Assert + // We should've said we were going to run this one + ASSERT_FALSE(result); + // We should've run 1 time on the main thread, and 1 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(SubmittableExecutorTests, SingleThreadedExecuteMultipleTasksSucceeds) { + absl::BlockingCounter blocking_counter(5); + + // Arrange + std::string expected(RUNNABLE_ALL_TEXT.c_str()); + + auto submittableExecutor = std::make_unique(); + std::unique_ptr output = std::make_unique(); + // Container to note threads that ran + auto threadIds = std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + // Act + for (int index = 0; index < 5; index++) { + submittableExecutor->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)); + blocking_counter.DecrementCount(); + }); + } + + blocking_counter.Wait(); + submittableExecutor->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)); + // We should've run all runnables on the worker thread + auto workerThreadId = threadIds->at(1); + for (int index = 1; index < threadIds->size(); index++) { + ASSERT_EQ(threadIds->at(index), workerThreadId); + } + + // We should of run them in the order submitted + ASSERT_EQ(*output.get(), expected); +} + +TEST(SubmittableExecutorTests, SingleThreadedDoSubmitMultipleTasksSucceeds) { + absl::BlockingCounter blocking_counter(5); + + // Arrange + std::string expected(RUNNABLE_ALL_TEXT.c_str()); + + auto submittableExecutor = std::make_unique(); + std::unique_ptr output = std::make_unique(); + // Container to note threads that ran + auto threadIds = std::make_unique>(); + + threadIds->push_back(std::this_thread::get_id()); + + // Act + bool result = true; + for (int index = 0; index < 5; index++) { + result &= submittableExecutor->DoSubmit([&, 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)); + blocking_counter.DecrementCount(); + }); + } + + blocking_counter.Wait(); + submittableExecutor->Shutdown(); + + // Assert + // All of these should have submitted + ASSERT_TRUE(result); + // 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)); + // We should've run all runnables on the worker thread + auto workerThreadId = threadIds->at(1); + for (int index = 1; index < threadIds->size(); index++) { + ASSERT_EQ(threadIds->at(index), workerThreadId); + } + + // We should of run them in the order submitted + ASSERT_EQ(*output.get(), expected); +} + +} // namespace +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/thread_pool_test.cc b/internal/platform/implementation/linux/thread_pool_test.cc new file mode 100644 index 00000000..f2c8327a --- /dev/null +++ b/internal/platform/implementation/linux/thread_pool_test.cc @@ -0,0 +1,71 @@ +// 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/thread_pool.h" + +#include + +#include "gtest/gtest.h" +#include "absl/synchronization/blocking_counter.h" +#include "absl/synchronization/notification.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" + +namespace nearby { +namespace linux { +namespace { + +constexpr int kTaskCount = 10; + +TEST(ThreadPool, TasksInSingleThreadRunInSequence) { + absl::BlockingCounter blocking_counter(kTaskCount); + auto pool = ThreadPool::Create(1); + std::vector completed_tasks; + std::vector expected_tasks; + + for (int i = 0; i < kTaskCount; ++i) { + expected_tasks.push_back(i); + pool->Run([&, i]() { + absl::SleepFor(absl::Milliseconds(200)); + completed_tasks.push_back(i); + blocking_counter.DecrementCount(); + }); + } + + blocking_counter.Wait(); + EXPECT_EQ(completed_tasks, expected_tasks); + pool->ShutDown(); +} + +TEST(ThreadPool, TasksInMultipleThreadsRunInParallel) { + absl::BlockingCounter blocking_counter(kTaskCount); + absl::Time start_time = absl::Now(); + + auto pool = ThreadPool::Create(2); + + for (int i = 0; i < kTaskCount; ++i) { + pool->Run([&]() { + absl::SleepFor(absl::Milliseconds(200)); + blocking_counter.DecrementCount(); + }); + } + + blocking_counter.Wait(); + EXPECT_TRUE(absl::Now() - start_time < absl::Milliseconds(1500)); + pool->ShutDown(); +} + +} // namespace +} // namespace linux +} // namespace nearby From aea2e169376478bed859e9f7b5a269f5b2ead694 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 9 Aug 2023 18:42:56 +0530 Subject: [PATCH 020/201] Walk through InterfacesAdded data correctly. --- .../implementation/linux/bluetooth_classic_medium.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index e298d6c0..6340179e 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -1,6 +1,6 @@ #include - #include + #include #include "absl/strings/str_replace.h" @@ -86,6 +86,11 @@ int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, } return 0; } + ret = sd_bus_message_skip(m, "a{sv}"); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << "Error skipping dict entry: " << ret; + return -1; + } } return 0; From c8af59666df17bffb024ab82016a376a7f2422bd Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 15 Aug 2023 20:52:51 +0530 Subject: [PATCH 021/201] Rewrite dbus code using sdbus-c++ --- internal/platform/implementation/linux/BUILD | 1 + .../implementation/linux/bluetooth_adapter.cc | 172 +++++----- .../implementation/linux/bluetooth_adapter.h | 23 +- .../linux/bluetooth_bluez_profile.cc | 298 ++++++++++------- .../linux/bluetooth_bluez_profile.h | 92 ++++-- .../linux/bluetooth_classic_device.cc | 149 ++++++--- .../linux/bluetooth_classic_device.h | 72 +++- .../linux/bluetooth_classic_medium.cc | 312 +++++++++--------- .../linux/bluetooth_classic_medium.h | 43 ++- .../linux/bluetooth_classic_server_socket.h | 15 +- .../linux/bluetooth_classic_socket.cc | 51 ++- .../linux/bluetooth_classic_socket.h | 33 +- .../implementation/linux/bluetooth_devices.cc | 49 +++ .../implementation/linux/bluetooth_devices.h | 42 +++ .../implementation/linux/bluetooth_pairing.cc | 163 ++++----- .../implementation/linux/bluetooth_pairing.h | 26 +- .../linux/bluetoth_classic_server_socket.cc | 19 +- .../platform/implementation/linux/bluez.cc | 32 ++ .../platform/implementation/linux/bluez.h | 33 +- .../linux/bluez_adapter_client_glue.h | 179 ++++++++++ .../linux/bluez_device_client_glue.h | 215 ++++++++++++ .../implementation/linux/bluez_profile_glue.h | 43 +++ .../linux/bluez_profile_manager_client_glue.h | 46 +++ .../implementation/linux/device_info.cc | 139 +++----- .../implementation/linux/device_info.h | 12 +- .../linux/org.bluez.Adapter1.xml | 36 ++ .../linux/org.bluez.Device1.xml | 44 +++ .../linux/org.bluez.Profile1.xml | 17 + .../linux/org.bluez.ProfileManager1.xml | 14 + 29 files changed, 1632 insertions(+), 738 deletions(-) create mode 100644 internal/platform/implementation/linux/bluetooth_devices.cc create mode 100644 internal/platform/implementation/linux/bluetooth_devices.h create mode 100644 internal/platform/implementation/linux/bluez.cc create mode 100644 internal/platform/implementation/linux/bluez_adapter_client_glue.h create mode 100644 internal/platform/implementation/linux/bluez_device_client_glue.h create mode 100644 internal/platform/implementation/linux/bluez_profile_glue.h create mode 100644 internal/platform/implementation/linux/bluez_profile_manager_client_glue.h create mode 100644 internal/platform/implementation/linux/org.bluez.Adapter1.xml create mode 100644 internal/platform/implementation/linux/org.bluez.Device1.xml create mode 100644 internal/platform/implementation/linux/org.bluez.Profile1.xml create mode 100644 internal/platform/implementation/linux/org.bluez.ProfileManager1.xml diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 3006bf08..067a3c51 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -16,6 +16,7 @@ cc_library( "//internal/platform:logging", "@com_google_absl//absl/strings", "@libsystemd//:lib", + "@sdbus_cpp//:lib", ], ) diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index b24c5395..5d30dc0f 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -1,71 +1,68 @@ -#include +#include +#include #include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { -using namespace api; - bool BluetoothAdapter::SetStatus(Status status) { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - - if (sd_bus_set_property( - system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Powered", &err, "b", - status == api::BluetoothAdapter::Status::kEnabled ? 1 : 0) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error setting adaptor status: " << err.message; + try { + bool val = status == api::BluetoothAdapter::Status::kEnabled; + Powered(val); + return true; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to set Powered status for adapter " + << getObjectPath(); return false; } - return true; } bool BluetoothAdapter::IsEnabled() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - int enabled = 0; + auto proxy = sdbus::createProxy(getProxy().getConnection(), + bluez::SERVICE_DEST, getObjectPath()); + proxy->finishRegistration(); - if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b', - &enabled) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adaptor status: " << err.message; + try { + return proxy->getProperty("Powered").onInterface(INTERFACE_NAME); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Powered status for adapter " + << getObjectPath(); + return false; } - return enabled; } BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - int powered = 0; - int discoverable = 0; - - if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Powered", &err, 'b', - &powered) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adaptor status: " << err.message; - return ScanMode::kUnknown; - } + bool powered = IsEnabled(); if (!powered) { return ScanMode::kNone; } - if (sd_bus_get_property_trivial(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, - 'b', &powered) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adaptor's discoverable status: " - << err.message; + try { + auto proxy = sdbus::createProxy(getProxy().getConnection(), + bluez::SERVICE_DEST, getObjectPath()); + proxy->finishRegistration(); + + bool discoverable = + proxy->getProperty("Discoverable").onInterface(INTERFACE_NAME); + return discoverable ? ScanMode::kConnectableDiscoverable + : ScanMode::kConnectable; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ << ": Got error '" << e.getName() << "' with message '" + << e.getMessage() + << "' while trying to get Discoverable status for adapter " + << getObjectPath(); return ScanMode::kUnknown; } - return discoverable ? ScanMode::kConnectableDiscoverable - : ScanMode::kConnectable; } bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { @@ -76,16 +73,18 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { if (!SetStatus(Status::kEnabled)) { return false; } - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - if (sd_bus_set_property(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Discoverable", &err, "b", - 1) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error setting adapter's discoverable status: " - << err.message; + + try { + Discoverable(true); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) + << __func__ << ": Got error '" << e.getName() << "' with message '" + << e.getMessage() + << "' while trying to set Discoverable status for adapter " + << getObjectPath(); return false; } + return true; } case ScanMode::kNone: @@ -96,65 +95,52 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { } std::string BluetoothAdapter::GetName() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *cname = nullptr; - if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Alias", &err, - &cname) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adapter's name: " << err.message; + auto proxy = sdbus::createProxy(getProxy().getConnection(), + bluez::SERVICE_DEST, getObjectPath()); + proxy->finishRegistration(); + + try { + return proxy->getProperty("Alias").onInterface(INTERFACE_NAME); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Alias for adapter " + << getObjectPath(); return std::string(); } - std::string name(cname); - free(cname); - return name; } bool BluetoothAdapter::SetName(absl::string_view name, bool persist) { - if (persist) { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - std::string pretty_hostname(name); - if (sd_bus_set_property(system_bus_, "org.freedesktop.hostname1", - "/org/freedesktop/hostname1", - "org.freedesktop.hostname1", "PrettyHostname", &err, - "s", pretty_hostname.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error setting PrettyHostname: " << err.message; - } - } return SetName(name); } bool BluetoothAdapter::SetName(absl::string_view name) { - std::string alias(name); - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - if (sd_bus_set_property(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Alias", &err, "s", - alias.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error setting adapter's name: " << err.message; + try { + Alias(std::string(name)); + return true; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to set Alias for adapter " + << getObjectPath(); return false; } - return true; } std::string BluetoothAdapter::GetMacAddress() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *caddr = nullptr; - if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "Address", &err, - &caddr) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting adapter's name: " << err.message; + auto proxy = sdbus::createProxy(getProxy().getConnection(), + bluez::SERVICE_DEST, getObjectPath()); + proxy->finishRegistration(); + + try { + return proxy->getProperty("Address").onInterface(INTERFACE_NAME); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Address for adapter " + << getObjectPath(); return std::string(); } - std::string addr(caddr); - free(caddr); - return addr; } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index b9c4b2c2..0bfe5f99 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -1,18 +1,26 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ - -#include +#include +#include #include "absl/strings/string_view.h" #include "internal/platform/implementation/bluetooth_adapter.h" -#include +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" namespace nearby { namespace linux { -class BluetoothAdapter : public api::BluetoothAdapter { +class BluetoothAdapter + : public api::BluetoothAdapter, + public sdbus::ProxyInterfaces { public: - BluetoothAdapter(sd_bus *bus) { system_bus_ = bus; } - ~BluetoothAdapter() override { sd_bus_unref(system_bus_); }; + BluetoothAdapter(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path) + : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, adapter_object_path) { + registerProxy(); + } + + ~BluetoothAdapter() override { unregisterProxy(); } bool SetStatus(Status status) override; bool IsEnabled() const override; @@ -25,9 +33,6 @@ public: bool SetName(absl::string_view name) override; bool SetName(absl::string_view name, bool persist) override; std::string GetMacAddress() const override; - -private: - sd_bus *system_bus_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index afb7d1a9..8503c503 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -1,80 +1,26 @@ -#include +#include #include #include #include +#include #include #include -#include -#include -#include +#include +#include +#include +#include +#include -#include "absl/strings/substitute.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" -const char *BLUEZ_PROFILEMANAGER_INTERFACE = "org.bluez.ProfileManager1"; - namespace nearby { namespace linux { -static int profile_release(sd_bus_message *m, void *userdata, - sd_bus_error *error) { - return 0; -} -static int profile_new_connection(sd_bus_message *m, void *userdata, - sd_bus_error *error) { - char *c_device_object = nullptr; - int fd = 0, ret; - - ret = sd_bus_message_read(m, "oh", &c_device_object, &fd); - if (ret < 0) { - return ret; - } - - std::string device_object(c_device_object); - fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); - if (fd < 0) { - return sd_bus_error_set_errno(error, errno); - } - - sd_bus *bus; - sd_bus_default_system(&bus); - - BluetoothDevice device(bus, device_object); - auto mac_addr = device.GetMacAddress(); - if (mac_addr.empty()) { - return -1; - } - - struct RegisteredService *service = - static_cast(userdata); - service->connections_lock.Lock(); - service->connections[mac_addr] = fd; - service->connections_lock.Unlock(); - - return 0; -} - -static int profile_request_disconnection(sd_bus_message *m, void *userdata, - sd_bus_error *error) { - // TODO - return 0; -} - -static const sd_bus_vtable vtable[] = { - SD_BUS_VTABLE_START(0), - SD_BUS_METHOD_WITH_ARGS("Release", SD_BUS_NO_ARGS, SD_BUS_NO_RESULT, - profile_release, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD_WITH_ARGS( - "NewConnection", SD_BUS_ARGS("o", path, "h", fd, "a{sq}", properties), - SD_BUS_NO_RESULT, profile_new_connection, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD_WITH_ARGS("RequestDisconnection", SD_BUS_ARGS("o", object), - SD_BUS_NO_RESULT, profile_request_disconnection, - SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_VTABLE_END}; bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { registered_service_uuids_lock_.ReaderLock(); @@ -83,99 +29,209 @@ bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { return registered; } -bool ProfileManager::RegisterProfile(absl::string_view name, - absl::string_view service_uuid) { +void Profile::Release() { + released_ = true; + NEARBY_LOGS(VERBOSE) << __func__ << "Profile object " << getObjectPath() + << " has been released"; +} + +void Profile::NewConnection( + const sdbus::ObjectPath &device_object_path, const sdbus::UnixFd &fd, + const std::map &fd_props) { + if (released_) { + NEARBY_LOGS(ERROR) << __func__ << "NewConnection called on released object " + << getObjectPath(); + throw sdbus::Error("org.bluez.Error.Rejected", + "NewConnection called on released object"); + } + + auto device = devices_.get_device_by_path(device_object_path); + + if (!device.has_value()) { + NEARBY_LOGS(ERROR) + << __func__ + << "NewConection called with a device object we don't know about: " + << device_object_path; + throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); + } + + auto alias = device->get().Alias(); + auto mac_addr = device->get().Address(); + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << ": Connected to " << device->get().getObjectPath(); + + FDProperties props(fd_props); + + absl::MutexLock l(&connections_lock_); + if (connections_.count(mac_addr) != 0) { + connections_[mac_addr].push_back(std::pair(fd, std::move(props))); + } else { + connections_[mac_addr] = std::vector{std::pair(fd, std::move(props))}; + } +} + +void Profile::RequestDisconnection( + const sdbus::ObjectPath &device_object_path) { + auto device = devices_.get_device_by_path(device_object_path); + if (!device.has_value()) { + NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() + << ": RequestDisconnection called with a device object " + "we don't know about: " + << device_object_path; + throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); + } + + auto mac_addr = device->get().Address(); + NEARBY_LOGS(VERBOSE) << __func__ << ": Disconnection requested for device " + << device_object_path; + + absl::MutexLock l(&connections_lock_); + if (connections_.count(mac_addr) == 0) { + NEARBY_LOGS(ERROR) + << __func__ + << "Disconnection requested, but we are not connected to this device"; + return; + } + + connections_.erase(mac_addr); +} + +bool ProfileManager::Register(std::optional name, + absl::string_view service_uuid) { if (ProfileRegistered(service_uuid)) { + NEARBY_LOGS(WARNING) << __func__ << ": Trying to register profile " + << service_uuid << " which was already registered."; return true; } - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - std::string uuid(service_uuid); - - auto profile_object_path = - absl::Substitute("/com/github/google/nearby/profiles/$0", uuid); - struct RegisteredService *service = new struct RegisteredService(uuid); - service->slot = nullptr; - - registered_service_uuids_lock_.Lock(); - auto ret = sd_bus_add_object_vtable(system_bus_, &service->slot, - profile_object_path.c_str(), - "org.bluez.Profile1", vtable, service); - if (ret < 0) { - sd_bus_error_set_errno(&err, ret); - - NEARBY_LOGS(ERROR) << __func__ << "Error adding object " - << profile_object_path << ": " << err.message; - registered_service_uuids_lock_.Unlock(); + auto profile_object_path = bluez::profile_object_path(service_uuid); + try { + std::map options; + if (name.has_value()) { + options["Name"] = std::string(*name); + } + RegisterProfile(profile_object_path, std::string(service_uuid), options); + } catch (const sdbus::Error &e) { + BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "RegisterProfile", e); return false; } - NEARBY_LOGS(VERBOSE) << __func__ - << "Registered a ProfileManager for service UUID " - << uuid << " at " << profile_object_path; - - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez", - BLUEZ_PROFILEMANAGER_INTERFACE, "RegisterProfile", - &err, nullptr, "osa{sq}", "/com/github/google/nearby", - uuid.c_str(), 1, "Name", - std::string(name).c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error calling RegisterProfile: " << err.name << ": " - << err.message; - registered_service_uuids_lock_.Unlock(); - return false; + { + absl::MutexLock l(®istered_service_uuids_lock_); + registered_services_.emplace( + std::string(service_uuid), + std::make_shared(getProxy().getConnection(), + profile_object_path, devices_)); } - registered_services_[uuid] = service; - registered_service_uuids_lock_.Unlock(); + NEARBY_LOGS(INFO) << __func__ + << ": Registered profile instancefor service uuid " + << service_uuid; + return true; } -std::optional -ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device, - absl::string_view service_uuid) { +void ProfileManager::Unregister(absl::string_view service_uuid) { if (!ProfileRegistered(service_uuid)) { + NEARBY_LOGS(WARNING) + << __func__ + << ": attempted to unregister a profile that is not registered"; + return; + } + + auto profile_object_path = bluez::profile_object_path(service_uuid); + NEARBY_LOGS(VERBOSE) << __func__ << ": Unregistering profile " + << profile_object_path; + + try { + UnregisterProfile(profile_object_path); + } catch (const sdbus::Error &e) { + BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "UnregisterProfile", e); + } + + { + absl::MutexLock l(®istered_service_uuids_lock_); + registered_services_.erase(std::string(service_uuid)); + } +} + +// Get a service record FD for a connected profile (identified by service_uuid) +// to the given device. +std::optional +ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device, + absl::string_view service_uuid, + CancellationFlag *cancellation_flag) { + if (!ProfileRegistered(service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << ": Service " << service_uuid + << " is not registered"; return std::nullopt; } auto mac_addr = remote_device.GetMacAddress(); registered_service_uuids_lock_.ReaderLock(); - auto service = registered_services_[std::string(service_uuid)]; + auto profile = registered_services_[std::string(service_uuid)]; registered_service_uuids_lock_.ReaderUnlock(); - service->connections_lock.Lock(); - auto cond = [mac_addr, service]() { - return service->connections.count(mac_addr) == 1; + NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() + << ": Attempting to get a FD for service " + << service_uuid << " on device " << mac_addr; + + auto cond = [mac_addr, profile, cancellation_flag]() { + return profile->connections_.count(mac_addr) != 0 || + (cancellation_flag != nullptr && cancellation_flag->Cancelled()); }; - service->connections_lock.Await(absl::Condition(&cond)); - int fd = service->connections[mac_addr]; - service->connections.erase(mac_addr); - service->connections_lock.Unlock(); + profile->connections_lock_.Lock(); + profile->connections_lock_.Await(absl::Condition(&cond)); + + if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) { + NEARBY_LOGS(WARNING) + << __func__ << ": " << profile->getObjectPath() << ": " + << remote_device.GetMacAddress() + << ": Cancelled waiting for a service record for profile " + << service_uuid; + profile->connections_lock_.Unlock(); + return std::nullopt; + } + + auto [fd, properties] = profile->connections_[mac_addr].back(); + profile->connections_[mac_addr].pop_back(); + if (profile->connections_[mac_addr].empty()) + profile->connections_.erase(mac_addr); + profile->connections_lock_.Unlock(); return fd; } -std::optional> +// Listen for a connected profile on any device, returning the connected device +// with its FD. +std::optional, sdbus::UnixFd>> ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { if (!ProfileRegistered(service_uuid)) { return std::nullopt; } registered_service_uuids_lock_.ReaderLock(); - auto service = registered_services_[std::string(service_uuid)]; + auto profile = registered_services_[std::string(service_uuid)]; registered_service_uuids_lock_.ReaderUnlock(); - service->connections_lock.Lock(); - auto cond = [service]() { return !service->connections.empty(); }; - service->connections_lock.Await(absl::Condition(&cond)); - auto it = service->connections.begin(); - auto mac_addr = it->first; - auto fd = it->second; - service->connections.erase(it); - service->connections_lock.Unlock(); - return std::pair(mac_addr, fd); + NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() + << ": Attempting to get a FD for service " + << profile->getObjectPath(); + + profile->connections_lock_.Lock(); + auto cond = [profile]() { return !profile->connections_.empty(); }; + profile->connections_lock_.Await(absl::Condition(&cond)); + + auto it = profile->connections_.begin(); + auto mac_addr = it->first; + auto [fd, properties] = it->second.back(); + it->second.pop_back(); + if (it->second.empty()) + profile->connections_.erase(it); + profile->connections_lock_.Unlock(); + + return std::pair(devices_.get_device_by_address(mac_addr).value(), fd); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index b579ddbc..e6ea176c 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -2,56 +2,102 @@ #define PLATFORM_IMPL_LINUX_BLUETOOTH_BLUEZ_PROFILE_H_ #include +#include #include +#include #include #include #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_profile_glue.h" +#include "internal/platform/implementation/linux/bluez_profile_manager_client_glue.h" namespace nearby { namespace linux { - -struct RegisteredService { +class Profile : public sdbus::AdaptorInterfaces { public: - sd_bus_slot *slot; - absl::Mutex connections_lock; - // Maps mac addresses to unclaimed FDs. Probably an awful way to do this, but - // whatever. - std::map connections; - std::string &uuid; - RegisteredService(std::string &uuid) : uuid(uuid) {} + Profile(sdbus::IConnection &system_bus, absl::string_view profile_object_path, + BluetoothDevices &devices) + : AdaptorInterfaces(system_bus, std::string(profile_object_path)), + released_(false), devices_(devices) { + registerAdaptor(); + } + ~Profile() { unregisterAdaptor(); } + + struct FDProperties { + FDProperties(const std::map &fd_props) { + if (fd_props.count("Version") == 1) { + version = fd_props.at("Version"); + } + if (fd_props.count("Features") == 1) { + features = fd_props.at("Features"); + } + } + + std::optional version; + std::optional features; + }; + + void Release() override; + void NewConnection(const sdbus::ObjectPath &, const sdbus::UnixFd &, + const std::map &) override; + void RequestDisconnection(const sdbus::ObjectPath &) override; + + std::atomic_bool released_; + + absl::Mutex connections_lock_; + std::map>> + connections_; + + BluetoothDevices &devices_; }; -class ProfileManager { +class ProfileManager + : private sdbus::ProxyInterfaces { public: - ProfileManager(sd_bus *system_bus) { system_bus_ = system_bus; } - ~ProfileManager() { sd_bus_unref(system_bus_); } + ProfileManager(sdbus::IConnection &system_bus, BluetoothDevices &devices) + : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, "/org/bluez"), + devices_(devices) { + registerProxy(); + } + ~ProfileManager() { unregisterProxy(); } bool ProfileRegistered(absl::string_view service_uuid); - bool RegisterProfile(absl::string_view service_name, - absl::string_view service_uuid); - bool RegisterProfile(absl::string_view service_uuid) { - return RegisterProfile("", service_uuid); + bool Register(std::optional service_name, + absl::string_view service_uuid); + bool Register(absl::string_view service_uuid) { + return Register(std::nullopt, service_uuid); } + void Unregister(absl::string_view service_uuid); - std::optional GetServiceRecordFD(api::BluetoothDevice &remote_device, - absl::string_view service_uuid); - std::optional> + std::optional + GetServiceRecordFD(api::BluetoothDevice &remote_device, + absl::string_view service_uuid, + CancellationFlag *cancellation_flag); + std::optional< + std::pair, sdbus::UnixFd>> GetServiceRecordFD(absl::string_view service_uuid); private: + BluetoothDevices &devices_; // Maps service UUIDs to RegisteredService - std::map registered_services_; + std::map> registered_services_; absl::Mutex registered_service_uuids_lock_; - - sd_bus *system_bus_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index ad325e71..b9df13e9 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -1,73 +1,124 @@ +#include +#include #include -#include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" -#include "absl/strings/substitute.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { - -BluetoothDevice::BluetoothDevice(sd_bus *system_bus, absl::string_view adapter, - absl::string_view address) { - mac_addr_ = std::string(address); - object_path_ = absl::Substitute("/org/bluez/$0/dev_$1", adapter, - absl::StrReplaceAll(address, {{":", "_"}})); - system_bus_ = system_bus; -} - -BluetoothDevice::BluetoothDevice(sd_bus *system_bus, - absl::string_view device_object_path) { - system_bus_ = system_bus; - object_path_ = device_object_path; -} - -BluetoothDevice::BluetoothDevice(const BluetoothDevice &device) { - if (!device.mac_addr_.empty()) { - mac_addr_ = device.mac_addr_; - } - object_path_ = device.object_path_; - system_bus_ = sd_bus_ref(device.system_bus_); +BluetoothDevice::BluetoothDevice(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &device_object_path) + : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, + std::string(device_object_path)) { + registerProxy(); } std::string BluetoothDevice::GetName() const { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *cname = nullptr; - if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, - object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "Alias", &err, &cname) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error getting alias for device " - << object_path_ << " :" << err.message; + auto bluez_device = + sdbus::createProxy(getProxy().getConnection(), bluez::SERVICE_DEST, + getProxy().getObjectPath()); + + try { + std::string alias = + bluez_device->getProperty("Alias").onInterface(bluez::DEVICE_INTERFACE); + return alias; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Alias for device " + << bluez_device->getObjectPath(); return std::string(); } - - std::string name(cname); - free(cname); - return name; } std::string BluetoothDevice::GetMacAddress() const { - if (!mac_addr_.empty()) { - return mac_addr_; - } + auto bluez_device = + sdbus::createProxy(getProxy().getConnection(), bluez::SERVICE_DEST, + getProxy().getObjectPath()); - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *c_addr = nullptr; - if (sd_bus_get_property_string(system_bus_, BLUEZ_SERVICE, - object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "Address", &err, &c_addr) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error getting address for device " - << object_path_ << " :" << err.message; + try { + std::string addr = bluez_device->getProperty("Address").onInterface( + bluez::DEVICE_INTERFACE); + return addr; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Address for device " + << bluez_device->getObjectPath(); return std::string(); } +} - std::string addr(c_addr); - free(c_addr); - return addr; +void BluetoothDevice::onConnectProfileReply(const sdbus::Error *error) { + if (error != nullptr && error->getName() != "org.bluez.Error.InProgress") { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << error->getName() + << "' with message '" << error->getMessage() + << " while connecting to profile."; + } +} + +bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { + try { + ConnectProfile(std::string(service_uuid)); + return true; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to asynchronously connect to profile " + << service_uuid << " on device " << getObjectPath(); + return false; + } +} + +MonitoredBluetoothDevice::MonitoredBluetoothDevice( + sdbus::IConnection &system_bus, const sdbus::ObjectPath &device_object_path, + ObserverList &observers) + : BluetoothDevice(system_bus, device_object_path), + ProxyInterfaces(system_bus, bluez::SERVICE_DEST, + std::string(device_object_path)), + observers_(observers) { + registerProxy(); +} + +void MonitoredBluetoothDevice::onPropertiesChanged( + const std::string &interfaceName, + const std::map &changedProperties, + const std::vector &invalidatedProperties) { + if (interfaceName != bluez::DEVICE_INTERFACE) { + return; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << ": Received PropertiesChanged signal for interface " + << interfaceName; + + for (auto it = changedProperties.begin(); it != changedProperties.end(); + it++) { + if (it->first == bluez::DEVICE_PROP_ADDRESS) { + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << ": Notifying observers about address change"; + std::string address = it->second; + for (auto &observer : observers_.GetObservers()) { + observer->DeviceAddressChanged(*this, address); + } + } else if (it->first == bluez::DEVICE_PROP_PAIRED) { + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << "Notifying observers about paired status change."; + for (auto &observer : observers_.GetObservers()) { + observer->DevicePairedChanged(*this, it->second); + } + } else if (it->first == bluez::DEVICE_PROP_CONNECTED) { + NEARBY_LOGS(VERBOSE) + << __func__ << ": " << getObjectPath() + << "Notifying observers about connected status change"; + for (auto &observer : observers_.GetObservers()) { + observer->DeviceConnectedStateChanged(*this, it->second); + } + } + } } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 18e93795..cab3058a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -1,23 +1,27 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ -#include +#include +#include +#include +#include +#include +#include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" +#include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluez_device_client_glue.h" namespace nearby { namespace linux { -const char *BLUEZ_DEVICE_INTERFACE = "org.bluez.Device1"; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. -class BluetoothDevice : public api::BluetoothDevice { +class BluetoothDevice + : public api::BluetoothDevice, + public sdbus::ProxyInterfaces { public: - BluetoothDevice(sd_bus *system_bus, absl::string_view adapter, - absl::string_view address); - BluetoothDevice(sd_bus *system_bus, absl::string_view device_object_path); - BluetoothDevice(const BluetoothDevice &device); - - ~BluetoothDevice() override { sd_bus_unref(system_bus_); }; + BluetoothDevice(sdbus::IConnection &system_bus, const sdbus::ObjectPath &); + ~BluetoothDevice() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() std::string GetName() const override; @@ -25,11 +29,55 @@ public: // Returns BT MAC address assigned to this device. std::string GetMacAddress() const override; + bool ConnectToProfile(absl::string_view service_uuid); + + void + set_pair_reply_callback(absl::AnyInvocable cb) { + absl::MutexLock l(&pair_callback_lock_); + on_pair_reply_cb_ = std::move(cb); + } + + void reset_pair_reply_callback() { + absl::MutexLock l(&pair_callback_lock_); + on_pair_reply_cb_ = DefaultCallback(); + } + +protected: + void onConnectProfileReply(const sdbus::Error *error) override; + void onPairReply(const sdbus::Error *error) override { + absl::ReaderMutexLock l(&pair_callback_lock_); + on_pair_reply_cb_(error); + }; + private: - sd_bus *system_bus_; - std::string object_path_; - std::string mac_addr_; + absl::Mutex pair_callback_lock_; + absl::AnyInvocable on_pair_reply_cb_ = + DefaultCallback(); }; + +class MonitoredBluetoothDevice + : public BluetoothDevice, + public sdbus::ProxyInterfaces { +public: + using sdbus::ProxyInterfaces::registerProxy; + using sdbus::ProxyInterfaces::unregisterProxy; + using sdbus::ProxyInterfaces::getObjectPath; + + MonitoredBluetoothDevice( + sdbus::IConnection &system_bus, const sdbus::ObjectPath &, + ObserverList &observers); + ~MonitoredBluetoothDevice() { unregisterProxy(); } + +protected: + void onPropertiesChanged( + const std::string &interfaceName, + const std::map &changedProperties, + const std::vector &invalidatedProperties) override; + +private: + ObserverList &observers_; +}; + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 6340179e..2115684f 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -1,9 +1,9 @@ #include #include -#include +#include +#include -#include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" #include "internal/platform/implementation/bluetooth_classic.h" @@ -18,120 +18,127 @@ namespace nearby { namespace linux { - -int bluez_interfaces_added_signal_handler(sd_bus_message *m, void *userdata, - sd_bus_error *ret_error) { - const sd_bus_error *reply_err = sd_bus_message_get_error(m); - if (reply_err) { - NEARBY_LOGS(ERROR) << __func__ - << "Received error while listening for InterfacesAdded: " - << reply_err->message; - return 0; - } - - struct BluetoothClassicMedium::DiscoveryParams *params = - static_cast(userdata); - char *c_object_path = nullptr; - int ret = sd_bus_message_read(m, "o", &c_object_path); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error reading object path from message: " << ret; - return ret; - } - - std::string object_path(c_object_path); - - if (!absl::StrContains(object_path, absl::StrCat(params->adapter_object_path, - "/", "dev_"))) { - // Interface added for an object we dont care about. - return 0; - } - - if (params->devices_by_path.count(object_path) != 0) { - // Object already exists - return 0; - } - - ret = sd_bus_message_enter_container(m, 'a', "{sa{sv}}"); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error entering container: " << ret; - return ret; - } - - while (true) { - const char *interface_name = nullptr; - ret = sd_bus_message_read(m, "s", &interface_name); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error reading dict entry: " << ret; - return ret; - } - if (ret == 0) - break; - - if (strcmp(interface_name, "org.bluez.Device1") == 0) { - NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " - << object_path; - sd_bus *system_bus = nullptr; - sd_bus_default_system(&system_bus); - - auto bluetoothDevice = std::make_unique( - BluetoothDevice(system_bus, object_path)); - params->devices_by_path[object_path] = std::move(bluetoothDevice); - - if (params->cb.device_discovered_cb != nullptr) { - params->cb.device_discovered_cb(*params->devices_by_path[object_path]); - } - for (auto &observer : params->observers_.GetObservers()) { - observer->DeviceAdded(*params->devices_by_path[object_path]); - } - return 0; - } - ret = sd_bus_message_skip(m, "a{sv}"); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error skipping dict entry: " << ret; - return -1; - } - } - - return 0; -} - -BluetoothClassicMedium::BluetoothClassicMedium(sd_bus *system_bus, +BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, absl::string_view adapter) - : profile_manager_(sd_bus_ref(system_bus)) { - system_bus_ = system_bus; - adapter_object_path_ = absl::Substitute("/org/bluez/$0/", adapter); + : devices_(system_bus, absl::Substitute("/org/bluez/$0/", adapter), + observers_), + profile_manager_(system_bus) { + bluez_adapter_proxy_ = sdbus::createProxy( + "org.bluez", absl::Substitute("/org/bluez/$0/", adapter)); + bluez_adapter_proxy_->finishRegistration(); + bluez_proxy_ = sdbus::createProxy("org.bluez", "/"); + bluez_proxy_->finishRegistration(); } -BluetoothClassicMedium::~BluetoothClassicMedium() { - sd_bus_unref(system_bus_); - if (system_bus_slot_) - sd_bus_slot_unref(system_bus_slot_); +void BluetoothClassicMedium::onInterfacesAdded(sdbus::Signal &signal) { + sdbus::ObjectPath object; + signal >> object; + + NEARBY_LOGS(VERBOSE) << __func__ << "New intefaces added at " << object; + + auto path_prefix = + absl::Substitute("$0/dev_", bluez_adapter_proxy_->getObjectPath()); + if (object.find(path_prefix) != 0) { + return; + } + + if (devices_.get_device_by_path(object).has_value()) { + // Device already exists. + return; + } + + std::map> interfaces; + signal >> interfaces; + + for (auto it = interfaces.begin(); it != interfaces.end(); it++) { + auto interface = it->first; + + if (interface == "org.bluez.Device1") { + NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " << object; + + auto &device = devices_.add_new_device(object); + + discovery_cb_lock_.ReaderLock(); + if (discovery_cb_.has_value() && + discovery_cb_->device_discovered_cb != nullptr) { + discovery_cb_->device_discovered_cb(device); + } + discovery_cb_lock_.ReaderUnlock(); + + for (auto &observer : observers_.GetObservers()) { + observer->DeviceAdded(device); + } + } + } +} + +void BluetoothClassicMedium::onInterfacesRemoved(sdbus::Signal &signal) { + sdbus::ObjectPath object; + signal >> object; + + NEARBY_LOGS(VERBOSE) << __func__ << ": Intefaces removed at " << object; + + auto path_prefix = + absl::Substitute("$0/dev_", bluez_adapter_proxy_->getObjectPath()); + if (object.find(path_prefix) != 0) { + return; + } + + std::vector interfaces; + signal >> interfaces; + + for (auto &interface : interfaces) { + if (interface == bluez::DEVICE_INTERFACE) { + + { + auto device = get_device_by_path(object); + if (!device.has_value()) { + NEARBY_LOGS(WARNING) << __func__ + << ": received InterfacesRemoved for a device " + "we don't know about: " + << object; + return; + } + + NEARBY_LOGS(INFO) << __func__ << ": " << object << " has been removed"; + for (auto &observer : observers_.GetObservers()) { + observer->DeviceRemoved(*device); + } + discovery_cb_lock_.ReaderLock(); + if (discovery_cb_.has_value() && + discovery_cb_->device_lost_cb != nullptr) { + discovery_cb_->device_lost_cb(*device); + } + discovery_cb_lock_.ReaderUnlock(); + } + remove_device_by_path(object); + } + } } bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { - if (!system_bus_) - return false; + discovery_cb_lock_.Lock(); + discovery_cb_ = std::move(discovery_callback); + discovery_cb_lock_.Unlock(); - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = - nullptr; + NEARBY_LOGS(VERBOSE) << __func__ + << ": Subscribing to InterfacesAdded on / at org.bluez"; - discovery_params_.cb = std::move(discovery_callback); - discovery_params_.adapter_object_path = adapter_object_path_; + bluez_proxy_->registerSignalHandler( + "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", + [this](sdbus::Signal &signal) { this->onInterfacesAdded(signal); }); + bluez_proxy_->registerSignalHandler( + "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", + [this](sdbus::Signal &signal) { this->onInterfacesRemoved(signal); }); - sd_bus_match_signal(system_bus_, &system_bus_slot_, BLUEZ_SERVICE, "/", - "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", - bluez_interfaces_added_signal_handler, - &discovery_params_); - - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, - adapter_object_path_.c_str(), BLUEZ_ADAPTER_INTERFACE, - "StartDiscovery", &err, &reply, nullptr) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error calling StartDiscovery on adapter " - << adapter_object_path_ << ": " << err.message; + try { + NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on " + << bluez_adapter_proxy_->getObjectPath(); + bluez_adapter_proxy_->callMethod("StartDiscovery") + .onInterface(bluez::ADAPTER_INTERFACE); + } catch (const sdbus::Error &e) { + BLUEZ_LOG_METHOD_CALL_ERROR(bluez_adapter_proxy_, "StartDiscovery", e); return false; } @@ -139,20 +146,24 @@ bool BluetoothClassicMedium::StartDiscovery( } bool BluetoothClassicMedium::StopDiscovery() { - if (!system_bus_) - return false; - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - __attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = - nullptr; - - int ret = sd_bus_call_method( - system_bus_, BLUEZ_SERVICE, adapter_object_path_.c_str(), - BLUEZ_ADAPTER_INTERFACE, "StopDiscovery", &err, &reply, nullptr); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error calling StopDiscovery on " - << adapter_object_path_ << ": " << err.message; + NEARBY_LOGS(VERBOSE) + << __func__ << ": Unsubscribing to InterfacesAdded on / at org.bluez"; + bluez_proxy_->unregisterSignalHandler("org.freedesktop.DBus.ObjectManager", + "InterfacesAdded"); + bluez_proxy_->unregisterSignalHandler("org.freedesktop.DBus.ObjectManager", + "InterfacesRemoved"); + try { + NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " + << bluez_adapter_proxy_->getObjectPath(); + bluez_adapter_proxy_->callMethodAsync("StopDiscovery") + .onInterface(bluez::ADAPTER_INTERFACE) + .uponReplyInvoke([this](const sdbus::Error *err) { + this->discovery_cb_lock_.Lock(); + this->discovery_cb_.reset(); + this->discovery_cb_lock_.Unlock(); + }); + } catch (const sdbus::Error &e) { + BLUEZ_LOG_METHOD_CALL_ERROR(bluez_adapter_proxy_, "StopDiscovery", e); return false; } @@ -163,24 +174,31 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, const std::string &service_uuid, CancellationFlag *cancellation_flag) { - auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress()); + auto device_object_path = bluez::device_object_path( + bluez_adapter_proxy_->getObjectPath(), remote_device.GetMacAddress()); if (!profile_manager_.ProfileRegistered(service_uuid)) { - if (!profile_manager_.RegisterProfile(service_uuid)) { - NEARBY_LOGS(ERROR) << __func__ << "Could not register profile " + if (!profile_manager_.Register("", service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " << service_uuid << " with Bluez"; return nullptr; } } - auto fd = profile_manager_.GetServiceRecordFD(remote_device, service_uuid); + + auto &device = devices_.get_device_by_path(device_object_path).value().get(); + device.ConnectToProfile(service_uuid); + + auto fd = profile_manager_.GetServiceRecordFD(remote_device, service_uuid, + cancellation_flag); if (!fd.has_value()) { - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get a new connection for profile " - << service_uuid << " for device " << device_object_path; + NEARBY_LOGS(WARNING) << __func__ + << ": Failed to get a new connection for profile " + << service_uuid << " for device " + << device_object_path; return nullptr; } - return std::unique_ptr(new BluetoothSocket( - remote_device, device_object_path, service_uuid, fd.value())); + return std::unique_ptr( + new BluetoothSocket(remote_device, fd.value())); } std::unique_ptr @@ -188,49 +206,33 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, const std::string &service_uuid) { if (!profile_manager_.ProfileRegistered(service_uuid)) { if (!profile_manager_.RegisterProfile(service_name, service_uuid)) { - NEARBY_LOGS(ERROR) << __func__ << "Could not register profile " + NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " << service_name << " " << service_uuid << " with Bluez"; return nullptr; } } - auto pair = profile_manager_.GetServiceRecordFD(service_uuid); - if (!pair.has_value()) { - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get a new connection for profile " - << service_uuid << " for device "; - return nullptr; - } - - auto device_object_path = GetDeviceObjectPath(pair->first); - auto device = BluetoothDevice(sd_bus_ref(system_bus_), device_object_path); - return std::unique_ptr( - new BluetoothServerSocket(sd_bus_ref(system_bus_), profile_manager_, - adapter_object_path_, service_uuid)); + new BluetoothServerSocket(profile_manager_, service_uuid)); } api::BluetoothDevice * BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { - if (devices_by_path_.count(mac_address) == 1) { - return devices_by_path_[mac_address].get(); - } + auto device = get_device_by_address(mac_address); + if (device.has_value()) + return nullptr; - return nullptr; + return &(device->get()); } std::unique_ptr BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) { - auto device_object_path = GetDeviceObjectPath(remote_device.GetMacAddress()); + auto device_object_path = bluez::device_object_path( + bluez_adapter_proxy_->getObjectPath(), remote_device.GetMacAddress()); return std::unique_ptr( - new BluetoothPairing(sd_bus_ref(system_bus_), device_object_path)); -} - -std::string -BluetoothClassicMedium::GetDeviceObjectPath(absl::string_view mac_address) { - return absl::Substitute("$0/dev_$1", adapter_object_path_, - absl::StrReplaceAll(mac_address, {{":", "_"}})); + new BluetoothPairing(bluez_adapter_proxy_->getObjectPath(), remote_device, + bluez_adapter_proxy_->getConnection())); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index c4d5217d..783cc728 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -1,15 +1,22 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_MEDIUM_H_ +#include #include #include +#include +#include +#include +#include #include +#include "absl/synchronization/mutex.h" #include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" namespace nearby { namespace linux { @@ -17,8 +24,9 @@ namespace linux { // medium. class BluetoothClassicMedium : public api::BluetoothClassicMedium { public: - BluetoothClassicMedium(sd_bus *system_bus, absl::string_view adapter); - ~BluetoothClassicMedium(); + BluetoothClassicMedium(sdbus::IConnection &system_bus, + absl::string_view adapter); + ~BluetoothClassicMedium() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() // @@ -80,27 +88,28 @@ public: observers_.RemoveObserver(observer); }; - struct DiscoveryParams { - std::string &adapter_object_path; - std::map> &devices_by_path; - ObserverList &observers_; - BluetoothClassicMedium::DiscoveryCallback cb; - }; + std::optional> + get_device_by_path(const sdbus::ObjectPath &); + std::optional> + get_device_by_address(const std::string &); + void remove_device_by_path(const sdbus::ObjectPath &); private: + void onInterfacesAdded(sdbus::Signal &signal); + void onInterfacesRemoved(sdbus::Signal &signal); + + BluetoothDevices devices_; + + absl::Mutex discovery_cb_lock_; + std::optional discovery_cb_; + ProfileManager profile_manager_; - - std::string GetDeviceObjectPath(absl::string_view mac_address); - - sd_bus *system_bus_ = nullptr; - sd_bus_slot *system_bus_slot_ = nullptr; - std::string adapter_object_path_ = std::string(); - std::map> devices_by_path_; ObserverList observers_; - DiscoveryParams discovery_params_ = {adapter_object_path_, devices_by_path_, - observers_}; + std::unique_ptr bluez_adapter_proxy_; + std::unique_ptr bluez_proxy_; }; + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h index ce0f2e7d..817c33ed 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -9,14 +9,9 @@ namespace nearby { namespace linux { class BluetoothServerSocket : public api::BluetoothServerSocket { public: - BluetoothServerSocket(sd_bus *system_bus, ProfileManager &profile_manager, - absl::string_view adapter_object_path, - absl::string_view service_uuid) - : profile_manager_(profile_manager) { - system_bus_ = system_bus; - adapter_object_path_ = adapter_object_path; - service_uuid_ = service_uuid; - } + BluetoothServerSocket(ProfileManager &profile_manager, + const std::string &service_uuid) + : profile_manager_(profile_manager), service_uuid_(service_uuid) {} ~BluetoothServerSocket() = default; // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept() @@ -36,10 +31,8 @@ public: Exception Close() override; private: - sd_bus *system_bus_; ProfileManager &profile_manager_; - std::string adapter_object_path_; - std::string service_uuid_; + const std::string &service_uuid_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 4ef2bade..2ad0acec 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -7,17 +7,18 @@ #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" -#include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" -#include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { ExceptionOr BluetoothInputStream::Read(std::int64_t size) { + if (!fd_.has_value()) + return Exception::kIo; + char *data = new char[size]; - ssize_t ret = read(fd_, data, size); + ssize_t ret = read(fd_->get(), data, size); if (ret == 0) { delete[] data; return ExceptionOr(ByteArray()); @@ -30,17 +31,23 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { } ExceptionOr BluetoothInputStream::Skip(std::size_t offset) { - auto off = lseek(fd_, offset, SEEK_CUR); + if (!fd_.has_value()) + return Exception::kIo; + + auto off = lseek(fd_->get(), offset, SEEK_CUR); if (off != offset) { - auto end = lseek(fd_, 0, SEEK_END); + auto end = lseek(fd_->get(), 0, SEEK_END); return off == end ? ExceptionOr((std::size_t)off) : Exception::kIo; } return ExceptionOr((std::size_t)(off)); } ExceptionOr BluetoothInputStream::ReadExactly(std::size_t size) { + if (!fd_.has_value()) + return Exception::kIo; + char *data = new char[size]; - ssize_t ret = read(fd_, data, size); + ssize_t ret = read(fd_->get(), data, size); if (ret < 0) { delete[] data; return Exception::kIo; @@ -50,9 +57,12 @@ ExceptionOr BluetoothInputStream::ReadExactly(std::size_t size) { } Exception BluetoothOutputStream::Write(const ByteArray &data) { + if (!fd_.has_value()) + return Exception{Exception::kIo}; + ssize_t written = 0; while (written < data.size()) { - ssize_t ret = write(fd_, data.data(), data.size()); + ssize_t ret = write(fd_->get(), data.data(), data.size()); if (ret < 1) { return Exception{Exception::kIo}; } @@ -66,32 +76,13 @@ Exception BluetoothOutputStream::Flush() { } Exception BluetoothOutputStream::Close() { - return close(fd_) < 0 ? Exception{Exception::kIo} - : Exception{Exception::kSuccess}; + return close(fd_->get()) < 0 ? Exception{Exception::kIo} + : Exception{Exception::kSuccess}; } Exception BluetoothSocket::Close() { - __attribute__((cleanup(sd_bus_unrefp))) sd_bus *system_bus = NULL; - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - - if (auto ret = sd_bus_default_system(&system_bus); ret < 0) { - sd_bus_error_set_errno(&err, ret); - NEARBY_LOGS(ERROR) << __func__ - << "Error connecting to system bus: " << err.name << ": " - << err.message; - return Exception{Exception::kFailed}; - } - - if (sd_bus_call_method(system_bus, BLUEZ_SERVICE, device_object_path_.c_str(), - BLUEZ_DEVICE_INTERFACE, "DisconnectProfile", &err, - nullptr, "s", connected_profile_uuid_.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error disconnecting from profile " - << connected_profile_uuid_ << " on device " - << device_object_path_ << ": " << err.name << ": " - << err.message; - return Exception{Exception::kFailed}; - } + input_stream_.fd_.reset(); + output_stream_.fd_.reset(); return Exception{Exception::kSuccess}; } diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index 7a40fc0a..a64ea74a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -2,7 +2,9 @@ #define PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_ #include +#include +#include #include #include "internal/platform/byte_array.h" @@ -14,7 +16,7 @@ namespace linux { class BluetoothInputStream : public InputStream { public: - BluetoothInputStream(int fd) { fd_ = fd; }; + BluetoothInputStream(sdbus::UnixFd &fd) : fd_(fd){}; ExceptionOr Read(std::int64_t size) override; ExceptionOr Skip(size_t offset) override; @@ -23,33 +25,29 @@ public: Exception Close() override; private: - int fd_; + friend class BluetoothSocket; + + std::optional fd_; }; class BluetoothOutputStream : public OutputStream { public: - BluetoothOutputStream(int fd) { fd_ = fd; }; + BluetoothOutputStream(sdbus::UnixFd &fd) : fd_(fd){}; Exception Write(const ByteArray &data) override; Exception Flush() override; Exception Close() override; private: - int fd_; + friend class BluetoothSocket; + + std::optional fd_; }; class BluetoothSocket : public api::BluetoothSocket { public: - BluetoothSocket(api::BluetoothDevice &device, - absl::string_view device_object_path, - absl::string_view connected_profile_uuid, int fd) - : device_(device) { - fd_ = fd; - device_object_path_ = device_object_path; - connected_profile_uuid_ = connected_profile_uuid; - input_stream_ = BluetoothInputStream(fd_); - output_stream_ = BluetoothOutputStream(fd_); - } + BluetoothSocket(api::BluetoothDevice &device, sdbus::UnixFd fd) + : device_(device), output_stream_(fd), input_stream_(fd) {} InputStream &GetInputStream() override { return input_stream_; } OutputStream &GetOutputStream() override { return output_stream_; } @@ -57,12 +55,9 @@ public: api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; private: - int fd_; - std::string device_object_path_; api::BluetoothDevice &device_; - std::string connected_profile_uuid_; - BluetoothInputStream input_stream_ = {-1}; - BluetoothOutputStream output_stream_ = {-1}; + BluetoothOutputStream output_stream_; + BluetoothInputStream input_stream_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc new file mode 100644 index 00000000..e3212857 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -0,0 +1,49 @@ +#include +#include + +#include + +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_devices.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "absl/synchronization/mutex.h" + +namespace nearby { +namespace linux { +std::optional> +BluetoothDevices::get_device_by_path( + const sdbus::ObjectPath &device_object_path) { + absl::ReaderMutexLock l(&devices_by_path_lock_); + + if (devices_by_path_.count(device_object_path) == 0) { + return std::nullopt; + } + + auto &device = devices_by_path_[device_object_path]; + return device; +} + +std::optional> +BluetoothDevices::get_device_by_address(const std::string &addr) { + auto device_object_path = + bluez::device_object_path(adapter_object_path_, addr); + return get_device_by_path(device_object_path); +} + +void BluetoothDevices::remove_device_by_path( + const sdbus::ObjectPath &device_object_path) { + absl::MutexLock l(&devices_by_path_lock_); + + devices_by_path_.erase(device_object_path); +} + +BluetoothDevice & +BluetoothDevices::add_new_device(sdbus::ObjectPath device_object_path) { + absl::MutexLock l(&devices_by_path_lock_); + auto pair = + devices_by_path_.emplace(device_object_path, system_bus_, + std::move(device_object_path), observers_); + return pair.first->second; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h new file mode 100644 index 00000000..093ebaa0 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -0,0 +1,42 @@ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_ +#define PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_ + +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/base/observer_list.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" + +namespace nearby { +namespace linux { +class BluetoothDevices { +public: + BluetoothDevices( + sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path, + ObserverList &observers) + : system_bus_(system_bus), observers_(observers), + adapter_object_path_(adapter_object_path) {} + + std::optional> + get_device_by_path(const sdbus::ObjectPath &); + std::optional> + get_device_by_address(const std::string &); + void remove_device_by_path(const sdbus::ObjectPath &); + BluetoothDevice &add_new_device(sdbus::ObjectPath); + +private: + absl::Mutex devices_by_path_lock_; + std::map devices_by_path_; + + sdbus::IConnection &system_bus_; + ObserverList &observers_; + sdbus::ObjectPath adapter_object_path_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 3d82511f..08d893d4 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -1,8 +1,11 @@ +#include +#include +#include #include #include #include "internal/platform/implementation/bluetooth_classic.h" -#include "internal/platform/implementation/linux/bluetooth_classic_device.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_pairing.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" @@ -10,117 +13,119 @@ namespace nearby { namespace linux { -int pairing_reply_handler(sd_bus_message *m, void *userdata, - sd_bus_error *err) { - auto pairing_cb = static_cast(userdata); - if (sd_bus_message_is_method_error(m, nullptr)) { - if (sd_bus_message_is_method_error( - m, "org.bluez.Error.AuthenticationCanceled")) { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthCanceled); - } else if (sd_bus_message_is_method_error( - m, "org.bluez.Error.AuthenticationFailed")) { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthFailed); - } else if (sd_bus_message_is_method_error( - m, "org.bluez.Error.AuthenticationRejected")) { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthRejected); - } else if (sd_bus_message_is_method_error( - m, "org.bluez.Error.AuthenticationTimeout")) { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthTimeout); +void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { + if (error != nullptr && error->isValid()) { + auto name = error->getName(); + api::BluetoothPairingCallback::PairingError err; + + NEARBY_LOGS(ERROR) << __func__ << ": " + << "Got error '" << error->getName() + << "' with message '" << error->getMessage() + << "' while pairing with device " + << device_.getObjectPath(); + + if (name == "org.bluez.Error.AuthenticationCanceled") { + err = api::BluetoothPairingCallback::PairingError::kAuthCanceled; + } else if (name == "org.bluez.Error.AuthenticationFailed") { + err = api::BluetoothPairingCallback::PairingError::kAuthFailed; + } else if (name == "org.bluez.Error.AuthenticationRejected") { + err = api::BluetoothPairingCallback::PairingError::kAuthRejected; + } else if (name == "org.bluez.Error.AuthenticationTimeout") { + err = api::BluetoothPairingCallback::PairingError::kAuthTimeout; } else { - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kAuthFailed); + err = api::BluetoothPairingCallback::PairingError::kAuthFailed; } - return 0; + + if (pairing_cb_.on_pairing_error_cb != nullptr) { + pairing_cb_.on_pairing_error_cb(err); + } + + return; } - if (err) { - NEARBY_LOGS(ERROR) << __func__ - << "Error pairing with device: " << err->message; - pairing_cb->on_pairing_error_cb( - api::BluetoothPairingCallback::PairingError::kUnknown); - } else { - pairing_cb->on_paired_cb(); + if (pairing_cb_.on_paired_cb != nullptr) { + pairing_cb_.on_paired_cb(); } - return 0; + return; } +BluetoothPairing::BluetoothPairing(const sdbus::ObjectPath &adapter_object_path, + BluetoothDevice &remote_device, + BluetoothAdapter &adapter, + sdbus::IConnection &system_bus) + : device_(remote_device), adapter_(adapter) {} + bool BluetoothPairing::InitiatePairing( api::BluetoothPairingCallback pairing_cb) { - if (!system_bus_) - return false; - pairing_cb_ = std::move(pairing_cb); + if (pairing_cb_.on_pairing_initiated_cb != nullptr) + pairing_cb_.on_pairing_initiated_cb(api::PairingParams{ + api::PairingParams::PairingType::kConsent, std::string()}); - if (sd_bus_call_method_async( - system_bus_, nullptr, BLUEZ_SERVICE, device_object_path_.c_str(), - BLUEZ_DEVICE_INTERFACE, "Pair", &pairing_reply_handler, &pairing_cb_, - nullptr) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error calling method Pair on device " - << device_object_path_; - return false; - } - pairing_cb.on_pairing_initiated_cb(api::PairingParams{ - api::PairingParams::PairingType::kConsent, std::string()}); return true; } bool BluetoothPairing::FinishPairing( std::optional pin_code) { + device_.set_pair_reply_callback([this](const sdbus::Error *error) { + this->pairing_reply_handler(error); + }); + + try { + pair_async_call_ = device_.Pair(); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to initiate pairing for device " + << device_.getObjectPath(); + return false; + } + return true; } bool BluetoothPairing::CancelPairing() { - if (!system_bus_) - return false; + try { + if (pair_async_call_.isPending()) { + pair_async_call_.cancel(); + } - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, - device_object_path_.c_str(), BLUEZ_DEVICE_INTERFACE, - "CancelPairing", &err, nullptr, nullptr) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error calling method CancelPairing on device " - << device_object_path_ << ": " << err.message; + device_.CancelPairing(); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to cancel pairing for device " + << device_.getObjectPath(); return false; } + return true; } bool BluetoothPairing::Unpair() { - if (!system_bus_) - return false; - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez/hci0", - BLUEZ_ADAPTER_INTERFACE, "RemoveDevice", &err, nullptr, - "o", device_object_path_.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error calling method CancelPairing on device " - << device_object_path_ << ": " << err.message; + try { + adapter_.RemoveDevice(device_.getObjectPath()); + return true; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to unpair device " + << device_.getObjectPath() << " on adapter " + << adapter_.getObjectPath(); return false; } - return true; } bool BluetoothPairing::IsPaired() { - if (!system_bus_) + try { + bool bonded = device_.Bonded(); + return bonded; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get Bonded state for device " + << device_.getObjectPath(); return false; - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - int paired = 0; - if (sd_bus_get_property_trivial( - system_bus_, BLUEZ_SERVICE, device_object_path_.c_str(), - BLUEZ_DEVICE_INTERFACE, "Bonded", &err, 'b', &paired) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << "Error getting Bonded property for device " - << device_object_path_ << ": " << err.message; } - return paired; } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index fa0f321d..157f095e 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -1,22 +1,26 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PROFILE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_ +#include #include +#include +#include +#include #include #include "absl/strings/string_view.h" -#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluetooth_classic_device.h" namespace nearby { namespace linux { class BluetoothPairing : public api::BluetoothPairing { public: - BluetoothPairing(sd_bus *system_bus, absl::string_view device_object_path) { - system_bus_ = system_bus; - device_object_path_ = device_object_path; - } - ~BluetoothPairing() { sd_bus_unref(system_bus_); } + BluetoothPairing(const sdbus::ObjectPath &adapter_object_path, + BluetoothDevice &remote_device, BluetoothAdapter &adapter, + sdbus::IConnection &system_bus); + ~BluetoothPairing() override = default; bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; bool FinishPairing(std::optional pin_code) override; @@ -25,8 +29,14 @@ public: bool IsPaired() override; private: - std::string device_object_path_; - sd_bus *system_bus_; + void pairing_reply_handler(const sdbus::Error *e); + + sdbus::PendingAsyncCall pair_async_call_; + + BluetoothDevice &device_; + BluetoothAdapter &adapter_; + + std::unique_ptr bluez_adapter_proxy_; api::BluetoothPairingCallback pairing_cb_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc index efe5dcac..c9215949 100644 --- a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc @@ -19,27 +19,16 @@ std::unique_ptr BluetoothServerSocket::Accept() { << service_uuid_ << " for device "; return nullptr; } - auto device_object_path = - absl::Substitute("$0/dev_$1", adapter_object_path_, - absl::StrReplaceAll(pair->first, {{":", "_"}})); - auto device = BluetoothDevice(sd_bus_ref(system_bus_), device_object_path); - return std::unique_ptr(new BluetoothSocket( - device, device_object_path, service_uuid_, pair->second)); + + auto [device, fd] = *pair; + return std::unique_ptr(new BluetoothSocket(device, fd)); } Exception BluetoothServerSocket::Close() { - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; auto profile_object_path = absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid_); - if (sd_bus_call_method(system_bus_, BLUEZ_SERVICE, "/org/bluez", - "org.bluez.ProfileManager1", "UnregisterProfile", &err, - nullptr, "o", profile_object_path.c_str()) < 0) { - NEARBY_LOGS(ERROR) << __func__ << "Error unregistering profile object " - << profile_object_path << ": " << err.message; - return {Exception::kFailed}; - } + profile_manager_.Unregister(service_uuid_); return {Exception::kSuccess}; } diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc new file mode 100644 index 00000000..2fde4c17 --- /dev/null +++ b/internal/platform/implementation/linux/bluez.cc @@ -0,0 +1,32 @@ +#include "absl/strings/substitute.h" +#include "absl/strings/string_view.h" +#include "absl/strings/str_replace.h" +#include "internal/platform/implementation/linux/bluez.h" +#include + +namespace nearby { +namespace linux { +namespace bluez { +const char *SERVICE = "org.bluez"; + +const char *ADAPTER_INTEFACE = "org.bluez.Adapter1"; + +const char *DEVICE_INTERFACE = "org.bluez.Device1"; +const char *DEVICE_PROP_ADDRESS = "Address"; +const char *DEVICE_PROP_ALIAS = "Alias"; +const char *DEVICE_PROP_PAIRED = "Paired"; +const char *DEVICE_PROP_CONNECTED = "Connected"; + +std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, + absl::string_view mac_address) { + return absl::Substitute("$0/dev_$1", adapter_object_path, + absl::StrReplaceAll(mac_address, {{":", "_"}})); +} + +sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) { + return absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid); +} + +} // namespace bluez +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 50316c95..45471fea 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -1,11 +1,40 @@ #ifndef PLATFORM_IMPL_LINUX_BLUEZ_H_ #define PLATFORM_IMPL_LINUX_BLUEZ_H_ +#include + +#include "absl/strings/string_view.h" + +#include + +#define BLUEZ_LOG_METHOD_CALL_ERROR(proxy, method, err) \ + do { \ + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (err).getName() \ + << "' with message '" << (err).getMessage() \ + << "' while calling " << method << " on object " \ + << (proxy)->getObjectPath(); \ + } while (false) + namespace nearby { namespace linux { -const char *BLUEZ_SERVICE = "org.bluez"; -const char *BLUEZ_ADAPTER_INTERFACE = "org.bluez.Adapter1"; +namespace bluez { +extern const char *SERVICE_DEST; +extern const char *ADAPTER_INTERFACE; + +extern const char *DEVICE_INTERFACE; +extern const char *DEVICE_PROP_ADDRESS; +extern const char *DEVICE_PROP_ALIAS; +extern const char *DEVICE_PROP_PAIRED; +extern const char *DEVICE_PROP_CONNECTED; + +extern std::string +device_object_path(const sdbus::ObjectPath &adapter_object_path, + absl::string_view mac_address); + +extern sdbus::ObjectPath profile_object_path(absl::string_view service_uuid); + +} // namespace bluez } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluez_adapter_client_glue.h b/internal/platform/implementation/linux/bluez_adapter_client_glue.h new file mode 100644 index 00000000..23884e28 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_adapter_client_glue.h @@ -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 +#include +#include + +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& 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 GetDiscoveryFilters() + { + std::vector result; + proxy_.callMethod("GetDiscoveryFilters").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void ConnectDevice(const std::map& 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 UUIDs() + { + return proxy_.getProperty("UUIDs").onInterface(INTERFACE_NAME); + } + + std::string Modalias() + { + return proxy_.getProperty("Modalias").onInterface(INTERFACE_NAME); + } + + std::vector Roles() + { + return proxy_.getProperty("Roles").onInterface(INTERFACE_NAME); + } + + std::vector ExperimentalFeatures() + { + return proxy_.getProperty("ExperimentalFeatures").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/bluez_device_client_glue.h b/internal/platform/implementation/linux/bluez_device_client_glue.h new file mode 100644 index 00000000..54102d1e --- /dev/null +++ b/internal/platform/implementation/linux/bluez_device_client_glue.h @@ -0,0 +1,215 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__bluez_device_client_glue_h__proxy__H__ +#define __sdbuscpp__bluez_device_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class Device1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.Device1"; + +protected: + Device1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Device1_proxy() = default; + + virtual void onConnectProfileReply(const sdbus::Error* error) = 0; + virtual void onPairReply(const sdbus::Error* error) = 0; + +public: + void Disconnect() + { + proxy_.callMethod("Disconnect").onInterface(INTERFACE_NAME); + } + + void Connect() + { + proxy_.callMethod("Connect").onInterface(INTERFACE_NAME); + } + + sdbus::PendingAsyncCall ConnectProfile(const std::string& UUID) + { + return proxy_.callMethodAsync("ConnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID).uponReplyInvoke([this](const sdbus::Error* error){ this->onConnectProfileReply(error); }); + } + + void DisconnectProfile(const std::string& UUID) + { + proxy_.callMethod("DisconnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID); + } + + sdbus::PendingAsyncCall Pair() + { + return proxy_.callMethodAsync("Pair").onInterface(INTERFACE_NAME).uponReplyInvoke([this](const sdbus::Error* error){ this->onPairReply(error); }); + } + + void CancelPairing() + { + proxy_.callMethod("CancelPairing").onInterface(INTERFACE_NAME); + } + +public: + std::string Address() + { + return proxy_.getProperty("Address").onInterface(INTERFACE_NAME); + } + + std::string AddressType() + { + return proxy_.getProperty("AddressType").onInterface(INTERFACE_NAME); + } + + std::string Name() + { + return proxy_.getProperty("Name").onInterface(INTERFACE_NAME); + } + + std::string Alias() + { + return proxy_.getProperty("Alias").onInterface(INTERFACE_NAME); + } + + void Alias(const std::string& value) + { + proxy_.setProperty("Alias").onInterface(INTERFACE_NAME).toValue(value); + } + + uint32_t Class() + { + return proxy_.getProperty("Class").onInterface(INTERFACE_NAME); + } + + uint16_t Appearance() + { + return proxy_.getProperty("Appearance").onInterface(INTERFACE_NAME); + } + + std::string Icon() + { + return proxy_.getProperty("Icon").onInterface(INTERFACE_NAME); + } + + bool Paired() + { + return proxy_.getProperty("Paired").onInterface(INTERFACE_NAME); + } + + bool Bonded() + { + return proxy_.getProperty("Bonded").onInterface(INTERFACE_NAME); + } + + bool Trusted() + { + return proxy_.getProperty("Trusted").onInterface(INTERFACE_NAME); + } + + void Trusted(const bool& value) + { + proxy_.setProperty("Trusted").onInterface(INTERFACE_NAME).toValue(value); + } + + bool Blocked() + { + return proxy_.getProperty("Blocked").onInterface(INTERFACE_NAME); + } + + void Blocked(const bool& value) + { + proxy_.setProperty("Blocked").onInterface(INTERFACE_NAME).toValue(value); + } + + bool LegacyPairing() + { + return proxy_.getProperty("LegacyPairing").onInterface(INTERFACE_NAME); + } + + int16_t RSSI() + { + return proxy_.getProperty("RSSI").onInterface(INTERFACE_NAME); + } + + bool Connected() + { + return proxy_.getProperty("Connected").onInterface(INTERFACE_NAME); + } + + std::vector 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 ManufacturerData() + { + return proxy_.getProperty("ManufacturerData").onInterface(INTERFACE_NAME); + } + + std::map 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 AdvertisingFlags() + { + return proxy_.getProperty("AdvertisingFlags").onInterface(INTERFACE_NAME); + } + + std::map 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> Sets() + { + return proxy_.getProperty("Sets").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/bluez_profile_glue.h b/internal/platform/implementation/linux/bluez_profile_glue.h new file mode 100644 index 00000000..6ae6e00f --- /dev/null +++ b/internal/platform/implementation/linux/bluez_profile_glue.h @@ -0,0 +1,43 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__bluez_profile_glue_h__adaptor__H__ +#define __sdbuscpp__bluez_profile_glue_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class Profile1_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.Profile1"; + +protected: + Profile1_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); }); + object_.registerMethod("NewConnection").onInterface(INTERFACE_NAME).withInputParamNames("device", "fd", "fd_properties").implementedAs([this](const sdbus::ObjectPath& device, const sdbus::UnixFd& fd, const std::map& fd_properties){ return this->NewConnection(device, fd, fd_properties); }); + object_.registerMethod("RequestDisconnection").onInterface(INTERFACE_NAME).withInputParamNames("device").implementedAs([this](const sdbus::ObjectPath& device){ return this->RequestDisconnection(device); }); + } + + ~Profile1_adaptor() = default; + +private: + virtual void Release() = 0; + virtual void NewConnection(const sdbus::ObjectPath& device, const sdbus::UnixFd& fd, const std::map& fd_properties) = 0; + virtual void RequestDisconnection(const sdbus::ObjectPath& device) = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/bluez_profile_manager_client_glue.h b/internal/platform/implementation/linux/bluez_profile_manager_client_glue.h new file mode 100644 index 00000000..61ee8e46 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_profile_manager_client_glue.h @@ -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 +#include +#include + +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& 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 diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index c45bf230..f492c56c 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -1,12 +1,12 @@ #include #include #include -#include - #include +#include #include -#include +#include +#include #include #include "internal/platform/implementation/device_info.h" @@ -14,7 +14,6 @@ #include "internal/platform/logging.h" namespace nearby { - namespace linux { const char *HOSTNAME_DEST = "org.freedesktop.hostname1"; @@ -25,78 +24,49 @@ const char *LOGIN_DEST = "org.freedesktop.login1"; const char *LOGIN_PATH = "/org/freedesktop/login1/session/_"; const char *LOGIN_INTERFACE = "org.freedesktop.login1.Session"; +DeviceInfo::DeviceInfo(sdbus::IConnection &system_bus) { + hostname_proxy_ = + sdbus::createProxy(system_bus, HOSTNAME_DEST, HOSTNAME_PATH); + hostname_proxy_->finishRegistration(); + login_proxy_ = sdbus::createProxy(system_bus, LOGIN_PATH, LOGIN_PATH); + login_proxy_->finishRegistration(); +} + std::optional DeviceInfo::GetOsDeviceName() const { - __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus = nullptr; - if (sd_bus_default_system(&bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; + try { + std::string hostname = hostname_proxy_->getProperty("PrettyHostname") + .onInterface(HOSTNAME_INTERFACE); + std::wstring_convert, char16_t> convert; + return convert.from_bytes(hostname); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get PrettyHostname"; return std::nullopt; } - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - - char *hostname = nullptr; - if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, - HOSTNAME_INTERFACE, "PrettyHostname", &err, - &hostname) < 0) { - NEARBY_LOGS(ERROR) - << __func__ - << ": Error getting PrettyHostname from org.freedesktop.hostname1: " - << err.message; - } - if (!hostname || hostname[0] == '\0') { - int ret = sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, - HOSTNAME_INTERFACE, "Hostname", &err, - &hostname); - if (ret < 0) { - NEARBY_LOGS(ERROR) - << __func__ - << ": Error getting Hostname from org.freedesktop.hostname1: " - << err.message; - return std::nullopt; - } - } - - std::wstring_convert, char16_t> convert; - - std::u16string name = convert.from_bytes(hostname); - free(hostname); - return name; } api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { - __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus; - if (sd_bus_default_system(&bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; + try { + std::string chasis = hostname_proxy_->getProperty("PrettyHostname") + .onInterface(HOSTNAME_INTERFACE); + api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; + if (chasis == "phone") { + device = api::DeviceInfo::DeviceType::kPhone; + } else if (chasis == "laptop" || chasis == "desktop") { + device = api::DeviceInfo::DeviceType::kLaptop; + } else if (chasis == "tablet") { + device = api::DeviceInfo::DeviceType::kTablet; + } else if (chasis == "handset") { + device = api::DeviceInfo::DeviceType::kPhone; + } + return device; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get PrettyHostname"; return api::DeviceInfo::DeviceType::kUnknown; } - - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - char *chasis = nullptr; - - if (sd_bus_get_property_string(bus, HOSTNAME_DEST, HOSTNAME_PATH, - HOSTNAME_INTERFACE, "Chasis", &err, - &chasis) < 0) { - NEARBY_LOGS(ERROR) - << __func__ << ": Error getting Chasis from org.freedesktop.hostname1: " - << err.message; - return api::DeviceInfo::DeviceType::kUnknown; - } - - api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; - - if (strcmp(chasis, "phone") == 0) { - device = api::DeviceInfo::DeviceType::kPhone; - } else if (strcmp(chasis, "laptop") == 0 || strcmp(chasis, "desktop") == 0) { - device = api::DeviceInfo::DeviceType::kLaptop; - } else if (strcmp(chasis, "tablet") == 0) { - device = api::DeviceInfo::DeviceType::kTablet; - } else if (strcmp(chasis, "handset") == 0) { - device = api::DeviceInfo::DeviceType::kPhone; - } - free(chasis); - return device; } std::optional DeviceInfo::GetFullName() const { @@ -170,34 +140,21 @@ bool DeviceInfo::IsScreenLocked() const { return false; } - __attribute__((cleanup(sd_bus_unrefp))) sd_bus *bus; - if (sd_bus_default_system(&bus) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to systemd bus."; - free(session); - return false; - } - std::string session_path(LOGIN_PATH); session_path += session; - free(session); - __attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = - SD_BUS_ERROR_NULL; - bool locked; - - if (sd_bus_get_property_trivial(bus, LOGIN_DEST, session_path.c_str(), - LOGIN_INTERFACE, "LockedHint", &err, 'b', - &locked) < 0) { - - NEARBY_LOGS(ERROR) - << __func__ - << ": Error getting LockedState from org.freedesktop.login1: " - << err.message; - locked = false; + try { + bool locked = + login_proxy_->getProperty("LockedHint").onInterface(LOGIN_INTERFACE); + return locked; + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while trying to get LockedHint for session " + << session_path; + return false; } - - return locked; } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 3d001486..3ca5b762 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -1,11 +1,12 @@ #ifndef PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ #define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ -#include - #include #include +#include +#include + #include "absl/strings/string_view.h" #include "internal/platform/implementation/device_info.h" @@ -14,7 +15,8 @@ namespace linux { class DeviceInfo : public api::DeviceInfo { public: - ~DeviceInfo() override; + DeviceInfo(sdbus::IConnection &system_bus); + ~DeviceInfo() override = default; std::optional GetOsDeviceName() const override; api::DeviceInfo::DeviceType GetDeviceType() const override; @@ -47,7 +49,9 @@ public: void UnregisterScreenLockedListener(absl::string_view listener_name) override{}; - sd_bus *system_bus; +private: + std::unique_ptr hostname_proxy_; + std::unique_ptr login_proxy_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/org.bluez.Adapter1.xml b/internal/platform/implementation/linux/org.bluez.Adapter1.xml new file mode 100644 index 00000000..b58180df --- /dev/null +++ b/internal/platform/implementation/linux/org.bluez.Adapter1.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.bluez.Device1.xml b/internal/platform/implementation/linux/org.bluez.Device1.xml new file mode 100644 index 00000000..afc55406 --- /dev/null +++ b/internal/platform/implementation/linux/org.bluez.Device1.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.bluez.Profile1.xml b/internal/platform/implementation/linux/org.bluez.Profile1.xml new file mode 100644 index 00000000..5ce94584 --- /dev/null +++ b/internal/platform/implementation/linux/org.bluez.Profile1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.bluez.ProfileManager1.xml b/internal/platform/implementation/linux/org.bluez.ProfileManager1.xml new file mode 100644 index 00000000..0a43476e --- /dev/null +++ b/internal/platform/implementation/linux/org.bluez.ProfileManager1.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From 9b742d920aeaecbc285580a69f5a095ecfcfdef6 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 16 Aug 2023 02:00:09 +0530 Subject: [PATCH 022/201] Add initial wifi medium code. --- internal/platform/implementation/linux/dbus.h | 29 + .../networkmanager_accesspoint_client_glue.h | 87 +++ .../linux/networkmanager_client_glue.h | 320 ++++++++++ ...etworkmanager_device_wifip2p_client_glue.h | 64 ++ ...tworkmanager_device_wireless_client_glue.h | 103 +++ .../networkmanager_ip4config_client_glue.h | 102 +++ ...freedesktop.NetworkManager.AccessPoint.xml | 99 +++ ...edesktop.NetworkManager.Device.WifiP2P.xml | 76 +++ ...desktop.NetworkManager.Device.Wireless.xml | 131 ++++ ...g.freedesktop.NetworkManager.IP4Config.xml | 117 ++++ .../linux/org.freedesktop.NetworkManager.xml | 598 ++++++++++++++++++ .../implementation/linux/wifi_medium.cc | 171 +++++ .../implementation/linux/wifi_medium.h | 130 ++++ 13 files changed, 2027 insertions(+) create mode 100644 internal/platform/implementation/linux/dbus.h create mode 100644 internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h create mode 100644 internal/platform/implementation/linux/networkmanager_client_glue.h create mode 100644 internal/platform/implementation/linux/networkmanager_device_wifip2p_client_glue.h create mode 100644 internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h create mode 100644 internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h create mode 100644 internal/platform/implementation/linux/org.freedesktop.NetworkManager.AccessPoint.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.WifiP2P.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.Wireless.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.NetworkManager.IP4Config.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.NetworkManager.xml create mode 100644 internal/platform/implementation/linux/wifi_medium.cc create mode 100644 internal/platform/implementation/linux/wifi_medium.h diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h new file mode 100644 index 00000000..53e57212 --- /dev/null +++ b/internal/platform/implementation/linux/dbus.h @@ -0,0 +1,29 @@ +#ifndef PLATFORM_IMPL_LINUX_DBUS_H_ +#define PLATFORM_IMPL_LINUX_DBUS_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) + +#endif diff --git a/internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h b/internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h new file mode 100644 index 00000000..0408af2c --- /dev/null +++ b/internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h @@ -0,0 +1,87 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__networkmanager_accesspoint_client_glue_h__proxy__H__ +#define __sdbuscpp__networkmanager_accesspoint_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class AccessPoint_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.AccessPoint"; + +protected: + AccessPoint_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~AccessPoint_proxy() = default; + +public: + uint32_t Flags() + { + return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME); + } + + uint32_t WpaFlags() + { + return proxy_.getProperty("WpaFlags").onInterface(INTERFACE_NAME); + } + + uint32_t RsnFlags() + { + return proxy_.getProperty("RsnFlags").onInterface(INTERFACE_NAME); + } + + std::vector Ssid() + { + return proxy_.getProperty("Ssid").onInterface(INTERFACE_NAME); + } + + uint32_t Frequency() + { + return proxy_.getProperty("Frequency").onInterface(INTERFACE_NAME); + } + + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + uint32_t Mode() + { + return proxy_.getProperty("Mode").onInterface(INTERFACE_NAME); + } + + uint32_t MaxBitrate() + { + return proxy_.getProperty("MaxBitrate").onInterface(INTERFACE_NAME); + } + + uint8_t Strength() + { + return proxy_.getProperty("Strength").onInterface(INTERFACE_NAME); + } + + int32_t LastSeen() + { + return proxy_.getProperty("LastSeen").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/networkmanager_client_glue.h b/internal/platform/implementation/linux/networkmanager_client_glue.h new file mode 100644 index 00000000..f13b9544 --- /dev/null +++ b/internal/platform/implementation/linux/networkmanager_client_glue.h @@ -0,0 +1,320 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__networkmanager_client_glue_h__proxy__H__ +#define __sdbuscpp__networkmanager_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { + +class NetworkManager_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager"; + +protected: + NetworkManager_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("CheckPermissions").onInterface(INTERFACE_NAME).call([this](){ this->onCheckPermissions(); }); + proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const uint32_t& state){ this->onStateChanged(state); }); + proxy_.uponSignal("DeviceAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& device_path){ this->onDeviceAdded(device_path); }); + proxy_.uponSignal("DeviceRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& device_path){ this->onDeviceRemoved(device_path); }); + } + + ~NetworkManager_proxy() = default; + + virtual void onCheckPermissions() = 0; + virtual void onStateChanged(const uint32_t& state) = 0; + virtual void onDeviceAdded(const sdbus::ObjectPath& device_path) = 0; + virtual void onDeviceRemoved(const sdbus::ObjectPath& device_path) = 0; + +public: + void Reload(const uint32_t& flags) + { + proxy_.callMethod("Reload").onInterface(INTERFACE_NAME).withArguments(flags); + } + + std::vector GetDevices() + { + std::vector result; + proxy_.callMethod("GetDevices").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::vector GetAllDevices() + { + std::vector result; + proxy_.callMethod("GetAllDevices").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath GetDeviceByIpIface(const std::string& iface) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetDeviceByIpIface").onInterface(INTERFACE_NAME).withArguments(iface).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath ActivateConnection(const sdbus::ObjectPath& connection, const sdbus::ObjectPath& device, const sdbus::ObjectPath& specific_object) + { + sdbus::ObjectPath result; + proxy_.callMethod("ActivateConnection").onInterface(INTERFACE_NAME).withArguments(connection, device, specific_object).storeResultsTo(result); + return result; + } + + std::tuple AddAndActivateConnection(const std::map>& connection, const sdbus::ObjectPath& device, const sdbus::ObjectPath& specific_object) + { + std::tuple result; + proxy_.callMethod("AddAndActivateConnection").onInterface(INTERFACE_NAME).withArguments(connection, device, specific_object).storeResultsTo(result); + return result; + } + + std::tuple> AddAndActivateConnection2(const std::map>& connection, const sdbus::ObjectPath& device, const sdbus::ObjectPath& specific_object, const std::map& options) + { + std::tuple> result; + proxy_.callMethod("AddAndActivateConnection2").onInterface(INTERFACE_NAME).withArguments(connection, device, specific_object, options).storeResultsTo(result); + return result; + } + + void DeactivateConnection(const sdbus::ObjectPath& active_connection) + { + proxy_.callMethod("DeactivateConnection").onInterface(INTERFACE_NAME).withArguments(active_connection); + } + + void Sleep(const bool& sleep) + { + proxy_.callMethod("Sleep").onInterface(INTERFACE_NAME).withArguments(sleep); + } + + void Enable(const bool& enable) + { + proxy_.callMethod("Enable").onInterface(INTERFACE_NAME).withArguments(enable); + } + + std::map GetPermissions() + { + std::map result; + proxy_.callMethod("GetPermissions").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void SetLogging(const std::string& level, const std::string& domains) + { + proxy_.callMethod("SetLogging").onInterface(INTERFACE_NAME).withArguments(level, domains); + } + + std::tuple GetLogging() + { + std::tuple result; + proxy_.callMethod("GetLogging").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + uint32_t CheckConnectivity() + { + uint32_t result; + proxy_.callMethod("CheckConnectivity").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + uint32_t state() + { + uint32_t result; + proxy_.callMethod("state").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath CheckpointCreate(const std::vector& devices, const uint32_t& rollback_timeout, const uint32_t& flags) + { + sdbus::ObjectPath result; + proxy_.callMethod("CheckpointCreate").onInterface(INTERFACE_NAME).withArguments(devices, rollback_timeout, flags).storeResultsTo(result); + return result; + } + + void CheckpointDestroy(const sdbus::ObjectPath& checkpoint) + { + proxy_.callMethod("CheckpointDestroy").onInterface(INTERFACE_NAME).withArguments(checkpoint); + } + + std::map CheckpointRollback(const sdbus::ObjectPath& checkpoint) + { + std::map result; + proxy_.callMethod("CheckpointRollback").onInterface(INTERFACE_NAME).withArguments(checkpoint).storeResultsTo(result); + return result; + } + + void CheckpointAdjustRollbackTimeout(const sdbus::ObjectPath& checkpoint, const uint32_t& add_timeout) + { + proxy_.callMethod("CheckpointAdjustRollbackTimeout").onInterface(INTERFACE_NAME).withArguments(checkpoint, add_timeout); + } + +public: + std::vector Devices() + { + return proxy_.getProperty("Devices").onInterface(INTERFACE_NAME); + } + + std::vector AllDevices() + { + return proxy_.getProperty("AllDevices").onInterface(INTERFACE_NAME); + } + + std::vector Checkpoints() + { + return proxy_.getProperty("Checkpoints").onInterface(INTERFACE_NAME); + } + + bool NetworkingEnabled() + { + return proxy_.getProperty("NetworkingEnabled").onInterface(INTERFACE_NAME); + } + + bool WirelessEnabled() + { + return proxy_.getProperty("WirelessEnabled").onInterface(INTERFACE_NAME); + } + + void WirelessEnabled(const bool& value) + { + proxy_.setProperty("WirelessEnabled").onInterface(INTERFACE_NAME).toValue(value); + } + + bool WirelessHardwareEnabled() + { + return proxy_.getProperty("WirelessHardwareEnabled").onInterface(INTERFACE_NAME); + } + + bool WwanEnabled() + { + return proxy_.getProperty("WwanEnabled").onInterface(INTERFACE_NAME); + } + + void WwanEnabled(const bool& value) + { + proxy_.setProperty("WwanEnabled").onInterface(INTERFACE_NAME).toValue(value); + } + + bool WwanHardwareEnabled() + { + return proxy_.getProperty("WwanHardwareEnabled").onInterface(INTERFACE_NAME); + } + + bool WimaxEnabled() + { + return proxy_.getProperty("WimaxEnabled").onInterface(INTERFACE_NAME); + } + + void WimaxEnabled(const bool& value) + { + proxy_.setProperty("WimaxEnabled").onInterface(INTERFACE_NAME).toValue(value); + } + + bool WimaxHardwareEnabled() + { + return proxy_.getProperty("WimaxHardwareEnabled").onInterface(INTERFACE_NAME); + } + + uint32_t RadioFlags() + { + return proxy_.getProperty("RadioFlags").onInterface(INTERFACE_NAME); + } + + std::vector ActiveConnections() + { + return proxy_.getProperty("ActiveConnections").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath PrimaryConnection() + { + return proxy_.getProperty("PrimaryConnection").onInterface(INTERFACE_NAME); + } + + std::string PrimaryConnectionType() + { + return proxy_.getProperty("PrimaryConnectionType").onInterface(INTERFACE_NAME); + } + + uint32_t Metered() + { + return proxy_.getProperty("Metered").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath ActivatingConnection() + { + return proxy_.getProperty("ActivatingConnection").onInterface(INTERFACE_NAME); + } + + bool Startup() + { + return proxy_.getProperty("Startup").onInterface(INTERFACE_NAME); + } + + std::string Version() + { + return proxy_.getProperty("Version").onInterface(INTERFACE_NAME); + } + + std::vector VersionInfo() + { + return proxy_.getProperty("VersionInfo").onInterface(INTERFACE_NAME); + } + + std::vector Capabilities() + { + return proxy_.getProperty("Capabilities").onInterface(INTERFACE_NAME); + } + + uint32_t State() + { + return proxy_.getProperty("State").onInterface(INTERFACE_NAME); + } + + uint32_t Connectivity() + { + return proxy_.getProperty("Connectivity").onInterface(INTERFACE_NAME); + } + + bool ConnectivityCheckAvailable() + { + return proxy_.getProperty("ConnectivityCheckAvailable").onInterface(INTERFACE_NAME); + } + + bool ConnectivityCheckEnabled() + { + return proxy_.getProperty("ConnectivityCheckEnabled").onInterface(INTERFACE_NAME); + } + + void ConnectivityCheckEnabled(const bool& value) + { + proxy_.setProperty("ConnectivityCheckEnabled").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ConnectivityCheckUri() + { + return proxy_.getProperty("ConnectivityCheckUri").onInterface(INTERFACE_NAME); + } + + std::map GlobalDnsConfiguration() + { + return proxy_.getProperty("GlobalDnsConfiguration").onInterface(INTERFACE_NAME); + } + + void GlobalDnsConfiguration(const std::map& value) + { + proxy_.setProperty("GlobalDnsConfiguration").onInterface(INTERFACE_NAME).toValue(value); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/networkmanager_device_wifip2p_client_glue.h b/internal/platform/implementation/linux/networkmanager_device_wifip2p_client_glue.h new file mode 100644 index 00000000..df968c97 --- /dev/null +++ b/internal/platform/implementation/linux/networkmanager_device_wifip2p_client_glue.h @@ -0,0 +1,64 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__networkmanager_device_wifip2p_client_glue_h__proxy__H__ +#define __sdbuscpp__networkmanager_device_wifip2p_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class WifiP2P_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.WifiP2P"; + +protected: + WifiP2P_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("PeerAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer){ this->onPeerAdded(peer); }); + proxy_.uponSignal("PeerRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer){ this->onPeerRemoved(peer); }); + } + + ~WifiP2P_proxy() = default; + + virtual void onPeerAdded(const sdbus::ObjectPath& peer) = 0; + virtual void onPeerRemoved(const sdbus::ObjectPath& peer) = 0; + +public: + void StartFind(const std::map& options) + { + proxy_.callMethod("StartFind").onInterface(INTERFACE_NAME).withArguments(options); + } + + void StopFind() + { + proxy_.callMethod("StopFind").onInterface(INTERFACE_NAME); + } + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + std::vector Peers() + { + return proxy_.getProperty("Peers").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h b/internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h new file mode 100644 index 00000000..b8a85787 --- /dev/null +++ b/internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h @@ -0,0 +1,103 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__networkmanager_device_wireless_client_glue_h__proxy__H__ +#define __sdbuscpp__networkmanager_device_wireless_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Wireless_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Wireless"; + +protected: + Wireless_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("AccessPointAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& access_point){ this->onAccessPointAdded(access_point); }); + proxy_.uponSignal("AccessPointRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& access_point){ this->onAccessPointRemoved(access_point); }); + } + + ~Wireless_proxy() = default; + + virtual void onAccessPointAdded(const sdbus::ObjectPath& access_point) = 0; + virtual void onAccessPointRemoved(const sdbus::ObjectPath& access_point) = 0; + +public: + std::vector GetAccessPoints() + { + std::vector result; + proxy_.callMethod("GetAccessPoints").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::vector GetAllAccessPoints() + { + std::vector result; + proxy_.callMethod("GetAllAccessPoints").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void RequestScan(const std::map& options) + { + proxy_.callMethod("RequestScan").onInterface(INTERFACE_NAME).withArguments(options); + } + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + std::string PermHwAddress() + { + return proxy_.getProperty("PermHwAddress").onInterface(INTERFACE_NAME); + } + + uint32_t Mode() + { + return proxy_.getProperty("Mode").onInterface(INTERFACE_NAME); + } + + uint32_t Bitrate() + { + return proxy_.getProperty("Bitrate").onInterface(INTERFACE_NAME); + } + + std::vector AccessPoints() + { + return proxy_.getProperty("AccessPoints").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath ActiveAccessPoint() + { + return proxy_.getProperty("ActiveAccessPoint").onInterface(INTERFACE_NAME); + } + + uint32_t WirelessCapabilities() + { + return proxy_.getProperty("WirelessCapabilities").onInterface(INTERFACE_NAME); + } + + int64_t LastScan() + { + return proxy_.getProperty("LastScan").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h b/internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h new file mode 100644 index 00000000..442180ff --- /dev/null +++ b/internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h @@ -0,0 +1,102 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__networkmanager_ip4config_client_glue_h__proxy__H__ +#define __sdbuscpp__networkmanager_ip4config_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class IP4Config_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.IP4Config"; + +protected: + IP4Config_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~IP4Config_proxy() = default; + +public: + std::vector> Addresses() + { + return proxy_.getProperty("Addresses").onInterface(INTERFACE_NAME); + } + + std::vector> AddressData() + { + return proxy_.getProperty("AddressData").onInterface(INTERFACE_NAME); + } + + std::string Gateway() + { + return proxy_.getProperty("Gateway").onInterface(INTERFACE_NAME); + } + + std::vector> Routes() + { + return proxy_.getProperty("Routes").onInterface(INTERFACE_NAME); + } + + std::vector> RouteData() + { + return proxy_.getProperty("RouteData").onInterface(INTERFACE_NAME); + } + + std::vector Nameservers() + { + return proxy_.getProperty("Nameservers").onInterface(INTERFACE_NAME); + } + + std::vector> NameserverData() + { + return proxy_.getProperty("NameserverData").onInterface(INTERFACE_NAME); + } + + std::vector Domains() + { + return proxy_.getProperty("Domains").onInterface(INTERFACE_NAME); + } + + std::vector Searches() + { + return proxy_.getProperty("Searches").onInterface(INTERFACE_NAME); + } + + std::vector DnsOptions() + { + return proxy_.getProperty("DnsOptions").onInterface(INTERFACE_NAME); + } + + int32_t DnsPriority() + { + return proxy_.getProperty("DnsPriority").onInterface(INTERFACE_NAME); + } + + std::vector WinsServers() + { + return proxy_.getProperty("WinsServers").onInterface(INTERFACE_NAME); + } + + std::vector WinsServerData() + { + return proxy_.getProperty("WinsServerData").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.AccessPoint.xml b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.AccessPoint.xml new file mode 100644 index 00000000..7340bda3 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.AccessPoint.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.WifiP2P.xml b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.WifiP2P.xml new file mode 100644 index 00000000..73b8cc0c --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.WifiP2P.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.Wireless.xml b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.Wireless.xml new file mode 100644 index 00000000..c428e998 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.Wireless.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.IP4Config.xml b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.IP4Config.xml new file mode 100644 index 00000000..f6e18b76 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.IP4Config.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.xml b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.xml new file mode 100644 index 00000000..c92c8017 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.xml @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc new file mode 100644 index 00000000..beba67c4 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi.h" + +namespace nearby { +namespace linux { + +std::unique_ptr +NetworkManagerObjectManager::GetIp4Config( + const sdbus::ObjectPath &access_point) { + auto objects = GetManagedObjects(); + for (auto &[object_path, interfaces] : objects) { + if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/", + 0) == 0) { + if (interfaces.count( + "org.freedesktop.NetworkManager.Connection.Active") == 1) { + auto props = + interfaces["org.freedesktop.NetworkManager.Connection.Active"]; + sdbus::ObjectPath specific_object = props["SpecificObject"]; + sdbus::ObjectPath ip4config = props["Ip4Config"]; + + if (specific_object == access_point) + return std::make_unique( + getProxy().getConnection(), ip4config); + } + } + } + + return nullptr; +} + +api::WifiCapability &NetworkManagerWifiMedium::GetCapability() { + try { + auto cap_mask = WirelessCapabilities(); + // https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMDeviceWifiCapabilities + capability_.supports_5_ghz = (cap_mask & 0x00000400); + capability_.supports_6_ghz = false; + capability_.support_wifi_direct = true; + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(&getProxy(), "WirelessCapabilities", e); + } + + return capability_; +} + +api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { + { + absl::ReaderMutexLock l(&active_access_point_lock_); + if (!active_access_point_.has_value()) { + information_ = api::WifiInformation{false}; + return information_; + } + } + try { + absl::MutexLock l(&active_access_point_lock_); + + auto ssid_vec = active_access_point_->Ssid(); + std::string ssid{ssid_vec.begin(), ssid_vec.end()}; + + information_ = + api::WifiInformation{true, ssid, active_access_point_->HwAddress(), + (int32_t)(active_access_point_->Frequency())}; + NetworkManagerObjectManager manager(getProxy().getConnection()); + auto ip4config = + manager.GetIp4Config(active_access_point_->getObjectPath()); + + if (ip4config != nullptr) { + auto address_data = ip4config->AddressData(); + if (address_data.size() > 0) { + std::string address = address_data[0]["address"]; + information_.ip_address_dot_decimal = address; + + struct in_addr addr; + inet_aton(address.c_str(), &addr); + + char addr_bytes[4]; + memcpy(addr_bytes, &addr.s_addr, sizeof(addr_bytes)); + information_.ip_address_4_bytes = std::string(addr_bytes, 4); + } + } else { + NEARBY_LOGS(ERROR) << __func__ + << ": Could not find the Ip4Config object for " + << active_access_point_->getObjectPath(); + } + } catch (const sdbus::Error &e) { + absl::ReaderMutexLock l(&active_access_point_lock_); + NEARBY_LOGS(ERROR) + << __func__ << ": Got error '" << e.getName() << "' with message '" + << e.getMessage() + << "' while populating network information for access point " + << active_access_point_->getObjectPath(); + } + + return information_; +} + +void NetworkManagerWifiMedium::onPropertiesChanged( + const std::string &interfaceName, + const std::map &changedProperties, + const std::vector &invalidatedProperties) { + if (interfaceName != org::freedesktop::NetworkManager::Device:: + Wireless_proxy::INTERFACE_NAME) { + return; + } + + for (auto &[property, _val] : changedProperties) { + if (property == "LastScan") { + absl::ReaderMutexLock l(&scan_result_callback_lock_); + if (scan_result_callback_.has_value()) { + // scan_result_callback_->get().OnScanResults() + } + } + } +} + +bool NetworkManagerWifiMedium::Scan( + const api::WifiMedium::ScanResultCallback &scan_result_callback) { + absl::MutexLock l(&scan_result_callback_lock_); + scan_result_callback_ = scan_result_callback; + + try { + RequestScan(std::map()); + } catch (const sdbus::Error &e) { + scan_result_callback_ = std::nullopt; + DBUS_LOG_METHOD_CALL_ERROR(&getProxy(), "RequestScan", e); + return false; + } + return true; +} + +api::WifiConnectionStatus +NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid, + absl::string_view password, + api::WifiAuthType auth_type) {} + +bool NetworkManagerWifiMedium::VerifyInternetConnectivity() { + auto network_manager_proxy_ = sdbus::createProxy( + "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager"); + network_manager_proxy_->finishRegistration(); + + try { + std::uint32_t connectivity; + network_manager_proxy_->callMethod("CheckConnectivity") + .onInterface("org.freedesktop.NetworkManager") + .storeResultsTo(connectivity); + return connectivity == 4; // NM_CONNECTIVITY_FULL + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(network_manager_proxy_, "CheckConnectivity", e); + return false; + } +} + +std::string NetworkManagerWifiMedium::GetIpAddress() { + GetInformation(); + return information_.ip_address_dot_decimal; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h new file mode 100644 index 00000000..116063df --- /dev/null +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -0,0 +1,130 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_MEDIUM_H_ +#define PLATFORM_IMPL_LINUX_WIFI_MEDIUM_H_ + +#include +#include +#include + +#include +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h" +#include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" +#include "internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h" +#include "internal/platform/implementation/wifi.h" + +namespace nearby { +namespace linux { +class NetworkManagerIP4Config + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::IP4Config_proxy> { +public: + NetworkManagerIP4Config(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &config_object_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + config_object_path) { + registerProxy(); + } + ~NetworkManagerIP4Config() { unregisterProxy(); } +}; + +class NetworkManagerObjectManager + : public sdbus::ProxyInterfaces { +public: + NetworkManagerObjectManager(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + "/org/freedesktop") { + registerProxy(); + } + ~NetworkManagerObjectManager() { unregisterProxy(); } + + std::unique_ptr + GetIp4Config(const sdbus::ObjectPath &access_point); + +protected: + void onInterfacesAdded( + const sdbus::ObjectPath &objectPath, + const std::map> + &interfacesAndProperties) override {} + void + onInterfacesRemoved(const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override {} +}; + +class NetworkManagerAccessPoint + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::AccessPoint_proxy> { +public: + NetworkManagerAccessPoint(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &access_point_object_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + access_point_object_path) { + registerProxy(); + } + ~NetworkManagerAccessPoint() { unregisterProxy(); } +}; + +class NetworkManagerWifiMedium + : public api::WifiMedium, + sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::Device::Wireless_proxy, + sdbus::Properties_proxy> { +public: + NetworkManagerWifiMedium(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &wireless_device_object_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + wireless_device_object_path) { + active_access_point_ = std::nullopt; + registerProxy(); + } + + ~NetworkManagerWifiMedium() override { unregisterProxy(); } + + class ScanResultCallback : public api::WifiMedium::ScanResultCallback { + public: + ~ScanResultCallback() override = default; + void OnScanResults( + const std::vector &scan_results) override { + // TODO: Add implementation at some point + } + }; + + bool IsInterfaceValid() const override { return true; }; + api::WifiCapability &GetCapability() override; + api::WifiInformation &GetInformation() override; + + bool Scan(const api::WifiMedium::ScanResultCallback &scan_result_callback) override; + + api::WifiConnectionStatus + ConnectToNetwork(absl::string_view ssid, absl::string_view password, + api::WifiAuthType auth_type) override; + + bool VerifyInternetConnectivity() override; + std::string GetIpAddress() override; + +protected: + void onPropertiesChanged( + const std::string &interfaceName, + const std::map &changedProperties, + const std::vector &invalidatedProperties) override; + +private: + api::WifiCapability capability_; + api::WifiInformation information_{false}; + + absl::Mutex active_access_point_lock_; + std::optional active_access_point_; + + absl::Mutex scan_result_callback_lock_; + std::optional< + std::reference_wrapper> + scan_result_callback_; +}; + +} // namespace linux +} // namespace nearby + +#endif From c5f818c90a4e39867b2ca88566d7da37b3e8eeba Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 16 Aug 2023 19:03:47 +0530 Subject: [PATCH 023/201] Use NetworkManager object for checking connectivity. --- .../implementation/linux/wifi_medium.cc | 29 ++++++++-------- .../implementation/linux/wifi_medium.h | 33 ++++++++++++++++--- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index beba67c4..8925356b 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -127,23 +127,25 @@ void NetworkManagerWifiMedium::onPropertiesChanged( bool NetworkManagerWifiMedium::Scan( const api::WifiMedium::ScanResultCallback &scan_result_callback) { - absl::MutexLock l(&scan_result_callback_lock_); - scan_result_callback_ = scan_result_callback; + // absl::MutexLock l(&scan_result_callback_lock_); + // scan_result_callback_ = scan_result_callback; - try { - RequestScan(std::map()); - } catch (const sdbus::Error &e) { - scan_result_callback_ = std::nullopt; - DBUS_LOG_METHOD_CALL_ERROR(&getProxy(), "RequestScan", e); - return false; - } - return true; + // try { + // RequestScan(std::map()); + // } catch (const sdbus::Error &e) { + // scan_result_callback_ = std::nullopt; + // DBUS_LOG_METHOD_CALL_ERROR(&getProxy(), "RequestScan", e); + // return false; + // } + return false; } api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid, absl::string_view password, - api::WifiAuthType auth_type) {} + api::WifiAuthType auth_type) { + return api::WifiConnectionStatus::kUnknown; +} bool NetworkManagerWifiMedium::VerifyInternetConnectivity() { auto network_manager_proxy_ = sdbus::createProxy( @@ -151,10 +153,7 @@ bool NetworkManagerWifiMedium::VerifyInternetConnectivity() { network_manager_proxy_->finishRegistration(); try { - std::uint32_t connectivity; - network_manager_proxy_->callMethod("CheckConnectivity") - .onInterface("org.freedesktop.NetworkManager") - .storeResultsTo(connectivity); + std::uint32_t connectivity = network_manager_.CheckConnectivity(); return connectivity == 4; // NM_CONNECTIVITY_FULL } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(network_manager_proxy_, "CheckConnectivity", e); diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 116063df..9d432012 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -12,12 +12,30 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h" +#include "internal/platform/implementation/linux/networkmanager_client_glue.h" #include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" #include "internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h" #include "internal/platform/implementation/wifi.h" namespace nearby { namespace linux { +class NetworkManager + : public sdbus::ProxyInterfaces { +public: + NetworkManager(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager") { + registerProxy(); + } + ~NetworkManager() { unregisterProxy(); } + +protected: + void onCheckPermissions() override {} + void onStateChanged(const uint32_t &state) override {} + void onDeviceAdded(const sdbus::ObjectPath &device_path) override {} + void onDeviceRemoved(const sdbus::ObjectPath &device_path) override {} +}; + class NetworkManagerIP4Config : public sdbus::ProxyInterfaces< org::freedesktop::NetworkManager::IP4Config_proxy> { @@ -73,10 +91,12 @@ class NetworkManagerWifiMedium org::freedesktop::NetworkManager::Device::Wireless_proxy, sdbus::Properties_proxy> { public: - NetworkManagerWifiMedium(sdbus::IConnection &system_bus, + NetworkManagerWifiMedium(NetworkManager &network_manager, + sdbus::IConnection &system_bus, const sdbus::ObjectPath &wireless_device_object_path) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - wireless_device_object_path) { + wireless_device_object_path), + network_manager_(network_manager) { active_access_point_ = std::nullopt; registerProxy(); } @@ -89,14 +109,15 @@ public: void OnScanResults( const std::vector &scan_results) override { // TODO: Add implementation at some point - } + } }; bool IsInterfaceValid() const override { return true; }; api::WifiCapability &GetCapability() override; api::WifiInformation &GetInformation() override; - bool Scan(const api::WifiMedium::ScanResultCallback &scan_result_callback) override; + bool Scan( + const api::WifiMedium::ScanResultCallback &scan_result_callback) override; api::WifiConnectionStatus ConnectToNetwork(absl::string_view ssid, absl::string_view password, @@ -112,6 +133,8 @@ protected: const std::vector &invalidatedProperties) override; private: + NetworkManager &network_manager_; + api::WifiCapability capability_; api::WifiInformation information_{false}; @@ -120,7 +143,7 @@ private: absl::Mutex scan_result_callback_lock_; std::optional< - std::reference_wrapper> + std::reference_wrapper> scan_result_callback_; }; From ba07f52103f7405d743e30c41ff13652ff1b6011 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 16 Aug 2023 21:04:18 +0530 Subject: [PATCH 024/201] Simplify Bluetooth code. --- .../linux/bluetooth_classic_medium.cc | 120 +++++++----------- .../linux/bluetooth_classic_medium.h | 30 +++-- .../implementation/linux/bluetooth_pairing.cc | 10 +- .../implementation/linux/bluetooth_pairing.h | 6 +- .../platform/implementation/linux/bluez.cc | 4 + .../platform/implementation/linux/bluez.h | 2 + 6 files changed, 78 insertions(+), 94 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 2115684f..f8552491 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -7,6 +7,7 @@ #include "absl/strings/string_view.h" #include "absl/strings/substitute.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" @@ -18,45 +19,45 @@ namespace nearby { namespace linux { -BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, - absl::string_view adapter) - : devices_(system_bus, absl::Substitute("/org/bluez/$0/", adapter), - observers_), - profile_manager_(system_bus) { - bluez_adapter_proxy_ = sdbus::createProxy( - "org.bluez", absl::Substitute("/org/bluez/$0/", adapter)); - bluez_adapter_proxy_->finishRegistration(); - bluez_proxy_ = sdbus::createProxy("org.bluez", "/"); - bluez_proxy_->finishRegistration(); +BluetoothClassicMedium::BluetoothClassicMedium( + sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path) + : ProxyInterfaces(system_bus, "org.bluez", "/"), + adapter_( + std::make_unique(system_bus, adapter_object_path)), + devices_(std::make_unique( + system_bus, adapter_object_path, observers_)), + profile_manager_( + std::make_unique(system_bus, *devices_)) { + registerProxy(); } -void BluetoothClassicMedium::onInterfacesAdded(sdbus::Signal &signal) { - sdbus::ObjectPath object; - signal >> object; +BluetoothClassicMedium::~BluetoothClassicMedium() { unregisterProxy(); } +void BluetoothClassicMedium::onInterfacesAdded( + const sdbus::ObjectPath &object, + const std::map> + &interfacesAndProperties) { NEARBY_LOGS(VERBOSE) << __func__ << "New intefaces added at " << object; - auto path_prefix = - absl::Substitute("$0/dev_", bluez_adapter_proxy_->getObjectPath()); + auto path_prefix = absl::Substitute("$0/dev_", adapter_->getObjectPath()); if (object.find(path_prefix) != 0) { return; } - if (devices_.get_device_by_path(object).has_value()) { + if (devices_->get_device_by_path(object).has_value()) { // Device already exists. return; } - std::map> interfaces; - signal >> interfaces; - - for (auto it = interfaces.begin(); it != interfaces.end(); it++) { + for (auto it = interfacesAndProperties.begin(); + it != interfacesAndProperties.end(); it++) { auto interface = it->first; if (interface == "org.bluez.Device1") { - NEARBY_LOGS(INFO) << __func__ << "Encountered new device at " << object; + NEARBY_LOGS(INFO) << __func__ << ": Encountered new device at " << object; - auto &device = devices_.add_new_device(object); + auto &device = devices_->add_new_device(object); discovery_cb_lock_.ReaderLock(); if (discovery_cb_.has_value() && @@ -72,21 +73,16 @@ void BluetoothClassicMedium::onInterfacesAdded(sdbus::Signal &signal) { } } -void BluetoothClassicMedium::onInterfacesRemoved(sdbus::Signal &signal) { - sdbus::ObjectPath object; - signal >> object; - +void BluetoothClassicMedium::onInterfacesRemoved( + const sdbus::ObjectPath &object, + const std::vector &interfaces) { NEARBY_LOGS(VERBOSE) << __func__ << ": Intefaces removed at " << object; - auto path_prefix = - absl::Substitute("$0/dev_", bluez_adapter_proxy_->getObjectPath()); + auto path_prefix = absl::Substitute("$0/dev_", adapter_->getObjectPath()); if (object.find(path_prefix) != 0) { return; } - std::vector interfaces; - signal >> interfaces; - for (auto &interface : interfaces) { if (interface == bluez::DEVICE_INTERFACE) { @@ -122,23 +118,12 @@ bool BluetoothClassicMedium::StartDiscovery( discovery_cb_ = std::move(discovery_callback); discovery_cb_lock_.Unlock(); - NEARBY_LOGS(VERBOSE) << __func__ - << ": Subscribing to InterfacesAdded on / at org.bluez"; - - bluez_proxy_->registerSignalHandler( - "org.freedesktop.DBus.ObjectManager", "InterfacesAdded", - [this](sdbus::Signal &signal) { this->onInterfacesAdded(signal); }); - bluez_proxy_->registerSignalHandler( - "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved", - [this](sdbus::Signal &signal) { this->onInterfacesRemoved(signal); }); - try { NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on " - << bluez_adapter_proxy_->getObjectPath(); - bluez_adapter_proxy_->callMethod("StartDiscovery") - .onInterface(bluez::ADAPTER_INTERFACE); + << adapter_->getObjectPath(); + adapter_->StartDiscovery(); } catch (const sdbus::Error &e) { - BLUEZ_LOG_METHOD_CALL_ERROR(bluez_adapter_proxy_, "StartDiscovery", e); + BLUEZ_LOG_METHOD_CALL_ERROR(adapter_, "StartDiscovery", e); return false; } @@ -146,24 +131,15 @@ bool BluetoothClassicMedium::StartDiscovery( } bool BluetoothClassicMedium::StopDiscovery() { - NEARBY_LOGS(VERBOSE) - << __func__ << ": Unsubscribing to InterfacesAdded on / at org.bluez"; - bluez_proxy_->unregisterSignalHandler("org.freedesktop.DBus.ObjectManager", - "InterfacesAdded"); - bluez_proxy_->unregisterSignalHandler("org.freedesktop.DBus.ObjectManager", - "InterfacesRemoved"); try { NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " - << bluez_adapter_proxy_->getObjectPath(); - bluez_adapter_proxy_->callMethodAsync("StopDiscovery") - .onInterface(bluez::ADAPTER_INTERFACE) - .uponReplyInvoke([this](const sdbus::Error *err) { - this->discovery_cb_lock_.Lock(); - this->discovery_cb_.reset(); - this->discovery_cb_lock_.Unlock(); - }); + << adapter_->getObjectPath(); + + absl::MutexLock l(&this->discovery_cb_lock_); + adapter_->StopDiscovery(); + this->discovery_cb_.reset(); } catch (const sdbus::Error &e) { - BLUEZ_LOG_METHOD_CALL_ERROR(bluez_adapter_proxy_, "StopDiscovery", e); + BLUEZ_LOG_METHOD_CALL_ERROR(adapter_, "StopDiscovery", e); return false; } @@ -175,20 +151,20 @@ BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, const std::string &service_uuid, CancellationFlag *cancellation_flag) { auto device_object_path = bluez::device_object_path( - bluez_adapter_proxy_->getObjectPath(), remote_device.GetMacAddress()); - if (!profile_manager_.ProfileRegistered(service_uuid)) { - if (!profile_manager_.Register("", service_uuid)) { + adapter_->getObjectPath(), remote_device.GetMacAddress()); + if (!profile_manager_->ProfileRegistered(service_uuid)) { + if (!profile_manager_->Register("", service_uuid)) { NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " << service_uuid << " with Bluez"; return nullptr; } } - auto &device = devices_.get_device_by_path(device_object_path).value().get(); + auto &device = devices_->get_device_by_path(device_object_path).value().get(); device.ConnectToProfile(service_uuid); - auto fd = profile_manager_.GetServiceRecordFD(remote_device, service_uuid, - cancellation_flag); + 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 " @@ -204,8 +180,8 @@ BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, std::unique_ptr BluetoothClassicMedium::ListenForService(const std::string &service_name, const std::string &service_uuid) { - if (!profile_manager_.ProfileRegistered(service_uuid)) { - if (!profile_manager_.RegisterProfile(service_name, service_uuid)) { + 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"; @@ -214,7 +190,7 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, } return std::unique_ptr( - new BluetoothServerSocket(profile_manager_, service_uuid)); + new BluetoothServerSocket(*profile_manager_, service_uuid)); } api::BluetoothDevice * @@ -228,11 +204,9 @@ BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { std::unique_ptr BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) { - auto device_object_path = bluez::device_object_path( - bluez_adapter_proxy_->getObjectPath(), remote_device.GetMacAddress()); + auto device = devices_->get_device_by_address(remote_device.GetMacAddress()); return std::unique_ptr( - new BluetoothPairing(bluez_adapter_proxy_->getObjectPath(), remote_device, - bluez_adapter_proxy_->getConnection())); + new BluetoothPairing(*adapter_, *device)); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 783cc728..0154b9a2 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -8,12 +8,15 @@ #include #include +#include +#include #include #include #include "absl/synchronization/mutex.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_devices.h" @@ -22,11 +25,13 @@ namespace nearby { namespace linux { // Container of operations that can be performed over the Bluetooth Classic // medium. -class BluetoothClassicMedium : public api::BluetoothClassicMedium { +class BluetoothClassicMedium + : public api::BluetoothClassicMedium, + sdbus::ProxyInterfaces { public: BluetoothClassicMedium(sdbus::IConnection &system_bus, - absl::string_view adapter); - ~BluetoothClassicMedium() = default; + const sdbus::ObjectPath &adapter_object_path); + ~BluetoothClassicMedium() override; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() // @@ -94,20 +99,23 @@ public: get_device_by_address(const std::string &); void remove_device_by_path(const sdbus::ObjectPath &); -private: - void onInterfacesAdded(sdbus::Signal &signal); - void onInterfacesRemoved(sdbus::Signal &signal); +protected: + void onInterfacesAdded( + const sdbus::ObjectPath &objectPath, + const std::map> + &interfacesAndProperties) override; + void onInterfacesRemoved(const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override; - BluetoothDevices devices_; +private: + std::unique_ptr adapter_; + std::unique_ptr devices_; absl::Mutex discovery_cb_lock_; std::optional discovery_cb_; - ProfileManager profile_manager_; + std::unique_ptr profile_manager_; ObserverList observers_; - - std::unique_ptr bluez_adapter_proxy_; - std::unique_ptr bluez_proxy_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 08d893d4..81bdbb89 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -1,13 +1,13 @@ +#include + #include #include #include #include -#include #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/implementation/linux/bluez.h" #include "internal/platform/logging.h" namespace nearby { @@ -48,10 +48,8 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { return; } -BluetoothPairing::BluetoothPairing(const sdbus::ObjectPath &adapter_object_path, - BluetoothDevice &remote_device, - BluetoothAdapter &adapter, - sdbus::IConnection &system_bus) +BluetoothPairing::BluetoothPairing(BluetoothAdapter &adapter, + BluetoothDevice &remote_device) : device_(remote_device), adapter_(adapter) {} bool BluetoothPairing::InitiatePairing( diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 157f095e..80fce60c 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -17,9 +17,8 @@ namespace nearby { namespace linux { class BluetoothPairing : public api::BluetoothPairing { public: - BluetoothPairing(const sdbus::ObjectPath &adapter_object_path, - BluetoothDevice &remote_device, BluetoothAdapter &adapter, - sdbus::IConnection &system_bus); + BluetoothPairing(BluetoothAdapter &adapter, + BluetoothDevice &remote_device); ~BluetoothPairing() override = default; bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; @@ -36,7 +35,6 @@ private: BluetoothDevice &device_; BluetoothAdapter &adapter_; - std::unique_ptr bluez_adapter_proxy_; api::BluetoothPairingCallback pairing_cb_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index 2fde4c17..b5c7c118 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -27,6 +27,10 @@ sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) { return absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid); } +sdbus::ObjectPath adapter_object_path(absl::string_view name) { + return absl::Substitute("/org/bluez/$0", name); +} + } // namespace bluez } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 45471fea..dc7bb55d 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -34,6 +34,8 @@ device_object_path(const sdbus::ObjectPath &adapter_object_path, extern sdbus::ObjectPath profile_object_path(absl::string_view service_uuid); +extern sdbus::ObjectPath adapter_object_path(absl::string_view name); + } // namespace bluez } // namespace linux } // namespace nearby From 90d8e208eb9c31b6943d919fadaacd9293c0a657 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Wed, 16 Aug 2023 21:31:31 -0500 Subject: [PATCH 025/201] Implemented a TimerQueue class and a Timer class The Windows implementation of the Timer class (in timer.h) used Timer Queues. This brings in implementation for a mostly Windows complient TimerQueue class to work with the Timer class. --- .../platform/implementation/linux/timer.cc | 120 +++++++++++++ .../platform/implementation/linux/timer.h | 56 +++++++ .../implementation/linux/timer_queue.cc | 157 ++++++++++++++++++ .../implementation/linux/timer_queue.h | 124 ++++++++++++++ 4 files changed, 457 insertions(+) create mode 100644 internal/platform/implementation/linux/timer.cc create mode 100644 internal/platform/implementation/linux/timer.h create mode 100644 internal/platform/implementation/linux/timer_queue.cc create mode 100644 internal/platform/implementation/linux/timer_queue.h diff --git a/internal/platform/implementation/linux/timer.cc b/internal/platform/implementation/linux/timer.cc new file mode 100644 index 00000000..2468a009 --- /dev/null +++ b/internal/platform/implementation/linux/timer.cc @@ -0,0 +1,120 @@ +// 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/timer.h" +#include "internal/platform/implementation/linux/timer_queue.h" + +#include "absl/synchronization/mutex.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +Timer::~Timer() { Stop(); } + +bool Timer::Create(int delay, int interval, + absl::AnyInvocable callback) { + absl::MutexLock lock(&mutex_); + + if ((delay < 0) || (interval < 0)) { + NEARBY_LOGS(WARNING) << "Delay and interval shouldn\'t be negative value."; + return false; + } + + if (timer_queue_handle_) { + return false; + } + + timer_queue_handle_ = TimerQueue::CreateTimerQueue(); + if (!timer_queue_handle_) { + NEARBY_LOGS(ERROR) << "Failed to create timer queue."; + return false; + } + + delay_ = delay; + interval_ = interval; + callback_ = std::move(callback); + + absl::StatusOr createStatus = timer_queue_handle_->CreateTimerQueueTimer(TimerRoutine, + &callback_, std::chrono::milliseconds(delay), std::chrono::milliseconds(interval), TimerQueue::WT_EXECUTEDEFAULT); + + if (!createStatus.ok()) { + if (!timer_queue_handle_->DeleteTimerQueueEx(TimerQueue::CE_IMEDIATERETURN).ok()) { + NEARBY_LOGS(ERROR) << "Failed to create timer in timer queue."; + } + delete timer_queue_handle_.release(); + return false; + } + handle_ = createStatus.value(); + return true; +} + +bool Timer::Stop() { + absl::MutexLock lock(&mutex_); + + if (!timer_queue_handle_) { + return true; + } + + absl::Status deleteStatus = timer_queue_handle_->DeleteTimerQueueTimer(handle_, TimerQueue::CE_IMEDIATERETURN); + + if (!deleteStatus.ok()) { + NEARBY_LOGS(ERROR) << "Failed to delete timer from queue: " << deleteStatus.message(); + } + + handle_ = 0; + + deleteStatus = timer_queue_handle_->DeleteTimerQueueEx(TimerQueue::CE_IMEDIATERETURN); + + if (!deleteStatus.ok()) { + NEARBY_LOGS(ERROR) << "Failed to delete timer queue: " << deleteStatus.message(); + return false; + } + + timer_queue_handle_ = nullptr; + return true; +} + +bool Timer::FireNow() { + absl::MutexLock lock(&mutex_); + + if (!timer_queue_handle_ || !callback_) { + return false; + } + + if (task_executor_ == nullptr) { + task_executor_ = std::make_unique(); + } + + if (task_executor_ == nullptr) { + NEARBY_LOGS(ERROR) + << "Failed to fire the task due to cannot create executor."; + return false; + } + + task_executor_->Execute([&]() { callback_(); }); + + return true; +} + +void Timer::TimerRoutine(void *lpParam) { + absl::AnyInvocable* callback = + reinterpret_cast*>(lpParam); + if (*callback != nullptr) { + (*callback)(); + } +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/timer.h b/internal/platform/implementation/linux/timer.h new file mode 100644 index 00000000..8a75163c --- /dev/null +++ b/internal/platform/implementation/linux/timer.h @@ -0,0 +1,56 @@ +// 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. + +#ifndef PLATFORM_IMPL_LINUX_TIMER_H_ +#define PLATFORM_IMPL_LINUX_TIMER_H_ + +#include + +#include "absl/base/thread_annotations.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/timer.h" +#include "internal/platform/implementation/linux/submittable_executor.h" +#include "internal/platform/implementation/linux/timer_queue.h" + +namespace nearby { +namespace linux { + +class Timer : public api::Timer { + public: + Timer() = default; + ~Timer() override; + + bool Create(int delay, int interval, + absl::AnyInvocable callback) override + ABSL_LOCKS_EXCLUDED(mutex_); + bool Stop() override ABSL_LOCKS_EXCLUDED(mutex_); + bool FireNow() override ABSL_LOCKS_EXCLUDED(mutex_); + + private: + static void TimerRoutine(void *lpParam); + + mutable absl::Mutex mutex_; + int delay_ ABSL_GUARDED_BY(mutex_); + int interval_ ABSL_GUARDED_BY(mutex_); + absl::AnyInvocable callback_; + uint16_t handle_ ABSL_GUARDED_BY(mutex_) = 0; + std::unique_ptr timer_queue_handle_; + std::unique_ptr task_executor_ ABSL_GUARDED_BY(mutex_) = + nullptr; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_TIMER_H_ diff --git a/internal/platform/implementation/linux/timer_queue.cc b/internal/platform/implementation/linux/timer_queue.cc new file mode 100644 index 00000000..5048008c --- /dev/null +++ b/internal/platform/implementation/linux/timer_queue.cc @@ -0,0 +1,157 @@ +// 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/timer_queue.h" + +#include "internal/platform/implementation/linux/utils.h" + +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +std::unique_ptr TimerQueue::CreateTimerQueue() { + return std::unique_ptr(new TimerQueue); +} + +TimerQueue::TimerQueue() { + thread_ = std::thread([this]() {Run();}); +} + +TimerQueue::~TimerQueue() { + DeleteTimerQueueEx(CE_WAITFORCALLBACKS); // NOLINT + cancelled_ = true; + thread_.join(); +} + +void TimerQueue::Run() { + while(!cancelled_ || !work_.empty()) { + absl::MutexLock lk(&mutex_); + empty_ = (work_.empty() ? true : false); + for (auto &workItem : work_) { + if (workItem.Finished) { + if (workItem.Due < std::chrono::steady_clock::now()) { + work_.erase(workItem); + break; + } + } + if (workItem.Cancelled) { + if (workItem.Worker.valid()) { + if (workItem.Worker.wait_for(std::chrono_literals::operator""ms(0)) == std::future_status::ready) { + work_.erase(workItem); + break; + } + } + } + if (workItem.Due <= std::chrono::steady_clock::now()) { + if ((workItem.Flags & WT_EXECUTEDEFAULT) == WT_EXECUTEDEFAULT) { + if ((workItem.Flags & WT_EXECUTEONLYONCE) == WT_EXECUTEONLYONCE) { + workItem.Worker = std::async(workItem.Callback, workItem.Parameter); + workItem.Finished = true; + } + else { + if (workItem.Period > std::chrono_literals::operator""ms(0)) { + workItem.Worker = std::async(workItem.Callback, workItem.Parameter); + workItem.Finished = true; + workItem.Due = std::chrono::steady_clock::now() + workItem.Period; + } + else { + workItem.Worker = std::async(workItem.Callback, workItem.Parameter); + workItem.Finished = true; + } + } + } + else if ((workItem.Flags & WT_EXECUTEINTIMERTHREAD) == WT_EXECUTEINTIMERTHREAD) { + if ((workItem.Flags & WT_EXECUTEONLYONCE) == WT_EXECUTEONLYONCE) { + workItem.Callback(workItem.Parameter); + workItem.Finished = true; + } + else { + if (workItem.Period > std::chrono_literals::operator""ms(0)) { + workItem.Callback(workItem.Parameter); + workItem.Finished = true; + workItem.Due = std::chrono::steady_clock::now() + workItem.Period; + } + else { + workItem.Callback(workItem.Parameter); + workItem.Finished = true; + } + } + } + } + } + } +} + +absl::StatusOr TimerQueue::CreateTimerQueueTimer(absl::AnyInvocable Callback, void *Parameter, std::chrono::milliseconds DueTime, std::chrono::milliseconds Period, unsigned long int Flags) { + TimerWork work; + + work.Callback = std::move(Callback); + work.WorkId = next_id_; + work.Flags = Flags; + next_id_++; + work.Due = std::chrono::steady_clock::now() + DueTime; + work.Period = Period; + work.Parameter = Parameter; + absl::MutexLock lk(&mutex_); + work_.insert(std::move(work)); + return next_id_ - 1; +} + +absl::Status TimerQueue::DeleteTimerQueueTimer(uint16_t WorkId, unsigned long int CompletionEvent) { + for (auto &workItem : work_) { + absl::MutexLock lk(&mutex_); + if (workItem.WorkId == WorkId) { + workItem.Cancelled = true; + } + } + return absl::OkStatus(); +} + +namespace { + bool check(bool *arg) { + return *arg; + } +} // namespace + +absl::Status TimerQueue::DeleteTimerQueueEx(unsigned int long CompletionEvent) { + switch (CompletionEvent) { + case CE_IMEDIATERETURN: { + absl::MutexLock lk(&mutex_); + for (auto workItem = work_.begin(); workItem != work_.end();) { + if (workItem->Worker.valid()) { + workItem->Worker.wait(); + } + workItem = work_.erase(workItem); + } + return absl::OkStatus(); + } + case CE_WAITFORCALLBACKS: { + mutex_.Lock(); + for (auto &workItem : work_) { + workItem.Cancelled = true; + } + clearing_ = true; + mutex_.Await(absl::Condition(check, &empty_)); + mutex_.Unlock(); + return absl::OkStatus(); + } + default: { + return absl::InvalidArgumentError("Invalid Completion Event value."); + } + } +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/timer_queue.h b/internal/platform/implementation/linux/timer_queue.h new file mode 100644 index 00000000..db745324 --- /dev/null +++ b/internal/platform/implementation/linux/timer_queue.h @@ -0,0 +1,124 @@ +// 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. + +#ifndef PLATFORM_IMPL_LINUX_TIMER_QUEUE_H_ +#define PLATFORM_IMPL_LINUX_TIMER_QUEUE_H_ + +#include +#include +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/functional/any_invocable.h" +#include "absl/functional/function_ref.h" +#include "absl/synchronization/mutex.h" +#include "absl/base/thread_annotations.h" + +namespace nearby { +namespace linux { + +/* + * This class represents a a que for timers. This class is built to try to replicate the Windows Timer-Queue functionality. + * https://learn.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-createtimerqueue + */ +class TimerQueue { +public: + /* + * Parameters to be used with the Timer Queue Timer. + * See https://learn.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-createtimerqueuetimer + */ + static constexpr unsigned long int WT_EXECUTEDEFAULT = 1 << 0; + static constexpr unsigned long int WT_EXECUTEINTIMERTHREAD = 1 << 1; + static constexpr unsigned long int WT_EXECUTEINIOTHREAD = 1 << 2; // Unused + static constexpr unsigned long int WT_EXECUTEINPERSISTENTTHREAD = 1 << 3; // Unused + static constexpr unsigned long int WT_EXECUTELONGFUNCTION = 1 << 4; // Unused + static constexpr unsigned long int WT_EXECUTEONLYONCE = 1 << 5; + static constexpr unsigned long int WT_TRANSFER_IMPERSONATION = 1 << 6; // Unused + static constexpr unsigned long int CE_WAITFORCALLBACKS = 1 << 0; // Equivalent to `INVALID_HANDLE_VALUE` when passing for a CompletionEvent + static constexpr unsigned long int CE_IMEDIATERETURN = 1 << 1; // Equivalent to `NULL` when passing for a CompletionEvent + // Creates a new timer queue for the user to use. + static std::unique_ptr CreateTimerQueue(); + + // Returns a thread unique identifier that the timer is running on if it is successful. Status if not. + absl::StatusOr CreateTimerQueueTimer(absl::AnyInvocable Callback, void *Parameter, std::chrono::milliseconds DueTime, std::chrono::milliseconds Period, unsigned long int Flags = WT_EXECUTEDEFAULT); + + // Removes a timer based on the thread id the timer is running on. + absl::Status DeleteTimerQueueTimer(uint16_t WorkId, unsigned long int CompletionEvent = CE_WAITFORCALLBACKS); + + // Removes all timers in the timer queue + absl::Status DeleteTimerQueueEx(unsigned long int CompletionEvent = CE_WAITFORCALLBACKS); + + ~TimerQueue(); + +private: + TimerQueue(); + + void Run(); + + uint16_t next_id_; + + // A struct that represents a timer of work that needs to be done. + struct TimerWork { + mutable std::chrono::time_point Due; + mutable absl::AnyInvocable Callback; + mutable std::chrono::milliseconds Period; + mutable void *Parameter = nullptr; + mutable long int Flags; + mutable std::future Worker; + mutable std::atomic_bool Cancelled = false; + mutable std::atomic_bool Finished = false; + uint16_t WorkId = 0; + + // Useful for time comparisons on other work items + bool operator<(const TimerWork &other) const { + return Due < other.Due; + } + bool operator>(const TimerWork &other) const { + return Due > other.Due; + } + bool operator==(const TimerWork &other) const { + return Due == other.Due; + } + bool operator!=(const TimerWork &other) const { + return !operator==(other); + } + bool operator<=(const TimerWork &other) const { + return (operator<(other) || operator==(other)); + } + bool operator>=(const TimerWork &other) const { + return (operator>(other) || operator==(other)); + } + }; + + std::set work_; + std::vector threads_; + + std::thread thread_; + + bool cancelled_; + bool clearing_; + bool empty_; + + absl::CondVar condvar_; + absl::Mutex mutex_; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_TIMER_QUEUE_H_ From 17786cbec353caad16875f57ab4ddada1a21555e Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Wed, 16 Aug 2023 21:36:04 -0500 Subject: [PATCH 026/201] Added base implementation for input_file and output_file This are unimplemented currently, but will be in the future. --- .../implementation/linux/input_file.h | 48 +++++++ .../implementation/linux/input_file_test.cc | 135 ++++++++++++++++++ .../implementation/linux/output_file.h | 45 ++++++ .../implementation/linux/output_file_test.cc | 80 +++++++++++ 4 files changed, 308 insertions(+) create mode 100644 internal/platform/implementation/linux/input_file.h create mode 100644 internal/platform/implementation/linux/input_file_test.cc create mode 100644 internal/platform/implementation/linux/output_file.h create mode 100644 internal/platform/implementation/linux/output_file_test.cc diff --git a/internal/platform/implementation/linux/input_file.h b/internal/platform/implementation/linux/input_file.h new file mode 100644 index 00000000..7d4df48a --- /dev/null +++ b/internal/platform/implementation/linux/input_file.h @@ -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_INPUT_FILE_H_ +#define PLATFORM_IMPL_LINUX_INPUT_FILE_H_ + +#include "internal/platform/implementation/input_file.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" + +namespace nearby { +namespace linux { + +// An InputFile represents a readable file on the system. +class InputFile : public api::InputFile { + public: + // TODO(b/184975123): replace with real implementation. + ~InputFile() override = default; + // TODO(b/184975123): replace with real implementation. + std::string GetFilePath() const override { return "Un-implemented"; } + // TODO(b/184975123): replace with real implementation. + std::int64_t GetTotalSize() const override { return 0; } + + // throws Exception::kIo + // TODO(b/184975123): replace with real implementation. + ExceptionOr Read(std::int64_t size) override { + return ExceptionOr(Exception::kFailed); + } + // throws Exception::kIo + // TODO(b/184975123): replace with real implementation. + Exception Close() override { return Exception{}; } +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_INPUT_FILE_H_ diff --git a/internal/platform/implementation/linux/input_file_test.cc b/internal/platform/implementation/linux/input_file_test.cc new file mode 100644 index 00000000..63268b0c --- /dev/null +++ b/internal/platform/implementation/linux/input_file_test.cc @@ -0,0 +1,135 @@ +// 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/input_file.h" + +#include + +#include "gtest/gtest.h" +#include "internal/platform/exception.h" +#include "internal/platform/payload_id.h" +#include "internal/platform/implementation/linux/test_utils.h" +#include "internal/platform/logging.h" + +class InputFileTests : public testing::Test { + protected: + // You can define per-test set-up logic as usual. + void SetUp() override { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + auto path = test_utils::GetPayloadPath(payloadId); + + file_.open(path, std::ios::out); + + if (!file_) { + NEARBY_LOG(ERROR, + "Failed to create OutputFile with payloadId: %s and error: %d", + test_utils::GetPayloadPath(payloadId).c_str(), std::strerror(errno)); + } + + const char* buffer = TEST_STRING; + + file_.write(buffer, std::strlen(buffer)); + + file_.close(); + } + + // You can define per-test tear-down logic as usual. + void TearDown() override { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + if (std::filesystem::exists(test_utils::GetPayloadPath(payloadId))) { + std::filesystem::remove(test_utils::GetPayloadPath(payloadId)); + } + } + + private: + std::fstream file_; +}; + +TEST_F(InputFileTests, SuccessfulCreation) { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + std::unique_ptr inputFile = nullptr; + + inputFile = nearby::api::ImplementationPlatform::CreateInputFile( + payloadId, strlen(TEST_STRING)); + + EXPECT_NE(inputFile, nullptr); + EXPECT_EQ(inputFile->Close(), nearby::Exception{nearby::Exception::kSuccess}); +} + +TEST_F(InputFileTests, SuccessfulGetFilePath) { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + std::unique_ptr inputFile = nullptr; + std::string fileName; + + inputFile = nearby::api::ImplementationPlatform::CreateInputFile( + payloadId, strlen(TEST_STRING)); + + fileName = inputFile->GetFilePath(); + + EXPECT_EQ(inputFile->Close(), nearby::Exception{nearby::Exception::kSuccess}); + + EXPECT_EQ(fileName, test_utils::GetPayloadPath(payloadId).c_str()); +} + +TEST_F(InputFileTests, SuccessfulGetTotalSize) { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + std::unique_ptr inputFile = nullptr; + int64_t size = -1; + + inputFile = nearby::api::ImplementationPlatform::CreateInputFile( + payloadId, strlen(TEST_STRING)); + + size = inputFile->GetTotalSize(); + + EXPECT_EQ(inputFile->Close(), nearby::Exception{nearby::Exception::kSuccess}); + + EXPECT_EQ(size, strlen(TEST_STRING)); +} + +TEST_F(InputFileTests, SuccessfulRead) { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + std::unique_ptr inputFile = nullptr; + + inputFile = nearby::api::ImplementationPlatform::CreateInputFile( + payloadId, strlen(TEST_STRING)); + + auto fileSize = inputFile->GetTotalSize(); + auto dataRead = inputFile->Read(fileSize); + + EXPECT_TRUE(dataRead.ok()); + EXPECT_EQ(inputFile->Close(), nearby::Exception{nearby::Exception::kSuccess}); + + EXPECT_STREQ(std::string(dataRead.result()).c_str(), TEST_STRING); +} + +TEST_F(InputFileTests, FailedRead) { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + std::unique_ptr inputFile = nullptr; + + inputFile = nearby::api::ImplementationPlatform::CreateInputFile( + payloadId, strlen(TEST_STRING)); + + auto fileSize = inputFile->GetTotalSize(); + EXPECT_NE(fileSize, -1); + + auto dataRead = inputFile->Read(fileSize); + EXPECT_TRUE(dataRead.ok()); + + dataRead = inputFile->Read(fileSize); + std::string data = std::string(dataRead.result()); + + inputFile->Close(); + + EXPECT_STREQ(data.c_str(), ""); +} diff --git a/internal/platform/implementation/linux/output_file.h b/internal/platform/implementation/linux/output_file.h new file mode 100644 index 00000000..53bcbddb --- /dev/null +++ b/internal/platform/implementation/linux/output_file.h @@ -0,0 +1,45 @@ +// 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_OUTPUT_FILE_H_ +#define PLATFORM_IMPL_LINUX_OUTPUT_FILE_H_ + +#include "internal/platform/implementation/output_file.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" + +namespace nearby { +namespace linux { + +// An OutputFile represents a writable file on the system. +class OutputFile : public api::OutputFile { + public: + // TODO(b/184975123): replace with real implementation. + ~OutputFile() override = default; + + // throws Exception::kIo + // TODO(b/184975123): replace with real implementation. + Exception Write(const ByteArray& data) override { return Exception{}; } + // throws Exception::kIo + // TODO(b/184975123): replace with real implementation. + Exception Flush() override { return Exception{}; } + // throws Exception::kIo + // TODO(b/184975123): replace with real implementation. + Exception Close() override { return Exception{}; } +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_OUTPUT_FILE_H_ diff --git a/internal/platform/implementation/linux/output_file_test.cc b/internal/platform/implementation/linux/output_file_test.cc new file mode 100644 index 00000000..bf490d27 --- /dev/null +++ b/internal/platform/implementation/linux/output_file_test.cc @@ -0,0 +1,80 @@ +// 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/output_file.h" + +#include "gtest/gtest.h" +#include "internal/platform/implementation/platform.h" +#include "internal/platform/exception.h" +#include "internal/platform/payload_id.h" +#include "internal/platform/implementation/windows/test_utils.h" + +class OutputFileTests : public testing::Test { + protected: + // You can define per-test set-up logic as usual. + void SetUp() override { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + if (std::filesystem::exists(test_utils::GetPayloadPath(payloadId))) { + std::filesystem::remove(test_utils::GetPayloadPath(payloadId)); + } + } + + // You can define per-test tear-down logic as usual. + void TearDown() override { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + if (std::filesystem::exists(test_utils::GetPayloadPath(payloadId).c_str())) { + std::filesystem::remove(test_utils::GetPayloadPath(payloadId).c_str()); + } + } +}; + +TEST_F(OutputFileTests, SuccessfulCreation) { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + std::unique_ptr outputFile = nullptr; + + EXPECT_NO_THROW( + outputFile = + nearby::api::ImplementationPlatform::CreateOutputFile(payloadId)); + + EXPECT_NE(outputFile, nullptr); + EXPECT_NO_THROW(outputFile->Close()); +} + +TEST_F(OutputFileTests, SuccessfulClose) { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + std::unique_ptr outputFile = nullptr; + + EXPECT_NO_THROW( + outputFile = + nearby::api::ImplementationPlatform::CreateOutputFile(payloadId)); + + EXPECT_NO_THROW(outputFile->Close()); + + std::filesystem::remove(test_utils::GetPayloadPath(payloadId).c_str()); +} + +TEST_F(OutputFileTests, SuccessfulWrite) { + nearby::PayloadId payloadId(TEST_PAYLOAD_ID); + nearby::ByteArray data(std::string(TEST_STRING)); + std::unique_ptr outputFile = nullptr; + + EXPECT_NO_THROW( + outputFile = + nearby::api::ImplementationPlatform::CreateOutputFile(payloadId)); + + EXPECT_NO_THROW(outputFile->Write(data)); + EXPECT_NO_THROW(outputFile->Close()); + + std::filesystem::remove(test_utils::GetPayloadPath(payloadId).c_str()); +} From 4a4056694a94e55cb309e01568537c9e37489125 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Wed, 16 Aug 2023 21:37:52 -0500 Subject: [PATCH 027/201] Implemented missing implementation files I missed some implementation when I was looking over them. These are them. --- .../implementation/linux/server_sync.h | 88 +++++++++++++++++++ .../implementation/linux/system_clock.cc | 41 +++++++++ .../implementation/linux/timer_test.cc | 68 ++++++++++++++ .../implementation/linux/utils_test.cc | 85 ++++++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 internal/platform/implementation/linux/server_sync.h create mode 100644 internal/platform/implementation/linux/system_clock.cc create mode 100644 internal/platform/implementation/linux/timer_test.cc create mode 100644 internal/platform/implementation/linux/utils_test.cc diff --git a/internal/platform/implementation/linux/server_sync.h b/internal/platform/implementation/linux/server_sync.h new file mode 100644 index 00000000..813aeefb --- /dev/null +++ b/internal/platform/implementation/linux/server_sync.h @@ -0,0 +1,88 @@ +// 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_SERVER_SYNC_H_ +#define PLATFORM_IMPL_LINUX_SERVER_SYNC_H_ + +#include "internal/platform/implementation/server_sync.h" + +namespace nearby { +namespace linux { + +// Abstraction that represents a Nearby endpoint exchanging data through +// ServerSync Medium. +class ServerSyncDevice : public api::ServerSyncDevice { + public: + // TODO(b/184975123): replace with real implementation. + ~ServerSyncDevice() override = default; + + // TODO(b/184975123): replace with real implementation. + std::string GetName() const override { return "Un-implemented"; } + // TODO(b/184975123): replace with real implementation. + std::string GetGuid() const override { return "Un-implemented"; } + // TODO(b/184975123): replace with real implementation. + std::string GetOwnGuid() const override { return "Un-implemented"; } +}; + +// Container of operations that can be performed over the Chrome Sync medium. +class ServerSyncMedium : public api::ServerSyncMedium { + public: + // TODO(b/184975123): replace with real implementation. + ~ServerSyncMedium() override = default; + + // TODO(b/184975123): replace with real implementation. + bool StartAdvertising(absl::string_view service_id, + absl::string_view endpoint_id, + const ByteArray& endpoint_info) override { + return false; + } + // TODO(b/184975123): replace with real implementation. + void StopAdvertising(absl::string_view service_id) override {} + + class DiscoveredDeviceCallback + : public api::ServerSyncMedium::DiscoveredDeviceCallback { + public: + // TODO(b/184975123): replace with real implementation. + ~DiscoveredDeviceCallback() override = default; + + // Called on a new ServerSyncDevice discovery. + // TODO(b/184975123): replace with real implementation. + void OnDeviceDiscovered(api::ServerSyncDevice* device, + absl::string_view service_id, + absl::string_view endpoint_id, + const ByteArray& endpoint_info) override {} + // Called when ServerSyncDevice is no longer reachable. + // TODO(b/184975123): replace with real implementation. + void OnDeviceLost(api::ServerSyncDevice* device, + absl::string_view service_id) override {} + }; + + // Returns true once the Chrome Sync scan has been initiated. + // TODO(b/184975123): replace with real implementation. + bool StartDiscovery(absl::string_view service_id, + const api::ServerSyncMedium::DiscoveredDeviceCallback& + discovered_device_callback) override { + return false; + } + // Returns true once Chrome Sync scan for service_id is well and truly + // stopped; after this returns, there must be no more invocations of the + // DiscoveredDeviceCallback passed in to startScanning() for service_id. + // TODO(b/184975123): replace with real implementation. + void StopDiscovery(absl::string_view service_id) override {} +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_SERVER_SYNC_H_ diff --git a/internal/platform/implementation/linux/system_clock.cc b/internal/platform/implementation/linux/system_clock.cc new file mode 100644 index 00000000..ea1edd85 --- /dev/null +++ b/internal/platform/implementation/linux/system_clock.cc @@ -0,0 +1,41 @@ +// 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. + +#ifndef PLATFORM_IMPL_LINUX_SYSTEM_CLOCK_H_ +#define PLATFORM_IMPL_LINUX_SYSTEM_CLOCK_H_ + +#include "internal/platform/implementation/system_clock.h" + +namespace nearby { + +// Initialize global system state. +void SystemClock::Init() { } + +// Returns current absolute time. It is guaranteed to be monotonic. +absl::Time SystemClock::ElapsedRealtime() { + return absl::FromUnixNanos( + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count()); +} + +// Pauses current thread for the specified duration. +Exception SystemClock::Sleep(absl::Duration duration) { + absl::SleepFor(duration); + return {Exception::kSuccess}; +} + +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_SYSTEM_CLOCK_H_ diff --git a/internal/platform/implementation/linux/timer_test.cc b/internal/platform/implementation/linux/timer_test.cc new file mode 100644 index 00000000..60308d24 --- /dev/null +++ b/internal/platform/implementation/linux/timer_test.cc @@ -0,0 +1,68 @@ +// 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/timer.h" + +#include // NOLINT +// NOLINT +#include +#include // NOLINT + +#include "gtest/gtest.h" +#include "internal/platform/implementation/platform.h" + +namespace nearby { +namespace linux { +namespace { + +TEST(Timer, TestCreateTimer) { + int count = 0; + + std::unique_ptr timer = + nearby::api::ImplementationPlatform::CreateTimer(); + + ASSERT_TRUE(timer != nullptr); + EXPECT_FALSE(timer->Create(-100, 0, [&]() { ++count; })); + EXPECT_TRUE(timer->Stop()); +} + +// This test case cannot run on Google3 +TEST(Timer, DISABLED_TestRepeatTimer) { + int count = 0; + + std::unique_ptr timer = + nearby::api::ImplementationPlatform::CreateTimer(); + + ASSERT_TRUE(timer != nullptr); + EXPECT_TRUE(timer->Create(300, 300, [&]() { ++count; })); + std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_TRUE(timer->Stop()); + EXPECT_EQ(count, 3); +} + +TEST(Timer, DISABLED_TestFireNow) { + int count = 0; + + auto timer = nearby::api::ImplementationPlatform::CreateTimer(); + + EXPECT_TRUE(timer != nullptr); + EXPECT_TRUE(timer->Create(3000, 3000, [&]() { ++count; })); + EXPECT_TRUE(timer->FireNow()); + EXPECT_TRUE(timer->Stop()); + EXPECT_EQ(count, 1); +} + +} // namespace +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/utils_test.cc b/internal/platform/implementation/linux/utils_test.cc new file mode 100644 index 00000000..228252f9 --- /dev/null +++ b/internal/platform/implementation/linux/utils_test.cc @@ -0,0 +1,85 @@ +// 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/utils.h" + +#include + +#include "gtest/gtest.h" + +namespace nearby { +namespace linux { + +TEST(UtilsTests, MacAddressToString) { + // Arrange + const uint64_t input = 0x000034363bc70c71; + std::string expected = "34:36:3B:C7:0C:71"; + + // Act + std::string result = uint64_to_mac_address_string(input); + + // Assert + EXPECT_EQ(result, expected); +} + +TEST(UtilsTests, StringToMacAddress) { + // Arrange + std::string input = "34:36:3B:C7:8C:71"; + const uint64_t expected = 0x000034363bc78c71; + + // Act + uint64_t result = mac_address_string_to_uint64(input); + + // Assert + EXPECT_EQ(result, expected); +} + +constexpr absl::string_view kIpDotdecimal{"192.168.1.37"}; + +constexpr char kIp4Bytes[] = {(char)192, (char)168, (char)1, (char)37}; + +TEST(UtilsTests, Ip4BytesToDotdecimal) { + std::string result = + ipaddr_4bytes_to_dotdecimal_string(absl::string_view(kIp4Bytes)); + + EXPECT_EQ(result, kIpDotdecimal); +} + +TEST(UtilsTests, IpDotdecimalTo4Bytes) { + std::string result = + ipaddr_dotdecimal_to_4bytes_string(std::string(kIpDotdecimal)); + + EXPECT_EQ(result, std::string(kIp4Bytes, 4)); +} + +/* +TEST(UtilsTests, ConvertBetweenWinrtGuidAndNearbyUuidSuccessfully) { + Uuid uuid(0x123e4567e89b12d3, 0xa456426614174000); + winrt::guid guid("{123e4567-e89b-12d3-a456-426614174000}"); + + EXPECT_EQ(uuid, winrt_guid_to_nearby_uuid(guid)); + EXPECT_EQ(nearby_uuid_to_winrt_guid(uuid), guid); + EXPECT_TRUE(is_nearby_uuid_equal_to_winrt_guid(uuid, guid)); +} + +TEST(UtilsTests, CompareWinrtGuidAndNearbyUuidSuccessfully) { + Uuid uuid(0x123e4567e89b12d3, 0xa456426614174000); + winrt::guid guid("123e4567-e89b-12d3-a456-426614074000"); + + EXPECT_NE(uuid, winrt_guid_to_nearby_uuid(guid)); +} +*/ + +} // namespace linux +} // namespace nearby From ff55edb5e418e387c17d909a70cb980b1fe64789 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 21 Aug 2023 23:19:01 +0530 Subject: [PATCH 028/201] Code dump. --- .../implementation/linux/atomic_boolean.h | 27 ++ .../implementation/linux/atomic_uint32.h | 28 ++ .../platform/implementation/linux/avahi.cc | 103 +++++ .../platform/implementation/linux/avahi.h | 78 ++++ .../linux/avahi_entrygroup_client_glue.h | 94 +++++ .../linux/avahi_server_client_glue.h | 399 ++++++++++++++++++ .../linux/avahi_servicebrowser_client_glue.h | 58 +++ .../linux/bluetooth_classic_socket.cc | 51 +-- .../linux/bluetooth_classic_socket.h | 41 +- .../implementation/linux/condition_variable.h | 36 ++ .../implementation/linux/credential_storage.h | 50 +++ .../platform/implementation/linux/dbus.cc | 35 ++ internal/platform/implementation/linux/dbus.h | 8 + .../implementation/linux/device_info.cc | 6 +- .../implementation/linux/log_message.cc | 111 +++++ .../implementation/linux/log_message.h | 118 ++++++ .../platform/implementation/linux/mutex.h | 56 +++ .../org.freedesktop.Avahi.EntryGroup.xml | 94 +++++ .../linux/org.freedesktop.Avahi.Server.xml | 398 +++++++++++++++++ .../org.freedesktop.Avahi.ServiceBrowser.xml | 58 +++ .../org.freedesktop.Avahi.ServiceResolver.xml | 57 +++ .../linux/org.freedesktop.LogControl1.xml | 17 + .../org_freedesktop_logcontrol_server_glue.h | 45 ++ .../platform/implementation/linux/platform.cc | 70 ++- .../platform/implementation/linux/stream.h | 40 ++ .../platform/implementation/linux/wifi_lan.cc | 240 +++++++++++ .../platform/implementation/linux/wifi_lan.h | 58 +++ .../linux/wifi_lan_server_socket.cc | 82 ++++ .../linux/wifi_lan_server_socket.h | 33 ++ .../implementation/linux/wifi_lan_socket.h | 42 ++ .../implementation/linux/wifi_medium.h | 8 +- .../implementation/linux/wifi_socket.h | 16 + 32 files changed, 2479 insertions(+), 78 deletions(-) create mode 100644 internal/platform/implementation/linux/atomic_boolean.h create mode 100644 internal/platform/implementation/linux/atomic_uint32.h create mode 100644 internal/platform/implementation/linux/avahi.cc create mode 100644 internal/platform/implementation/linux/avahi.h create mode 100644 internal/platform/implementation/linux/avahi_entrygroup_client_glue.h create mode 100644 internal/platform/implementation/linux/avahi_server_client_glue.h create mode 100644 internal/platform/implementation/linux/avahi_servicebrowser_client_glue.h create mode 100644 internal/platform/implementation/linux/condition_variable.h create mode 100644 internal/platform/implementation/linux/credential_storage.h create mode 100644 internal/platform/implementation/linux/dbus.cc create mode 100644 internal/platform/implementation/linux/log_message.cc create mode 100644 internal/platform/implementation/linux/log_message.h create mode 100644 internal/platform/implementation/linux/mutex.h create mode 100644 internal/platform/implementation/linux/org.freedesktop.Avahi.EntryGroup.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.Avahi.Server.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceBrowser.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceResolver.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.LogControl1.xml create mode 100644 internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h create mode 100644 internal/platform/implementation/linux/stream.h create mode 100644 internal/platform/implementation/linux/wifi_lan.cc create mode 100644 internal/platform/implementation/linux/wifi_lan.h create mode 100644 internal/platform/implementation/linux/wifi_lan_server_socket.cc create mode 100644 internal/platform/implementation/linux/wifi_lan_server_socket.h create mode 100644 internal/platform/implementation/linux/wifi_lan_socket.h create mode 100644 internal/platform/implementation/linux/wifi_socket.h diff --git a/internal/platform/implementation/linux/atomic_boolean.h b/internal/platform/implementation/linux/atomic_boolean.h new file mode 100644 index 00000000..61bc5565 --- /dev/null +++ b/internal/platform/implementation/linux/atomic_boolean.h @@ -0,0 +1,27 @@ +#ifndef PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_ +#define PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_ + +#include "internal/platform/implementation/atomic_boolean.h" +#include +namespace nearby { +namespace linux { +// A boolean value that may be updated atomically. +class AtomicBoolean : public api::AtomicBoolean { +public: + AtomicBoolean(bool initial_value) : 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 + diff --git a/internal/platform/implementation/linux/atomic_uint32.h b/internal/platform/implementation/linux/atomic_uint32.h new file mode 100644 index 00000000..f5fbf88b --- /dev/null +++ b/internal/platform/implementation/linux/atomic_uint32.h @@ -0,0 +1,28 @@ +#ifndef PLATFORM_IMPL_LINUX_ATOMIC_UINT32_H_ +#define PLATFORM_IMPL_LINUX_ATOMIC_UINT32_H_ + +#include "internal/platform/implementation/atomic_reference.h" +#include +#include + +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 diff --git a/internal/platform/implementation/linux/avahi.cc b/internal/platform/implementation/linux/avahi.cc new file mode 100644 index 00000000..c762ccce --- /dev/null +++ b/internal/platform/implementation/linux/avahi.cc @@ -0,0 +1,103 @@ +#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; + + 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; + } + + 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; + 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; + } + + 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 diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h new file mode 100644 index 00000000..a0ed8cec --- /dev/null +++ b/internal/platform/implementation/linux/avahi.h @@ -0,0 +1,78 @@ +#ifndef PLATFORM_IMPL_LINUX_AVAHI_H_ +#define PLATFORM_IMPL_LINUX_AVAHI_H_ + +#include +#include +#include + +#include "internal/platform/implementation/linux/avahi_entrygroup_client_glue.h" +#include "internal/platform/implementation/linux/avahi_server_client_glue.h" +#include "internal/platform/implementation/linux/avahi_servicebrowser_client_glue.h" +#include "internal/platform/implementation/wifi_lan.h" + +namespace nearby { +namespace linux { +namespace avahi { +class Server + : public sdbus::ProxyInterfaces { +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 + : public sdbus::ProxyInterfaces { +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() { unregisterProxy(); } + +protected: + void onStateChanged(const int32_t &state, const std::string &error) override { + } +}; + +class ServiceBrowser : 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) + : ProxyInterfaces(system_bus, "org.freedesktop.Avahi", + service_browser_object_path), + discovery_cb_(std::move(callback)) { + registerProxy(); + } + ~ServiceBrowser() { 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: + api::WifiLanMedium::DiscoveredServiceCallback discovery_cb_; + std::shared_ptr server_; +}; +} // namespace avahi +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/avahi_entrygroup_client_glue.h b/internal/platform/implementation/linux/avahi_entrygroup_client_glue.h new file mode 100644 index 00000000..8070deae --- /dev/null +++ b/internal/platform/implementation/linux/avahi_entrygroup_client_glue.h @@ -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 +#include +#include + +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>& 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>& 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& rdata) + { + proxy_.callMethod("AddRecord").onInterface(INTERFACE_NAME).withArguments(interface, protocol, flags, name, clazz, type, ttl, rdata); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/avahi_server_client_glue.h b/internal/platform/implementation/linux/avahi_server_client_glue.h new file mode 100644 index 00000000..6810ac8a --- /dev/null +++ b/internal/platform/implementation/linux/avahi_server_client_glue.h @@ -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 +#include +#include + +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 ResolveHostName(const int32_t& interface, const int32_t& protocol, const std::string& name, const int32_t& aprotocol, const uint32_t& flags) + { + std::tuple result; + proxy_.callMethod("ResolveHostName").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, aprotocol, flags).storeResultsTo(result); + return result; + } + + std::tuple ResolveAddress(const int32_t& interface, const int32_t& protocol, const std::string& address, const uint32_t& flags) + { + std::tuple result; + proxy_.callMethod("ResolveAddress").onInterface(INTERFACE_NAME).withArguments(interface, protocol, address, flags).storeResultsTo(result); + return result; + } + + std::tuple>, 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>, 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 ResolveHostName(const int32_t& interface, const int32_t& protocol, const std::string& name, const int32_t& aprotocol, const uint32_t& flags) + { + std::tuple result; + proxy_.callMethod("ResolveHostName").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, aprotocol, flags).storeResultsTo(result); + return result; + } + + std::tuple ResolveAddress(const int32_t& interface, const int32_t& protocol, const std::string& address, const uint32_t& flags) + { + std::tuple result; + proxy_.callMethod("ResolveAddress").onInterface(INTERFACE_NAME).withArguments(interface, protocol, address, flags).storeResultsTo(result); + return result; + } + + std::tuple>, 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>, 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 diff --git a/internal/platform/implementation/linux/avahi_servicebrowser_client_glue.h b/internal/platform/implementation/linux/avahi_servicebrowser_client_glue.h new file mode 100644 index 00000000..09206c00 --- /dev/null +++ b/internal/platform/implementation/linux/avahi_servicebrowser_client_glue.h @@ -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 +#include +#include + +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 diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 2ad0acec..68877889 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -13,7 +13,7 @@ namespace nearby { namespace linux { -ExceptionOr BluetoothInputStream::Read(std::int64_t size) { +ExceptionOr InputStream::Read(std::int64_t size) { if (!fd_.has_value()) return Exception::kIo; @@ -30,33 +30,17 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { return ExceptionOr(ByteArray(data, size)); } -ExceptionOr BluetoothInputStream::Skip(std::size_t offset) { +Exception InputStream::Close() { if (!fd_.has_value()) - return Exception::kIo; + return Exception{Exception::kIo}; - auto off = lseek(fd_->get(), offset, SEEK_CUR); - if (off != offset) { - auto end = lseek(fd_->get(), 0, SEEK_END); - return off == end ? ExceptionOr((std::size_t)off) : Exception::kIo; - } - return ExceptionOr((std::size_t)(off)); + auto ret = close(fd_->get()) < 0 ? Exception{Exception::kIo} + : Exception{Exception::kSuccess}; + fd_.reset(); + return ret; } -ExceptionOr BluetoothInputStream::ReadExactly(std::size_t size) { - if (!fd_.has_value()) - return Exception::kIo; - - char *data = new char[size]; - ssize_t ret = read(fd_->get(), data, size); - if (ret < 0) { - delete[] data; - return Exception::kIo; - } - - return ExceptionOr(ByteArray(data, size)); -} - -Exception BluetoothOutputStream::Write(const ByteArray &data) { +Exception OutputStream::Write(const ByteArray &data) { if (!fd_.has_value()) return Exception{Exception::kIo}; @@ -71,18 +55,21 @@ Exception BluetoothOutputStream::Write(const ByteArray &data) { return Exception{Exception::kSuccess}; } -Exception BluetoothOutputStream::Flush() { - return Exception{Exception::kSuccess}; -} +Exception OutputStream::Flush() { return Exception{Exception::kSuccess}; } -Exception BluetoothOutputStream::Close() { - return close(fd_->get()) < 0 ? Exception{Exception::kIo} - : Exception{Exception::kSuccess}; +Exception OutputStream::Close() { + if (!fd_.has_value()) + return Exception{Exception::kIo}; + + auto ret = close(fd_->get()) < 0 ? Exception{Exception::kIo} + : Exception{Exception::kSuccess}; + fd_.reset(); + return ret; } Exception BluetoothSocket::Close() { - input_stream_.fd_.reset(); - output_stream_.fd_.reset(); + input_stream_.Close(); + output_stream_.Close(); return Exception{Exception::kSuccess}; } diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index a64ea74a..fefe55e7 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -7,57 +7,26 @@ #include #include -#include "internal/platform/byte_array.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/linux/stream.h" namespace nearby { namespace linux { - -class BluetoothInputStream : public InputStream { -public: - BluetoothInputStream(sdbus::UnixFd &fd) : fd_(fd){}; - - ExceptionOr Read(std::int64_t size) override; - ExceptionOr Skip(size_t offset) override; - ExceptionOr ReadExactly(std::size_t size); - - Exception Close() override; - -private: - friend class BluetoothSocket; - - std::optional fd_; -}; - -class BluetoothOutputStream : public OutputStream { -public: - BluetoothOutputStream(sdbus::UnixFd &fd) : fd_(fd){}; - - Exception Write(const ByteArray &data) override; - Exception Flush() override; - Exception Close() override; - -private: - friend class BluetoothSocket; - - std::optional fd_; -}; - class BluetoothSocket : public api::BluetoothSocket { public: BluetoothSocket(api::BluetoothDevice &device, sdbus::UnixFd fd) : device_(device), output_stream_(fd), input_stream_(fd) {} - InputStream &GetInputStream() override { return input_stream_; } - OutputStream &GetOutputStream() override { return output_stream_; } + nearby::InputStream &GetInputStream() override { return input_stream_; } + nearby::OutputStream &GetOutputStream() override { return output_stream_; } Exception Close() override; api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; private: api::BluetoothDevice &device_; - BluetoothOutputStream output_stream_; - BluetoothInputStream input_stream_; + OutputStream output_stream_; + InputStream input_stream_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/condition_variable.h b/internal/platform/implementation/linux/condition_variable.h new file mode 100644 index 00000000..b1b545b5 --- /dev/null +++ b/internal/platform/implementation/linux/condition_variable.h @@ -0,0 +1,36 @@ +#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(mutex)->GetRegularMutex()) {} + ~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 diff --git a/internal/platform/implementation/linux/credential_storage.h b/internal/platform/implementation/linux/credential_storage.h new file mode 100644 index 00000000..8730dd1b --- /dev/null +++ b/internal/platform/implementation/linux/credential_storage.h @@ -0,0 +1,50 @@ +#ifndef PLATFORM_IMPL_LINUX_CREDENTIAL_STORAGE_H_ +#define PLATFORM_IMPL_LINUX_CREDENTIAL_STORAGE_H_ +#include + +#include +#include +#include + +#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 &Local_credentials, + const std::vector &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 proxy; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc new file mode 100644 index 00000000..b329a8a9 --- /dev/null +++ b/internal/platform/implementation/linux/dbus.cc @@ -0,0 +1,35 @@ +#include +#include + +#include + +#include "internal/platform/implementation/linux/dbus.h" +#include "absl/base/call_once.h" + +namespace nearby { +namespace linux { +static std::unique_ptr global_system_bus_connection = + nullptr; +static std::unique_ptr global_default_bus_connection = + nullptr; +static absl::once_flag bus_connection_init_; + +static void initBusConnections() { + global_system_bus_connection = + sdbus::createSystemBusConnection("/com/github/google/nearby"); + global_default_bus_connection = + sdbus::createDefaultBusConnection("/com/github/google/nearby"); +} + +sdbus::IConnection &getSystemBusConnection() { + absl::call_once(bus_connection_init_, initBusConnections); + assert(global_system_bus_connection != nullptr); + return *global_system_bus_connection; +} +sdbus::IConnection &getDefaultBusConnection() { + absl::call_once(bus_connection_init_, initBusConnections); + assert(global_default_bus_connection != nullptr); + return *global_default_bus_connection; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h index 53e57212..547cd2b9 100644 --- a/internal/platform/implementation/linux/dbus.h +++ b/internal/platform/implementation/linux/dbus.h @@ -1,6 +1,8 @@ #ifndef PLATFORM_IMPL_LINUX_DBUS_H_ #define PLATFORM_IMPL_LINUX_DBUS_H_ + #include "internal/platform/logging.h" +#include #define DBUS_LOG_METHOD_CALL_ERROR(p, m, e) \ do { \ @@ -26,4 +28,10 @@ << " on object " << (p)->getObjectPath(); \ } while (false) +namespace nearby { +namespace linux { +extern sdbus::IConnection &getSystemBusConnection(); +extern sdbus::IConnection &getDefaultBusConnection(); +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index f492c56c..ef86ca67 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -91,10 +91,6 @@ std::optional DeviceInfo::GetProfileUserName() const { std::optional DeviceInfo::GetDownloadPath() const { char *dir = getenv("XDG_DOWNLOAD_DIR"); - if (dir == NULL) { - std::filesystem::path home_path(std::string(getenv("HOME"))); - return home_path / "Desktop"; - } return std::filesystem::path(std::string(dir)); } @@ -103,7 +99,7 @@ std::optional DeviceInfo::GetLocalAppDataPath() const { if (dir == NULL) { return std::filesystem::path("/tmp"); } - return std::filesystem::path(std::string(dir)) / "com.github.google.nearby"; + return std::filesystem::path(std::string(dir)) / "Google Nearby"; } std::optional DeviceInfo::GetTemporaryPath() const { diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc new file mode 100644 index 00000000..f2825d92 --- /dev/null +++ b/internal/platform/implementation/linux/log_message.cc @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include + +#define SD_JOURNAL_SUPPRESS_LOCATION true +#include + +#include "absl/base/call_once.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/log_message.h" + +namespace nearby { +static std::unique_ptr global_log_control_; +static absl::once_flag log_control_init_; + +static void init_log_control() { + global_log_control_ = + std::make_unique(linux::getDefaultBusConnection()); +} + +namespace api { +void LogMessage::SetMinLogSeverity(Severity severity) { + absl::call_once(log_control_init_, init_log_control, nullptr); + assert(global_log_control_ != nullptr); + global_log_control_->LogLevel(severity); +} + +bool LogMessage::ShouldCreateLogMessage(Severity severity) { + absl::call_once(log_control_init_, init_log_control, nullptr); + assert(global_log_control_ != nullptr); + return severity >= global_log_control_->GetLogLevel(); +} + +} // namespace api +namespace linux { + +static inline int ConvertSeverityToSyslog(google::LogSeverity severity) { + switch (severity) { + case google::GLOG_WARNING: + return LOG_WARNING; + case google::GLOG_ERROR: + return LOG_ERR; + case google::GLOG_FATAL: + return LOG_EMERG; + case google::GLOG_INFO: + default: + return LOG_INFO; + } +} + +void LogControl::send(google::LogSeverity severity, const char *full_filename, + const char *base_filename, int line, + const struct ::tm *tm_time, const char *message, + size_t message_len) { + switch (log_target_) { + case kJournal: + sd_journal_send("MESSAGE=%s", message, "PRIORITY=%d", + ConvertSeverityToSyslog(severity), "CODE_FILE=%s", + base_filename, "CODE_LINE=%d", line, NULL); + break; + case kSyslog: { + auto str = LogSink::ToString(severity, base_filename, line, tm_time, + message, message_len); + syslog(ConvertSeverityToSyslog(severity), "%s", str.c_str()); + } + case kConsole: + default: + std::cout << LogSink::ToString(severity, base_filename, line, tm_time, + message, message_len) + << "\n"; + break; + } +} + +static inline google::LogSeverity +ConvertSeverity(api::LogMessage::Severity severity) { + switch (severity) { + case api::LogMessage::Severity::kVerbose: + case api::LogMessage::Severity::kInfo: + return google::GLOG_INFO; + case api::LogMessage::Severity::kWarning: + return google::GLOG_WARNING; + case api::LogMessage::Severity::kError: + return google::GLOG_ERROR; + case api::LogMessage::Severity::kFatal: + return google::GLOG_FATAL; + } +} + +// TODO: Set a LogSink depending on the target set by LogControl +LogMessage::LogMessage(const char *file, int line, Severity severity) + : log_streamer_(file, line, ConvertSeverity(severity), + global_log_control_.get(), false) {} + +void LogMessage::Print(const char *format, ...) { + va_list ap; + va_start(ap, format); + char *buf = nullptr; + vasprintf(&buf, format, ap); + va_end(ap); + log_streamer_.stream() << std::string(buf); +} + +std::ostream &LogMessage::Stream() { return log_streamer_.stream(); } + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h new file mode 100644 index 00000000..56093a64 --- /dev/null +++ b/internal/platform/implementation/linux/log_message.h @@ -0,0 +1,118 @@ +#ifndef PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ +#define PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ + +#include "absl/synchronization/mutex.h" +#include "glog/logging.h" +#include "internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h" +#include "internal/platform/implementation/log_message.h" +#include +#include + +namespace nearby { +namespace linux { + +// See documentation in +// cpp/platform/api/log_message.h +class LogMessage : public api::LogMessage { +public: + LogMessage(const char *file, int line, Severity severity); + ~LogMessage() override; + + void Print(const char *format, ...) override; + + std::ostream &Stream() override; + +private: + google::LogMessage log_streamer_; + static api::LogMessage::Severity min_log_severity_; +}; + +class LogControl + : public sdbus::AdaptorInterfaces, + public google::LogSink { +public: + LogControl(sdbus::IConnection &system_bus) + : AdaptorInterfaces(system_bus, "/com/github/google/nearby"), + severity_(api::LogMessage::LogMessage::Severity::kVerbose) { + registerAdaptor(); + } + ~LogControl() { unregisterAdaptor(); } + + void LogLevel(const LogMessage::Severity &severity) { severity_ = severity; } + + LogMessage::Severity GetLogLevel() { return severity_; } + +protected: + std::string LogLevel() override { + switch (severity_) { + case api::LogMessage::Severity::kVerbose: + return "debug"; + break; + case api::LogMessage::Severity::kInfo: + return "info"; + break; + case api::LogMessage::Severity::kWarning: + return "warning"; + break; + case api::LogMessage::Severity::kError: + return "err"; + case api::LogMessage::Severity::kFatal: + return "emerg"; + } + } + + void LogLevel(const std::string &value) override { + if (value == "debug") + severity_ = api::LogMessage::Severity::kVerbose; + else if (value == "info") + severity_ = api::LogMessage::Severity::kInfo; + else if (value == "warning") + severity_ = api::LogMessage::Severity::kWarning; + else if (value == "err") + severity_ = api::LogMessage::Severity::kError; + else if (value == "crit" || value == "alert" || value == "emerg") + severity_ = api::LogMessage::Severity::kFatal; + } + + enum LogTarget { kConsole, kKernel, kJournal, kSyslog }; + + std::string LogTarget() override { + switch (log_target_) { + case kConsole: + return "console"; + case kKernel: + return "kmsg"; + case kJournal: + return "journal"; + case kSyslog: + return "syslog"; + } + } + + void LogTarget(const std::string &value) override { + if (value == "console") + log_target_ = kConsole; + else if (value == "kmsg") + log_target_ = kKernel; + else if (value == "journal") + log_target_ = kJournal; + else if (value == "syslog") + log_target_ = kSyslog; + } + + std::string SyslogIdentifier() override { + return "com.github.com.google.nearby"; + } + + void send(google::LogSeverity severity, const char *full_filename, + const char *base_filename, int line, const struct ::tm *tm_time, + const char *message, size_t message_len) override; + +private: + std::atomic severity_; + std::atomic log_target_; +}; +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ diff --git a/internal/platform/implementation/linux/mutex.h b/internal/platform/implementation/linux/mutex.h new file mode 100644 index 00000000..7007aee4 --- /dev/null +++ b/internal/platform/implementation/linux/mutex.h @@ -0,0 +1,56 @@ +#ifndef PLATFORM_IMPL_LINUX_MUTEX_H_ +#define PLATFORM_IMPL_LINUX_MUTEX_H_ + +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/mutex.h" + +namespace nearby { +namespace linux { +class ABSL_LOCKABLE Mutex : public api::Mutex { +public: + explicit Mutex(Mode mode) : mode_(mode) { + if (mode == Mode::kRecursive) + mutex_.emplace(); + else + mutex_.emplace(); + } + + ~Mutex() override = default; + Mutex(Mutex &&) = delete; + Mutex &operator=(Mutex &&) = delete; + Mutex(const Mutex &) = delete; + Mutex &operator=(const Mutex &) = delete; + + void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override { + if (auto mutex = std::get_if(&mutex_); mutex != nullptr) { + if (mode_ == Mode::kRegularNoCheck) { + mutex->ForgetDeadlockInfo(); + } + mutex->Lock(); + } else { + std::get_if(&mutex_)->lock(); + } + } + + void Unlock() ABSL_UNLOCK_FUNCTION() override { + if (auto mutex = std::get_if(&mutex_); mutex != nullptr) { + mutex->Unlock(); + } else { + std::get_if(&mutex_)->unlock(); + } + } + + absl::Mutex *GetRegularMutex() { + return std::get_if(&mutex_); + } + +private: + std::variant mutex_; + Mode mode_; +}; +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/org.freedesktop.Avahi.EntryGroup.xml b/internal/platform/implementation/linux/org.freedesktop.Avahi.EntryGroup.xml new file mode 100644 index 00000000..434cc0f8 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.Avahi.EntryGroup.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.Avahi.Server.xml b/internal/platform/implementation/linux/org.freedesktop.Avahi.Server.xml new file mode 100644 index 00000000..5485a972 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.Avahi.Server.xml @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceBrowser.xml b/internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceBrowser.xml new file mode 100644 index 00000000..4e2e240f --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceBrowser.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceResolver.xml b/internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceResolver.xml new file mode 100644 index 00000000..898287ce --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceResolver.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.LogControl1.xml b/internal/platform/implementation/linux/org.freedesktop.LogControl1.xml new file mode 100644 index 00000000..2c32116f --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.LogControl1.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h b/internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h new file mode 100644 index 00000000..f74e3d1a --- /dev/null +++ b/internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h @@ -0,0 +1,45 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__org_freedesktop_logcontrol_server_glue_h__adaptor__H__ +#define __sdbuscpp__org_freedesktop_logcontrol_server_glue_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { + +class LogControl1_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.LogControl1"; + +protected: + LogControl1_adaptor(sdbus::IObject& object) + : object_(object) + { + object_.registerProperty("LogLevel").onInterface(INTERFACE_NAME).withGetter([this](){ return this->LogLevel(); }).withSetter([this](const std::string& value){ this->LogLevel(value); }).withUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL).markAsPrivileged(); + object_.registerProperty("LogTarget").onInterface(INTERFACE_NAME).withGetter([this](){ return this->LogTarget(); }).withSetter([this](const std::string& value){ this->LogTarget(value); }).withUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL).markAsPrivileged(); + object_.registerProperty("SyslogIdentifier").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SyslogIdentifier(); }).withUpdateBehavior(sdbus::Flags::EMITS_NO_SIGNAL); + } + + ~LogControl1_adaptor() = default; + +private: + virtual std::string LogLevel() = 0; + virtual void LogLevel(const std::string& value) = 0; + virtual std::string LogTarget() = 0; + virtual void LogTarget(const std::string& value) = 0; + virtual std::string SyslogIdentifier() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 11b37bcf..2bfb771d 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -1,12 +1,74 @@ -#include "internal/platform/implementation/platform.h" - #include +#include #include +#include "internal/platform/implementation/linux/condition_variable.h" +#include "internal/platform/implementation/linux/mutex.h" +#include "internal/platform/implementation/platform.h" +#include "internal/platform/implementation/atomic_boolean.h" +#include "internal/platform/implementation/atomic_reference.h" +#include "internal/platform/implementation/count_down_latch.h" +#include "internal/platform/implementation/linux/atomic_boolean.h" +#include "internal/platform/implementation/linux/atomic_uint32.h" +#include "internal/platform/implementation/shared/count_down_latch.h" +#include "log_message.h" + namespace nearby { namespace api { -namespace { - std::string ImplementationPlatform::GetCustomSavePath() +std::string ImplementationPlatform::GetCustomSavePath(const std::string &parent_folder, const std::string & file_name) { + auto fs = std::filesystem::path(parent_folder); + return fs / file_name; } + +std::string ImplementationPlatform::GetDownloadPath(const std::string& parent_folder, const std::string &file_name) { + auto downloads = std::filesystem::path(getenv("XDG_DOWNLOAD_DIR")); + + return downloads / std::filesystem::path(parent_folder).filename() / std::filesystem::path(file_name).filename(); +} + +std::string ImplementationPlatform::GetDownloadPath(const std::string& file_name) { + auto downloads = std::filesystem::path(getenv("XDG_DOWNLOAD_DIR")); + return downloads / std::filesystem::path(file_name).filename(); +} + +std::string ImplementationPlatform::GetAppDataPath(const std::string &file_name) { + auto state = std::filesystem::path(getenv("XDG_STATE_HOME")); + return state / std::filesystem::path(file_name).filename(); +} + +OSName GetCurrentOS() { return OSName::kWindows; } + +std::unique_ptr CreateAtomicBoolean(bool initial_value) { + return std::make_unique(initial_value); +} + +std::unique_ptr CreateAtomicUint32(std::uint32_t value) { + return std::make_unique(value); +} + +std::unique_ptr ImplementationPlatform::CreateCountDownLatch(std::int32_t count) { + return std::make_unique(count); +} + +#pragma push_macro("CreateMutex") +#undef CreateMutex +std::unique_ptr ImplementationPlatform::CreateMutex(Mutex::Mode mode) { + return std::make_unique(mode); +} +#pragma pop_macro("CreateMutex") + +std::unique_ptr +ImplementationPlatform::CreateConditionVariable(api::Mutex *mutex) { + return std::make_unique(mutex); +} + +std::unique_ptr ImplementationPlatform::CreateLogMessage( + const char *file, int line, LogMessage::Severity severity + ) { + return std::make_unique(file, line, severity); +} + + + } // namespace api } // namespace nearby diff --git a/internal/platform/implementation/linux/stream.h b/internal/platform/implementation/linux/stream.h new file mode 100644 index 00000000..e761442f --- /dev/null +++ b/internal/platform/implementation/linux/stream.h @@ -0,0 +1,40 @@ +#ifndef PLATFORM_IMPL_LINUX_STREAM_H_ +#define PLATFORM_IMPL_LINUX_STREAM_H_ + +#include + +#include + +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" + +namespace nearby { +namespace linux { +class InputStream : public nearby::InputStream { +public: + InputStream(sdbus::UnixFd &fd) : fd_(fd){}; + + ExceptionOr Read(std::int64_t size) override; + + Exception Close() override; + +private: + std::optional fd_; +}; + +class OutputStream : public nearby::OutputStream { +public: + OutputStream(sdbus::UnixFd &fd) : fd_(fd){}; + + Exception Write(const ByteArray &data) override; + Exception Flush() override; + Exception Close() override; + +private: + std::optional fd_; +}; + +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc new file mode 100644 index 00000000..2d5d3f4b --- /dev/null +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -0,0 +1,240 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "absl/strings/substitute.h" +#include "internal/platform/implementation/linux/avahi.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/wifi_lan.h" +#include "internal/platform/implementation/linux/wifi_lan_server_socket.h" +#include "internal/platform/implementation/linux/wifi_lan_socket.h" +#include "internal/platform/implementation/wifi_lan.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus, + NetworkManager &network_manager) + : system_bus_(system_bus), network_manager_(network_manager), + avahi_(std::make_shared(system_bus)), + entry_group_(nullptr) {} + +WifiLanMedium::~WifiLanMedium() { + if (entry_group_ != nullptr) { + entry_group_->Free(); + } +} + +bool WifiLanMedium::IsNetworkConnected() const { + auto state = network_manager_.getState(); + return state >= 50; // NM_STATE_CONNECTED_LOCAL +} + +bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { + if (entry_group_ == nullptr) { + try { + auto object_path = avahi_->EntryGroupNew(); + entry_group_ = + std::make_unique(system_bus_, object_path); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(avahi_, "EntryGroupNew", e); + NEARBY_LOGS(ERROR) << __func__ << ": Could not create a new entry group."; + return false; + } + } + + if (advertising_) { + NEARBY_LOGS(ERROR) << __func__ + << ": Cannot advertise while we are already advertising"; + return false; + } + + auto txt_records_map = nsd_service_info.GetTxtRecords(); + std::vector> txt_records(txt_records_map.size()); + std::size_t i = 0; + + for (auto [key, value] : nsd_service_info.GetTxtRecords()) { + std::string entry = absl::Substitute("$0=$1", key, value); + txt_records[i++] = std::vector(entry.begin(), entry.end()); + } + + try { + entry_group_->AddService(-1, // AVAHI_IF_UNSPEC + -1, // AVAHI_PROTO_UNSPED + 0, nsd_service_info.GetServiceName(), + nsd_service_info.GetServiceType(), std::string(), + nsd_service_info.GetIPAddress(), + nsd_service_info.GetPort(), txt_records); + entry_group_->Commit(); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while adding service"; + } + + advertising_ = true; + return true; +} + +bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) { + if (!advertising_) { + NEARBY_LOGS(ERROR) << __func__ << ": Advertising is already stopped."; + return false; + } + if (entry_group_ == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": No entry group registered."; + return false; + } + + try { + if (entry_group_->IsEmpty()) { + NEARBY_LOGS(ERROR) + << __func__ << ": Cannot stop advertising on an empty entry group."; + return false; + } + entry_group_->Reset(); + entry_group_->Commit(); + } catch (const sdbus::Error &e) { + NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() + << "' while removing service"; + } + + advertising_ = false; + return true; +} + +bool WifiLanMedium::StartDiscovery( + const std::string &service_type, + api::WifiLanMedium::DiscoveredServiceCallback callback) { + if (service_browsers_.count(service_type) != 0) { + auto &object = service_browsers_[service_type]; + NEARBY_LOGS(ERROR) << __func__ << ": A service browser for service type " + << service_type << " already exists at " + << object->getObjectPath(); + return false; + } + + try { + sdbus::ObjectPath browser_object_path = + avahi_->ServiceBrowserPrepare(-1, // AVAHI_IF_UNSPEC + -1, // AVAHI_PROTO_UNSPED + service_type, std::string(), 0); + NEARBY_LOGS(VERBOSE) + << __func__ + << ": Created a new org.freedesktop.Avahi.ServiceBrowser object at " + << browser_object_path; + service_browsers_.emplace(service_type, system_bus_, browser_object_path, + std::move(callback)); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(avahi_, "ServiceBrowserPrepare", e); + } + + auto &browser = service_browsers_[service_type]; + try { + NEARBY_LOGS(VERBOSE) << __func__ << ": Starting service discovery for " + << browser->getObjectPath(); + browser->Start(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(browser, "Start", e); + } + + return true; +} + +bool WifiLanMedium::StopDiscovery(const std::string &service_type) { + if (service_browsers_.count(service_type) == 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Service type " << service_type + << " has not been registered for discovery"; + return false; + } + + auto &browser = service_browsers_[service_type]; + try { + browser->Free(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(browser, "Free", e); + } + + service_browsers_.erase(service_type); + + return true; +} + +std::unique_ptr +WifiLanMedium::ConnectToService(const std::string &ip_address, int port, + CancellationFlag *cancellation_flag) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return nullptr; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" + << port; + struct sockaddr_in addr; + addr.sin_addr.s_addr = inet_addr(ip_address.c_str()); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + auto ret = + connect(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " + << std::strerror(errno); + return nullptr; + } + + sdbus::UnixFd fd(sock); + return std::make_unique(std::move(fd)); +} + +std::unique_ptr ListenForService(int port = 0) { + auto sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return nullptr; + } + + NEARBY_LOGS(VERBOSE) << __func__ << "Listening for services "; + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + auto ret = + bind(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error binding to socket: " << std::strerror(errno); + return nullptr; + } + + ret = listen(sock, 0); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " + << std::strerror(errno); + return nullptr; + } + + return std::make_unique(sdbus::UnixFd(sock)); +} + +absl::optional> + GetDynamicPortRange() { + return absl::nullopt; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h new file mode 100644 index 00000000..8059512e --- /dev/null +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -0,0 +1,58 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_LAN_H_ +#define PLATFORM_IMPL_LINUX_WIFI_LAN_H_ +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "internal/platform/implementation/linux/avahi.h" +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi_lan.h" +#include "internal/platform/nsd_service_info.h" + +namespace nearby { +namespace linux { +class WifiLanMedium : public api::WifiLanMedium { +public: + WifiLanMedium(sdbus::IConnection &system_bus, + NetworkManager &network_manager); + ~WifiLanMedium() override; + + bool IsNetworkConnected() const override; + bool StartAdvertising(const NsdServiceInfo &nsd_service_info) override; + bool StopAdvertising(const NsdServiceInfo &nsd_service_info) override; + bool StartDiscovery(const std::string &service_type, + DiscoveredServiceCallback callback) override; + bool StopDiscovery(const std::string &service_type) override; + std::unique_ptr + ConnectToService(const NsdServiceInfo &remote_service_info, + CancellationFlag *cancellation_flag) override { + return ConnectToService(remote_service_info.GetIPAddress(), + remote_service_info.GetPort(), cancellation_flag); + }; + std::unique_ptr + ConnectToService(const std::string &ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr + ListenForService(int port = 0) override; + absl::optional> + GetDynamicPortRange() override; + +private: + DiscoveredServiceCallback discovery_cb_; + + sdbus::IConnection &system_bus_; + + NetworkManager &network_manager_; + + std::shared_ptr avahi_; + std::unique_ptr entry_group_; + + absl::flat_hash_map> + service_browsers_; + + bool advertising_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc new file mode 100644 index 00000000..71927deb --- /dev/null +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "internal/platform/implementation/linux/wifi_lan_server_socket.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/wifi_lan_socket.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +std::string WifiLanServerSocket::GetIPAddress() const { + struct ifaddrs *addrs = nullptr; + getifaddrs(&addrs); + + for (auto ifaddr = addrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) { + if (ifaddr->ifa_addr == nullptr) { + continue; + } + if (ifaddr->ifa_addr->sa_family == AF_INET) { + auto addr = + &(reinterpret_cast(ifaddr->ifa_addr))->sin_addr; + char buf[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN); + + return std::string(buf); + } + } + + return std::string(); +} + +int WifiLanServerSocket::GetPort() const { + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + auto ret = + getsockname(fd_.get(), reinterpret_cast(&sin), &len); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error getting information for socket " + << fd_.get() << ": " << std::strerror(errno); + return 0; + } + + return ntohs(sin.sin_port); +} + +std::unique_ptr WifiLanServerSocket::Accept() { + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + + auto conn = + accept(fd_.get(), reinterpret_cast(&addr), &len); + if (conn < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error accepting incoming connections on socket " + << fd_.get() << ": " << std::strerror(errno); + return nullptr; + } + + return std::make_unique(sdbus::UnixFd(conn)); +} + +Exception WifiLanServerSocket::Close() { + int fd = fd_.release(); + auto ret = close(fd); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " + << std::strerror(errno); + return {Exception::kFailed}; + } + + return {Exception::kSuccess}; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.h b/internal/platform/implementation/linux/wifi_lan_server_socket.h new file mode 100644 index 00000000..5bed26ce --- /dev/null +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.h @@ -0,0 +1,33 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_LAN_SERVER_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_LAN_SERVER_SOCKET_H_ + +#include + +#include + +#include "internal/platform/exception.h" +#include "internal/platform/implementation/wifi_lan.h" + +namespace nearby { +namespace linux { +class WifiLanServerSocket : public api::WifiLanServerSocket { +public: + WifiLanServerSocket(int socket) { + fd_ = sdbus::UnixFd(socket); + } + + ~WifiLanServerSocket() override = default; + + std::string GetIPAddress() const override; + + int GetPort() const override; + + std::unique_ptr Accept() override; + + Exception Close() override; + + sdbus::UnixFd fd_; +}; +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/wifi_lan_socket.h b/internal/platform/implementation/linux/wifi_lan_socket.h new file mode 100644 index 00000000..198c97da --- /dev/null +++ b/internal/platform/implementation/linux/wifi_lan_socket.h @@ -0,0 +1,42 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_ + +#include + +#include + +#include "internal/platform/implementation/linux/stream.h" +#include "internal/platform/implementation/wifi_lan.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" + +namespace nearby { +namespace linux { +class WifiLanSocket : public api::WifiLanSocket { +public: + WifiLanSocket(sdbus::UnixFd fd) + : fd_(fd), output_stream_(fd), input_stream_(fd) {} + ~WifiLanSocket() = default; + + 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}; + }; + +private: + sdbus::UnixFd fd_; + OutputStream output_stream_; + InputStream input_stream_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 9d432012..97c1555e 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -1,6 +1,7 @@ #ifndef PLATFORM_IMPL_LINUX_WIFI_MEDIUM_H_ #define PLATFORM_IMPL_LINUX_WIFI_MEDIUM_H_ +#include #include #include #include @@ -29,11 +30,16 @@ public: } ~NetworkManager() { unregisterProxy(); } + std::uint32_t getState() const { return state_; } + protected: void onCheckPermissions() override {} - void onStateChanged(const uint32_t &state) override {} + void onStateChanged(const uint32_t &state) override { state_ = state; } void onDeviceAdded(const sdbus::ObjectPath &device_path) override {} void onDeviceRemoved(const sdbus::ObjectPath &device_path) override {} + +private: + std::atomic_uint32_t state_; }; class NetworkManagerIP4Config diff --git a/internal/platform/implementation/linux/wifi_socket.h b/internal/platform/implementation/linux/wifi_socket.h new file mode 100644 index 00000000..0d70b4c7 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_socket.h @@ -0,0 +1,16 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_ + +namespace nearby { + namespace api { + class WifiLanSocket { + public: + ~WifiLanSocket() = default; + + private: + int fd; + }; + } +} + +#endif From f395618633a15cd62c7acc9ac17ca0dad4ce4bf9 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 23 Aug 2023 00:48:22 +0530 Subject: [PATCH 029/201] Add additional WiFi code. --- ...orkmanager_connection_active_client_glue.h | 126 +++++++++ ...sktop.NetworkManager.Connection.Active.xml | 185 ++++++++++++ .../implementation/linux/wifi_hotspot.cc | 191 +++++++++++++ .../implementation/linux/wifi_hotspot.h | 50 ++++ .../platform/implementation/linux/wifi_lan.cc | 22 +- .../platform/implementation/linux/wifi_lan.h | 5 +- .../linux/wifi_lan_server_socket.cc | 44 ++- .../linux/wifi_lan_server_socket.h | 16 +- .../implementation/linux/wifi_medium.cc | 266 ++++++++++++++++-- .../implementation/linux/wifi_medium.h | 150 +++++++++- 10 files changed, 982 insertions(+), 73 deletions(-) create mode 100644 internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h create mode 100644 internal/platform/implementation/linux/org.freedesktop.NetworkManager.Connection.Active.xml create mode 100644 internal/platform/implementation/linux/wifi_hotspot.cc create mode 100644 internal/platform/implementation/linux/wifi_hotspot.h diff --git a/internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h b/internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h new file mode 100644 index 00000000..8b077ad6 --- /dev/null +++ b/internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h @@ -0,0 +1,126 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__networkmanager_connection_active_client_glue_h__proxy__H__ +#define __sdbuscpp__networkmanager_connection_active_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Connection { + +class Active_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Connection.Active"; + +protected: + Active_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const uint32_t& state, const uint32_t& reason){ this->onStateChanged(state, reason); }); + } + + ~Active_proxy() = default; + + virtual void onStateChanged(const uint32_t& state, const uint32_t& reason) = 0; + +public: + sdbus::ObjectPath Connection() + { + return proxy_.getProperty("Connection").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath SpecificObject() + { + return proxy_.getProperty("SpecificObject").onInterface(INTERFACE_NAME); + } + + std::string Id() + { + return proxy_.getProperty("Id").onInterface(INTERFACE_NAME); + } + + std::string Uuid() + { + return proxy_.getProperty("Uuid").onInterface(INTERFACE_NAME); + } + + std::string Type() + { + return proxy_.getProperty("Type").onInterface(INTERFACE_NAME); + } + + std::vector Devices() + { + return proxy_.getProperty("Devices").onInterface(INTERFACE_NAME); + } + + uint32_t State() + { + return proxy_.getProperty("State").onInterface(INTERFACE_NAME); + } + + uint32_t StateFlags() + { + return proxy_.getProperty("StateFlags").onInterface(INTERFACE_NAME); + } + + bool Default() + { + return proxy_.getProperty("Default").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Ip4Config() + { + return proxy_.getProperty("Ip4Config").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Dhcp4Config() + { + return proxy_.getProperty("Dhcp4Config").onInterface(INTERFACE_NAME); + } + + bool Default6() + { + return proxy_.getProperty("Default6").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Ip6Config() + { + return proxy_.getProperty("Ip6Config").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Dhcp6Config() + { + return proxy_.getProperty("Dhcp6Config").onInterface(INTERFACE_NAME); + } + + bool Vpn() + { + return proxy_.getProperty("Vpn").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Controller() + { + return proxy_.getProperty("Controller").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Master() + { + return proxy_.getProperty("Master").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Connection.Active.xml b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Connection.Active.xml new file mode 100644 index 00000000..faab73a0 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Connection.Active.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc new file mode 100644 index 00000000..61735b0f --- /dev/null +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -0,0 +1,191 @@ +#include +#include + +#include +#include + +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h" +#include "internal/platform/implementation/linux/wifi_hotspot.h" +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +bool NetworkManagerWifiHotspotMedium::ConnectWifiHotspot( + HotspotCredentials *hotspot_credentials) { + if (hotspot_credentials == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": hotspot_credentials cannot be null"; + return false; + } + + auto ssid = hotspot_credentials->GetSSID(); + auto password = hotspot_credentials->GetPassword(); + + return wireless_device_->ConnectToNetwork(ssid, password, + api::WifiAuthType::kWpaPsk) == + api::WifiConnectionStatus::kConnected; +} + +bool NetworkManagerWifiHotspotMedium::DisconnectWifiHotspot() { + if (!WifiHotspotActive()) { + NEARBY_LOGS(ERROR) << __func__ << ": WiFi hotspot is not active"; + return false; + } + + sdbus::ObjectPath active_ap_path; + + try { + active_ap_path = wireless_device_->ActiveAccessPoint(); + if (active_ap_path.empty()) { + NEARBY_LOGS(ERROR) << __func__ + << ": Not connected to any access points on " + << wireless_device_->getObjectPath(); + return false; + } + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "ActiveAccessPoint", e); + } + + auto object_manager = NetworkManagerObjectManager(system_bus_); + + auto objects = object_manager.GetManagedObjects(); + + for (auto &[path, interfaces] : objects) { + if (path.find("/org/freedesktop/NetworkManager/ActiveConnection/") == 0) { + if (interfaces.count(org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME) == 1) { + sdbus::ObjectPath specific_object = + interfaces[org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME]["SpecificObject"]; + if (specific_object == active_ap_path) { + NEARBY_LOGS(INFO) << __func__ << ": Deactivating active connection " + << active_ap_path; + + try { + network_manager_->DeactivateConnection(path); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactiveConnection", + e); + return false; + } + return true; + } + } + } + } + + NEARBY_LOGS(ERROR) + << __func__ + << ": Could not find an active connection with the access point " + << active_ap_path; + return false; +} + +bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( + HotspotCredentials *hotspot_credentials) { + if (WifiHotspotActive()) { + NEARBY_LOGS(ERROR) << __func__ << ": " << wireless_device_->getObjectPath() + << ": cannot start WiFi hotspot, a hotspot is already " + "active on this device"; + return false; + } + + sd_id128_t id; + if (auto ret = sd_id128_randomize(&id); ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": error generating a 128-bit ID: " + << std::strerror(ret); + return false; + } + std::string ssid = absl::StrCat("DIRECT-", SD_ID128_TO_STRING(id)); + ssid.resize(32); + hotspot_credentials->SetSSID(ssid); + + if (auto ret = sd_id128_randomize(&id); ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": error generating a 128-bit ID: " + << std::strerror(ret); + return false; + } + std::string password = std::string(SD_ID128_TO_STRING(id), 15); + hotspot_credentials->SetPassword(password); + + if (auto ret = sd_id128_randomize(&id); ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": error generating a 128-bit ID: " + << std::strerror(ret); + return false; + } + + std::vector ssid_bytes(ssid.begin(), ssid.end()); + std::map> + connection_settings{ + { + "connection", + std::map{ + {"uuid", SD_ID128_TO_UUID_STRING(id)}, + {"id", "Google Nearby Hotspot"}, + {"type", "802-11-wireless"}, + {"zone", "Public"}}, + }, + {"802-11-wireless", + std::map{ + {"assigned-mac-address", "random"}, + {"mode", "ap"}, + {"ssid", ssid_bytes}, + {"security", "802-11-wireless-security"}}}, + {"802-11-wireless-security", + std::map{ + {"group", std::vector{"ccmp"}}, + {"key-mgmt", "wpa-psk"}, + { + "pairwise", + std::vector{"ccmp"}, + }, + {"proto", std::vector{"rsn"}}, + {"psk", password}}}, + {"ipv4", std::map{"method", "shared"}}, + {"ipv6", std::map{ + {"addr-gen-mode", static_cast(1)}, + {"method", "shared"}, + }}}; + std::unique_ptr active_conn; + try { + auto [path, active_path, result] = network_manager_->AddAndActivateConnection2( + connection_settings, wireless_device_->getObjectPath(), "/", + {{"persist", "volatile"}, {"bind-activation", "dbus-client"}}); + active_conn = std::make_unique(system_bus_, + active_path); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "AddAndActivateConnection2", + e); + return false; + } + + auto [reason, timeout] = active_conn->WaitForConnection(); + if (timeout) { + NEARBY_LOGS(ERROR) << __func__ << ": " + << ": timed out while waiting for connection " + << active_conn->getObjectPath() + << " to be activated, last NMActiveConnectionStateReason: " + << reason.value(); + DisconnectWifiHotspot(); + return false; + } + + NEARBY_LOGS(INFO) << __func__ << ": Started a WiFi hotspot on device " + << wireless_device_->getObjectPath() << " at " + << active_conn->getObjectPath(); + return true; +} + +bool NetworkManagerWifiHotspotMedium::WifiHotspotActive() { + try { + auto mode = wireless_device_->Mode(); + return mode == 3; // NM_802_11_MODE_AP + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e); + return false; + } +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot.h b/internal/platform/implementation/linux/wifi_hotspot.h new file mode 100644 index 00000000..9f4f0f55 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_hotspot.h @@ -0,0 +1,50 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_HOTSPOT_H_ +#define PLATFORM_IMPL_LINUX_WIFI_HOTSPOT_H_ + +#include +#include + +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi_hotspot.h" + +namespace nearby { + namespace linux { + class NetworkManagerWifiHotspotMedium : api::WifiHotspotMedium { + public: + NetworkManagerWifiHotspotMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + const sdbus::ObjectPath &wireless_device_object_path) + : system_bus_(system_bus), + wireless_device_(std::make_unique( + network_manager, system_bus, wireless_device_object_path)), + network_manager_(network_manager) {} + ~NetworkManagerWifiHotspotMedium() {} + + bool IsInterfaceValid() const override { return true; } + std::unique_ptr + ConnectToService(absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr + ListenForService(int port) override; + + bool StartWifiHotspot(HotspotCredentials *hotspot_credentials) override; + bool StopWifiHotspot() override; + + bool ConnectWifiHotspot(HotspotCredentials *hotspot_credentials) override; + bool DisconnectWifiHotspot() override; + + absl::optional> + GetDynamicPortRange() override {return absl::nullopt;} + + private: + bool WifiHotspotActive(); + + sdbus::IConnection &system_bus_; + std::unique_ptr wireless_device_; + std::shared_ptr network_manager_; + }; + } +} + +#endif diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 2d5d3f4b..4e9df5ec 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -16,14 +16,15 @@ #include "internal/platform/implementation/linux/wifi_lan.h" #include "internal/platform/implementation/linux/wifi_lan_server_socket.h" #include "internal/platform/implementation/linux/wifi_lan_socket.h" +#include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { -WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus, - NetworkManager &network_manager) - : system_bus_(system_bus), network_manager_(network_manager), +WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus) + : system_bus_(system_bus), + network_manager_(std::make_shared(system_bus)), avahi_(std::make_shared(system_bus)), entry_group_(nullptr) {} @@ -34,7 +35,7 @@ WifiLanMedium::~WifiLanMedium() { } bool WifiLanMedium::IsNetworkConnected() const { - auto state = network_manager_.getState(); + auto state = network_manager_->getState(); return state >= 50; // NM_STATE_CONNECTED_LOCAL } @@ -171,7 +172,7 @@ bool WifiLanMedium::StopDiscovery(const std::string &service_type) { std::unique_ptr WifiLanMedium::ConnectToService(const std::string &ip_address, int port, - CancellationFlag *cancellation_flag) { + CancellationFlag *cancellation_flag) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -180,7 +181,7 @@ WifiLanMedium::ConnectToService(const std::string &ip_address, int port, } NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" - << port; + << port; struct sockaddr_in addr; addr.sin_addr.s_addr = inet_addr(ip_address.c_str()); addr.sin_family = AF_INET; @@ -198,7 +199,7 @@ WifiLanMedium::ConnectToService(const std::string &ip_address, int port, return std::make_unique(std::move(fd)); } -std::unique_ptr ListenForService(int port = 0) { +std::unique_ptr WifiLanMedium::ListenForService(int port) { auto sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -206,7 +207,7 @@ std::unique_ptr ListenForService(int port = 0) { return nullptr; } - NEARBY_LOGS(VERBOSE) << __func__ << "Listening for services "; + NEARBY_LOGS(VERBOSE) << __func__ << "Listening for services"; struct sockaddr_in addr; addr.sin_family = AF_INET; @@ -228,11 +229,10 @@ std::unique_ptr ListenForService(int port = 0) { return nullptr; } - return std::make_unique(sdbus::UnixFd(sock)); + return std::make_unique(sock, network_manager_); } -absl::optional> - GetDynamicPortRange() { +absl::optional> GetDynamicPortRange() { return absl::nullopt; } diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 8059512e..24010163 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -13,8 +13,7 @@ namespace nearby { namespace linux { class WifiLanMedium : public api::WifiLanMedium { public: - WifiLanMedium(sdbus::IConnection &system_bus, - NetworkManager &network_manager); + WifiLanMedium(sdbus::IConnection &system_bus); ~WifiLanMedium() override; bool IsNetworkConnected() const override; @@ -42,7 +41,7 @@ private: sdbus::IConnection &system_bus_; - NetworkManager &network_manager_; + std::shared_ptr network_manager_; std::shared_ptr avahi_; std::unique_ptr entry_group_; diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index 71927deb..20313149 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,35 +6,54 @@ #include #include #include -#include #include -#include "internal/platform/implementation/linux/wifi_lan_server_socket.h" #include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/wifi_lan_server_socket.h" #include "internal/platform/implementation/linux/wifi_lan_socket.h" +#include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { std::string WifiLanServerSocket::GetIPAddress() const { - struct ifaddrs *addrs = nullptr; - getifaddrs(&addrs); + std::vector connection_paths; + try { + connection_paths = network_manager_->ActiveConnections(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(network_manager_, "ActiveConnections", e); + return std::string(); + } - for (auto ifaddr = addrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next) { - if (ifaddr->ifa_addr == nullptr) { + for (auto &path : connection_paths) { + auto active_connection = + std::make_unique(system_bus_, path); + std::string conn_type; + try { + conn_type = active_connection->Type(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(active_connection, "Type", e); continue; } - if (ifaddr->ifa_addr->sa_family == AF_INET) { - auto addr = - &(reinterpret_cast(ifaddr->ifa_addr))->sin_addr; - char buf[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN); + if (conn_type == "802-11-wireless" || conn_type == "802-3-ethernet") { + auto ip4config_path = active_connection->Ip4Config(); + NetworkManagerIP4Config ip4config(system_bus_, ip4config_path); + std::vector> address_data; - return std::string(buf); + try { + address_data = ip4config.AddressData(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "IP4Config", e); + } + + return address_data[0]["address"]; } } + NEARBY_LOGS(ERROR) + << __func__ << ": Could not find any active IP addresses for this device"; return std::string(); } diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.h b/internal/platform/implementation/linux/wifi_lan_server_socket.h index 5bed26ce..3e139721 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.h @@ -3,30 +3,34 @@ #include +#include #include #include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_lan.h" namespace nearby { namespace linux { class WifiLanServerSocket : public api::WifiLanServerSocket { public: - WifiLanServerSocket(int socket) { - fd_ = sdbus::UnixFd(socket); - } - + WifiLanServerSocket(int socket, + std::shared_ptr network_manager, + sdbus::IConnection &system_bus) + : fd_(sdbus::UnixFd(socket)), network_manager_(network_manager), + system_bus_(system_bus) {} ~WifiLanServerSocket() override = default; std::string GetIPAddress() const override; - int GetPort() const override; std::unique_ptr Accept() override; - Exception Close() override; +private: sdbus::UnixFd fd_; + std::shared_ptr network_manager_; + sdbus::IConnection &system_bus_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 8925356b..4aa0d5a8 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -7,9 +7,11 @@ #include #include #include +#include #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h" #include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi.h" @@ -17,21 +19,60 @@ namespace nearby { namespace linux { +std::ostream &operator<<(std::ostream &s, + const ActiveConnectionStateReason &reason) { + switch (reason) { + case kStateReasonUnknown: + return s << "The reason for the active connection state change is unknown."; + case kStateReasonNone: + return s << "No reason was given for the active connection state change."; + case kStateReasonUserDisconnected: + return s << "The active connection changed state because the user " + "disconnected it."; + case kStateReasonDeviceDisconnected: + return s << "The active connection changed state because the device it was " + "using was disconnected."; + case kStateReasonServiceStopped: + return s << "The service providing the VPN connection was stopped."; + case kStateReasonIPConfigInvalid: + return s << "The IP config of the active connection was invalid."; + case kStateReasonConnectTimeout: + return s << "The connection attempt to the VPN service timed out."; + case kStateReasonServiceStartTimeout: + return s << "A timeout occurred while starting the service providing the " + "VPN connection."; + case kStateReasonServiceStartFailed: + return s << "Starting the service providing the VPN connection failed."; + case kStateReasonNoSecrets: + return s << "Necessary secrets for the connection were not provided."; + case kStateReasonLoginFailed: + return s << "Authentication to the server failed."; + case kStateReasonConnectionRemoved: + return s << "The connection was deleted from settings."; + case kStateReasonDependencyFailed: + return s << "Master connection of this connection failed to activate."; + case kStateReasonDeviceRealizeFailed: + return s << "Could not create the software device link."; + case kStateReasonDeviceRemoved: + return s << "The device this connection depended on disappeared."; + } +} + std::unique_ptr NetworkManagerObjectManager::GetIp4Config( - const sdbus::ObjectPath &access_point) { + const sdbus::ObjectPath &active_connection) { auto objects = GetManagedObjects(); for (auto &[object_path, interfaces] : objects) { if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/", 0) == 0) { - if (interfaces.count( - "org.freedesktop.NetworkManager.Connection.Active") == 1) { - auto props = - interfaces["org.freedesktop.NetworkManager.Connection.Active"]; + if (interfaces.count(org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME) == 1) { + auto props = interfaces[org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME]; sdbus::ObjectPath specific_object = props["SpecificObject"]; sdbus::ObjectPath ip4config = props["Ip4Config"]; - if (specific_object == access_point) + if (specific_object == active_connection) return std::make_unique( getProxy().getConnection(), ip4config); } @@ -56,25 +97,29 @@ api::WifiCapability &NetworkManagerWifiMedium::GetCapability() { } api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { - { - absl::ReaderMutexLock l(&active_access_point_lock_); - if (!active_access_point_.has_value()) { + std::unique_ptr active_access_point; + + try { + auto ap_path = ActiveAccessPoint(); + if (ap_path.empty()) { information_ = api::WifiInformation{false}; return information_; } + active_access_point = std::make_unique( + getProxy().getConnection(), ap_path); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "ActiveAccessPoint", e); } - try { - absl::MutexLock l(&active_access_point_lock_); - auto ssid_vec = active_access_point_->Ssid(); + try { + auto ssid_vec = active_access_point->Ssid(); std::string ssid{ssid_vec.begin(), ssid_vec.end()}; information_ = - api::WifiInformation{true, ssid, active_access_point_->HwAddress(), - (int32_t)(active_access_point_->Frequency())}; + api::WifiInformation{true, ssid, active_access_point->HwAddress(), + (int32_t)(active_access_point->Frequency())}; NetworkManagerObjectManager manager(getProxy().getConnection()); - auto ip4config = - manager.GetIp4Config(active_access_point_->getObjectPath()); + auto ip4config = manager.GetIp4Config(active_access_point->getObjectPath()); if (ip4config != nullptr) { auto address_data = ip4config->AddressData(); @@ -90,17 +135,16 @@ api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { information_.ip_address_4_bytes = std::string(addr_bytes, 4); } } else { - NEARBY_LOGS(ERROR) << __func__ + NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() << ": Could not find the Ip4Config object for " - << active_access_point_->getObjectPath(); + << active_access_point->getObjectPath(); } } catch (const sdbus::Error &e) { - absl::ReaderMutexLock l(&active_access_point_lock_); NEARBY_LOGS(ERROR) - << __func__ << ": Got error '" << e.getName() << "' with message '" - << e.getMessage() + << __func__ << ": " << getObjectPath() << ": Got error '" << e.getName() + << "' with message '" << e.getMessage() << "' while populating network information for access point " - << active_access_point_->getObjectPath(); + << active_access_point->getObjectPath(); } return information_; @@ -115,8 +159,12 @@ void NetworkManagerWifiMedium::onPropertiesChanged( return; } - for (auto &[property, _val] : changedProperties) { + for (auto &[property, val] : changedProperties) { if (property == "LastScan") { + { + absl::MutexLock l(&last_scan_lock_); + last_scan_ = val; + } absl::ReaderMutexLock l(&scan_result_callback_lock_); if (scan_result_callback_.has_value()) { // scan_result_callback_->get().OnScanResults() @@ -140,23 +188,181 @@ bool NetworkManagerWifiMedium::Scan( return false; } +std::shared_ptr +NetworkManagerWifiMedium::SearchBySSIDNoScan( + std::vector &ssid_bytes) { + absl::ReaderMutexLock l(&known_access_points_lock_); + for (auto &[object_path, ap] : known_access_points_) { + if (ap->Ssid() == ssid_bytes) { + return ap; + } + } + + return nullptr; +} + +std::shared_ptr +NetworkManagerWifiMedium::SearchBySSID(absl::string_view ssid, + absl::Duration scan_timeout) { + std::vector ssid_bytes(ssid.begin(), ssid.end()); + // First, try to see if we already know an AP with this SSID. + auto ap = SearchBySSIDNoScan(ssid_bytes); + if (ap != nullptr) { + return ap; + } + + NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath() << ": SSID " << ssid + << " not currently known by device " << getObjectPath() + << ", requesting a scan"; + + std::int64_t cur_last_scan; + { + absl::ReaderMutexLock l(&last_scan_lock_); + cur_last_scan = last_scan_; + } + + // Otherwise, request a Scan first and wait for it to finish. + try { + RequestScan( + {{"ssids", std::vector>{ssid_bytes}}}); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "RequestScan", e); + } + + auto scan_finish = [cur_last_scan, this]() { + this->last_scan_lock_.AssertReaderHeld(); + return cur_last_scan != this->last_scan_; + }; + + absl::Condition cond(&scan_finish); + bool success = last_scan_lock_.ReaderLockWhenWithTimeout(cond, scan_timeout); + last_scan_lock_.ReaderUnlock(); + + if (!success) { + NEARBY_LOGS(WARNING) << __func__ << ": " << getObjectPath() + << ": timed out waiting for scan to finish"; + } + + ap = SearchBySSIDNoScan(ssid_bytes); + if (ap == nullptr) { + NEARBY_LOGS(WARNING) << __func__ << ": " << getObjectPath() + << ": Couldn't find SSID " << ssid; + } + + return ap; +} + +static inline std::pair +AuthAlgAndKeyMgmt(api::WifiAuthType auth_type) { + switch (auth_type) { + case api::WifiAuthType::kUnknown: + return {"open", "none"}; + case api::WifiAuthType::kOpen: + return {"open", "none"}; + case api::WifiAuthType::kWpaPsk: + return {"shared", "wpa-psk"}; + case api::WifiAuthType::kWep: + return {"none", "wep"}; + } +} + api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid, absl::string_view password, api::WifiAuthType auth_type) { - return api::WifiConnectionStatus::kUnknown; + + auto ap = SearchBySSID(ssid); + if (ap == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() + << ": Couldn't find SSID " << ssid; + return api::WifiConnectionStatus::kConnectionFailure; + } + + std::vector ssid_bytes(ssid.begin(), ssid.end()); + std::string connection_id; + + { + sd_id128_t id; + if (auto ret = sd_id128_randomize(&id); ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": could not generation a connection UUID"; + return api::WifiConnectionStatus::kUnknown; + } + connection_id = SD_ID128_TO_UUID_STRING(id); + } + + auto [auth_alg, key_mgmt] = AuthAlgAndKeyMgmt(auth_type); + + std::map> + connection_settings{ + {"connection", + std::map{ + {"uuid", connection_id}, + {"autoconnect", true}, + {"id", ssid}, + {"type", "802-11-wireless"}, + {"zone", "Public"}, + }}, + {"802-11-wireless", + std::map{ + {"ssid", ssid_bytes}, + {"mode", "infrastructure"}, + {"security", "802-11-wireless-security"}, + {"assigned-mac-address", "random"}, + }}, + {"802-11-wireless-security", + std::map{{"auth-alg", auth_alg}, + {"key-mgmt", key_mgmt}}}}; + if (!password.empty()) { + connection_settings["802-11-wireless-security"]["psk"] = + std::string(password); + } + + sdbus::ObjectPath connection_path, active_conn_path; + try { + auto [cp, acp, _r] = network_manager_->AddAndActivateConnection2( + connection_settings, getObjectPath(), ap->getObjectPath(), + {{"persist", "volatile"}, {"bind-activation", "dbus-client"}}); + connection_path = std::move(cp); + active_conn_path = std::move(acp); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "AddAndActivateConnection2", e); + return api::WifiConnectionStatus::kUnknown; + } + + NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath() + << ": Added a new connection at " << connection_path; + auto active_connection = NetworkManagerActiveConnection( + getProxy().getConnection(), active_conn_path); + auto [reason, timeout] = active_connection.WaitForConnection(); + if (timeout) { + NEARBY_LOGS(ERROR) + << __func__ << ": " << getObjectPath() + << ": timed out while waiting for connection " << active_conn_path + << " to be activated, last NMActiveConnectionStateReason: " + << reason.value(); + return api::WifiConnectionStatus::kUnknown; + } + + if (reason.has_value()) { + NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() << ": connection " + << active_conn_path + << " failed to activate, NMActiveConnectionStateReason:" + << *reason; + if (*reason == ActiveConnectionStateReason::kStateReasonNoSecrets || + *reason == ActiveConnectionStateReason::kStateReasonLoginFailed) + return api::WifiConnectionStatus::kAuthFailure; + } + + return api::WifiConnectionStatus::kConnected; } bool NetworkManagerWifiMedium::VerifyInternetConnectivity() { - auto network_manager_proxy_ = sdbus::createProxy( - "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager"); - network_manager_proxy_->finishRegistration(); - try { - std::uint32_t connectivity = network_manager_.CheckConnectivity(); + std::uint32_t connectivity = network_manager_->CheckConnectivity(); return connectivity == 4; // NM_CONNECTIVITY_FULL } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(network_manager_proxy_, "CheckConnectivity", e); + DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "CheckConnectivity", e); return false; } } diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 97c1555e..2af8ff6b 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -3,20 +3,25 @@ #include #include +#include #include #include +#include #include #include #include #include #include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h" #include "internal/platform/implementation/linux/networkmanager_client_glue.h" +#include "internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h" #include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" #include "internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h" #include "internal/platform/implementation/wifi.h" +#include "internal/platform/logging.h" namespace nearby { namespace linux { @@ -27,6 +32,11 @@ public: : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager") { registerProxy(); + try { + state_ = State(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); + } } ~NetworkManager() { unregisterProxy(); } @@ -91,19 +101,112 @@ public: ~NetworkManagerAccessPoint() { unregisterProxy(); } }; +enum ActiveConnectionState { + kStateUnknown = 0, + kStateActivating = 1, + kStateActivated = 2, + kStateDeactivating = 3, + kStateDeactivated = 4 +}; +enum ActiveConnectionStateReason { + kStateReasonUnknown = 0, + kStateReasonNone = 1, + kStateReasonUserDisconnected = 2, + kStateReasonDeviceDisconnected = 3, + kStateReasonServiceStopped = 4, + kStateReasonIPConfigInvalid = 5, + kStateReasonConnectTimeout = 6, + kStateReasonServiceStartTimeout = 7, + kStateReasonServiceStartFailed = 8, + kStateReasonNoSecrets = 9, + kStateReasonLoginFailed = 10, + kStateReasonConnectionRemoved = 11, + kStateReasonDependencyFailed = 12, + kStateReasonDeviceRealizeFailed = 13, + kStateReasonDeviceRemoved = 14, +}; + +extern std::ostream &operator<<(std::ostream &s, + const ActiveConnectionStateReason &reason); + +class NetworkManagerActiveConnection + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::Connection::Active_proxy> { +public: + NetworkManagerActiveConnection( + sdbus::IConnection &system_bus, + const sdbus::ObjectPath &active_connection_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + active_connection_path) { + registerProxy(); + try { + auto state = State(); + if (state >= kStateUnknown && state <= kStateDeactivated) { + state_ = static_cast(state); + } + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); + } + } + ~NetworkManagerActiveConnection() { unregisterProxy(); } + +protected: + void onStateChanged(const uint32_t &state, const uint32_t &reason) override + ABSL_LOCKS_EXCLUDED(state_mutex_) { + absl::MutexLock l(&state_mutex_); + if (state >= kStateUnknown && state <= kStateDeactivated) { + state_ = static_cast(state); + } + if (reason >= kStateReasonUnknown && reason <= kStateReasonDeviceRemoved) { + reason_ = static_cast(reason); + } + } + +public: + std::pair, bool> + WaitForConnection(absl::Duration timeout = absl::Seconds(10)) + ABSL_LOCKS_EXCLUDED(state_mutex_) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Waiting for an update to " + << getObjectPath() << "'s state"; + + auto state_changed = [this]() { + this->state_mutex_.AssertReaderHeld(); + return this->state_ == kStateActivated || + this->state_ == kStateDeactivated; + }; + + absl::Condition cond(&state_changed); + auto success = state_mutex_.ReaderLockWhenWithTimeout(cond, timeout); + auto reason = reason_; + auto state = state_; + state_mutex_.ReaderUnlock(); + + if (!success) { + return {reason, true}; + } + + return state == kStateActivated ? std::pair{std::nullopt, false} + : std::pair{std::optional(reason), false}; + }; + +private: + absl::Mutex state_mutex_; + ActiveConnectionState state_ ABSL_GUARDED_BY(state_mutex_); + ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_); +}; + class NetworkManagerWifiMedium : public api::WifiMedium, - sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::Device::Wireless_proxy, - sdbus::Properties_proxy> { + public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::Device::Wireless_proxy, + sdbus::Properties_proxy> { public: - NetworkManagerWifiMedium(NetworkManager &network_manager, + NetworkManagerWifiMedium(std::shared_ptr network_manager, sdbus::IConnection &system_bus, const sdbus::ObjectPath &wireless_device_object_path) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", wireless_device_object_path), - network_manager_(network_manager) { - active_access_point_ = std::nullopt; + network_manager_(std::move(network_manager)) { registerProxy(); } @@ -121,10 +224,14 @@ public: bool IsInterfaceValid() const override { return true; }; api::WifiCapability &GetCapability() override; api::WifiInformation &GetInformation() override; - bool Scan( const api::WifiMedium::ScanResultCallback &scan_result_callback) override; + std::shared_ptr + SearchBySSID(absl::string_view ssid, + absl::Duration scan_timeout = absl::Seconds(15)) + ABSL_LOCKS_EXCLUDED(known_access_points_lock_); + api::WifiConnectionStatus ConnectToNetwork(absl::string_view ssid, absl::string_view password, api::WifiAuthType auth_type) override; @@ -138,19 +245,40 @@ protected: const std::map &changedProperties, const std::vector &invalidatedProperties) override; + void onAccessPointAdded(const sdbus::ObjectPath &access_point) override + ABSL_LOCKS_EXCLUDED(known_access_points_lock_) { + absl::MutexLock l(&known_access_points_lock_); + known_access_points_.erase(access_point); + known_access_points_.emplace(access_point, getProxy().getConnection(), + access_point); + } + void onAccessPointRemoved(const sdbus::ObjectPath &access_point) override + ABSL_LOCKS_EXCLUDED(known_access_points_lock_) { + absl::MutexLock l(&known_access_points_lock_); + known_access_points_.erase(access_point); + } + private: - NetworkManager &network_manager_; + std::shared_ptr + SearchBySSIDNoScan(std::vector &ssid) + ABSL_LOCKS_EXCLUDED(known_access_points_lock_); + + std::shared_ptr network_manager_; api::WifiCapability capability_; api::WifiInformation information_{false}; - absl::Mutex active_access_point_lock_; - std::optional active_access_point_; + absl::Mutex known_access_points_lock_; + std::map> + known_access_points_ ABSL_GUARDED_BY(known_access_points_lock_); absl::Mutex scan_result_callback_lock_; std::optional< std::reference_wrapper> - scan_result_callback_; + scan_result_callback_ ABSL_GUARDED_BY(scan_result_callback_lock_); + + absl::Mutex last_scan_lock_; + std::int64_t last_scan_ ABSL_GUARDED_BY(last_scan_lock_); }; } // namespace linux From c916ea039dd6e994d059486b51bcf87d5c1f27db Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 23 Aug 2023 16:01:39 +0530 Subject: [PATCH 030/201] Add more wifi code. --- .../implementation/linux/wifi_hotspot.cc | 250 +++++++++++++----- .../implementation/linux/wifi_hotspot.h | 74 +++--- .../linux/wifi_hotspot_server_socket.cc | 67 +++++ .../linux/wifi_hotspot_server_socket.h | 37 +++ .../linux/wifi_hotspot_socket.h | 33 +++ .../platform/implementation/linux/wifi_lan.cc | 11 +- .../linux/wifi_lan_server_socket.cc | 5 +- .../implementation/linux/wifi_medium.cc | 80 +++++- .../implementation/linux/wifi_medium.h | 85 ++++-- 9 files changed, 509 insertions(+), 133 deletions(-) create mode 100644 internal/platform/implementation/linux/wifi_hotspot_server_socket.cc create mode 100644 internal/platform/implementation/linux/wifi_hotspot_server_socket.h create mode 100644 internal/platform/implementation/linux/wifi_hotspot_socket.h diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 61735b0f..3d4ce648 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -1,86 +1,114 @@ +#include #include #include +#include #include +#include #include #include "internal/platform/implementation/linux/dbus.h" -#include "internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h" #include "internal/platform/implementation/linux/wifi_hotspot.h" +#include "internal/platform/implementation/linux/wifi_hotspot_server_socket.h" +#include "internal/platform/implementation/linux/wifi_hotspot_socket.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { -bool NetworkManagerWifiHotspotMedium::ConnectWifiHotspot( - HotspotCredentials *hotspot_credentials) { - if (hotspot_credentials == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": hotspot_credentials cannot be null"; - return false; +std::unique_ptr +NetworkManagerWifiHotspotMedium::ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) { + if (!WifiHotspotActive()) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Cannot connect to service without an active WiFi hotspot"; + return nullptr; } - auto ssid = hotspot_credentials->GetSSID(); - auto password = hotspot_credentials->GetPassword(); + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return nullptr; + } - return wireless_device_->ConnectToNetwork(ssid, password, - api::WifiAuthType::kWpaPsk) == - api::WifiConnectionStatus::kConnected; + NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" + << port; + struct sockaddr_in addr; + addr.sin_addr.s_addr = inet_addr(std::string(ip_address).c_str()); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + auto ret = + connect(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " + << std::strerror(errno); + return nullptr; + } + + return std::make_unique(sock); } -bool NetworkManagerWifiHotspotMedium::DisconnectWifiHotspot() { +std::unique_ptr +NetworkManagerWifiHotspotMedium::ListenForService(int port) { if (!WifiHotspotActive()) { - NEARBY_LOGS(ERROR) << __func__ << ": WiFi hotspot is not active"; - return false; + NEARBY_LOGS(ERROR) + << __func__ + << ": Cannot connect to service without an active WiFi hotspot"; + return nullptr; + } + + auto active_connection = wireless_device_->GetActiveConnection(); + if (active_connection == nullptr) { + return nullptr; + } + + auto ip4addresses = active_connection->GetIP4Addresses(); + if (ip4addresses.empty()) { + NEARBY_LOGS(ERROR) + << __func__ + << "Could not find any IPv4 addresses for active connection " + << active_connection->getObjectPath(); + return nullptr; + } + + auto sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return nullptr; + } + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(ip4addresses[0].c_str()); + addr.sin_port = htons(port); + + auto ret = + bind(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error binding to socket: " << std::strerror(errno); + return nullptr; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": Listening for services on " + << ip4addresses[0] << ":" << port << " on device " + << wireless_device_->getObjectPath(); + + ret = listen(sock, 0); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " + << std::strerror(errno); + return nullptr; } - sdbus::ObjectPath active_ap_path; - - try { - active_ap_path = wireless_device_->ActiveAccessPoint(); - if (active_ap_path.empty()) { - NEARBY_LOGS(ERROR) << __func__ - << ": Not connected to any access points on " - << wireless_device_->getObjectPath(); - return false; - } - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "ActiveAccessPoint", e); - } - - auto object_manager = NetworkManagerObjectManager(system_bus_); - - auto objects = object_manager.GetManagedObjects(); - - for (auto &[path, interfaces] : objects) { - if (path.find("/org/freedesktop/NetworkManager/ActiveConnection/") == 0) { - if (interfaces.count(org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME) == 1) { - sdbus::ObjectPath specific_object = - interfaces[org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME]["SpecificObject"]; - if (specific_object == active_ap_path) { - NEARBY_LOGS(INFO) << __func__ << ": Deactivating active connection " - << active_ap_path; - - try { - network_manager_->DeactivateConnection(path); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactiveConnection", - e); - return false; - } - return true; - } - } - } - } - - NEARBY_LOGS(ERROR) - << __func__ - << ": Could not find an active connection with the access point " - << active_ap_path; - return false; + return std::make_unique(sock, + system_bus_, active_connection->getObjectPath(), network_manager_); } bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( @@ -150,11 +178,12 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( }}}; std::unique_ptr active_conn; try { - auto [path, active_path, result] = network_manager_->AddAndActivateConnection2( - connection_settings, wireless_device_->getObjectPath(), "/", - {{"persist", "volatile"}, {"bind-activation", "dbus-client"}}); + auto [path, active_path, result] = + network_manager_->AddAndActivateConnection2( + connection_settings, wireless_device_->getObjectPath(), "/", + {{"persist", "volatile"}, {"bind-activation", "dbus-client"}}); active_conn = std::make_unique(system_bus_, - active_path); + active_path); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "AddAndActivateConnection2", e); @@ -163,13 +192,14 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( auto [reason, timeout] = active_conn->WaitForConnection(); if (timeout) { - NEARBY_LOGS(ERROR) << __func__ << ": " - << ": timed out while waiting for connection " - << active_conn->getObjectPath() + NEARBY_LOGS(ERROR) + << __func__ << ": " + << ": timed out while waiting for connection " + << active_conn->getObjectPath() << " to be activated, last NMActiveConnectionStateReason: " << reason.value(); DisconnectWifiHotspot(); - return false; + return false; } NEARBY_LOGS(INFO) << __func__ << ": Started a WiFi hotspot on device " @@ -178,6 +208,87 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( return true; } +bool NetworkManagerWifiHotspotMedium::StopWifiHotspot() { + if (!WifiHotspotActive()) { + NEARBY_LOGS(ERROR) + << __func__ << ": " << wireless_device_->getObjectPath() + << ": Cannot stop WiFi hotspot as a WiFi hotspot is not active"; + } + + // Get the active connection object for the hotspot AP. + sdbus::ObjectPath active_ap_path; + + try { + active_ap_path = wireless_device_->ActiveAccessPoint(); + if (active_ap_path.empty()) { + NEARBY_LOGS(ERROR) << __func__ << ": No active access points on " + << wireless_device_->getObjectPath(); + return false; + } + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "ActiveAccessPoint", e); + } + + auto object_manager = NetworkManagerObjectManager(system_bus_); + auto active_connection = wireless_device_->GetActiveConnection(); + if (active_connection == nullptr) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Could not find an active connection using the access point " + << active_ap_path; + return false; + } + + NEARBY_LOGS(INFO) << __func__ << ": " << wireless_device_->getObjectPath() + << ": Deactivating active connection " + << active_connection->getObjectPath(); + + try { + network_manager_->DeactivateConnection(active_connection->getObjectPath()); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactivateConnection", e); + return false; + } + + return true; +} + +bool NetworkManagerWifiHotspotMedium::ConnectWifiHotspot( + HotspotCredentials *hotspot_credentials) { + if (hotspot_credentials == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": hotspot_credentials cannot be null"; + return false; + } + + auto ssid = hotspot_credentials->GetSSID(); + auto password = hotspot_credentials->GetPassword(); + + return wireless_device_->ConnectToNetwork(ssid, password, + api::WifiAuthType::kWpaPsk) == + api::WifiConnectionStatus::kConnected; +} + +bool NetworkManagerWifiHotspotMedium::DisconnectWifiHotspot() { + if (!WifiHotspotActive()) { + NEARBY_LOGS(ERROR) << __func__ << ": WiFi hotspot is not active"; + return false; + } + + auto active_connection = wireless_device_->GetActiveConnection(); + if (active_connection == nullptr) { + return false; + } + + try { + network_manager_->DeactivateConnection(active_connection->getObjectPath()); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactivateConnection", e); + return false; + } + + return true; +} + bool NetworkManagerWifiHotspotMedium::WifiHotspotActive() { try { auto mode = wireless_device_->Mode(); @@ -187,5 +298,6 @@ bool NetworkManagerWifiHotspotMedium::WifiHotspotActive() { return false; } } + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot.h b/internal/platform/implementation/linux/wifi_hotspot.h index 9f4f0f55..ec0af3bb 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.h +++ b/internal/platform/implementation/linux/wifi_hotspot.h @@ -8,43 +8,51 @@ #include "internal/platform/implementation/wifi_hotspot.h" namespace nearby { - namespace linux { - class NetworkManagerWifiHotspotMedium : api::WifiHotspotMedium { - public: - NetworkManagerWifiHotspotMedium( - sdbus::IConnection &system_bus, - std::shared_ptr network_manager, - const sdbus::ObjectPath &wireless_device_object_path) - : system_bus_(system_bus), - wireless_device_(std::make_unique( - network_manager, system_bus, wireless_device_object_path)), - network_manager_(network_manager) {} - ~NetworkManagerWifiHotspotMedium() {} +namespace linux { +class NetworkManagerWifiHotspotMedium : public api::WifiHotspotMedium { +public: + NetworkManagerWifiHotspotMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + const sdbus::ObjectPath &wireless_device_object_path) + : system_bus_(system_bus), + wireless_device_(std::make_unique( + network_manager, system_bus, wireless_device_object_path)), + network_manager_(network_manager) {} + NetworkManagerWifiHotspotMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + std::unique_ptr wireless_device) + : system_bus_(system_bus), wireless_device_(std::move(wireless_device)), + network_manager_(network_manager) {} + ~NetworkManagerWifiHotspotMedium() {} - bool IsInterfaceValid() const override { return true; } - std::unique_ptr - ConnectToService(absl::string_view ip_address, int port, - CancellationFlag *cancellation_flag) override; - std::unique_ptr - ListenForService(int port) override; + bool IsInterfaceValid() const override { return true; } + std::unique_ptr + ConnectToService(absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr + ListenForService(int port) override; - bool StartWifiHotspot(HotspotCredentials *hotspot_credentials) override; - bool StopWifiHotspot() override; + bool StartWifiHotspot(HotspotCredentials *hotspot_credentials) override; + bool StopWifiHotspot() override; - bool ConnectWifiHotspot(HotspotCredentials *hotspot_credentials) override; - bool DisconnectWifiHotspot() override; + bool ConnectWifiHotspot(HotspotCredentials *hotspot_credentials) override; + bool DisconnectWifiHotspot() override; - absl::optional> - GetDynamicPortRange() override {return absl::nullopt;} - - private: - bool WifiHotspotActive(); - - sdbus::IConnection &system_bus_; - std::unique_ptr wireless_device_; - std::shared_ptr network_manager_; - }; + absl::optional> + GetDynamicPortRange() override { + return absl::nullopt; } -} + +private: + bool WifiHotspotActive(); + + sdbus::IConnection &system_bus_; + std::unique_ptr wireless_device_; + std::shared_ptr network_manager_; +}; +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc new file mode 100644 index 00000000..531dd7e0 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc @@ -0,0 +1,67 @@ +#include +#include + +#include "internal/platform/implementation/linux/wifi_hotspot_server_socket.h" +#include "internal/platform/implementation/linux/wifi_hotspot_socket.h" +#include "internal/platform/implementation/linux/wifi_medium.h" + +namespace nearby { +namespace linux { +std::string NetworkManagerWifiHotspotServerSocket::GetIPAddress() const { + NetworkManagerActiveConnection active_conn(system_bus_, + active_connection_path_); + auto ip4addresses = active_conn.GetIP4Addresses(); + if (ip4addresses.empty()) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Could not find any IPv4 addresses for active connection " + << active_connection_path_; + return std::string(); + } + return ip4addresses[0]; +} + +int NetworkManagerWifiHotspotServerSocket::GetPort() const { + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + auto ret = + getsockname(fd_.get(), reinterpret_cast(&sin), &len); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error getting information for socket " + << fd_.get() << ": " << std::strerror(errno); + return 0; + } + + return ntohs(sin.sin_port); +} + +std::unique_ptr +NetworkManagerWifiHotspotServerSocket::Accept() { + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + + auto conn = + accept(fd_.get(), reinterpret_cast(&addr), &len); + if (conn < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error accepting incoming connections on socket " + << fd_.get() << ": " << std::strerror(errno); + return nullptr; + } + + return std::make_unique(conn); +} + +Exception NetworkManagerWifiHotspotServerSocket::Close() { + int fd = fd_.release(); + auto ret = close(fd); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " + << std::strerror(errno); + return {Exception::kFailed}; + } + + return {Exception::kSuccess}; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h new file mode 100644 index 00000000..7a8f2ac3 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h @@ -0,0 +1,37 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_SERVER_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_SERVER_SOCKET_H_ + +#include + +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi_hotspot.h" + +namespace nearby { +namespace linux { +class NetworkManagerWifiHotspotServerSocket + : public api::WifiHotspotServerSocket { +public: + NetworkManagerWifiHotspotServerSocket( + int socket, sdbus::IConnection &system_bus, + const sdbus::ObjectPath &active_connection_path, + std::shared_ptr network_manager) + : fd_(socket), system_bus_(system_bus), + active_connection_path_(active_connection_path), + network_manager_(network_manager) {} + ~NetworkManagerWifiHotspotServerSocket() {} + + std::string GetIPAddress() const override; + int GetPort() const override; + std::unique_ptr Accept() override; + Exception Close() override; + +private: + sdbus::UnixFd fd_; + sdbus::IConnection &system_bus_; + sdbus::ObjectPath active_connection_path_; + std::shared_ptr network_manager_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/wifi_hotspot_socket.h b/internal/platform/implementation/linux/wifi_hotspot_socket.h new file mode 100644 index 00000000..7e0d2d56 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_hotspot_socket.h @@ -0,0 +1,33 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_HOTSPOT_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_HOTSPOT_SOCKET_H_ + +#include "internal/platform/implementation/linux/stream.h" +#include "internal/platform/implementation/wifi_hotspot.h" + +namespace nearby { +namespace linux { +class WifiHotspotSocket : public api::WifiHotspotSocket { +public: + WifiHotspotSocket(int connection_fd) + : fd_(sdbus::UnixFd(connection_fd)), output_stream_(fd_), + input_stream_(fd_) {} + ~WifiHotspotSocket() {} + + 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}; + }; + +private: + sdbus::UnixFd fd_; + OutputStream output_stream_; + InputStream input_stream_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 4e9df5ec..079772dc 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -79,6 +79,7 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while adding service"; + return false; } advertising_ = true; @@ -107,6 +108,7 @@ bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while removing service"; + return false; } advertising_ = false; @@ -137,6 +139,7 @@ bool WifiLanMedium::StartDiscovery( std::move(callback)); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(avahi_, "ServiceBrowserPrepare", e); + return false; } auto &browser = service_browsers_[service_type]; @@ -146,6 +149,7 @@ bool WifiLanMedium::StartDiscovery( browser->Start(); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(browser, "Start", e); + return false; } return true; @@ -163,6 +167,7 @@ bool WifiLanMedium::StopDiscovery(const std::string &service_type) { browser->Free(); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(browser, "Free", e); + return false; } service_browsers_.erase(service_type); @@ -199,7 +204,8 @@ WifiLanMedium::ConnectToService(const std::string &ip_address, int port, return std::make_unique(std::move(fd)); } -std::unique_ptr WifiLanMedium::ListenForService(int port) { +std::unique_ptr +WifiLanMedium::ListenForService(int port) { auto sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -229,7 +235,8 @@ std::unique_ptr WifiLanMedium::ListenForService(int po return nullptr; } - return std::make_unique(sock, network_manager_); + return std::make_unique(sock, network_manager_, + system_bus_); } absl::optional> GetDynamicPortRange() { diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index 20313149..89ac1ca6 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -46,9 +46,12 @@ std::string WifiLanServerSocket::GetIPAddress() const { address_data = ip4config.AddressData(); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "IP4Config", e); + continue; } - return address_data[0]["address"]; + if (address_data.size() > 0) { + return address_data[0]["address"]; + } } } diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 4aa0d5a8..b79fb7a9 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -61,7 +61,16 @@ std::ostream &operator<<(std::ostream &s, std::unique_ptr NetworkManagerObjectManager::GetIp4Config( const sdbus::ObjectPath &active_connection) { - auto objects = GetManagedObjects(); + std::map>> + objects; + try { + objects = GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); + return nullptr; + } + for (auto &[object_path, interfaces] : objects) { if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/", 0) == 0) { @@ -82,6 +91,44 @@ NetworkManagerObjectManager::GetIp4Config( return nullptr; } +std::unique_ptr +NetworkManagerObjectManager::GetActiveConnectionForAccessPoint( + const sdbus::ObjectPath &access_point, + const sdbus::ObjectPath &device_path) { + std::map>> + objects; + try { + objects = GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); + return nullptr; + } + + for (auto &[object_path, interfaces] : objects) { + if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/") == + 0) { + if (interfaces.count(org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME) == 1) { + auto props = interfaces[org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME]; + sdbus::ObjectPath specific_object = props["SpecificObject"]; + if (specific_object == access_point) { + std::vector devices = props["Devices"]; + for (auto &path : devices) { + if (path == device_path) { + return std::make_unique( + getProxy().getConnection(), object_path); + } + } + } + } + } + } + + return nullptr; +} + api::WifiCapability &NetworkManagerWifiMedium::GetCapability() { try { auto cap_mask = WirelessCapabilities(); @@ -331,7 +378,7 @@ NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid, } NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath() - << ": Added a new connection at " << connection_path; + << ": Added a new connection at " << connection_path; auto active_connection = NetworkManagerActiveConnection( getProxy().getConnection(), active_conn_path); auto [reason, timeout] = active_connection.WaitForConnection(); @@ -372,5 +419,34 @@ std::string NetworkManagerWifiMedium::GetIpAddress() { return information_.ip_address_dot_decimal; } +std::unique_ptr +NetworkManagerWifiMedium::GetActiveConnection() { + sdbus::ObjectPath active_ap_path; + + try { + active_ap_path = ActiveAccessPoint(); + if (active_ap_path.empty()) { + NEARBY_LOGS(ERROR) << __func__ << ": No active access points on " + << getObjectPath(); + return nullptr; + } + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "ActiveAccessPoint", e); + return nullptr; + } + + auto object_manager = NetworkManagerObjectManager(getProxy().getConnection()); + auto conn = object_manager.GetActiveConnectionForAccessPoint(active_ap_path, + getObjectPath()); + + if (conn == nullptr) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Could not find an active connection using the access point " + << active_ap_path << " and device " << getObjectPath(); + } + return conn; +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 2af8ff6b..b9aa318f 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -65,29 +65,6 @@ public: ~NetworkManagerIP4Config() { unregisterProxy(); } }; -class NetworkManagerObjectManager - : public sdbus::ProxyInterfaces { -public: - NetworkManagerObjectManager(sdbus::IConnection &system_bus) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - "/org/freedesktop") { - registerProxy(); - } - ~NetworkManagerObjectManager() { unregisterProxy(); } - - std::unique_ptr - GetIp4Config(const sdbus::ObjectPath &access_point); - -protected: - void onInterfacesAdded( - const sdbus::ObjectPath &objectPath, - const std::map> - &interfacesAndProperties) override {} - void - onInterfacesRemoved(const sdbus::ObjectPath &objectPath, - const std::vector &interfaces) override {} -}; - class NetworkManagerAccessPoint : public sdbus::ProxyInterfaces< org::freedesktop::NetworkManager::AccessPoint_proxy> { @@ -187,7 +164,35 @@ public: return state == kStateActivated ? std::pair{std::nullopt, false} : std::pair{std::optional(reason), false}; - }; + } + + std::vector GetIP4Addresses() { + sdbus::ObjectPath ip4config_path; + try { + ip4config_path = Ip4Config(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "Ip4Config", e); + return {}; + } + + NetworkManagerIP4Config ip4config(getProxy().getConnection(), + ip4config_path); + std::vector> address_data; + try { + address_data = ip4config.AddressData(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "AddressData", e); + return {}; + } + + std::vector ip4addresses; + for (auto &data : address_data) { + if (data.count("address") == 1) { + ip4addresses.push_back(data["address"]); + } + } + return ip4addresses; + } private: absl::Mutex state_mutex_; @@ -195,11 +200,37 @@ private: ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_); }; +class NetworkManagerObjectManager + : public sdbus::ProxyInterfaces { +public: + NetworkManagerObjectManager(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + "/org/freedesktop") { + registerProxy(); + } + ~NetworkManagerObjectManager() { unregisterProxy(); } + + std::unique_ptr + GetIp4Config(const sdbus::ObjectPath &access_point); + std::unique_ptr + GetActiveConnectionForAccessPoint(const sdbus::ObjectPath &access_point_path, + const sdbus::ObjectPath &device_path); + +protected: + void onInterfacesAdded( + const sdbus::ObjectPath &objectPath, + const std::map> + &interfacesAndProperties) override {} + void + onInterfacesRemoved(const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override {} +}; + class NetworkManagerWifiMedium : public api::WifiMedium, public sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::Device::Wireless_proxy, - sdbus::Properties_proxy> { + org::freedesktop::NetworkManager::Device::Wireless_proxy, + sdbus::Properties_proxy> { public: NetworkManagerWifiMedium(std::shared_ptr network_manager, sdbus::IConnection &system_bus, @@ -239,6 +270,8 @@ public: bool VerifyInternetConnectivity() override; std::string GetIpAddress() override; + std::unique_ptr GetActiveConnection(); + protected: void onPropertiesChanged( const std::string &interfaceName, From 65f61333c0c71a27896d806b15dd65eea8084611 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 23 Aug 2023 16:01:57 +0530 Subject: [PATCH 031/201] Add BluezObjectManager. --- .../platform/implementation/linux/bluez.h | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index dc7bb55d..94591f1b 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -1,6 +1,8 @@ #ifndef PLATFORM_IMPL_LINUX_BLUEZ_H_ #define PLATFORM_IMPL_LINUX_BLUEZ_H_ +#include +#include #include #include "absl/strings/string_view.h" @@ -36,6 +38,25 @@ extern sdbus::ObjectPath profile_object_path(absl::string_view service_uuid); extern sdbus::ObjectPath adapter_object_path(absl::string_view name); +class BluezObjectManager + : public sdbus::ProxyInterfaces { +public: + BluezObjectManager(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.bluez", "/") { + registerProxy(); + } + ~BluezObjectManager() { unregisterProxy(); } + +protected: + void onInterfacesAdded( + const sdbus::ObjectPath &objectPath, + const std::map> + &interfacesAndProperties) override {} + void + onInterfacesRemoved(const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override {} +}; + } // namespace bluez } // namespace linux } // namespace nearby From e7be02752d94b2a341d80144bba639ae2512c959 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 23 Aug 2023 17:29:59 +0530 Subject: [PATCH 032/201] Add headers to library comm. --- internal/platform/implementation/linux/BUILD | 29 +++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 067a3c51..63b0900b 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -3,11 +3,13 @@ licenses(["notice"]) cc_library( name = "types", hdrs = [ + "atomic_boolean.h", "device_info.h", ], srcs = [ "device_info.cc", - "bluetooth_adapter.h", + "log_message.cc", + "timer.cc" ], visibility = ["//third_party/nearby/sharing/internal/impl/linux:__pkg__"], deps = [ @@ -23,14 +25,38 @@ cc_library( cc_library( name = "comm", hdrs = [ + "avahi.h", + "avahi_entrygroup_client_glue.h", + "avahi_server_client_glue.h", + "avahi_servicebrowser_client_glue.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_adapter_client_glue.h", + "bluez_profile_glue.h", + "bluez_profile_manager_client_glue.h", + "dbus.h", + "networkmanager_accesspoint_client_glue.h", + "networkmanager_client_glue.h", + "networkmanager_connection_active_client_glue.h", + "networkmanager_device_wifip2p_client_glue.h", + "networkmanager_device_wireless_client_glue.h", + "networkmanager_ip4config_client_glue.h", + "stream.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", @@ -51,6 +77,7 @@ cc_library( "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", "@libsystemd//:lib", + "@sdbus_cpp//:lib", ], visibility = ["//visibility:private"], ) From 409d4c1fdbf82925a00b43c57adbfdb024b82d3d Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 23 Aug 2023 17:30:14 +0530 Subject: [PATCH 033/201] Add additional impls. --- .../platform/implementation/linux/platform.cc | 148 ++++++++++++++++-- 1 file changed, 133 insertions(+), 15 deletions(-) diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 2bfb771d..30335c3c 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -1,37 +1,57 @@ #include #include +#include +#include #include -#include "internal/platform/implementation/linux/condition_variable.h" -#include "internal/platform/implementation/linux/mutex.h" -#include "internal/platform/implementation/platform.h" #include "internal/platform/implementation/atomic_boolean.h" #include "internal/platform/implementation/atomic_reference.h" #include "internal/platform/implementation/count_down_latch.h" #include "internal/platform/implementation/linux/atomic_boolean.h" #include "internal/platform/implementation/linux/atomic_uint32.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/implementation/linux/bluetooth_classic_medium.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" +#include "internal/platform/implementation/linux/condition_variable.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/mutex.h" +#include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" +#include "internal/platform/implementation/linux/wifi_hotspot.h" +#include "internal/platform/implementation/linux/wifi_lan.h" +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/platform.h" #include "internal/platform/implementation/shared/count_down_latch.h" +#include "internal/platform/implementation/wifi_hotspot.h" +#include "internal/platform/implementation/wifi_lan.h" #include "log_message.h" namespace nearby { namespace api { -std::string ImplementationPlatform::GetCustomSavePath(const std::string &parent_folder, const std::string & file_name) { +std::string +ImplementationPlatform::GetCustomSavePath(const std::string &parent_folder, + const std::string &file_name) { auto fs = std::filesystem::path(parent_folder); return fs / file_name; } -std::string ImplementationPlatform::GetDownloadPath(const std::string& parent_folder, const std::string &file_name) { +std::string +ImplementationPlatform::GetDownloadPath(const std::string &parent_folder, + const std::string &file_name) { auto downloads = std::filesystem::path(getenv("XDG_DOWNLOAD_DIR")); - - return downloads / std::filesystem::path(parent_folder).filename() / std::filesystem::path(file_name).filename(); + + return downloads / std::filesystem::path(parent_folder).filename() / + std::filesystem::path(file_name).filename(); } -std::string ImplementationPlatform::GetDownloadPath(const std::string& file_name) { +std::string +ImplementationPlatform::GetDownloadPath(const std::string &file_name) { auto downloads = std::filesystem::path(getenv("XDG_DOWNLOAD_DIR")); return downloads / std::filesystem::path(file_name).filename(); } -std::string ImplementationPlatform::GetAppDataPath(const std::string &file_name) { +std::string +ImplementationPlatform::GetAppDataPath(const std::string &file_name) { auto state = std::filesystem::path(getenv("XDG_STATE_HOME")); return state / std::filesystem::path(file_name).filename(); } @@ -46,13 +66,15 @@ std::unique_ptr CreateAtomicUint32(std::uint32_t value) { return std::make_unique(value); } -std::unique_ptr ImplementationPlatform::CreateCountDownLatch(std::int32_t count) { +std::unique_ptr +ImplementationPlatform::CreateCountDownLatch(std::int32_t count) { return std::make_unique(count); } #pragma push_macro("CreateMutex") #undef CreateMutex -std::unique_ptr ImplementationPlatform::CreateMutex(Mutex::Mode mode) { +std::unique_ptr +ImplementationPlatform::CreateMutex(Mutex::Mode mode) { return std::make_unique(mode); } #pragma pop_macro("CreateMutex") @@ -62,13 +84,109 @@ ImplementationPlatform::CreateConditionVariable(api::Mutex *mutex) { return std::make_unique(mutex); } -std::unique_ptr ImplementationPlatform::CreateLogMessage( - const char *file, int line, LogMessage::Severity severity - ) { - return std::make_unique(file, line, severity); +std::unique_ptr +ImplementationPlatform::CreateLogMessage(const char *file, int line, + LogMessage::Severity severity) { + return std::make_unique(file, line, severity); } +std::unique_ptr +ImplementationPlatform::CreateBluetoothAdapter() { + auto manager = + linux::bluez::BluezObjectManager(linux::getSystemBusConnection()); + try { + auto interfaces = manager.GetManagedObjects(); + for (auto &[object, properties] : interfaces) { + if (properties.count(org::bluez::Adapter1_proxy::INTERFACE_NAME) == 1) { + NEARBY_LOGS(INFO) + << __func__ << ": found bluetooth adapter " << object; + return std::make_unique( + linux::getSystemBusConnection(), object); + } + } + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&manager, "GetManagedObjects", e); + } + NEARBY_LOGS(ERROR) << __func__ + << ": couldn't find a bluetooth adapter on this system"; + return nullptr; +} + +std::unique_ptr +ImplementationPlatform::CreateBluetoothClassicMedium( + BluetoothAdapter &adapter) { + auto path = static_cast(&adapter)->getObjectPath(); + return std::make_unique( + linux::getSystemBusConnection(), path); +} + +static std::unique_ptr +createWifiMedium(std::shared_ptr nm) { + std::vector device_paths; + + try { + device_paths = nm->GetAllDevices(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(nm, "GetAllDevices", e); + return nullptr; + } + + auto manager = + linux::NetworkManagerObjectManager(linux::getSystemBusConnection()); + + std::map>> + objects; + try { + objects = manager.GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(nm, "GetManagedObjects", e); + return nullptr; + } + + for (auto &device_path : device_paths) { + if (objects.count(device_path) == 1) { + auto device = objects[device_path]; + if (device.count(org::freedesktop::NetworkManager::Device:: + Wireless_proxy::INTERFACE_NAME) == 1) { + NEARBY_LOGS(INFO) << __func__ + << ": Found a wireless device at :" << device_path; + return std::make_unique(nm, linux::getSystemBusConnection(), device_path); + } + } + } + + NEARBY_LOGS(ERROR) << __func__ + << ": couldn't find a wireless device on this system"; + return nullptr; +} + +std::unique_ptr ImplementationPlatform::CreateWifiMedium() { + auto nm = + std::make_shared(linux::getSystemBusConnection()); + return createWifiMedium(nm); +} + +std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { + return std::make_unique( + linux::getSystemBusConnection()); +} + +std::unique_ptr +ImplementationPlatform::CreateWifiHotspotMedium() { + auto nm = + std::make_shared(linux::getSystemBusConnection()); + auto wifiMedium = createWifiMedium(nm); + + if (wifiMedium == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": Could not create a WiFi medium"; + return nullptr; + } + + return std::make_unique( + linux::getSystemBusConnection(), nm, std::move(wifiMedium)); +} } // namespace api } // namespace nearby From 24f6c7944574dfcc7ee29317994ef09a119c2ccc Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 23 Aug 2023 17:47:27 +0530 Subject: [PATCH 034/201] Use XDG_RUNTIME_PATH for GetTemporaryPath --- internal/platform/implementation/linux/device_info.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index ef86ca67..83a63ab1 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -48,7 +48,7 @@ std::optional DeviceInfo::GetOsDeviceName() const { api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { try { - std::string chasis = hostname_proxy_->getProperty("PrettyHostname") + std::string chasis = hostname_proxy_->getProperty("Chasis") .onInterface(HOSTNAME_INTERFACE); api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; if (chasis == "phone") { @@ -103,7 +103,7 @@ std::optional DeviceInfo::GetLocalAppDataPath() const { } std::optional DeviceInfo::GetTemporaryPath() const { - char *dir = getenv("XDG_CACHE_HOME"); + char *dir = getenv("XDG_RUNTIME_PATH"); if (dir == NULL) { return std::filesystem::path("/tmp"); } From dc6aa72db613996e42ab78b860ab9a325d79f9b2 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 23 Aug 2023 20:33:57 +0530 Subject: [PATCH 035/201] Use sdbus-c++ glue proxies for device info. --- .../implementation/linux/device_info.cc | 85 +++--- .../implementation/linux/device_info.h | 53 +++- .../linux/hostname_client_glue.h | 198 ++++++++++++++ .../linux/login_session_client_glue.h | 254 ++++++++++++++++++ .../linux/org.freedesktop.hostname1.xml | 86 ++++++ .../linux/org.freedesktop.login1.Session.xml | 121 +++++++++ 6 files changed, 751 insertions(+), 46 deletions(-) create mode 100644 internal/platform/implementation/linux/hostname_client_glue.h create mode 100644 internal/platform/implementation/linux/login_session_client_glue.h create mode 100644 internal/platform/implementation/linux/org.freedesktop.hostname1.xml create mode 100644 internal/platform/implementation/linux/org.freedesktop.login1.Session.xml diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 83a63ab1..b5ed037e 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -7,49 +7,64 @@ #include #include -#include #include "internal/platform/implementation/device_info.h" +#include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/device_info.h" #include "internal/platform/logging.h" +#include "absl/synchronization/mutex.h" namespace nearby { namespace linux { +void CurrentUserSession::RegisterScreenLockedListener( + absl::string_view listener_name, + std::function callback) { + absl::MutexLock l(&screen_lock_listeners_mutex_); + screen_lock_listeners_[listener_name] = callback; +} -const char *HOSTNAME_DEST = "org.freedesktop.hostname1"; -const char *HOSTNAME_PATH = "/org/freedesktop/hostname1"; -const char *HOSTNAME_INTERFACE = "org.freedesktop.hostname1"; +void + CurrentUserSession::UnregisterScreenLockedListener(absl::string_view listener_name) +{ + absl::MutexLock l(&screen_lock_listeners_mutex_); + screen_lock_listeners_.erase(listener_name); +} -const char *LOGIN_DEST = "org.freedesktop.login1"; -const char *LOGIN_PATH = "/org/freedesktop/login1/session/_"; -const char *LOGIN_INTERFACE = "org.freedesktop.login1.Session"; +void CurrentUserSession::onLock() { + absl::ReaderMutexLock l(&screen_lock_listeners_mutex_); + for (auto &[_, callback] : screen_lock_listeners_) { + callback(api::DeviceInfo::ScreenStatus::kLocked); + } +} -DeviceInfo::DeviceInfo(sdbus::IConnection &system_bus) { - hostname_proxy_ = - sdbus::createProxy(system_bus, HOSTNAME_DEST, HOSTNAME_PATH); - hostname_proxy_->finishRegistration(); - login_proxy_ = sdbus::createProxy(system_bus, LOGIN_PATH, LOGIN_PATH); - login_proxy_->finishRegistration(); +void CurrentUserSession::onUnlock() { + absl::ReaderMutexLock l(&screen_lock_listeners_mutex_); + for (auto &[_, callback] : screen_lock_listeners_) { + callback(api::DeviceInfo::ScreenStatus::kUnlocked); + } +} + +DeviceInfo::DeviceInfo(sdbus::IConnection &system_bus) + : system_bus_(system_bus), + current_user_session_(std::make_unique(system_bus_)) { } std::optional DeviceInfo::GetOsDeviceName() const { + Hostnamed hostnamed(system_bus_); try { - std::string hostname = hostname_proxy_->getProperty("PrettyHostname") - .onInterface(HOSTNAME_INTERFACE); + std::string hostname = hostnamed.PrettyHostname(); std::wstring_convert, char16_t> convert; return convert.from_bytes(hostname); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get PrettyHostname"; + DBUS_LOG_PROPERTY_GET_ERROR(&hostnamed, "PrettyHostname", e); return std::nullopt; } } api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { + Hostnamed hostnamed(system_bus_); try { - std::string chasis = hostname_proxy_->getProperty("Chasis") - .onInterface(HOSTNAME_INTERFACE); + std::string chasis = hostnamed.Chassis(); api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; if (chasis == "phone") { device = api::DeviceInfo::DeviceType::kPhone; @@ -62,9 +77,7 @@ api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { } return device; } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get PrettyHostname"; + DBUS_LOG_PROPERTY_GET_ERROR(&hostnamed, "Chasis", e); return api::DeviceInfo::DeviceType::kUnknown; } } @@ -107,7 +120,7 @@ std::optional DeviceInfo::GetTemporaryPath() const { if (dir == NULL) { return std::filesystem::path("/tmp"); } - return std::filesystem::path(std::string(dir)) / "com.github.google.nearby"; + return std::filesystem::path(std::string(dir)) / "Google Nearby"; } std::optional DeviceInfo::GetLogPath() const { @@ -115,7 +128,7 @@ std::optional DeviceInfo::GetLogPath() const { if (dir == NULL) { return std::filesystem::path("/tmp"); } - return std::filesystem::path(std::string(dir)) / "com.github.google.nearby" / + return std::filesystem::path(std::string(dir)) / "Google Nearby" / "logs"; } @@ -124,31 +137,15 @@ std::optional DeviceInfo::GetCrashDumpPath() const { if (dir == NULL) { return std::filesystem::path("/tmp"); } - return std::filesystem::path(std::string(dir)) / "com.github.google.nearby" / + return std::filesystem::path(std::string(dir)) / "Google Nearby" / "crashes"; } bool DeviceInfo::IsScreenLocked() const { - char *session = nullptr; - if (sd_pid_get_session(getpid(), &session) < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error getting session for current user"; - return false; - } - - std::string session_path(LOGIN_PATH); - session_path += session; - free(session); - try { - bool locked = - login_proxy_->getProperty("LockedHint").onInterface(LOGIN_INTERFACE); - return locked; + return current_user_session_->LockedHint(); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get LockedHint for session " - << session_path; + DBUS_LOG_PROPERTY_GET_ERROR(current_user_session_, "LockedHint", e); return false; } } diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 3ca5b762..b1c4c7de 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -2,17 +2,66 @@ #define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ #include +#include #include #include #include +#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/hostname_client_glue.h" +#include "internal/platform/implementation/linux/login_session_client_glue.h" namespace nearby { namespace linux { +class CurrentUserSession + : public sdbus::ProxyInterfaces { +public: + CurrentUserSession(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.login1", + "/org/freedesktop/login1/session/auto") { + registerProxy(); + } + ~CurrentUserSession() { unregisterProxy(); } + + void RegisterScreenLockedListener( + absl::string_view listener_name, + std::function 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> + screen_lock_listeners_ ABSL_GUARDED_BY(screen_lock_listeners_mutex_); +}; + +class Hostnamed + : public sdbus::ProxyInterfaces { +public: + Hostnamed(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.hostname1", + "/org/freedesktop/hostname1") { + registerProxy(); + } + ~Hostnamed() { unregisterProxy(); } +}; + class DeviceInfo : public api::DeviceInfo { public: DeviceInfo(sdbus::IConnection &system_bus); @@ -50,8 +99,8 @@ public: UnregisterScreenLockedListener(absl::string_view listener_name) override{}; private: - std::unique_ptr hostname_proxy_; - std::unique_ptr login_proxy_; + sdbus::IConnection &system_bus_; + std::unique_ptr current_user_session_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/hostname_client_glue.h b/internal/platform/implementation/linux/hostname_client_glue.h new file mode 100644 index 00000000..de07c548 --- /dev/null +++ b/internal/platform/implementation/linux/hostname_client_glue.h @@ -0,0 +1,198 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__hostname_client_glue_h__proxy__H__ +#define __sdbuscpp__hostname_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { + +class hostname1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.hostname1"; + +protected: + hostname1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~hostname1_proxy() = default; + +public: + void SetHostname(const std::string& hostname, const bool& interactive) + { + proxy_.callMethod("SetHostname").onInterface(INTERFACE_NAME).withArguments(hostname, interactive); + } + + void SetStaticHostname(const std::string& hostname, const bool& interactive) + { + proxy_.callMethod("SetStaticHostname").onInterface(INTERFACE_NAME).withArguments(hostname, interactive); + } + + void SetPrettyHostname(const std::string& hostname, const bool& interactive) + { + proxy_.callMethod("SetPrettyHostname").onInterface(INTERFACE_NAME).withArguments(hostname, interactive); + } + + void SetIconName(const std::string& icon, const bool& interactive) + { + proxy_.callMethod("SetIconName").onInterface(INTERFACE_NAME).withArguments(icon, interactive); + } + + void SetChassis(const std::string& chassis, const bool& interactive) + { + proxy_.callMethod("SetChassis").onInterface(INTERFACE_NAME).withArguments(chassis, interactive); + } + + void SetDeployment(const std::string& deployment, const bool& interactive) + { + proxy_.callMethod("SetDeployment").onInterface(INTERFACE_NAME).withArguments(deployment, interactive); + } + + void SetLocation(const std::string& location, const bool& interactive) + { + proxy_.callMethod("SetLocation").onInterface(INTERFACE_NAME).withArguments(location, interactive); + } + + std::vector GetProductUUID(const bool& interactive) + { + std::vector result; + proxy_.callMethod("GetProductUUID").onInterface(INTERFACE_NAME).withArguments(interactive).storeResultsTo(result); + return result; + } + + std::string GetHardwareSerial() + { + std::string result; + proxy_.callMethod("GetHardwareSerial").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::string Describe() + { + std::string result; + proxy_.callMethod("Describe").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + +public: + std::string Hostname() + { + return proxy_.getProperty("Hostname").onInterface(INTERFACE_NAME); + } + + std::string StaticHostname() + { + return proxy_.getProperty("StaticHostname").onInterface(INTERFACE_NAME); + } + + std::string PrettyHostname() + { + return proxy_.getProperty("PrettyHostname").onInterface(INTERFACE_NAME); + } + + std::string DefaultHostname() + { + return proxy_.getProperty("DefaultHostname").onInterface(INTERFACE_NAME); + } + + std::string HostnameSource() + { + return proxy_.getProperty("HostnameSource").onInterface(INTERFACE_NAME); + } + + std::string IconName() + { + return proxy_.getProperty("IconName").onInterface(INTERFACE_NAME); + } + + std::string Chassis() + { + return proxy_.getProperty("Chassis").onInterface(INTERFACE_NAME); + } + + std::string Deployment() + { + return proxy_.getProperty("Deployment").onInterface(INTERFACE_NAME); + } + + std::string Location() + { + return proxy_.getProperty("Location").onInterface(INTERFACE_NAME); + } + + std::string KernelName() + { + return proxy_.getProperty("KernelName").onInterface(INTERFACE_NAME); + } + + std::string KernelRelease() + { + return proxy_.getProperty("KernelRelease").onInterface(INTERFACE_NAME); + } + + std::string KernelVersion() + { + return proxy_.getProperty("KernelVersion").onInterface(INTERFACE_NAME); + } + + std::string OperatingSystemPrettyName() + { + return proxy_.getProperty("OperatingSystemPrettyName").onInterface(INTERFACE_NAME); + } + + std::string OperatingSystemCPEName() + { + return proxy_.getProperty("OperatingSystemCPEName").onInterface(INTERFACE_NAME); + } + + uint64_t OperatingSystemSupportEnd() + { + return proxy_.getProperty("OperatingSystemSupportEnd").onInterface(INTERFACE_NAME); + } + + std::string HomeURL() + { + return proxy_.getProperty("HomeURL").onInterface(INTERFACE_NAME); + } + + std::string HardwareVendor() + { + return proxy_.getProperty("HardwareVendor").onInterface(INTERFACE_NAME); + } + + std::string HardwareModel() + { + return proxy_.getProperty("HardwareModel").onInterface(INTERFACE_NAME); + } + + std::string FirmwareVersion() + { + return proxy_.getProperty("FirmwareVersion").onInterface(INTERFACE_NAME); + } + + std::string FirmwareVendor() + { + return proxy_.getProperty("FirmwareVendor").onInterface(INTERFACE_NAME); + } + + uint64_t FirmwareDate() + { + return proxy_.getProperty("FirmwareDate").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/login_session_client_glue.h b/internal/platform/implementation/linux/login_session_client_glue.h new file mode 100644 index 00000000..77cd9e97 --- /dev/null +++ b/internal/platform/implementation/linux/login_session_client_glue.h @@ -0,0 +1,254 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__login_session_client_glue_h__proxy__H__ +#define __sdbuscpp__login_session_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace login1 { + +class Session_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.login1.Session"; + +protected: + Session_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("PauseDevice").onInterface(INTERFACE_NAME).call([this](const uint32_t& major, const uint32_t& minor, const std::string& type){ this->onPauseDevice(major, minor, type); }); + proxy_.uponSignal("ResumeDevice").onInterface(INTERFACE_NAME).call([this](const uint32_t& major, const uint32_t& minor, const sdbus::UnixFd& fd){ this->onResumeDevice(major, minor, fd); }); + proxy_.uponSignal("Lock").onInterface(INTERFACE_NAME).call([this](){ this->onLock(); }); + proxy_.uponSignal("Unlock").onInterface(INTERFACE_NAME).call([this](){ this->onUnlock(); }); + } + + ~Session_proxy() = default; + + virtual void onPauseDevice(const uint32_t& major, const uint32_t& minor, const std::string& type) = 0; + virtual void onResumeDevice(const uint32_t& major, const uint32_t& minor, const sdbus::UnixFd& fd) = 0; + virtual void onLock() = 0; + virtual void onUnlock() = 0; + +public: + void Terminate() + { + proxy_.callMethod("Terminate").onInterface(INTERFACE_NAME); + } + + void Activate() + { + proxy_.callMethod("Activate").onInterface(INTERFACE_NAME); + } + + void Lock() + { + proxy_.callMethod("Lock").onInterface(INTERFACE_NAME); + } + + void Unlock() + { + proxy_.callMethod("Unlock").onInterface(INTERFACE_NAME); + } + + void SetIdleHint(const bool& idle) + { + proxy_.callMethod("SetIdleHint").onInterface(INTERFACE_NAME).withArguments(idle); + } + + void SetLockedHint(const bool& locked) + { + proxy_.callMethod("SetLockedHint").onInterface(INTERFACE_NAME).withArguments(locked); + } + + void Kill(const std::string& who, const int32_t& signal_number) + { + proxy_.callMethod("Kill").onInterface(INTERFACE_NAME).withArguments(who, signal_number); + } + + void TakeControl(const bool& force) + { + proxy_.callMethod("TakeControl").onInterface(INTERFACE_NAME).withArguments(force); + } + + void ReleaseControl() + { + proxy_.callMethod("ReleaseControl").onInterface(INTERFACE_NAME); + } + + void SetType(const std::string& type) + { + proxy_.callMethod("SetType").onInterface(INTERFACE_NAME).withArguments(type); + } + + void SetDisplay(const std::string& display) + { + proxy_.callMethod("SetDisplay").onInterface(INTERFACE_NAME).withArguments(display); + } + + void SetTTY(const sdbus::UnixFd& tty_fd) + { + proxy_.callMethod("SetTTY").onInterface(INTERFACE_NAME).withArguments(tty_fd); + } + + std::tuple TakeDevice(const uint32_t& major, const uint32_t& minor) + { + std::tuple result; + proxy_.callMethod("TakeDevice").onInterface(INTERFACE_NAME).withArguments(major, minor).storeResultsTo(result); + return result; + } + + void ReleaseDevice(const uint32_t& major, const uint32_t& minor) + { + proxy_.callMethod("ReleaseDevice").onInterface(INTERFACE_NAME).withArguments(major, minor); + } + + void PauseDeviceComplete(const uint32_t& major, const uint32_t& minor) + { + proxy_.callMethod("PauseDeviceComplete").onInterface(INTERFACE_NAME).withArguments(major, minor); + } + + void SetBrightness(const std::string& subsystem, const std::string& name, const uint32_t& brightness) + { + proxy_.callMethod("SetBrightness").onInterface(INTERFACE_NAME).withArguments(subsystem, name, brightness); + } + +public: + std::string Id() + { + return proxy_.getProperty("Id").onInterface(INTERFACE_NAME); + } + + sdbus::Struct User() + { + return proxy_.getProperty("User").onInterface(INTERFACE_NAME); + } + + std::string Name() + { + return proxy_.getProperty("Name").onInterface(INTERFACE_NAME); + } + + uint64_t Timestamp() + { + return proxy_.getProperty("Timestamp").onInterface(INTERFACE_NAME); + } + + uint64_t TimestampMonotonic() + { + return proxy_.getProperty("TimestampMonotonic").onInterface(INTERFACE_NAME); + } + + uint32_t VTNr() + { + return proxy_.getProperty("VTNr").onInterface(INTERFACE_NAME); + } + + sdbus::Struct Seat() + { + return proxy_.getProperty("Seat").onInterface(INTERFACE_NAME); + } + + std::string TTY() + { + return proxy_.getProperty("TTY").onInterface(INTERFACE_NAME); + } + + std::string Display() + { + return proxy_.getProperty("Display").onInterface(INTERFACE_NAME); + } + + bool Remote() + { + return proxy_.getProperty("Remote").onInterface(INTERFACE_NAME); + } + + std::string RemoteHost() + { + return proxy_.getProperty("RemoteHost").onInterface(INTERFACE_NAME); + } + + std::string RemoteUser() + { + return proxy_.getProperty("RemoteUser").onInterface(INTERFACE_NAME); + } + + std::string Service() + { + return proxy_.getProperty("Service").onInterface(INTERFACE_NAME); + } + + std::string Desktop() + { + return proxy_.getProperty("Desktop").onInterface(INTERFACE_NAME); + } + + std::string Scope() + { + return proxy_.getProperty("Scope").onInterface(INTERFACE_NAME); + } + + uint32_t Leader() + { + return proxy_.getProperty("Leader").onInterface(INTERFACE_NAME); + } + + uint32_t Audit() + { + return proxy_.getProperty("Audit").onInterface(INTERFACE_NAME); + } + + std::string Type() + { + return proxy_.getProperty("Type").onInterface(INTERFACE_NAME); + } + + std::string Class() + { + return proxy_.getProperty("Class").onInterface(INTERFACE_NAME); + } + + bool Active() + { + return proxy_.getProperty("Active").onInterface(INTERFACE_NAME); + } + + std::string State() + { + return proxy_.getProperty("State").onInterface(INTERFACE_NAME); + } + + bool IdleHint() + { + return proxy_.getProperty("IdleHint").onInterface(INTERFACE_NAME); + } + + uint64_t IdleSinceHint() + { + return proxy_.getProperty("IdleSinceHint").onInterface(INTERFACE_NAME); + } + + uint64_t IdleSinceHintMonotonic() + { + return proxy_.getProperty("IdleSinceHintMonotonic").onInterface(INTERFACE_NAME); + } + + bool LockedHint() + { + return proxy_.getProperty("LockedHint").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/org.freedesktop.hostname1.xml b/internal/platform/implementation/linux/org.freedesktop.hostname1.xml new file mode 100644 index 00000000..822e99b2 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.hostname1.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/org.freedesktop.login1.Session.xml b/internal/platform/implementation/linux/org.freedesktop.login1.Session.xml new file mode 100644 index 00000000..dbad22f3 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.login1.Session.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1b703351849ee9137c83e7d994aeea2497a49ad8 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 26 Aug 2023 16:46:25 +0530 Subject: [PATCH 036/201] Implement remaining platform methods. --- .../platform/implementation/linux/platform.cc | 169 +++++++++++++++++- 1 file changed, 160 insertions(+), 9 deletions(-) diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 30335c3c..b1d2c45c 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -1,12 +1,18 @@ #include #include -#include -#include #include +#include +#include +#include + +#include "device_info.h" #include "internal/platform/implementation/atomic_boolean.h" #include "internal/platform/implementation/atomic_reference.h" +#include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/count_down_latch.h" +#include "internal/platform/implementation/http_loader.h" +#include "internal/platform/implementation/input_file.h" #include "internal/platform/implementation/linux/atomic_boolean.h" #include "internal/platform/implementation/linux/atomic_uint32.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" @@ -16,15 +22,20 @@ #include "internal/platform/implementation/linux/condition_variable.h" #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/mutex.h" -#include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" +#include "internal/platform/implementation/linux/submittable_executor.h" +#include "internal/platform/implementation/linux/timer.h" #include "internal/platform/implementation/linux/wifi_hotspot.h" #include "internal/platform/implementation/linux/wifi_lan.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/platform.h" #include "internal/platform/implementation/shared/count_down_latch.h" +#include "internal/platform/implementation/shared/file.h" +#include "internal/platform/implementation/submittable_executor.h" #include "internal/platform/implementation/wifi_hotspot.h" #include "internal/platform/implementation/wifi_lan.h" +#include "internal/platform/payload_id.h" #include "log_message.h" +#include "scheduled_executor.h" namespace nearby { namespace api { @@ -84,12 +95,59 @@ ImplementationPlatform::CreateConditionVariable(api::Mutex *mutex) { return std::make_unique(mutex); } +std::unique_ptr +ImplementationPlatform::CreateInputFile(PayloadId id, std::int64_t total_size) { + auto path = GetDownloadPath(std::to_string(id)); + return nearby::shared::IOFile::CreateInputFile(path, total_size); +} + +std::unique_ptr +ImplementationPlatform::CreateInputFile(const std::string &file_path, + size_t size) { + return nearby::shared::IOFile::CreateInputFile(file_path, size); +} + +std::unique_ptr +ImplementationPlatform::CreateOutputFile(PayloadId payload_id) { + return nearby::shared::IOFile::CreateOutputFile( + GetDownloadPath("", std::to_string(payload_id))); +} + +std::unique_ptr +ImplementationPlatform::CreateOutputFile(const std::string &file_path) { + std::filesystem::path path(file_path); + try { + std::filesystem::create_directories(path.parent_path()); + } catch (std::filesystem::filesystem_error const &err) { + NEARBY_LOGS(ERROR) << __func__ << ": error creating directory tree " + << path.parent_path() << ": " << err.what(); + } + + return nearby::shared::IOFile::CreateOutputFile(path.string()); +} + std::unique_ptr ImplementationPlatform::CreateLogMessage(const char *file, int line, LogMessage::Severity severity) { return std::make_unique(file, line, severity); } +std::unique_ptr +ImplementationPlatform::CreateSingleThreadExecutor() { + return std::make_unique(); +} + +std::unique_ptr +ImplementationPlatform::CreateMultiThreadExecutor( + std::int32_t max_concurrency) { + return std::make_unique(max_concurrency); +} + +std::unique_ptr +ImplementationPlatform::CreateScheduledExecutor() { + return std::make_unique(); +} + std::unique_ptr ImplementationPlatform::CreateBluetoothAdapter() { auto manager = @@ -98,10 +156,9 @@ ImplementationPlatform::CreateBluetoothAdapter() { auto interfaces = manager.GetManagedObjects(); for (auto &[object, properties] : interfaces) { if (properties.count(org::bluez::Adapter1_proxy::INTERFACE_NAME) == 1) { - NEARBY_LOGS(INFO) - << __func__ << ": found bluetooth adapter " << object; - return std::make_unique( - linux::getSystemBusConnection(), object); + NEARBY_LOGS(INFO) << __func__ << ": found bluetooth adapter " << object; + return std::make_unique( + linux::getSystemBusConnection(), object); } } } catch (const sdbus::Error &e) { @@ -121,6 +178,16 @@ ImplementationPlatform::CreateBluetoothClassicMedium( linux::getSystemBusConnection(), path); } +std::unique_ptr +ImplementationPlatform::CreateBleMedium(BluetoothAdapter &) { + return nullptr; +} + +std::unique_ptr +ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { + return nullptr; +} + static std::unique_ptr createWifiMedium(std::shared_ptr nm) { std::vector device_paths; @@ -152,7 +219,8 @@ createWifiMedium(std::shared_ptr nm) { Wireless_proxy::INTERFACE_NAME) == 1) { NEARBY_LOGS(INFO) << __func__ << ": Found a wireless device at :" << device_path; - return std::make_unique(nm, linux::getSystemBusConnection(), device_path); + return std::make_unique( + nm, linux::getSystemBusConnection(), device_path); } } } @@ -168,7 +236,8 @@ std::unique_ptr ImplementationPlatform::CreateWifiMedium() { return createWifiMedium(nm); } -std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { +std::unique_ptr +ImplementationPlatform::CreateWifiLanMedium() { return std::make_unique( linux::getSystemBusConnection()); } @@ -188,5 +257,87 @@ ImplementationPlatform::CreateWifiHotspotMedium() { linux::getSystemBusConnection(), nm, std::move(wifiMedium)); } +std::unique_ptr +ImplementationPlatform::CreateWifiDirectMedium() { + return nullptr; +} + +std::unique_ptr ImplementationPlatform::CreateTimer() { + return std::make_unique(); +} + +std::unique_ptr ImplementationPlatform::CreateDeviceInfo() { + return std::make_unique(linux::getSystemBusConnection()); +} + +absl::StatusOr +ImplementationPlatform::SendRequest(const WebRequest &request) { + if (request.body.size() >= (8 * 1024 * 1024)) { + return absl::Status(absl::StatusCode::kResourceExhausted, + "request body too large"); + } + + CURL *handle = curl_easy_init(); + char errbuf[CURL_ERROR_SIZE]; + errbuf[0] = '\0'; + + curl_easy_setopt(handle, CURLOPT_URL, request.url.c_str()); + curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errbuf); + + if (request.method == "GET") + curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L); + else if (request.method == "POST") + curl_easy_setopt(handle, CURLOPT_HTTPPOST, 1L); + else + curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, request.method.c_str()); + + curl_easy_setopt(handle, CURLOPT_UPLOAD, request.body.c_str()); + + struct curl_slist *headers_slist = nullptr; + + for (auto &[key, value] : request.headers) { + auto hdr = absl::StrCat(key, ": ", value); + auto temp = curl_slist_append(headers_slist, hdr.c_str()); + if (temp == nullptr) { + if (headers_slist != nullptr) { + curl_slist_free_all(headers_slist); + } + return absl::Status(absl::StatusCode::kResourceExhausted, + "failed to append header to slist"); + } + } + + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers_slist); + + api::WebResponse response; + + if (curl_easy_perform(handle) != CURLE_OK) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error performing HTTP request: " << errbuf; + return absl::Status(absl::StatusCode::kUnknown, errbuf); + } + + struct curl_header *prev = nullptr; + struct curl_header *h; + + h = curl_easy_nextheader(handle, CURLH_HEADER, 0, prev); + while (h != nullptr) { + response.headers.emplace(h->name, h->value); + } + + auto writefn = [](char *ptr, size_t size, size_t nmemb, void *userdata) { + std::string *body = static_cast(userdata); + body->append(ptr, size * nmemb); + }; + + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writefn); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, + static_cast(&response.body)); + long status; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &status); + response.status_code = status; + return response; +} + } // namespace api } // namespace nearby From 2a05ca9620a792c4913ed606a13c9a956a0dbf79 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 26 Aug 2023 21:49:42 +0530 Subject: [PATCH 037/201] Add additional files. --- internal/platform/implementation/linux/BUILD | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 08a2b54a..46d9e8ca 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -5,6 +5,17 @@ cc_library( hdrs = [ "atomic_boolean.h", "device_info.h", + "atomic_reference.h", + "bluetooth_adapter.h", + "condition_variable.h", + "device_info.h", + "executor.h", + "future.h", + "mutex.h", + "preferences_manager.h", + "scheduled_executor.h", + "submittable_executor.h", + "timer.h", ], srcs = [ "device_info.cc", @@ -98,12 +109,29 @@ cc_library( cc_library( name = "linux", srcs = [ + "avahi.cc", "bluetooth_adapter.cc", "bluetooth_bluez_profile.cc", "bluetooth_classic_device.cc", "bluetooth_classic_medium.cc", "bluetooth_classic_socket.cc", "bluetooth_pairing.cc", + "bluez.cc", + "dbus.cc", + "executor.cc", + "platform.cc", + "preferences_manager.cc", + "preferences_repository.cc", + "scheduled_executor.cc", + "submittable_executor.cc", + "system_clock.cc", + "thread_pool.cc", + "utils.cc", + "wifi_hotspot.cc", + "wifi_hotspot_server_socket.cc", + "wifi_lan.cc", + "wifi_lan_server_socket.cc", + "wifi_medium.cc", ], visibility = [ "//connections:__subpackages__", From b5403f443a20141574e7a6502aef6ac7cbaa4936 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 00:17:56 +0530 Subject: [PATCH 038/201] Add ConnectedToWifi. --- .../platform/implementation/linux/wifi_hotspot.cc | 14 ++++++++++++-- .../platform/implementation/linux/wifi_hotspot.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 3d4ce648..f448dd92 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -269,8 +269,8 @@ bool NetworkManagerWifiHotspotMedium::ConnectWifiHotspot( } bool NetworkManagerWifiHotspotMedium::DisconnectWifiHotspot() { - if (!WifiHotspotActive()) { - NEARBY_LOGS(ERROR) << __func__ << ": WiFi hotspot is not active"; + if (!ConnectedToWifi()) { + NEARBY_LOGS(ERROR) << __func__ << ": Not connected to a WiFi hotspot"; return false; } @@ -299,5 +299,15 @@ bool NetworkManagerWifiHotspotMedium::WifiHotspotActive() { } } +bool NetworkManagerWifiHotspotMedium::ConnectedToWifi() { + try { + auto mode = wireless_device_->Mode(); + return mode == 2; // NM_802_11_MODE_INFRA + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e); + return false; + } +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot.h b/internal/platform/implementation/linux/wifi_hotspot.h index ec0af3bb..18daf48f 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.h +++ b/internal/platform/implementation/linux/wifi_hotspot.h @@ -47,6 +47,7 @@ public: private: bool WifiHotspotActive(); + bool ConnectedToWifi(); sdbus::IConnection &system_bus_; std::unique_ptr wireless_device_; From 0df941c5604105665a2493e5362f970f40b7ad35 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 00:32:55 +0530 Subject: [PATCH 039/201] Add Wifi Direct medium --- .../platform/implementation/linux/platform.cc | 14 +- .../implementation/linux/wifi_direct.cc | 160 ++++++++++++++++++ .../implementation/linux/wifi_direct.h | 48 ++++++ .../linux/wifi_direct_server_socket.cc | 66 ++++++++ .../linux/wifi_direct_server_socket.h | 30 ++++ .../implementation/linux/wifi_direct_socket.h | 28 +++ 6 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 internal/platform/implementation/linux/wifi_direct.cc create mode 100644 internal/platform/implementation/linux/wifi_direct.h create mode 100644 internal/platform/implementation/linux/wifi_direct_server_socket.cc create mode 100644 internal/platform/implementation/linux/wifi_direct_server_socket.h create mode 100644 internal/platform/implementation/linux/wifi_direct_socket.h diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index b1d2c45c..f40831a5 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -24,6 +24,7 @@ #include "internal/platform/implementation/linux/mutex.h" #include "internal/platform/implementation/linux/submittable_executor.h" #include "internal/platform/implementation/linux/timer.h" +#include "internal/platform/implementation/linux/wifi_direct.h" #include "internal/platform/implementation/linux/wifi_hotspot.h" #include "internal/platform/implementation/linux/wifi_lan.h" #include "internal/platform/implementation/linux/wifi_medium.h" @@ -163,6 +164,7 @@ ImplementationPlatform::CreateBluetoothAdapter() { } } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(&manager, "GetManagedObjects", e); + return nullptr; } NEARBY_LOGS(ERROR) << __func__ @@ -259,7 +261,17 @@ ImplementationPlatform::CreateWifiHotspotMedium() { std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { - return nullptr; + auto nm = + std::make_shared(linux::getSystemBusConnection()); + auto wifiMedium = createWifiMedium(nm); + + if (wifiMedium == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": Could not create a WiFi medium"; + return nullptr; + } + + return std::make_unique( + linux::getSystemBusConnection(), nm, std::move(wifiMedium)); } std::unique_ptr ImplementationPlatform::CreateTimer() { diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc new file mode 100644 index 00000000..2e7884c0 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -0,0 +1,160 @@ +#include +#include +#include +#include + +#include "internal/platform/implementation/linux/wifi_direct.h" +#include "internal/platform/implementation/linux/wifi_direct_server_socket.h" +#include "internal/platform/implementation/linux/wifi_direct_socket.h" +#include "internal/platform/implementation/linux/wifi_hotspot.h" +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi_direct.h" +#include "internal/platform/wifi_credential.h" + +namespace nearby { +namespace linux { +std::unique_ptr +NetworkManagerWifiDirectMedium::ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return nullptr; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" + << port; + struct sockaddr_in addr; + addr.sin_addr.s_addr = inet_addr(std::string(ip_address).c_str()); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + auto ret = + connect(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " + << std::strerror(errno); + return nullptr; + } + + return std::make_unique(sock); +} + +std::unique_ptr +NetworkManagerWifiDirectMedium::ListenForService(int port) { + auto active_connection = wireless_device_->GetActiveConnection(); + if (active_connection == nullptr) { + return nullptr; + } + + auto ip4addresses = active_connection->GetIP4Addresses(); + if (ip4addresses.empty()) { + NEARBY_LOGS(ERROR) + << __func__ + << "Could not find any IPv4 addresses for active connection " + << active_connection->getObjectPath(); + return nullptr; + } + + auto sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return nullptr; + } + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(ip4addresses[0].c_str()); + addr.sin_port = htons(port); + + auto ret = + bind(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error binding to socket: " << std::strerror(errno); + return nullptr; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": Listening for services on " + << ip4addresses[0] << ":" << port << " on device " + << wireless_device_->getObjectPath(); + + ret = listen(sock, 0); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " + << std::strerror(errno); + return nullptr; + } + + return std::make_unique( + sock, system_bus_, active_connection->getObjectPath(), network_manager_); +} + +bool NetworkManagerWifiDirectMedium::ConnectWifiDirect( + WifiDirectCredentials *wifi_direct_credentials) { + if (wifi_direct_credentials == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": hotspot_credentials cannot be null"; + return false; + } + + auto ssid = wifi_direct_credentials->GetSSID(); + auto password = wifi_direct_credentials->GetPassword(); + + return wireless_device_->ConnectToNetwork(ssid, password, + api::WifiAuthType::kWpaPsk) == + api::WifiConnectionStatus::kConnected; +} + +bool NetworkManagerWifiDirectMedium::DisconnectWifiDirect() { + if (!ConnectedToWifi()) { + NEARBY_LOGS(ERROR) << __func__ << ": Not connected to a WiFi hotspot"; + return false; + } + + auto active_connection = wireless_device_->GetActiveConnection(); + if (active_connection == nullptr) { + return false; + } + + try { + network_manager_->DeactivateConnection(active_connection->getObjectPath()); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "DeactivateConnection", e); + return false; + } + + return true; +} + +bool NetworkManagerWifiDirectMedium::StartWifiDirect( + WifiDirectCredentials *wifi_direct_credentials) { + // According to the comments in the windows implementation, the wifi direct + // medium is currently just a regular wifi hotspot. + auto wireless_device = std::make_unique( + network_manager_, system_bus_, wireless_device_->getObjectPath()); + auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, + std::move(wireless_device)); + + HotspotCredentials hotspot_creds; + if (!hotspot.StartWifiHotspot(&hotspot_creds)) + return false; + + wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID()); + wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword()); + return true; +} + +bool NetworkManagerWifiDirectMedium::StopWifiDirect() { + auto wireless_device = std::make_unique( + network_manager_, system_bus_, wireless_device_->getObjectPath()); + auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, + std::move(wireless_device)); + + return hotspot.DisconnectWifiHotspot(); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_direct.h b/internal/platform/implementation/linux/wifi_direct.h new file mode 100644 index 00000000..4c038c3e --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct.h @@ -0,0 +1,48 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_DIRECT_H_ +#define PLATFORM_IMPL_LINUX_WIFI_DIRECT_H_ +#include + +#include +#include + +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi_direct.h" + +namespace nearby { +namespace linux { +class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium { +public: + NetworkManagerWifiDirectMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + std::unique_ptr wireless_device) + : system_bus_(system_bus), network_manager_(network_manager), + wireless_device_(std::move(wireless_device)) {} + ~NetworkManagerWifiDirectMedium() {} + + bool IsInterfaceValid() const override { return true; } + std::unique_ptr + ConnectToService(absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr + ListenForService(int port) override; + bool + ConnectWifiDirect(WifiDirectCredentials *wifi_direct_credentials) override; + bool DisconnectWifiDirect() override; + + bool StartWifiDirect(WifiDirectCredentials *wifi_direct_credentials) override; + bool StopWifiDirect() override; + + absl::optional> + GetDynamicPortRange() override { + return std::nullopt; + } + + sdbus::IConnection &system_bus_; + std::shared_ptr network_manager_; + std::unique_ptr wireless_device_; +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.cc b/internal/platform/implementation/linux/wifi_direct_server_socket.cc new file mode 100644 index 00000000..65f4de96 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.cc @@ -0,0 +1,66 @@ +#include "internal/platform/implementation/linux/wifi_direct_server_socket.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/wifi_direct_socket.h" +#include +#include + +namespace nearby { +namespace linux { +std::string NetworkManagerWifiDirectServerSocket::GetIPAddress() const { + NetworkManagerActiveConnection active_conn(system_bus_, + active_connection_path_); + auto ip4addresses = active_conn.GetIP4Addresses(); + if (ip4addresses.empty()) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Could not find any IPv4 addresses for active connection " + << active_connection_path_; + return std::string(); + } + return ip4addresses[0]; +} + +int NetworkManagerWifiDirectServerSocket::GetPort() const { + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + auto ret = + getsockname(fd_.get(), reinterpret_cast(&sin), &len); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error getting information for socket " + << fd_.get() << ": " << std::strerror(errno); + return 0; + } + + return ntohs(sin.sin_port); +} + +std::unique_ptr +NetworkManagerWifiDirectServerSocket::Accept() { + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + + auto conn = + accept(fd_.get(), reinterpret_cast(&addr), &len); + if (conn < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error accepting incoming connections on socket " + << fd_.get() << ": " << std::strerror(errno); + return nullptr; + } + + return std::make_unique(conn); +} + +Exception NetworkManagerWifiDirectServerSocket::Close() { + int fd = fd_.release(); + auto ret = close(fd); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " + << std::strerror(errno); + return {Exception::kFailed}; + } + + return {Exception::kSuccess}; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.h b/internal/platform/implementation/linux/wifi_direct_server_socket.h new file mode 100644 index 00000000..713f5e07 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.h @@ -0,0 +1,30 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_DIRECT_SERVER_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_DIRECT_SERVER_SOCKET_H_ + +#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/wifi_direct.h" +#include +namespace nearby { + namespace linux { + class NetworkManagerWifiDirectServerSocket + : public api::WifiDirectServerSocket { +public: + NetworkManagerWifiDirectServerSocket(int socket, sdbus::IConnection &system_bus, + const sdbus::ObjectPath &active_connection_path, + std::shared_ptr network_manager) : fd_(socket), system_bus_(system_bus), active_connection_path_(active_connection_path), network_manager_(network_manager) {} + ~NetworkManagerWifiDirectServerSocket() {} + + std::string GetIPAddress() const override; + int GetPort() const override; + std::unique_ptr Accept() override; + Exception Close() override; +private: + sdbus::UnixFd fd_; + sdbus::IConnection &system_bus_; + sdbus::ObjectPath active_connection_path_; + std::shared_ptr network_manager_ ; + }; + } +} + +#endif diff --git a/internal/platform/implementation/linux/wifi_direct_socket.h b/internal/platform/implementation/linux/wifi_direct_socket.h new file mode 100644 index 00000000..79ec3556 --- /dev/null +++ b/internal/platform/implementation/linux/wifi_direct_socket.h @@ -0,0 +1,28 @@ +#ifndef PLATFORM_IMPL_LINUX_WIFI_DIRECT_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_WIFI_DIRECT_SOCKET_H_ + +#include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/stream.h" +#include "internal/platform/implementation/wifi_direct.h" + +namespace nearby { +namespace linux { +class WifiDirectSocket : public api::WifiDirectSocket { +public: + WifiDirectSocket(int socket); + ~WifiDirectSocket() = default; + + InputStream &GetInputStream() override; + OutputStream &GetOutputStream() override; + + Exception Close() override; + +private: + sdbus::UnixFd fd_; + OutputStream output_stream_; + InputStream input_stream_; +}; +} // namespace linux +} // namespace nearby + +#endif From c4f805b37748048b62688f205d60165b87d589ef Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 00:35:28 +0530 Subject: [PATCH 040/201] Add WifiDirectSocket methods. --- .../implementation/linux/wifi_direct_socket.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_direct_socket.h b/internal/platform/implementation/linux/wifi_direct_socket.h index 79ec3556..932b3257 100644 --- a/internal/platform/implementation/linux/wifi_direct_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_socket.h @@ -9,13 +9,19 @@ namespace nearby { namespace linux { class WifiDirectSocket : public api::WifiDirectSocket { public: - WifiDirectSocket(int socket); + WifiDirectSocket(int socket) + : fd_(sdbus::UnixFd(socket)), output_stream_(fd_), input_stream_(fd_) {} ~WifiDirectSocket() = default; - InputStream &GetInputStream() override; - OutputStream &GetOutputStream() override; + InputStream &GetInputStream() override { return input_stream_; }; + OutputStream &GetOutputStream() override { return output_stream_; }; - Exception Close() override; + Exception Close() override { + input_stream_.Close(); + output_stream_.Close(); + + return Exception{Exception::kSuccess}; + }; private: sdbus::UnixFd fd_; From f5c66fb83ff79913420e0c2fc65b69a3713ff5c5 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 00:35:37 +0530 Subject: [PATCH 041/201] Add Wifi Direct files. --- internal/platform/implementation/linux/BUILD | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 46d9e8ca..044880b6 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -60,6 +60,9 @@ cc_library( "networkmanager_device_wireless_client_glue.h", "networkmanager_ip4config_client_glue.h", "stream.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", @@ -127,6 +130,8 @@ cc_library( "system_clock.cc", "thread_pool.cc", "utils.cc", + "wifi_direct.cc", + "wifi_direct_server_socket.cc", "wifi_hotspot.cc", "wifi_hotspot_server_socket.cc", "wifi_lan.cc", From f2d9e1feeb8af70a72376bae9bf00b9dc307e8bc Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 09:44:13 +0530 Subject: [PATCH 042/201] Add method ConnectedToWifi. --- internal/platform/implementation/linux/wifi_direct.cc | 10 ++++++++++ internal/platform/implementation/linux/wifi_direct.h | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index 2e7884c0..9ff6fde2 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -129,6 +129,16 @@ bool NetworkManagerWifiDirectMedium::DisconnectWifiDirect() { return true; } +bool NetworkManagerWifiDirectMedium::ConnectedToWifi() { + try { + auto mode = wireless_device_->Mode(); + return mode == 2; // NM_802_11_MODE_INFRA + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e); + return false; + } +} + bool NetworkManagerWifiDirectMedium::StartWifiDirect( WifiDirectCredentials *wifi_direct_credentials) { // According to the comments in the windows implementation, the wifi direct diff --git a/internal/platform/implementation/linux/wifi_direct.h b/internal/platform/implementation/linux/wifi_direct.h index 4c038c3e..1346fc60 100644 --- a/internal/platform/implementation/linux/wifi_direct.h +++ b/internal/platform/implementation/linux/wifi_direct.h @@ -11,7 +11,7 @@ namespace nearby { namespace linux { class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium { -public: +public: NetworkManagerWifiDirectMedium( sdbus::IConnection &system_bus, std::shared_ptr network_manager, @@ -32,12 +32,15 @@ public: bool StartWifiDirect(WifiDirectCredentials *wifi_direct_credentials) override; bool StopWifiDirect() override; - + absl::optional> GetDynamicPortRange() override { return std::nullopt; } +private: + bool ConnectedToWifi(); + sdbus::IConnection &system_bus_; std::shared_ptr network_manager_; std::unique_ptr wireless_device_; From de32aec38231481924e26fd15c7acac389348654 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 12:24:02 +0530 Subject: [PATCH 043/201] GetDownloadPathInternal: Construct DeviceInfo correctly. --- internal/platform/implementation/linux/file_path.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/file_path.cc b/internal/platform/implementation/linux/file_path.cc index f66fe6a4..9e31b880 100644 --- a/internal/platform/implementation/linux/file_path.cc +++ b/internal/platform/implementation/linux/file_path.cc @@ -22,6 +22,7 @@ #include #include "absl/strings/str_cat.h" +#include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/utils.h" #include "internal/platform/implementation/linux/device_info.h" #include "internal/platform/logging.h" @@ -50,7 +51,7 @@ std::wstring FilePath::GetDownloadPath(std::wstring parent_folder, std::wstring FilePath::GetDownloadPathInternal(std::wstring parent_folder, std::wstring file_name) { - DeviceInfo info = DeviceInfo(); + DeviceInfo info = DeviceInfo(linux::getSystemBusConnection()); std::optional download_path = info.GetDownloadPath(); From e1139bfba736cf7680a13afa37f009130c016e94 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 12:24:22 +0530 Subject: [PATCH 044/201] GetLocalAppDataPath: Use XDG_CONFIG_HOME. --- internal/platform/implementation/linux/device_info.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index b5ed037e..d3d1c950 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -108,7 +108,7 @@ std::optional DeviceInfo::GetDownloadPath() const { } std::optional DeviceInfo::GetLocalAppDataPath() const { - char *dir = getenv("XDG_STATE_HOME"); + char *dir = getenv("XDG_CONFIG_HOME"); if (dir == NULL) { return std::filesystem::path("/tmp"); } From a931c295d272e282f47b52a7526dde0bd4941254 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 12:24:36 +0530 Subject: [PATCH 045/201] initBusConnections: Start an async event loop after creating connections. --- internal/platform/implementation/linux/dbus.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index b329a8a9..cf3ba938 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -17,8 +17,10 @@ static absl::once_flag bus_connection_init_; static void initBusConnections() { global_system_bus_connection = sdbus::createSystemBusConnection("/com/github/google/nearby"); + global_system_bus_connection->enterEventLoopAsync(); global_default_bus_connection = sdbus::createDefaultBusConnection("/com/github/google/nearby"); + global_default_bus_connection->enterEventLoopAsync(); } sdbus::IConnection &getSystemBusConnection() { From 5379eb4695b078f6cf7376f9c41a61758df2a2df Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 12:25:01 +0530 Subject: [PATCH 046/201] Add CreatePreferencesManager implementation. --- internal/platform/implementation/linux/platform.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index f40831a5..7ac90c14 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -22,6 +22,7 @@ #include "internal/platform/implementation/linux/condition_variable.h" #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/mutex.h" +#include "internal/platform/implementation/linux/preferences_manager.h" #include "internal/platform/implementation/linux/submittable_executor.h" #include "internal/platform/implementation/linux/timer.h" #include "internal/platform/implementation/linux/wifi_direct.h" @@ -351,5 +352,12 @@ ImplementationPlatform::SendRequest(const WebRequest &request) { return response; } +#ifndef NEARBY_CHROMIUM +std::unique_ptr +ImplementationPlatform::CreatePreferencesManager(absl::string_view path) { + return std::make_unique(path); +} +#endif + } // namespace api } // namespace nearby From 24cd7837557f9d738e27c603bdad4a405467d4fc Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 14:06:10 +0530 Subject: [PATCH 047/201] Add missing headers. --- internal/platform/implementation/linux/BUILD | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 044880b6..720b22b2 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -4,8 +4,8 @@ cc_library( name = "types", hdrs = [ "atomic_boolean.h", - "device_info.h", "atomic_reference.h", + "atomic_uint32.h", "bluetooth_adapter.h", "condition_variable.h", "device_info.h", @@ -13,9 +13,17 @@ cc_library( "future.h", "mutex.h", "preferences_manager.h", + "preferences_repository.h", "scheduled_executor.h", "submittable_executor.h", "timer.h", + "timer_queue.h", + "thread_pool.h", + "log_message.h", + "org_freedesktop_logcontrol_server_glue.h", + "hostname_client_glue.h", + "login_session_client_glue.h", + "utils.h", ], srcs = [ "device_info.cc", @@ -50,6 +58,7 @@ cc_library( "bluetooth_pairing.h", "bluez.h", "bluez_adapter_client_glue.h", + "bluez_device_client_glue.h", "bluez_profile_glue.h", "bluez_profile_manager_client_glue.h", "dbus.h", @@ -143,6 +152,7 @@ cc_library( "//fastpair:__subpackages__", "//location/nearby:__subpackages__", "//presence:__subpackages__", + "//third_party/nearby/sharing:__subpackages__", ], deps = [ ":comm", @@ -161,8 +171,6 @@ cc_library( "//internal/platform/implementation:types", "//internal/platform/implementation/shared:count_down_latch", "//internal/platform/implementation/shared:file", - "//third_party/webrtc/files/stable/webrtc/api/task_queue:default_task_queue_factory", - "//third_party/webrtc/files/stable/webrtc/rtc_base:checks", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/functional:any_invocable", @@ -176,6 +184,7 @@ cc_library( "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", "@nlohmann_json//:json", + "@libsystemd//:lib", "@sdbus_cpp//:lib", ], ) From f50abe167783541b6c1036d5d9b848dbd4a3794c Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 14:06:50 +0530 Subject: [PATCH 048/201] Fix compilation errors. --- .../implementation/linux/log_message.cc | 10 ++++---- .../implementation/linux/log_message.h | 13 +++++------ .../platform/implementation/linux/platform.cc | 2 +- .../implementation/linux/wifi_hotspot.cc | 23 ++++++++++++------- .../platform/implementation/linux/wifi_lan.cc | 6 +++-- .../implementation/linux/wifi_medium.cc | 10 +++++--- .../implementation/linux/wifi_medium.h | 5 ++-- 7 files changed, 42 insertions(+), 27 deletions(-) diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index f2825d92..3fc10a47 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -17,7 +18,7 @@ namespace nearby { static std::unique_ptr global_log_control_; static absl::once_flag log_control_init_; -static void init_log_control() { +static void init_log_control(std::nullptr_t) { global_log_control_ = std::make_unique(linux::getDefaultBusConnection()); } @@ -79,15 +80,16 @@ void LogControl::send(google::LogSeverity severity, const char *full_filename, static inline google::LogSeverity ConvertSeverity(api::LogMessage::Severity severity) { switch (severity) { - case api::LogMessage::Severity::kVerbose: - case api::LogMessage::Severity::kInfo: - return google::GLOG_INFO; case api::LogMessage::Severity::kWarning: return google::GLOG_WARNING; case api::LogMessage::Severity::kError: return google::GLOG_ERROR; case api::LogMessage::Severity::kFatal: return google::GLOG_FATAL; + case api::LogMessage::Severity::kVerbose: + case api::LogMessage::Severity::kInfo: + default: + return google::GLOG_INFO; } } diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h index 56093a64..f4cbd5f8 100644 --- a/internal/platform/implementation/linux/log_message.h +++ b/internal/platform/implementation/linux/log_message.h @@ -45,19 +45,17 @@ public: protected: std::string LogLevel() override { switch (severity_) { - case api::LogMessage::Severity::kVerbose: - return "debug"; - break; case api::LogMessage::Severity::kInfo: return "info"; - break; case api::LogMessage::Severity::kWarning: return "warning"; - break; case api::LogMessage::Severity::kError: return "err"; case api::LogMessage::Severity::kFatal: return "emerg"; + case api::LogMessage::Severity::kVerbose: + default: + return "debug"; } } @@ -78,14 +76,15 @@ protected: std::string LogTarget() override { switch (log_target_) { - case kConsole: - return "console"; case kKernel: return "kmsg"; case kJournal: return "journal"; case kSyslog: return "syslog"; + case kConsole: + default: + return "console"; } } diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 7ac90c14..8f8c24cc 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -300,7 +300,7 @@ ImplementationPlatform::SendRequest(const WebRequest &request) { if (request.method == "GET") curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L); else if (request.method == "POST") - curl_easy_setopt(handle, CURLOPT_HTTPPOST, 1L); + curl_easy_setopt(handle, CURLOPT_POST, 1L); else curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, request.method.c_str()); diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index f448dd92..4640db2b 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -72,7 +72,7 @@ NetworkManagerWifiHotspotMedium::ListenForService(int port) { NEARBY_LOGS(ERROR) << __func__ << "Could not find any IPv4 addresses for active connection " - << active_connection->getObjectPath(); + << active_connection->getObjectPath(); return nullptr; } @@ -106,9 +106,9 @@ NetworkManagerWifiHotspotMedium::ListenForService(int port) { << std::strerror(errno); return nullptr; } - - return std::make_unique(sock, - system_bus_, active_connection->getObjectPath(), network_manager_); + + return std::make_unique( + sock, system_bus_, active_connection->getObjectPath(), network_manager_); } bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( @@ -126,7 +126,11 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( << std::strerror(ret); return false; } - std::string ssid = absl::StrCat("DIRECT-", SD_ID128_TO_STRING(id)); + + char id_cstr[SD_ID128_STRING_MAX]; + sd_id128_to_string(id, id_cstr); + + std::string ssid = absl::StrCat("DIRECT-", id_cstr); ssid.resize(32); hotspot_credentials->SetSSID(ssid); @@ -135,7 +139,9 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( << std::strerror(ret); return false; } - std::string password = std::string(SD_ID128_TO_STRING(id), 15); + + sd_id128_to_string(id, id_cstr); + std::string password = std::string(id_cstr, 15); hotspot_credentials->SetPassword(password); if (auto ret = sd_id128_randomize(&id); ret < 0) { @@ -143,6 +149,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( << std::strerror(ret); return false; } + sd_id128_to_string(id, id_cstr); std::vector ssid_bytes(ssid.begin(), ssid.end()); std::map> @@ -150,7 +157,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( { "connection", std::map{ - {"uuid", SD_ID128_TO_UUID_STRING(id)}, + {"uuid", std::string(id_cstr)}, {"id", "Google Nearby Hotspot"}, {"type", "802-11-wireless"}, {"zone", "Public"}}, @@ -171,7 +178,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( }, {"proto", std::vector{"rsn"}}, {"psk", password}}}, - {"ipv4", std::map{"method", "shared"}}, + {"ipv4", std::map{{"method", "shared"}}}, {"ipv6", std::map{ {"addr-gen-mode", static_cast(1)}, {"method", "shared"}, diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 079772dc..d5d90e26 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -135,8 +135,10 @@ bool WifiLanMedium::StartDiscovery( << __func__ << ": Created a new org.freedesktop.Avahi.ServiceBrowser object at " << browser_object_path; - service_browsers_.emplace(service_type, system_bus_, browser_object_path, - std::move(callback)); + service_browsers_.emplace( + service_type, + std::make_unique( + system_bus_, browser_object_path, std::move(callback))); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(avahi_, "ServiceBrowserPrepare", e); return false; diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index b79fb7a9..bc111e74 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -330,12 +330,16 @@ NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid, { sd_id128_t id; + char id_cstr[SD_ID128_UUID_STRING_MAX]; + if (auto ret = sd_id128_randomize(&id); ret < 0) { NEARBY_LOGS(ERROR) << __func__ << ": could not generation a connection UUID"; return api::WifiConnectionStatus::kUnknown; } - connection_id = SD_ID128_TO_UUID_STRING(id); + + sd_id128_to_uuid_string(id, id_cstr); + connection_id = std::string(id_cstr); } auto [auth_alg, key_mgmt] = AuthAlgAndKeyMgmt(auth_type); @@ -346,7 +350,7 @@ NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid, std::map{ {"uuid", connection_id}, {"autoconnect", true}, - {"id", ssid}, + {"id", std::string(ssid)}, {"type", "802-11-wireless"}, {"zone", "Public"}, }}, @@ -438,7 +442,7 @@ NetworkManagerWifiMedium::GetActiveConnection() { auto object_manager = NetworkManagerObjectManager(getProxy().getConnection()); auto conn = object_manager.GetActiveConnectionForAccessPoint(active_ap_path, getObjectPath()); - + if (conn == nullptr) { NEARBY_LOGS(ERROR) << __func__ diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index b9aa318f..e8ffcbdf 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -282,8 +282,9 @@ protected: ABSL_LOCKS_EXCLUDED(known_access_points_lock_) { absl::MutexLock l(&known_access_points_lock_); known_access_points_.erase(access_point); - known_access_points_.emplace(access_point, getProxy().getConnection(), - access_point); + known_access_points_.emplace(access_point, + std::make_unique( + getProxy().getConnection(), access_point)); } void onAccessPointRemoved(const sdbus::ObjectPath &access_point) override ABSL_LOCKS_EXCLUDED(known_access_points_lock_) { From e63c5087f97f3b211f0e935765b332f6c21cbbab Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 14:34:16 +0530 Subject: [PATCH 049/201] Comment out wifi scan callback code --- internal/platform/implementation/linux/wifi_medium.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index bc111e74..945cca13 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -212,10 +212,9 @@ void NetworkManagerWifiMedium::onPropertiesChanged( absl::MutexLock l(&last_scan_lock_); last_scan_ = val; } - absl::ReaderMutexLock l(&scan_result_callback_lock_); - if (scan_result_callback_.has_value()) { - // scan_result_callback_->get().OnScanResults() - } + // absl::ReaderMutexLock l(&scan_result_callback_lock_); + // if (scan_result_callback_.has_value()) { + // } } } } From 6350b14f3bdf67af8b1f40e2be02b9e890e8f2f4 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 14:59:43 +0530 Subject: [PATCH 050/201] Add support for inhibition locks. --- .../implementation/linux/device_info.cc | 44 ++++++++++++++----- .../implementation/linux/device_info.h | 38 +++++++++++++++- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index d3d1c950..83af0413 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -8,24 +8,23 @@ #include #include +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/device_info.h" #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/device_info.h" #include "internal/platform/logging.h" -#include "absl/synchronization/mutex.h" namespace nearby { namespace linux { void CurrentUserSession::RegisterScreenLockedListener( - absl::string_view listener_name, - std::function callback) { + absl::string_view listener_name, + std::function callback) { absl::MutexLock l(&screen_lock_listeners_mutex_); screen_lock_listeners_[listener_name] = callback; } -void - CurrentUserSession::UnregisterScreenLockedListener(absl::string_view listener_name) -{ +void CurrentUserSession::UnregisterScreenLockedListener( + absl::string_view listener_name) { absl::MutexLock l(&screen_lock_listeners_mutex_); screen_lock_listeners_.erase(listener_name); } @@ -46,8 +45,8 @@ void CurrentUserSession::onUnlock() { DeviceInfo::DeviceInfo(sdbus::IConnection &system_bus) : system_bus_(system_bus), - current_user_session_(std::make_unique(system_bus_)) { -} + current_user_session_(std::make_unique(system_bus_)), + login_manager_(std::make_unique(system_bus_)) {} std::optional DeviceInfo::GetOsDeviceName() const { Hostnamed hostnamed(system_bus_); @@ -128,8 +127,7 @@ std::optional DeviceInfo::GetLogPath() const { if (dir == NULL) { return std::filesystem::path("/tmp"); } - return std::filesystem::path(std::string(dir)) / "Google Nearby" / - "logs"; + return std::filesystem::path(std::string(dir)) / "Google Nearby" / "logs"; } std::optional DeviceInfo::GetCrashDumpPath() const { @@ -137,8 +135,7 @@ std::optional DeviceInfo::GetCrashDumpPath() const { if (dir == NULL) { return std::filesystem::path("/tmp"); } - return std::filesystem::path(std::string(dir)) / "Google Nearby" / - "crashes"; + return std::filesystem::path(std::string(dir)) / "Google Nearby" / "crashes"; } bool DeviceInfo::IsScreenLocked() const { @@ -149,5 +146,28 @@ bool DeviceInfo::IsScreenLocked() const { 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 diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index b1c4c7de..c2ca6287 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -13,6 +14,7 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/device_info.h" #include "internal/platform/implementation/linux/hostname_client_glue.h" +#include "internal/platform/implementation/linux/login_manager_client_glue.h" #include "internal/platform/implementation/linux/login_session_client_glue.h" namespace nearby { @@ -62,6 +64,33 @@ public: ~Hostnamed() { unregisterProxy(); } }; +class LoginManager + : public sdbus::ProxyInterfaces { +public: + LoginManager(sdbus::IConnection &system_bus) + : ProxyInterfaces("org.freedesktop.login1", + "/org/freedesktop/hostname1") { + 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 : public api::DeviceInfo { public: DeviceInfo(sdbus::IConnection &system_bus); @@ -94,13 +123,18 @@ public: // TODO: Implement listening to logind for changes to LockedState. void RegisterScreenLockedListener( absl::string_view listener_name, - std::function callback) override{}; + std::function callback) override {} void - UnregisterScreenLockedListener(absl::string_view listener_name) override{}; + UnregisterScreenLockedListener(absl::string_view listener_name) override {} + + bool PreventSleep() override; + bool AllowSleep() override; private: sdbus::IConnection &system_bus_; std::unique_ptr current_user_session_; + std::unique_ptr login_manager_; + std::optional inhibit_fd_; }; } // namespace linux } // namespace nearby From 4018ff6240aaf6b57a257540ea608d7527f6e8da Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 15:00:03 +0530 Subject: [PATCH 051/201] Fix deps. --- internal/platform/implementation/linux/BUILD | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 720b22b2..acb2e297 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -22,6 +22,7 @@ cc_library( "log_message.h", "org_freedesktop_logcontrol_server_glue.h", "hostname_client_glue.h", + "login_manager_client_glue.h", "login_session_client_glue.h", "utils.h", ], @@ -34,7 +35,6 @@ cc_library( deps = [ ":comm", "//internal/platform/implementation:types", - "//internal/platform:logging", "@com_google_absl//absl/strings", "@libsystemd//:lib", "@sdbus_cpp//:lib", @@ -162,7 +162,6 @@ cc_library( "//internal/platform:base", "//internal/platform:cancellation_flag", "//internal/platform:comm", - "//internal/platform:logging", "//internal/platform:types", "//internal/platform:uuid", "//internal/platform/flags:platform_flags", @@ -241,7 +240,6 @@ cc_test( ":types", ":windows", "//internal/platform:base", - "//internal/platform:logging", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation:types", From 9976d475fbf8daafe366cf3fcf50cdd0c677a213 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 15:12:44 +0530 Subject: [PATCH 052/201] DeviceInfo: Register and unregister screen lock listeners. --- internal/platform/implementation/linux/device_info.cc | 2 +- internal/platform/implementation/linux/device_info.h | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 83af0413..a3ec5668 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -20,7 +20,7 @@ void CurrentUserSession::RegisterScreenLockedListener( absl::string_view listener_name, std::function callback) { absl::MutexLock l(&screen_lock_listeners_mutex_); - screen_lock_listeners_[listener_name] = callback; + screen_lock_listeners_[listener_name] = std::move(callback); } void CurrentUserSession::UnregisterScreenLockedListener( diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index c2ca6287..4c7b0596 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -120,12 +120,16 @@ public: std::optional GetCrashDumpPath() const override; bool IsScreenLocked() const override; - // TODO: Implement listening to logind for changes to LockedState. void RegisterScreenLockedListener( absl::string_view listener_name, - std::function callback) override {} + std::function callback) override { + current_user_session_->RegisterScreenLockedListener(listener_name, + std::move(callback)); + } void - UnregisterScreenLockedListener(absl::string_view listener_name) override {} + UnregisterScreenLockedListener(absl::string_view listener_name) override { + current_user_session_->UnregisterScreenLockedListener(listener_name); + } bool PreventSleep() override; bool AllowSleep() override; From bf4c0c5d3ae21a539ddcfe314067c31ab265c27c Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 16:34:27 +0530 Subject: [PATCH 053/201] Use /com/google/nearby as the object path. --- .../implementation/linux/bluetoth_classic_server_socket.cc | 2 +- internal/platform/implementation/linux/bluez.cc | 2 +- internal/platform/implementation/linux/dbus.cc | 4 ++-- internal/platform/implementation/linux/log_message.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc index c9215949..e6bc2e75 100644 --- a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc @@ -26,7 +26,7 @@ std::unique_ptr BluetoothServerSocket::Accept() { Exception BluetoothServerSocket::Close() { auto profile_object_path = - absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid_); + absl::Substitute("/com/google/nearby/profiles/$0", service_uuid_); profile_manager_.Unregister(service_uuid_); diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index b5c7c118..58c6c188 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -24,7 +24,7 @@ std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, } sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) { - return absl::Substitute("/com/github/google/nearby/profiles/$0", service_uuid); + return absl::Substitute("/com/google/nearby/profiles/$0", service_uuid); } sdbus::ObjectPath adapter_object_path(absl::string_view name) { diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index cf3ba938..e6160767 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -16,10 +16,10 @@ static absl::once_flag bus_connection_init_; static void initBusConnections() { global_system_bus_connection = - sdbus::createSystemBusConnection("/com/github/google/nearby"); + sdbus::createSystemBusConnection("/com/google/nearby"); global_system_bus_connection->enterEventLoopAsync(); global_default_bus_connection = - sdbus::createDefaultBusConnection("/com/github/google/nearby"); + sdbus::createDefaultBusConnection("/com/google/nearby"); global_default_bus_connection->enterEventLoopAsync(); } diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h index f4cbd5f8..294c25b0 100644 --- a/internal/platform/implementation/linux/log_message.h +++ b/internal/platform/implementation/linux/log_message.h @@ -32,7 +32,7 @@ class LogControl public google::LogSink { public: LogControl(sdbus::IConnection &system_bus) - : AdaptorInterfaces(system_bus, "/com/github/google/nearby"), + : AdaptorInterfaces(system_bus, "/com/google/nearby"), severity_(api::LogMessage::LogMessage::Severity::kVerbose) { registerAdaptor(); } From 61b4e1d74d8da159ad88d8e1e6e63ce8c3e93f81 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 20:48:09 +0530 Subject: [PATCH 054/201] Fix more compilation errors. --- .../linux/bluetooth_classic_medium.cc | 6 +-- .../linux/bluetooth_classic_medium.h | 6 --- .../implementation/linux/bluetooth_devices.cc | 15 +++---- .../implementation/linux/bluetooth_devices.h | 6 ++- .../linux/bluetoth_classic_server_socket.cc | 36 ---------------- .../platform/implementation/linux/bluez.cc | 10 ----- .../platform/implementation/linux/bluez.h | 20 ++++----- .../implementation/linux/log_message.cc | 42 +++++++++---------- .../implementation/linux/log_message.h | 2 +- .../platform/implementation/linux/wifi_lan.h | 4 +- 10 files changed, 50 insertions(+), 97 deletions(-) delete mode 100644 internal/platform/implementation/linux/bluetoth_classic_server_socket.cc diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index f8552491..40ecf848 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -87,7 +87,7 @@ void BluetoothClassicMedium::onInterfacesRemoved( if (interface == bluez::DEVICE_INTERFACE) { { - auto device = get_device_by_path(object); + auto device = devices_->get_device_by_path(object); if (!device.has_value()) { NEARBY_LOGS(WARNING) << __func__ << ": received InterfacesRemoved for a device " @@ -107,7 +107,7 @@ void BluetoothClassicMedium::onInterfacesRemoved( } discovery_cb_lock_.ReaderUnlock(); } - remove_device_by_path(object); + devices_->remove_device_by_path(object); } } } @@ -195,7 +195,7 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, api::BluetoothDevice * BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { - auto device = get_device_by_address(mac_address); + auto device = devices_->get_device_by_address(mac_address); if (device.has_value()) return nullptr; diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 0154b9a2..27165b14 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -93,12 +93,6 @@ public: observers_.RemoveObserver(observer); }; - std::optional> - get_device_by_path(const sdbus::ObjectPath &); - std::optional> - get_device_by_address(const std::string &); - void remove_device_by_path(const sdbus::ObjectPath &); - protected: void onInterfacesAdded( const sdbus::ObjectPath &objectPath, diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index e3212857..549ae5f0 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -3,10 +3,10 @@ #include +#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 "absl/synchronization/mutex.h" namespace nearby { namespace linux { @@ -19,8 +19,8 @@ BluetoothDevices::get_device_by_path( return std::nullopt; } - auto &device = devices_by_path_[device_object_path]; - return device; + auto &device = devices_by_path_.at(device_object_path); + return *device; } std::optional> @@ -40,10 +40,11 @@ void BluetoothDevices::remove_device_by_path( BluetoothDevice & BluetoothDevices::add_new_device(sdbus::ObjectPath device_object_path) { absl::MutexLock l(&devices_by_path_lock_); - auto pair = - devices_by_path_.emplace(device_object_path, system_bus_, - std::move(device_object_path), observers_); - return pair.first->second; + auto pair = devices_by_path_.emplace( + std::string(device_object_path), + std::make_unique( + system_bus_, std::move(device_object_path), observers_)); + return *pair.first->second; } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 093ebaa0..a1d9d46c 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -1,6 +1,8 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_ +#include + #include #include #include @@ -20,6 +22,7 @@ public: ObserverList &observers) : system_bus_(system_bus), observers_(observers), adapter_object_path_(adapter_object_path) {} + ~BluetoothDevices() = default; std::optional> get_device_by_path(const sdbus::ObjectPath &); @@ -30,7 +33,8 @@ public: private: absl::Mutex devices_by_path_lock_; - std::map devices_by_path_; + std::map> + devices_by_path_; sdbus::IConnection &system_bus_; ObserverList &observers_; diff --git a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc deleted file mode 100644 index e6bc2e75..00000000 --- a/internal/platform/implementation/linux/bluetoth_classic_server_socket.cc +++ /dev/null @@ -1,36 +0,0 @@ -#include "absl/strings/str_replace.h" -#include "absl/strings/substitute.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_server_socket.h" -#include "internal/platform/implementation/linux/bluetooth_classic_socket.h" -#include "internal/platform/implementation/linux/bluez.h" -#include "internal/platform/logging.h" -#include - -namespace nearby { -namespace linux { -std::unique_ptr BluetoothServerSocket::Accept() { - auto pair = profile_manager_.GetServiceRecordFD(service_uuid_); - if (!pair.has_value()) { - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get a new connection for profile " - << service_uuid_ << " for device "; - return nullptr; - } - - auto [device, fd] = *pair; - return std::unique_ptr(new BluetoothSocket(device, fd)); -} - -Exception BluetoothServerSocket::Close() { - auto profile_object_path = - absl::Substitute("/com/google/nearby/profiles/$0", service_uuid_); - - profile_manager_.Unregister(service_uuid_); - - return {Exception::kSuccess}; -} -} // namespace linux -} // namespace nearby diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index 58c6c188..736a6c49 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -7,16 +7,6 @@ namespace nearby { namespace linux { namespace bluez { -const char *SERVICE = "org.bluez"; - -const char *ADAPTER_INTEFACE = "org.bluez.Adapter1"; - -const char *DEVICE_INTERFACE = "org.bluez.Device1"; -const char *DEVICE_PROP_ADDRESS = "Address"; -const char *DEVICE_PROP_ALIAS = "Alias"; -const char *DEVICE_PROP_PAIRED = "Paired"; -const char *DEVICE_PROP_CONNECTED = "Connected"; - std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, absl::string_view mac_address) { return absl::Substitute("$0/dev_$1", adapter_object_path, diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 94591f1b..ace3a142 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -20,23 +20,23 @@ namespace nearby { namespace linux { namespace bluez { -extern const char *SERVICE_DEST; +static constexpr const char *SERVICE_DEST = "org.bluez"; -extern const char *ADAPTER_INTERFACE; +static constexpr const char *ADAPTER_INTERFACE = "org.bluez.Adapter1"; -extern const char *DEVICE_INTERFACE; -extern const char *DEVICE_PROP_ADDRESS; -extern const char *DEVICE_PROP_ALIAS; -extern const char *DEVICE_PROP_PAIRED; -extern const char *DEVICE_PROP_CONNECTED; +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"; -extern std::string + std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, absl::string_view mac_address); -extern sdbus::ObjectPath profile_object_path(absl::string_view service_uuid); + sdbus::ObjectPath profile_object_path(absl::string_view service_uuid); -extern sdbus::ObjectPath adapter_object_path(absl::string_view name); + sdbus::ObjectPath adapter_object_path(absl::string_view name); class BluezObjectManager : public sdbus::ProxyInterfaces { diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index 3fc10a47..bd8f670d 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -38,7 +38,21 @@ bool LogMessage::ShouldCreateLogMessage(Severity severity) { } // namespace api namespace linux { - +static inline google::LogSeverity +ConvertSeverity(api::LogMessage::Severity severity) { + switch (severity) { + case api::LogMessage::Severity::kWarning: + return google::GLOG_WARNING; + case api::LogMessage::Severity::kError: + return google::GLOG_ERROR; + case api::LogMessage::Severity::kFatal: + return google::GLOG_FATAL; + case api::LogMessage::Severity::kVerbose: + case api::LogMessage::Severity::kInfo: + default: + return google::GLOG_INFO; + } +} static inline int ConvertSeverityToSyslog(google::LogSeverity severity) { switch (severity) { case google::GLOG_WARNING: @@ -53,6 +67,11 @@ static inline int ConvertSeverityToSyslog(google::LogSeverity severity) { } } +// TODO: Set a LogSink depending on the target set by LogControl +LogMessage::LogMessage(const char *file, int line, Severity severity) + : log_streamer_(file, line, ConvertSeverity(severity), + global_log_control_.get(), false) {} + void LogControl::send(google::LogSeverity severity, const char *full_filename, const char *base_filename, int line, const struct ::tm *tm_time, const char *message, @@ -77,27 +96,6 @@ void LogControl::send(google::LogSeverity severity, const char *full_filename, } } -static inline google::LogSeverity -ConvertSeverity(api::LogMessage::Severity severity) { - switch (severity) { - case api::LogMessage::Severity::kWarning: - return google::GLOG_WARNING; - case api::LogMessage::Severity::kError: - return google::GLOG_ERROR; - case api::LogMessage::Severity::kFatal: - return google::GLOG_FATAL; - case api::LogMessage::Severity::kVerbose: - case api::LogMessage::Severity::kInfo: - default: - return google::GLOG_INFO; - } -} - -// TODO: Set a LogSink depending on the target set by LogControl -LogMessage::LogMessage(const char *file, int line, Severity severity) - : log_streamer_(file, line, ConvertSeverity(severity), - global_log_control_.get(), false) {} - void LogMessage::Print(const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h index 294c25b0..0a473e3a 100644 --- a/internal/platform/implementation/linux/log_message.h +++ b/internal/platform/implementation/linux/log_message.h @@ -16,7 +16,7 @@ namespace linux { class LogMessage : public api::LogMessage { public: LogMessage(const char *file, int line, Severity severity); - ~LogMessage() override; + ~LogMessage() override {}; void Print(const char *format, ...) override; diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 24010163..3600f500 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -34,7 +34,9 @@ public: std::unique_ptr ListenForService(int port = 0) override; absl::optional> - GetDynamicPortRange() override; + GetDynamicPortRange() override { + return std::nullopt; + } private: DiscoveredServiceCallback discovery_cb_; From 4978e6bea95a760a46a7fd9bace4133e251465e6 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 20:50:26 +0530 Subject: [PATCH 055/201] Rewrite timer to use POSIX timers. --- internal/platform/implementation/linux/BUILD | 7 +- .../platform/implementation/linux/timer.cc | 134 ++++++++------- .../platform/implementation/linux/timer.h | 20 +-- .../implementation/linux/timer_queue.cc | 157 ------------------ .../implementation/linux/timer_queue.h | 124 -------------- 5 files changed, 88 insertions(+), 354 deletions(-) delete mode 100644 internal/platform/implementation/linux/timer_queue.cc delete mode 100644 internal/platform/implementation/linux/timer_queue.h diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index acb2e297..9de52edd 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -17,7 +17,6 @@ cc_library( "scheduled_executor.h", "submittable_executor.h", "timer.h", - "timer_queue.h", "thread_pool.h", "log_message.h", "org_freedesktop_logcontrol_server_glue.h", @@ -29,8 +28,9 @@ cc_library( srcs = [ "device_info.cc", "log_message.cc", - "timer.cc" + "timer.cc", ], + copts = ["-lrt"], visibility = ["//third_party/nearby/sharing/internal/impl/linux:__pkg__"], deps = [ ":comm", @@ -127,6 +127,8 @@ cc_library( "bluetooth_classic_device.cc", "bluetooth_classic_medium.cc", "bluetooth_classic_socket.cc", + "bluetooth_classic_server_socket.cc", + "bluetooth_devices.cc", "bluetooth_pairing.cc", "bluez.cc", "dbus.cc", @@ -185,6 +187,7 @@ cc_library( "@nlohmann_json//:json", "@libsystemd//:lib", "@sdbus_cpp//:lib", + "@libcurl//:lib" ], ) diff --git a/internal/platform/implementation/linux/timer.cc b/internal/platform/implementation/linux/timer.cc index 2468a009..21e54788 100644 --- a/internal/platform/implementation/linux/timer.cc +++ b/internal/platform/implementation/linux/timer.cc @@ -12,8 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include +#include +#include +#include +#include + +#include "internal/platform/implementation/linux/submittable_executor.h" #include "internal/platform/implementation/linux/timer.h" -#include "internal/platform/implementation/linux/timer_queue.h" #include "absl/synchronization/mutex.h" #include "internal/platform/logging.h" @@ -21,100 +28,109 @@ namespace nearby { namespace linux { -Timer::~Timer() { Stop(); } +static void timer_callback(union sigval val) { + absl::AnyInvocable *callback = + reinterpret_cast *>(val.sival_ptr); + if (*callback != nullptr) + (*callback)(); +} + +Timer::~Timer() { + absl::MutexLock l(&mutex_); + if (timerid_.has_value()) + if (timer_delete(*timerid_) < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error deleting POSIX timer: " + << std::strerror(errno); + } +} bool Timer::Create(int delay, int interval, absl::AnyInvocable callback) { - absl::MutexLock lock(&mutex_); - - if ((delay < 0) || (interval < 0)) { - NEARBY_LOGS(WARNING) << "Delay and interval shouldn\'t be negative value."; + if (delay < 0 || interval < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Delay and interval cannot be negative."; return false; } - if (timer_queue_handle_) { + absl::MutexLock l(&mutex_); + if (timerid_.has_value()) { + NEARBY_LOGS(ERROR) << __func__ + << "Timer has already been created and armed."; return false; } - timer_queue_handle_ = TimerQueue::CreateTimerQueue(); - if (!timer_queue_handle_) { - NEARBY_LOGS(ERROR) << "Failed to create timer queue."; - return false; - } - - delay_ = delay; - interval_ = interval; callback_ = std::move(callback); + + struct sigevent ev; + ev.sigev_value.sival_ptr = &callback_; + ev.sigev_notify_function = timer_callback; + + timer_t timerid; - absl::StatusOr createStatus = timer_queue_handle_->CreateTimerQueueTimer(TimerRoutine, - &callback_, std::chrono::milliseconds(delay), std::chrono::milliseconds(interval), TimerQueue::WT_EXECUTEDEFAULT); + struct itimerspec spec; - if (!createStatus.ok()) { - if (!timer_queue_handle_->DeleteTimerQueueEx(TimerQueue::CE_IMEDIATERETURN).ok()) { - NEARBY_LOGS(ERROR) << "Failed to create timer in timer queue."; - } - delete timer_queue_handle_.release(); + spec.it_value.tv_nsec = delay * 1000000; + spec.it_value.tv_sec = 0; + + spec.it_interval.tv_nsec = interval * 1000000; + spec.it_interval.tv_sec = 0; + + if (timer_create(CLOCK_MONOTONIC, &ev, &timerid) < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error creating POSIX timer: " + << std::strerror(errno); return false; } - handle_ = createStatus.value(); + + if (timer_settime(&timerid, 0, &spec, nullptr) < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error arming POSIX timer: " + << std::strerror(errno); + if (!timer_delete(&timerid)) { + NEARBY_LOGS(ERROR) << __func__ << ": error deleting POSIX timer: " + << std::strerror(errno); + } + return false; + } + + timerid_ = timerid; return true; } bool Timer::Stop() { - absl::MutexLock lock(&mutex_); - - if (!timer_queue_handle_) { + absl::MutexLock l(&mutex_); + if (!timerid_.has_value()) { + NEARBY_LOGS(WARNING) << __func__ << ": no timer created"; return true; } - absl::Status deleteStatus = timer_queue_handle_->DeleteTimerQueueTimer(handle_, TimerQueue::CE_IMEDIATERETURN); - - if (!deleteStatus.ok()) { - NEARBY_LOGS(ERROR) << "Failed to delete timer from queue: " << deleteStatus.message(); - } - - handle_ = 0; - - deleteStatus = timer_queue_handle_->DeleteTimerQueueEx(TimerQueue::CE_IMEDIATERETURN); - - if (!deleteStatus.ok()) { - NEARBY_LOGS(ERROR) << "Failed to delete timer queue: " << deleteStatus.message(); + if (!timer_delete(&*timerid_)) { + NEARBY_LOGS(ERROR) << __func__ << ": error deleting POSIX timer: " + << std::strerror(errno); return false; } - timer_queue_handle_ = nullptr; + timerid_.reset(); + return true; } bool Timer::FireNow() { absl::MutexLock lock(&mutex_); - - if (!timer_queue_handle_ || !callback_) { + if (!timerid_.has_value()) { + NEARBY_LOGS(ERROR) << __func__ << ": No timer has been created"; + return false; + } + if (callback_ == nullptr) { + NEARBY_LOGS(ERROR) << __func__ << ": No callback has been set"; return false; } - if (task_executor_ == nullptr) { task_executor_ = std::make_unique(); } - if (task_executor_ == nullptr) { - NEARBY_LOGS(ERROR) - << "Failed to fire the task due to cannot create executor."; - return false; - } - - task_executor_->Execute([&]() { callback_(); }); + task_executor_->Execute([&]() {callback_();}); return true; } -void Timer::TimerRoutine(void *lpParam) { - absl::AnyInvocable* callback = - reinterpret_cast*>(lpParam); - if (*callback != nullptr) { - (*callback)(); - } -} - -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/timer.h b/internal/platform/implementation/linux/timer.h index 8a75163c..444dfab9 100644 --- a/internal/platform/implementation/linux/timer.h +++ b/internal/platform/implementation/linux/timer.h @@ -16,19 +16,21 @@ #define PLATFORM_IMPL_LINUX_TIMER_H_ #include +#include +#include +#include #include "absl/base/thread_annotations.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/timer.h" #include "internal/platform/implementation/linux/submittable_executor.h" -#include "internal/platform/implementation/linux/timer_queue.h" namespace nearby { namespace linux { class Timer : public api::Timer { public: - Timer() = default; + Timer() : timerid_(nullptr) {} ; ~Timer() override; bool Create(int delay, int interval, @@ -37,17 +39,11 @@ class Timer : public api::Timer { bool Stop() override ABSL_LOCKS_EXCLUDED(mutex_); bool FireNow() override ABSL_LOCKS_EXCLUDED(mutex_); - private: - static void TimerRoutine(void *lpParam); - - mutable absl::Mutex mutex_; - int delay_ ABSL_GUARDED_BY(mutex_); - int interval_ ABSL_GUARDED_BY(mutex_); +private: + absl::Mutex mutex_; + std::optional timerid_ ABSL_GUARDED_BY(mutex_); absl::AnyInvocable callback_; - uint16_t handle_ ABSL_GUARDED_BY(mutex_) = 0; - std::unique_ptr timer_queue_handle_; - std::unique_ptr task_executor_ ABSL_GUARDED_BY(mutex_) = - nullptr; + std::unique_ptr task_executor_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/timer_queue.cc b/internal/platform/implementation/linux/timer_queue.cc deleted file mode 100644 index 5048008c..00000000 --- a/internal/platform/implementation/linux/timer_queue.cc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2021 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "internal/platform/implementation/linux/timer_queue.h" - -#include "internal/platform/implementation/linux/utils.h" - -#include "internal/platform/logging.h" - -namespace nearby { -namespace linux { - -std::unique_ptr TimerQueue::CreateTimerQueue() { - return std::unique_ptr(new TimerQueue); -} - -TimerQueue::TimerQueue() { - thread_ = std::thread([this]() {Run();}); -} - -TimerQueue::~TimerQueue() { - DeleteTimerQueueEx(CE_WAITFORCALLBACKS); // NOLINT - cancelled_ = true; - thread_.join(); -} - -void TimerQueue::Run() { - while(!cancelled_ || !work_.empty()) { - absl::MutexLock lk(&mutex_); - empty_ = (work_.empty() ? true : false); - for (auto &workItem : work_) { - if (workItem.Finished) { - if (workItem.Due < std::chrono::steady_clock::now()) { - work_.erase(workItem); - break; - } - } - if (workItem.Cancelled) { - if (workItem.Worker.valid()) { - if (workItem.Worker.wait_for(std::chrono_literals::operator""ms(0)) == std::future_status::ready) { - work_.erase(workItem); - break; - } - } - } - if (workItem.Due <= std::chrono::steady_clock::now()) { - if ((workItem.Flags & WT_EXECUTEDEFAULT) == WT_EXECUTEDEFAULT) { - if ((workItem.Flags & WT_EXECUTEONLYONCE) == WT_EXECUTEONLYONCE) { - workItem.Worker = std::async(workItem.Callback, workItem.Parameter); - workItem.Finished = true; - } - else { - if (workItem.Period > std::chrono_literals::operator""ms(0)) { - workItem.Worker = std::async(workItem.Callback, workItem.Parameter); - workItem.Finished = true; - workItem.Due = std::chrono::steady_clock::now() + workItem.Period; - } - else { - workItem.Worker = std::async(workItem.Callback, workItem.Parameter); - workItem.Finished = true; - } - } - } - else if ((workItem.Flags & WT_EXECUTEINTIMERTHREAD) == WT_EXECUTEINTIMERTHREAD) { - if ((workItem.Flags & WT_EXECUTEONLYONCE) == WT_EXECUTEONLYONCE) { - workItem.Callback(workItem.Parameter); - workItem.Finished = true; - } - else { - if (workItem.Period > std::chrono_literals::operator""ms(0)) { - workItem.Callback(workItem.Parameter); - workItem.Finished = true; - workItem.Due = std::chrono::steady_clock::now() + workItem.Period; - } - else { - workItem.Callback(workItem.Parameter); - workItem.Finished = true; - } - } - } - } - } - } -} - -absl::StatusOr TimerQueue::CreateTimerQueueTimer(absl::AnyInvocable Callback, void *Parameter, std::chrono::milliseconds DueTime, std::chrono::milliseconds Period, unsigned long int Flags) { - TimerWork work; - - work.Callback = std::move(Callback); - work.WorkId = next_id_; - work.Flags = Flags; - next_id_++; - work.Due = std::chrono::steady_clock::now() + DueTime; - work.Period = Period; - work.Parameter = Parameter; - absl::MutexLock lk(&mutex_); - work_.insert(std::move(work)); - return next_id_ - 1; -} - -absl::Status TimerQueue::DeleteTimerQueueTimer(uint16_t WorkId, unsigned long int CompletionEvent) { - for (auto &workItem : work_) { - absl::MutexLock lk(&mutex_); - if (workItem.WorkId == WorkId) { - workItem.Cancelled = true; - } - } - return absl::OkStatus(); -} - -namespace { - bool check(bool *arg) { - return *arg; - } -} // namespace - -absl::Status TimerQueue::DeleteTimerQueueEx(unsigned int long CompletionEvent) { - switch (CompletionEvent) { - case CE_IMEDIATERETURN: { - absl::MutexLock lk(&mutex_); - for (auto workItem = work_.begin(); workItem != work_.end();) { - if (workItem->Worker.valid()) { - workItem->Worker.wait(); - } - workItem = work_.erase(workItem); - } - return absl::OkStatus(); - } - case CE_WAITFORCALLBACKS: { - mutex_.Lock(); - for (auto &workItem : work_) { - workItem.Cancelled = true; - } - clearing_ = true; - mutex_.Await(absl::Condition(check, &empty_)); - mutex_.Unlock(); - return absl::OkStatus(); - } - default: { - return absl::InvalidArgumentError("Invalid Completion Event value."); - } - } -} - -} // namespace linux -} // namespace nearby diff --git a/internal/platform/implementation/linux/timer_queue.h b/internal/platform/implementation/linux/timer_queue.h deleted file mode 100644 index db745324..00000000 --- a/internal/platform/implementation/linux/timer_queue.h +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2021 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PLATFORM_IMPL_LINUX_TIMER_QUEUE_H_ -#define PLATFORM_IMPL_LINUX_TIMER_QUEUE_H_ - -#include -#include -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/functional/any_invocable.h" -#include "absl/functional/function_ref.h" -#include "absl/synchronization/mutex.h" -#include "absl/base/thread_annotations.h" - -namespace nearby { -namespace linux { - -/* - * This class represents a a que for timers. This class is built to try to replicate the Windows Timer-Queue functionality. - * https://learn.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-createtimerqueue - */ -class TimerQueue { -public: - /* - * Parameters to be used with the Timer Queue Timer. - * See https://learn.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-createtimerqueuetimer - */ - static constexpr unsigned long int WT_EXECUTEDEFAULT = 1 << 0; - static constexpr unsigned long int WT_EXECUTEINTIMERTHREAD = 1 << 1; - static constexpr unsigned long int WT_EXECUTEINIOTHREAD = 1 << 2; // Unused - static constexpr unsigned long int WT_EXECUTEINPERSISTENTTHREAD = 1 << 3; // Unused - static constexpr unsigned long int WT_EXECUTELONGFUNCTION = 1 << 4; // Unused - static constexpr unsigned long int WT_EXECUTEONLYONCE = 1 << 5; - static constexpr unsigned long int WT_TRANSFER_IMPERSONATION = 1 << 6; // Unused - static constexpr unsigned long int CE_WAITFORCALLBACKS = 1 << 0; // Equivalent to `INVALID_HANDLE_VALUE` when passing for a CompletionEvent - static constexpr unsigned long int CE_IMEDIATERETURN = 1 << 1; // Equivalent to `NULL` when passing for a CompletionEvent - // Creates a new timer queue for the user to use. - static std::unique_ptr CreateTimerQueue(); - - // Returns a thread unique identifier that the timer is running on if it is successful. Status if not. - absl::StatusOr CreateTimerQueueTimer(absl::AnyInvocable Callback, void *Parameter, std::chrono::milliseconds DueTime, std::chrono::milliseconds Period, unsigned long int Flags = WT_EXECUTEDEFAULT); - - // Removes a timer based on the thread id the timer is running on. - absl::Status DeleteTimerQueueTimer(uint16_t WorkId, unsigned long int CompletionEvent = CE_WAITFORCALLBACKS); - - // Removes all timers in the timer queue - absl::Status DeleteTimerQueueEx(unsigned long int CompletionEvent = CE_WAITFORCALLBACKS); - - ~TimerQueue(); - -private: - TimerQueue(); - - void Run(); - - uint16_t next_id_; - - // A struct that represents a timer of work that needs to be done. - struct TimerWork { - mutable std::chrono::time_point Due; - mutable absl::AnyInvocable Callback; - mutable std::chrono::milliseconds Period; - mutable void *Parameter = nullptr; - mutable long int Flags; - mutable std::future Worker; - mutable std::atomic_bool Cancelled = false; - mutable std::atomic_bool Finished = false; - uint16_t WorkId = 0; - - // Useful for time comparisons on other work items - bool operator<(const TimerWork &other) const { - return Due < other.Due; - } - bool operator>(const TimerWork &other) const { - return Due > other.Due; - } - bool operator==(const TimerWork &other) const { - return Due == other.Due; - } - bool operator!=(const TimerWork &other) const { - return !operator==(other); - } - bool operator<=(const TimerWork &other) const { - return (operator<(other) || operator==(other)); - } - bool operator>=(const TimerWork &other) const { - return (operator>(other) || operator==(other)); - } - }; - - std::set work_; - std::vector threads_; - - std::thread thread_; - - bool cancelled_; - bool clearing_; - bool empty_; - - absl::CondVar condvar_; - absl::Mutex mutex_; -}; - -} // namespace linux -} // namespace nearby - -#endif // PLATFORM_IMPL_LINUX_TIMER_QUEUE_H_ From a597feabaa88f9c73fb45df5789d2379cc0b1097 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 27 Aug 2023 20:50:36 +0530 Subject: [PATCH 056/201] Fix signatures. --- internal/platform/implementation/linux/platform.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 8f8c24cc..fb33b1f2 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -69,13 +69,13 @@ ImplementationPlatform::GetAppDataPath(const std::string &file_name) { return state / std::filesystem::path(file_name).filename(); } -OSName GetCurrentOS() { return OSName::kWindows; } +OSName ImplementationPlatform::GetCurrentOS() { return OSName::kWindows; } -std::unique_ptr CreateAtomicBoolean(bool initial_value) { +std::unique_ptr ImplementationPlatform::CreateAtomicBoolean(bool initial_value) { return std::make_unique(initial_value); } -std::unique_ptr CreateAtomicUint32(std::uint32_t value) { +std::unique_ptr ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) { return std::make_unique(value); } From dc48cdbc98377ccae74838dac9741e9175f96a82 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 28 Aug 2023 01:15:55 +0530 Subject: [PATCH 057/201] Use bus name only for default connection. --- internal/platform/implementation/linux/dbus.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index e6160767..bec2244e 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -16,10 +16,10 @@ static absl::once_flag bus_connection_init_; static void initBusConnections() { global_system_bus_connection = - sdbus::createSystemBusConnection("/com/google/nearby"); + sdbus::createSystemBusConnection(); global_system_bus_connection->enterEventLoopAsync(); global_default_bus_connection = - sdbus::createDefaultBusConnection("/com/google/nearby"); + sdbus::createDefaultBusConnection("com.google.nearby"); global_default_bus_connection->enterEventLoopAsync(); } From 55a8283e8df4bd6896fd7fbf136b93b9ee0e3ff1 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 28 Aug 2023 01:16:41 +0530 Subject: [PATCH 058/201] Synchronize writes to std::cout. --- internal/platform/implementation/linux/log_message.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index bd8f670d..06fa54e9 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -11,6 +11,7 @@ #include #include "absl/base/call_once.h" +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/log_message.h" @@ -72,6 +73,8 @@ LogMessage::LogMessage(const char *file, int line, Severity severity) : log_streamer_(file, line, ConvertSeverity(severity), global_log_control_.get(), false) {} +static absl::Mutex cout_mutex; + void LogControl::send(google::LogSeverity severity, const char *full_filename, const char *base_filename, int line, const struct ::tm *tm_time, const char *message, @@ -89,6 +92,7 @@ void LogControl::send(google::LogSeverity severity, const char *full_filename, } case kConsole: default: + absl::MutexLock l(&cout_mutex); std::cout << LogSink::ToString(severity, base_filename, line, tm_time, message, message_len) << "\n"; From 0dcdeaae6e537b8bd996b5a23dc8c6a03514e41b Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 11:42:43 +0530 Subject: [PATCH 059/201] Add login_manager_client_glue.h --- .../linux/login_manager_client_glue.h | 631 ++++++++++++++++++ .../linux/org.freedesktop.login1.Manager.xml | 388 +++++++++++ 2 files changed, 1019 insertions(+) create mode 100644 internal/platform/implementation/linux/login_manager_client_glue.h create mode 100644 internal/platform/implementation/linux/org.freedesktop.login1.Manager.xml diff --git a/internal/platform/implementation/linux/login_manager_client_glue.h b/internal/platform/implementation/linux/login_manager_client_glue.h new file mode 100644 index 00000000..4de655b9 --- /dev/null +++ b/internal/platform/implementation/linux/login_manager_client_glue.h @@ -0,0 +1,631 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__login_manager_client_glue_h__proxy__H__ +#define __sdbuscpp__login_manager_client_glue_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace login1 { + +class Manager_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.login1.Manager"; + +protected: + Manager_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("SessionNew").onInterface(INTERFACE_NAME).call([this](const std::string& session_id, const sdbus::ObjectPath& object_path){ this->onSessionNew(session_id, object_path); }); + proxy_.uponSignal("SessionRemoved").onInterface(INTERFACE_NAME).call([this](const std::string& session_id, const sdbus::ObjectPath& object_path){ this->onSessionRemoved(session_id, object_path); }); + proxy_.uponSignal("UserNew").onInterface(INTERFACE_NAME).call([this](const uint32_t& uid, const sdbus::ObjectPath& object_path){ this->onUserNew(uid, object_path); }); + proxy_.uponSignal("UserRemoved").onInterface(INTERFACE_NAME).call([this](const uint32_t& uid, const sdbus::ObjectPath& object_path){ this->onUserRemoved(uid, object_path); }); + proxy_.uponSignal("SeatNew").onInterface(INTERFACE_NAME).call([this](const std::string& seat_id, const sdbus::ObjectPath& object_path){ this->onSeatNew(seat_id, object_path); }); + proxy_.uponSignal("SeatRemoved").onInterface(INTERFACE_NAME).call([this](const std::string& seat_id, const sdbus::ObjectPath& object_path){ this->onSeatRemoved(seat_id, object_path); }); + proxy_.uponSignal("PrepareForShutdown").onInterface(INTERFACE_NAME).call([this](const bool& start){ this->onPrepareForShutdown(start); }); + proxy_.uponSignal("PrepareForSleep").onInterface(INTERFACE_NAME).call([this](const bool& start){ this->onPrepareForSleep(start); }); + } + + ~Manager_proxy() = default; + + virtual void onSessionNew(const std::string& session_id, const sdbus::ObjectPath& object_path) = 0; + virtual void onSessionRemoved(const std::string& session_id, const sdbus::ObjectPath& object_path) = 0; + virtual void onUserNew(const uint32_t& uid, const sdbus::ObjectPath& object_path) = 0; + virtual void onUserRemoved(const uint32_t& uid, const sdbus::ObjectPath& object_path) = 0; + virtual void onSeatNew(const std::string& seat_id, const sdbus::ObjectPath& object_path) = 0; + virtual void onSeatRemoved(const std::string& seat_id, const sdbus::ObjectPath& object_path) = 0; + virtual void onPrepareForShutdown(const bool& start) = 0; + virtual void onPrepareForSleep(const bool& start) = 0; + +public: + sdbus::ObjectPath GetSession(const std::string& session_id) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetSession").onInterface(INTERFACE_NAME).withArguments(session_id).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath GetSessionByPID(const uint32_t& pid) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetSessionByPID").onInterface(INTERFACE_NAME).withArguments(pid).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath GetUser(const uint32_t& uid) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetUser").onInterface(INTERFACE_NAME).withArguments(uid).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath GetUserByPID(const uint32_t& pid) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetUserByPID").onInterface(INTERFACE_NAME).withArguments(pid).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath GetSeat(const std::string& seat_id) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetSeat").onInterface(INTERFACE_NAME).withArguments(seat_id).storeResultsTo(result); + return result; + } + + std::vector> ListSessions() + { + std::vector> result; + proxy_.callMethod("ListSessions").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::vector> ListUsers() + { + std::vector> result; + proxy_.callMethod("ListUsers").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::vector> ListSeats() + { + std::vector> result; + proxy_.callMethod("ListSeats").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::vector> ListInhibitors() + { + std::vector> result; + proxy_.callMethod("ListInhibitors").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::tuple CreateSession(const uint32_t& uid, const uint32_t& pid, const std::string& service, const std::string& type, const std::string& class_, const std::string& desktop, const std::string& seat_id, const uint32_t& vtnr, const std::string& tty, const std::string& display, const bool& remote, const std::string& remote_user, const std::string& remote_host, const std::vector>& properties) + { + std::tuple result; + proxy_.callMethod("CreateSession").onInterface(INTERFACE_NAME).withArguments(uid, pid, service, type, class_, desktop, seat_id, vtnr, tty, display, remote, remote_user, remote_host, properties).storeResultsTo(result); + return result; + } + + void ReleaseSession(const std::string& session_id) + { + proxy_.callMethod("ReleaseSession").onInterface(INTERFACE_NAME).withArguments(session_id); + } + + void ActivateSession(const std::string& session_id) + { + proxy_.callMethod("ActivateSession").onInterface(INTERFACE_NAME).withArguments(session_id); + } + + void ActivateSessionOnSeat(const std::string& session_id, const std::string& seat_id) + { + proxy_.callMethod("ActivateSessionOnSeat").onInterface(INTERFACE_NAME).withArguments(session_id, seat_id); + } + + void LockSession(const std::string& session_id) + { + proxy_.callMethod("LockSession").onInterface(INTERFACE_NAME).withArguments(session_id); + } + + void UnlockSession(const std::string& session_id) + { + proxy_.callMethod("UnlockSession").onInterface(INTERFACE_NAME).withArguments(session_id); + } + + void LockSessions() + { + proxy_.callMethod("LockSessions").onInterface(INTERFACE_NAME); + } + + void UnlockSessions() + { + proxy_.callMethod("UnlockSessions").onInterface(INTERFACE_NAME); + } + + void KillSession(const std::string& session_id, const std::string& who, const int32_t& signal_number) + { + proxy_.callMethod("KillSession").onInterface(INTERFACE_NAME).withArguments(session_id, who, signal_number); + } + + void KillUser(const uint32_t& uid, const int32_t& signal_number) + { + proxy_.callMethod("KillUser").onInterface(INTERFACE_NAME).withArguments(uid, signal_number); + } + + void TerminateSession(const std::string& session_id) + { + proxy_.callMethod("TerminateSession").onInterface(INTERFACE_NAME).withArguments(session_id); + } + + void TerminateUser(const uint32_t& uid) + { + proxy_.callMethod("TerminateUser").onInterface(INTERFACE_NAME).withArguments(uid); + } + + void TerminateSeat(const std::string& seat_id) + { + proxy_.callMethod("TerminateSeat").onInterface(INTERFACE_NAME).withArguments(seat_id); + } + + void SetUserLinger(const uint32_t& uid, const bool& enable, const bool& interactive) + { + proxy_.callMethod("SetUserLinger").onInterface(INTERFACE_NAME).withArguments(uid, enable, interactive); + } + + void AttachDevice(const std::string& seat_id, const std::string& sysfs_path, const bool& interactive) + { + proxy_.callMethod("AttachDevice").onInterface(INTERFACE_NAME).withArguments(seat_id, sysfs_path, interactive); + } + + void FlushDevices(const bool& interactive) + { + proxy_.callMethod("FlushDevices").onInterface(INTERFACE_NAME).withArguments(interactive); + } + + void PowerOff(const bool& interactive) + { + proxy_.callMethod("PowerOff").onInterface(INTERFACE_NAME).withArguments(interactive); + } + + void PowerOffWithFlags(const uint64_t& flags) + { + proxy_.callMethod("PowerOffWithFlags").onInterface(INTERFACE_NAME).withArguments(flags); + } + + void Reboot(const bool& interactive) + { + proxy_.callMethod("Reboot").onInterface(INTERFACE_NAME).withArguments(interactive); + } + + void RebootWithFlags(const uint64_t& flags) + { + proxy_.callMethod("RebootWithFlags").onInterface(INTERFACE_NAME).withArguments(flags); + } + + void Halt(const bool& interactive) + { + proxy_.callMethod("Halt").onInterface(INTERFACE_NAME).withArguments(interactive); + } + + void HaltWithFlags(const uint64_t& flags) + { + proxy_.callMethod("HaltWithFlags").onInterface(INTERFACE_NAME).withArguments(flags); + } + + void Suspend(const bool& interactive) + { + proxy_.callMethod("Suspend").onInterface(INTERFACE_NAME).withArguments(interactive); + } + + void SuspendWithFlags(const uint64_t& flags) + { + proxy_.callMethod("SuspendWithFlags").onInterface(INTERFACE_NAME).withArguments(flags); + } + + void Hibernate(const bool& interactive) + { + proxy_.callMethod("Hibernate").onInterface(INTERFACE_NAME).withArguments(interactive); + } + + void HibernateWithFlags(const uint64_t& flags) + { + proxy_.callMethod("HibernateWithFlags").onInterface(INTERFACE_NAME).withArguments(flags); + } + + void HybridSleep(const bool& interactive) + { + proxy_.callMethod("HybridSleep").onInterface(INTERFACE_NAME).withArguments(interactive); + } + + void HybridSleepWithFlags(const uint64_t& flags) + { + proxy_.callMethod("HybridSleepWithFlags").onInterface(INTERFACE_NAME).withArguments(flags); + } + + void SuspendThenHibernate(const bool& interactive) + { + proxy_.callMethod("SuspendThenHibernate").onInterface(INTERFACE_NAME).withArguments(interactive); + } + + void SuspendThenHibernateWithFlags(const uint64_t& flags) + { + proxy_.callMethod("SuspendThenHibernateWithFlags").onInterface(INTERFACE_NAME).withArguments(flags); + } + + std::string CanPowerOff() + { + std::string result; + proxy_.callMethod("CanPowerOff").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::string CanReboot() + { + std::string result; + proxy_.callMethod("CanReboot").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::string CanHalt() + { + std::string result; + proxy_.callMethod("CanHalt").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::string CanSuspend() + { + std::string result; + proxy_.callMethod("CanSuspend").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::string CanHibernate() + { + std::string result; + proxy_.callMethod("CanHibernate").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::string CanHybridSleep() + { + std::string result; + proxy_.callMethod("CanHybridSleep").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::string CanSuspendThenHibernate() + { + std::string result; + proxy_.callMethod("CanSuspendThenHibernate").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void ScheduleShutdown(const std::string& type, const uint64_t& usec) + { + proxy_.callMethod("ScheduleShutdown").onInterface(INTERFACE_NAME).withArguments(type, usec); + } + + bool CancelScheduledShutdown() + { + bool result; + proxy_.callMethod("CancelScheduledShutdown").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + sdbus::UnixFd Inhibit(const std::string& what, const std::string& who, const std::string& why, const std::string& mode) + { + sdbus::UnixFd result; + proxy_.callMethod("Inhibit").onInterface(INTERFACE_NAME).withArguments(what, who, why, mode).storeResultsTo(result); + return result; + } + + std::string CanRebootParameter() + { + std::string result; + proxy_.callMethod("CanRebootParameter").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void SetRebootParameter(const std::string& parameter) + { + proxy_.callMethod("SetRebootParameter").onInterface(INTERFACE_NAME).withArguments(parameter); + } + + std::string CanRebootToFirmwareSetup() + { + std::string result; + proxy_.callMethod("CanRebootToFirmwareSetup").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void SetRebootToFirmwareSetup(const bool& enable) + { + proxy_.callMethod("SetRebootToFirmwareSetup").onInterface(INTERFACE_NAME).withArguments(enable); + } + + std::string CanRebootToBootLoaderMenu() + { + std::string result; + proxy_.callMethod("CanRebootToBootLoaderMenu").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void SetRebootToBootLoaderMenu(const uint64_t& timeout) + { + proxy_.callMethod("SetRebootToBootLoaderMenu").onInterface(INTERFACE_NAME).withArguments(timeout); + } + + std::string CanRebootToBootLoaderEntry() + { + std::string result; + proxy_.callMethod("CanRebootToBootLoaderEntry").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void SetRebootToBootLoaderEntry(const std::string& boot_loader_entry) + { + proxy_.callMethod("SetRebootToBootLoaderEntry").onInterface(INTERFACE_NAME).withArguments(boot_loader_entry); + } + + void SetWallMessage(const std::string& wall_message, const bool& enable) + { + proxy_.callMethod("SetWallMessage").onInterface(INTERFACE_NAME).withArguments(wall_message, enable); + } + +public: + bool EnableWallMessages() + { + return proxy_.getProperty("EnableWallMessages").onInterface(INTERFACE_NAME); + } + + void EnableWallMessages(const bool& value) + { + proxy_.setProperty("EnableWallMessages").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WallMessage() + { + return proxy_.getProperty("WallMessage").onInterface(INTERFACE_NAME); + } + + void WallMessage(const std::string& value) + { + proxy_.setProperty("WallMessage").onInterface(INTERFACE_NAME).toValue(value); + } + + uint32_t NAutoVTs() + { + return proxy_.getProperty("NAutoVTs").onInterface(INTERFACE_NAME); + } + + std::vector KillOnlyUsers() + { + return proxy_.getProperty("KillOnlyUsers").onInterface(INTERFACE_NAME); + } + + std::vector KillExcludeUsers() + { + return proxy_.getProperty("KillExcludeUsers").onInterface(INTERFACE_NAME); + } + + bool KillUserProcesses() + { + return proxy_.getProperty("KillUserProcesses").onInterface(INTERFACE_NAME); + } + + std::string RebootParameter() + { + return proxy_.getProperty("RebootParameter").onInterface(INTERFACE_NAME); + } + + bool RebootToFirmwareSetup() + { + return proxy_.getProperty("RebootToFirmwareSetup").onInterface(INTERFACE_NAME); + } + + uint64_t RebootToBootLoaderMenu() + { + return proxy_.getProperty("RebootToBootLoaderMenu").onInterface(INTERFACE_NAME); + } + + std::string RebootToBootLoaderEntry() + { + return proxy_.getProperty("RebootToBootLoaderEntry").onInterface(INTERFACE_NAME); + } + + std::vector BootLoaderEntries() + { + return proxy_.getProperty("BootLoaderEntries").onInterface(INTERFACE_NAME); + } + + bool IdleHint() + { + return proxy_.getProperty("IdleHint").onInterface(INTERFACE_NAME); + } + + uint64_t IdleSinceHint() + { + return proxy_.getProperty("IdleSinceHint").onInterface(INTERFACE_NAME); + } + + uint64_t IdleSinceHintMonotonic() + { + return proxy_.getProperty("IdleSinceHintMonotonic").onInterface(INTERFACE_NAME); + } + + std::string BlockInhibited() + { + return proxy_.getProperty("BlockInhibited").onInterface(INTERFACE_NAME); + } + + std::string DelayInhibited() + { + return proxy_.getProperty("DelayInhibited").onInterface(INTERFACE_NAME); + } + + uint64_t InhibitDelayMaxUSec() + { + return proxy_.getProperty("InhibitDelayMaxUSec").onInterface(INTERFACE_NAME); + } + + uint64_t UserStopDelayUSec() + { + return proxy_.getProperty("UserStopDelayUSec").onInterface(INTERFACE_NAME); + } + + std::string HandlePowerKey() + { + return proxy_.getProperty("HandlePowerKey").onInterface(INTERFACE_NAME); + } + + std::string HandlePowerKeyLongPress() + { + return proxy_.getProperty("HandlePowerKeyLongPress").onInterface(INTERFACE_NAME); + } + + std::string HandleRebootKey() + { + return proxy_.getProperty("HandleRebootKey").onInterface(INTERFACE_NAME); + } + + std::string HandleRebootKeyLongPress() + { + return proxy_.getProperty("HandleRebootKeyLongPress").onInterface(INTERFACE_NAME); + } + + std::string HandleSuspendKey() + { + return proxy_.getProperty("HandleSuspendKey").onInterface(INTERFACE_NAME); + } + + std::string HandleSuspendKeyLongPress() + { + return proxy_.getProperty("HandleSuspendKeyLongPress").onInterface(INTERFACE_NAME); + } + + std::string HandleHibernateKey() + { + return proxy_.getProperty("HandleHibernateKey").onInterface(INTERFACE_NAME); + } + + std::string HandleHibernateKeyLongPress() + { + return proxy_.getProperty("HandleHibernateKeyLongPress").onInterface(INTERFACE_NAME); + } + + std::string HandleLidSwitch() + { + return proxy_.getProperty("HandleLidSwitch").onInterface(INTERFACE_NAME); + } + + std::string HandleLidSwitchExternalPower() + { + return proxy_.getProperty("HandleLidSwitchExternalPower").onInterface(INTERFACE_NAME); + } + + std::string HandleLidSwitchDocked() + { + return proxy_.getProperty("HandleLidSwitchDocked").onInterface(INTERFACE_NAME); + } + + uint64_t HoldoffTimeoutUSec() + { + return proxy_.getProperty("HoldoffTimeoutUSec").onInterface(INTERFACE_NAME); + } + + std::string IdleAction() + { + return proxy_.getProperty("IdleAction").onInterface(INTERFACE_NAME); + } + + uint64_t IdleActionUSec() + { + return proxy_.getProperty("IdleActionUSec").onInterface(INTERFACE_NAME); + } + + bool PreparingForShutdown() + { + return proxy_.getProperty("PreparingForShutdown").onInterface(INTERFACE_NAME); + } + + bool PreparingForSleep() + { + return proxy_.getProperty("PreparingForSleep").onInterface(INTERFACE_NAME); + } + + sdbus::Struct ScheduledShutdown() + { + return proxy_.getProperty("ScheduledShutdown").onInterface(INTERFACE_NAME); + } + + bool Docked() + { + return proxy_.getProperty("Docked").onInterface(INTERFACE_NAME); + } + + bool LidClosed() + { + return proxy_.getProperty("LidClosed").onInterface(INTERFACE_NAME); + } + + bool OnExternalPower() + { + return proxy_.getProperty("OnExternalPower").onInterface(INTERFACE_NAME); + } + + bool RemoveIPC() + { + return proxy_.getProperty("RemoveIPC").onInterface(INTERFACE_NAME); + } + + uint64_t RuntimeDirectorySize() + { + return proxy_.getProperty("RuntimeDirectorySize").onInterface(INTERFACE_NAME); + } + + uint64_t RuntimeDirectoryInodesMax() + { + return proxy_.getProperty("RuntimeDirectoryInodesMax").onInterface(INTERFACE_NAME); + } + + uint64_t InhibitorsMax() + { + return proxy_.getProperty("InhibitorsMax").onInterface(INTERFACE_NAME); + } + + uint64_t NCurrentInhibitors() + { + return proxy_.getProperty("NCurrentInhibitors").onInterface(INTERFACE_NAME); + } + + uint64_t SessionsMax() + { + return proxy_.getProperty("SessionsMax").onInterface(INTERFACE_NAME); + } + + uint64_t NCurrentSessions() + { + return proxy_.getProperty("NCurrentSessions").onInterface(INTERFACE_NAME); + } + + uint64_t StopIdleSessionUSec() + { + return proxy_.getProperty("StopIdleSessionUSec").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/org.freedesktop.login1.Manager.xml b/internal/platform/implementation/linux/org.freedesktop.login1.Manager.xml new file mode 100644 index 00000000..52417e27 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.login1.Manager.xml @@ -0,0 +1,388 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 93673e9d2c2bc88dba94f1a3d55d1274a9a1587a Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 13:05:39 +0530 Subject: [PATCH 060/201] Add bluetooth_classic_server_socket.cc --- .../linux/bluetooth_classic_server_socket.cc | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 internal/platform/implementation/linux/bluetooth_classic_server_socket.cc diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc new file mode 100644 index 00000000..e6bc2e75 --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc @@ -0,0 +1,36 @@ +#include "absl/strings/str_replace.h" +#include "absl/strings/substitute.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_server_socket.h" +#include "internal/platform/implementation/linux/bluetooth_classic_socket.h" +#include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/logging.h" +#include + +namespace nearby { +namespace linux { +std::unique_ptr BluetoothServerSocket::Accept() { + auto pair = profile_manager_.GetServiceRecordFD(service_uuid_); + if (!pair.has_value()) { + NEARBY_LOGS(ERROR) << __func__ + << "Failed to get a new connection for profile " + << service_uuid_ << " for device "; + return nullptr; + } + + auto [device, fd] = *pair; + return std::unique_ptr(new BluetoothSocket(device, fd)); +} + +Exception BluetoothServerSocket::Close() { + auto profile_object_path = + absl::Substitute("/com/google/nearby/profiles/$0", service_uuid_); + + profile_manager_.Unregister(service_uuid_); + + return {Exception::kSuccess}; +} +} // namespace linux +} // namespace nearby From 67bc378a8326f6aa535fc19b81eaab41f2e318a9 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 13:05:59 +0530 Subject: [PATCH 061/201] Add org.freedesktop.Accounts.User.xml. --- .../linux/org.freedesktop.Accounts.User.xml | 1003 +++++++++++++++++ 1 file changed, 1003 insertions(+) create mode 100644 internal/platform/implementation/linux/org.freedesktop.Accounts.User.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.Accounts.User.xml b/internal/platform/implementation/linux/org.freedesktop.Accounts.User.xml new file mode 100644 index 00000000..d54ba441 --- /dev/null +++ b/internal/platform/implementation/linux/org.freedesktop.Accounts.User.xml @@ -0,0 +1,1003 @@ + + + + + + + + + + The new username. + + + + + + + Sets the userʼs username. Note that it is usually not allowed + to have multiple users with the same username. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the username of any user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new name, typically in the form "Firstname Lastname". + + + + + + + Sets the userʼs real name. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own name + + + org.freedesktop.accounts.user-administration + To change the name of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new email address. + + + + + + + Sets the userʼs email address. + + + Note that setting an email address in the AccountsService is + not the same as configuring a mail client. Mail clients might + default to email address that is configured here, though. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own email address + + + org.freedesktop.accounts.user-administration + To change the email address of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new language, as a locale specification like "de_DE.UTF-8". + + + + + + + Sets the user's language. + + + The expectation is that display managers will start the + userʼs session with this locale. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The user's preferred languages, as an array of locale specification like "de_DE.UTF-8". + + + + + + + Sets the userʼs preferred languages. The first item in the list will + be used to set the Language property. + + + The expectation is that package installers will use + this to know which languages the user is interested in, so as + to install extra data, like translations, dictionaries, etc. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own preferred languages + + + org.freedesktop.accounts.user-administration + To change the preferred languages of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + The new xsession to start (e.g. "gnome") + + + + + + + Sets the userʼs x session. + + + The expectation is that display managers will log the user in to this + specified session, if available. + + Note this call is deprecated and has been superceded by SetSession since + not all graphical sessions use X as the display server. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + The new session to start (e.g. "gnome-xorg") + + + + + + + Sets the userʼs wayland or x session. + + + The expectation is that display managers will log the user in to this + specified session, if available. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + The type of the new session to start (e.g. "wayland" or "x11") + + + + + + + Sets the session type of the userʼs session. + + + Display managers may use this property to decide what type of display server to use when + loading the session + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new location as a freeform string. + + + + + + + Sets the userʼs location. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own location + + + org.freedesktop.accounts.user-administration + To change the location of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new homedir as an absolute path. + + + + + + + Sets the userʼs home directory. + + + Note that changing the userʼs home directory moves all the content + from the old location to the new one, and is potentially an + expensive operation. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the home directory of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new user shell. + + + + + + + Sets the userʼs shell. + + + Note that setting the shell to a non-allowed program may + prevent the user from logging in. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the shell of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The absolute filename of a png file to use as the userʼs icon. + + + + + + + Sets the userʼs icon. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own icon + + + org.freedesktop.accounts.user-administration + To change the icon of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + Whether to lock or unlock the userʼs account. + + + + + + + Locks or unlocks a userʼs account. + + + Locking an account prevents the user from logging in. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To lock or unlock user accounts + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new account type, encoded as an integer: + + + 0 + Standard user + + + 1 + Administrator + + + + + + + + + Changes the userʼs account type. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change an account type + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new password mode, encoded as an integer: + + + 0 + Regular password + + + 1 + Password must be set at next login + + + 2 + No password + + + + + + + + + Changes the userʼs password mode. + + + Note that changing the password mode has the side-effect of + unlocking the account. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change a userʼs password mode + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The crypted password. + + + + + + + The password hint. + + + + + + + Sets a new password for this user. + + + Note that setting a password has the side-effect of + unlocking the account. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the password of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The password hint. + + + + + + + Sets the userʼs password hint. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change their own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + Whether to enable automatic login for this user. + + + + + + + Enables or disables automatic login for a user. + + + Note that usually only one user can have automatic login + enabled, so turning it on for a user will disable it for + the previously configured autologin user. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.set-login-option + To change the login screen configuration + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The uid of the user. + + + + + + + + + + The username of the user. + + + + + + + + + + The userʼs real name. + + + + + + + + + + The userʼs account type, encoded as an integer: + + + 0 + Standard user + + + 1 + Administrator + + + + + + + + + + + + The userʼs home directory. + + + + + + + + + + The userʼs shell. + + + + + + + + + + The email address. + + + + + + + + + + The user's main language, as a locale specification like "de_DE.UTF-8". + + + + + + + + + + The user's other preferred languages, as a locale specification like "de_DE.UTF-8". + + + + + + + + + + The userʼs Wayland or X session. + + + + + + + + + + The type of session the user should use (e.g. "wayland" or "x11") + + + + + + + + + + The userʼs x session. + + + + + + + + + + The userʼs location. + + + + + + + + + + How often the user has logged in. + + + + + + + + + + The last login time. + + + + + + + + + + + The login history for this user. + Each entry in the array represents a login session. The first two + members are the login time and logout time, as timestamps (seconds since the epoch). If the session is still running, the logout time + is 0. + + + The a{sv} member is a dictionary containing additional information + about the session. Possible members include 'type' (with values like ':0', 'tty0', 'pts/0' etc). + + + + + + + + + + The filename of a png file containing the userʼs icon. + + + + + + + + + + Whether the userʼs account has retained state + + + + + + + + + + Whether the userʼs account is locked. + + + + + + + + + + The password mode for the user account, encoded as an integer: + + + 0 + Regular password + + + 1 + Password must be set at next login + + + 2 + No password + + + + + + + + + + + + The password hint for the user. + + + + + + + + + + Whether automatic login is enabled for the user. + + + + + + + + + + Whether this is a 'system' account, like 'root' or 'nobody'. + System accounts should normally not appear in lists of + users, and ListCachedUsers will not include such accounts. + + + + + + + + + + Whether the user is a local account or not. + + + + + + + + + + Emitted when the user is changed. + + + + + + + From 7f80090388ca5db44c52cbc7891a21599f6ecb0c Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 13:06:35 +0530 Subject: [PATCH 062/201] Rewrite ThreadPool. --- .../implementation/linux/thread_pool.cc | 151 ++++++++---------- .../implementation/linux/thread_pool.h | 49 +++--- 2 files changed, 88 insertions(+), 112 deletions(-) diff --git a/internal/platform/implementation/linux/thread_pool.cc b/internal/platform/implementation/linux/thread_pool.cc index 2eb1fa12..dcbc72ef 100644 --- a/internal/platform/implementation/linux/thread_pool.cc +++ b/internal/platform/implementation/linux/thread_pool.cc @@ -12,117 +12,106 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/thread_pool.h" - +#include #include #include -#include "absl/memory/memory.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/thread_pool.h" #include "internal/platform/logging.h" #include "internal/platform/runnable.h" namespace nearby { namespace linux { - -std::unique_ptr ThreadPool::Create(int max_pool_size) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Create thread pool with maximum size(" - << max_pool_size << ")."; - - if (max_pool_size <= 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Maximum pool size must be positive integer value."; - return nullptr; - } - - std::unique_ptr> thread_pool = std::make_unique>(); - - // Sets thread pool maximum value. - thread_pool->resize(max_pool_size); - - return absl::WrapUnique( - new ThreadPool(thread_pool, max_pool_size)); +ThreadPool::ThreadPool(size_t max_pool_size) + : max_pool_size_(max_pool_size), shut_down_(false) { + threads_.reserve(max_pool_size); } -ThreadPool::ThreadPool(std::unique_ptr> &thread_pool, int max_pool_size) - : thread_pool_(std::move(thread_pool)), - max_pool_size_(max_pool_size) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Thread pool(" << this - << ") is created with size:" << max_pool_size_; +ThreadPool::~ThreadPool() { ShutDown(); } - for (int size = 0; size < max_pool_size_; size++) { - thread_pool_->at(size) = std::thread([this]() { - while (!tasks_.empty()) { - RunNextTask(); - // Possibly don't need but here to prevent 100% usage for loop - sleep(300); +bool ThreadPool::Start() { + shut_down_.store(false, std::memory_order_acquire); + + absl::MutexLock l(&mutex_); + if (!threads_.empty()) { + NEARBY_LOGS(ERROR) << __func__ << "thread pool is already active"; + return false; + } + + auto runner = [&]() { + while (true) { + if (shut_down_) { + return; } - }); + + auto task = NextTask(); + + if (task == nullptr) { + NEARBY_LOGS(WARNING) << __func__ << ": Tried to run a null task."; + continue; + } + task(); + } + }; + + for (size_t i = 0; i < max_pool_size_; i++) { + threads_.emplace_back(runner); } + + return true; } -ThreadPool::~ThreadPool() { - NEARBY_LOGS(VERBOSE) << __func__ << ": Thread pool(" << this - << ") is released."; +bool ThreadPool::Run(Runnable &&task) { + if (shut_down_) { + NEARBY_LOGS(ERROR) << __func__ << "thread pool has shut down"; + return false; + } - ShutDown(); -} - -bool ThreadPool::Run(Runnable task) { - absl::MutexLock lock(&mutex_); - - if (thread_pool_->size() == max_pool_size_) { + absl::MutexLock l(&mutex_); + if (threads_.empty()) { + NEARBY_LOGS(ERROR) << __func__ << "thread pool is not active"; return false; } tasks_.push(std::move(task)); - NEARBY_LOGS(VERBOSE) << __func__ << ": Scheduled to run task(" - << &tasks_.back() << ")."; return true; } void ThreadPool::ShutDown() { - absl::MutexLock lock(&mutex_); + shut_down_.store(true, std::memory_order_acquire); - if (!thread_pool_->empty()) { - NEARBY_LOGS(WARNING) << __func__ << ": Request to shutdown thread pool with " << thread_pool_->size() << " tasks not finished(" << this << ")."; - } - - NEARBY_LOGS(VERBOSE) << __func__ << ": Shutdown thread pool(" << this << ")."; - if (thread_pool_ == nullptr) { - NEARBY_LOGS(WARNING) << __func__ << ": Shutdown on closed thread pool(" - << this << ")."; - return; - } - - thread_pool_.reset(); -} - -void ThreadPool::RunNextTask() { - Runnable task = nullptr; + NEARBY_LOGS(INFO) + << __func__ << ": asked to shut down, waiting for active threads to stop"; { - absl::MutexLock lock(&mutex_); - - if (!thread_pool_) { - return; - } - if (!tasks_.empty()) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Run task(" << &tasks_.front() - << ")."; - - task = std::move(tasks_.front()); - tasks_.pop(); + absl::ReaderMutexLock l(&mutex_); + for (auto &thread : threads_) { + thread.join(); } } - if (task == nullptr) { - NEARBY_LOGS(WARNING) << __func__ - << ": Tried to run task in an empty thread pool."; - return; - } - task(); + absl::MutexLock l(&mutex_); + threads_.clear(); + NEARBY_LOGS(INFO) << __func__ << ": shut down thread pool"; } -} // namespace linux -} // namespace nearby +Runnable ThreadPool::NextTask() { + Runnable task; + auto task_available = [&]() { + mutex_.AssertReaderHeld(); + return !tasks_.empty(); + }; + + { + absl::MutexLock l(&mutex_, absl::Condition(&task_available)); + + task = std::move(tasks_.front()); + tasks_.pop(); + } + + return task; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/thread_pool.h b/internal/platform/implementation/linux/thread_pool.h index 889fe8b6..a5a9aa42 100644 --- a/internal/platform/implementation/linux/thread_pool.h +++ b/internal/platform/implementation/linux/thread_pool.h @@ -15,11 +15,12 @@ #ifndef PLATFORM_IMPL_LINUX_THREAD_POOL_H_ #define PLATFORM_IMPL_LINUX_THREAD_POOL_H_ +#include #include #include +#include #include #include -#include #include "absl/base/thread_annotations.h" #include "absl/synchronization/mutex.h" @@ -29,44 +30,30 @@ namespace nearby { namespace linux { class ThreadPool { - public: - virtual ~ThreadPool(); - static std::unique_ptr Create(int max_pool_size); +public: + ThreadPool(size_t max_pool_size); + ~ThreadPool(); + + bool Start() ABSL_LOCKS_EXCLUDED(mutex_); // Runs a task on thread pool. The result indicates whether the task is put // into the thread pool. - bool Run(Runnable task) ABSL_LOCKS_EXCLUDED(mutex_); + bool Run(Runnable &&task) ABSL_LOCKS_EXCLUDED(mutex_); - // The thread pool is closed immediately if there is no outstanding work, - // I/O, timer, or wait objects that are bound to the pool; otherwise, the - // thread pool is released asynchronously after the outstanding objects are - // freed. void ShutDown() ABSL_LOCKS_EXCLUDED(mutex_); - private: - ThreadPool(std::unique_ptr> &thread_pool, int max_pool_size); +private: + Runnable NextTask() ABSL_LOCKS_EXCLUDED(mutex_); - void RunNextTask(); +private: + size_t max_pool_size_; + std::atomic_bool shut_down_; - // Starts each task and injects a function that removes the task when it is finished - std::thread tasks_runner_; - - // Protects the access to tasks of the thread pool. - mutable absl::Mutex mutex_; - - // The task queue of the thread pool. Thread pool will pick up task to run - // when it is idle. + absl::Mutex mutex_; + std::vector threads_ ABSL_GUARDED_BY(mutex_); std::queue tasks_ ABSL_GUARDED_BY(mutex_); - - // All the threads run in the pool - std::unique_ptr> thread_pool_ ABSL_GUARDED_BY(mutex_); - - // The maximum thread count in the thread pool - int max_pool_size_ ABSL_GUARDED_BY(mutex_) = 0; - }; +} // namespace linux +} // namespace nearby -} // namespace linux -} // namespace nearby - -#endif // PLATFORM_IMPL_LINUX_THREAD_POOL_H_ +#endif // PLATFORM_IMPL_LINUX_THREAD_POOL_H_ From 2e88b4aa7fd439b874fe9f91aa1561717b11fc22 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 13:07:30 +0530 Subject: [PATCH 063/201] Minor refactor. --- .../platform/implementation/linux/executor.cc | 17 +++++++--------- .../platform/implementation/linux/executor.h | 4 +--- .../linux/scheduled_executor.cc | 20 ++++++++++--------- .../linux/submittable_executor.cc | 4 +--- .../linux/submittable_executor.h | 3 +-- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/internal/platform/implementation/linux/executor.cc b/internal/platform/implementation/linux/executor.cc index 37dfcd9c..c222d1b2 100644 --- a/internal/platform/implementation/linux/executor.cc +++ b/internal/platform/implementation/linux/executor.cc @@ -16,21 +16,18 @@ #include +#include "internal/platform/implementation/linux/thread_pool.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { - -Executor::Executor() : Executor(1) {} - -Executor::Executor(int32_t max_concurrency) - : max_concurrency_(max_concurrency) { - assert(max_concurrency_ >= 1); - thread_pool_ = linux::ThreadPool::Create(max_concurrency); +Executor::Executor(size_t max_concurrency) + : thread_pool_(std::make_unique(max_concurrency)) { + assert(max_concurrency >= 1); assert(thread_pool_ != nullptr); } -void Executor::Execute(Runnable&& runnable) { +void Executor::Execute(Runnable &&runnable) { if (shut_down_) { NEARBY_LOGS(VERBOSE) << "Warning: " << __func__ << ": Attempt to execute on a shut down pool."; @@ -51,5 +48,5 @@ void Executor::Shutdown() { thread_pool_ = nullptr; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/executor.h b/internal/platform/implementation/linux/executor.h index bd96ef06..7552945a 100644 --- a/internal/platform/implementation/linux/executor.h +++ b/internal/platform/implementation/linux/executor.h @@ -28,8 +28,7 @@ namespace linux { // Executor. class Executor : public api::Executor { public: - Executor(); - explicit Executor(int max_concurrency); + Executor(size_t max_concurrency = 1); // Before returning from destructor, executor must wait for all pending // jobs to finish. @@ -41,7 +40,6 @@ class Executor : public api::Executor { private: std::unique_ptr thread_pool_ = nullptr; std::atomic shut_down_ = false; - int32_t max_concurrency_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/scheduled_executor.cc b/internal/platform/implementation/linux/scheduled_executor.cc index ff8b3a1d..e8a0be76 100644 --- a/internal/platform/implementation/linux/scheduled_executor.cc +++ b/internal/platform/implementation/linux/scheduled_executor.cc @@ -32,8 +32,8 @@ ScheduledExecutor::ScheduledExecutor() // We want Cancelable to live until both caller and executor are done with it. // Exclusive ownership model does not work for this case; // using std:shared_ptr<> instead of std::unique_ptr<>. -std::shared_ptr ScheduledExecutor::Schedule( - Runnable&& runnable, absl::Duration duration) { +std::shared_ptr +ScheduledExecutor::Schedule(Runnable &&runnable, absl::Duration duration) { if (shut_down_) { NEARBY_LOGS(ERROR) << __func__ << ": Attempt to Schedule on a shut down executor."; @@ -42,9 +42,11 @@ std::shared_ptr ScheduledExecutor::Schedule( } // Cleans completed tasks - std::remove_if( - scheduled_tasks_.begin(), scheduled_tasks_.end(), - [](std::shared_ptr& task) { return task->IsDone(); }); + scheduled_tasks_.erase( + std::remove_if( + scheduled_tasks_.begin(), scheduled_tasks_.end(), + [](std::shared_ptr &task) { return task->IsDone(); }), + scheduled_tasks_.end()); std::shared_ptr task = std::make_shared(std::move(runnable), duration); @@ -54,7 +56,7 @@ std::shared_ptr ScheduledExecutor::Schedule( return task; } -void ScheduledExecutor::Execute(Runnable&& runnable) { +void ScheduledExecutor::Execute(Runnable &&runnable) { if (shut_down_) { NEARBY_LOGS(ERROR) << __func__ << ": Attempt to Execute on a shut down executor."; @@ -67,7 +69,7 @@ void ScheduledExecutor::Execute(Runnable&& runnable) { void ScheduledExecutor::Shutdown() { if (!shut_down_) { shut_down_ = true; - for (auto& task : scheduled_tasks_) { + for (auto &task : scheduled_tasks_) { task->Cancel(); } @@ -78,5 +80,5 @@ void ScheduledExecutor::Shutdown() { NEARBY_LOGS(ERROR) << __func__ << ": Attempt to Shutdown on a shut down executor."; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/submittable_executor.cc b/internal/platform/implementation/linux/submittable_executor.cc index 3b721522..d9eb5ca2 100644 --- a/internal/platform/implementation/linux/submittable_executor.cc +++ b/internal/platform/implementation/linux/submittable_executor.cc @@ -20,9 +20,7 @@ namespace nearby { namespace linux { -SubmittableExecutor::SubmittableExecutor() : SubmittableExecutor(1) {} - -SubmittableExecutor::SubmittableExecutor(int32_t max_concurrancy) +SubmittableExecutor::SubmittableExecutor(size_t max_concurrancy) : executor_(std::make_unique(max_concurrancy)), shut_down_(false) {} diff --git a/internal/platform/implementation/linux/submittable_executor.h b/internal/platform/implementation/linux/submittable_executor.h index 63b1ef0b..133c144e 100644 --- a/internal/platform/implementation/linux/submittable_executor.h +++ b/internal/platform/implementation/linux/submittable_executor.h @@ -27,8 +27,7 @@ namespace linux { // Platform must override bool submit(absl::AnyInvocable) method. class SubmittableExecutor : public api::SubmittableExecutor { public: - SubmittableExecutor(); - SubmittableExecutor(int32_t maxConcurrancy); + SubmittableExecutor(size_t maxConcurrancy = 1); ~SubmittableExecutor() override = default; // Submit a callable (with no delay). From 7c22d03e7f0f66526abb715e9eb648cb0c3f92e3 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 13:59:20 +0530 Subject: [PATCH 064/201] StartAdvertising: Let avahi handle the host name. --- .../platform/implementation/linux/wifi_lan.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index d5d90e26..c094ddee 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -45,6 +45,8 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { auto object_path = avahi_->EntryGroupNew(); entry_group_ = std::make_unique(system_bus_, object_path); + NEARBY_LOGS(VERBOSE) << __func__ << "Created a new entry group at " + << entry_group_->getObjectPath(); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(avahi_, "EntryGroupNew", e); NEARBY_LOGS(ERROR) << __func__ << ": Could not create a new entry group."; @@ -68,12 +70,11 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { } try { - entry_group_->AddService(-1, // AVAHI_IF_UNSPEC - -1, // AVAHI_PROTO_UNSPED - 0, nsd_service_info.GetServiceName(), - nsd_service_info.GetServiceType(), std::string(), - nsd_service_info.GetIPAddress(), - nsd_service_info.GetPort(), txt_records); + entry_group_->AddService( + -1, // AVAHI_IF_UNSPEC + -1, // AVAHI_PROTO_UNSPED + 0, nsd_service_info.GetServiceName(), nsd_service_info.GetServiceType(), + std::string(), std::string(), nsd_service_info.GetPort(), txt_records); entry_group_->Commit(); } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() @@ -215,8 +216,6 @@ WifiLanMedium::ListenForService(int port) { return nullptr; } - NEARBY_LOGS(VERBOSE) << __func__ << "Listening for services"; - struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); @@ -237,6 +236,8 @@ WifiLanMedium::ListenForService(int port) { return nullptr; } + NEARBY_LOGS(VERBOSE) << __func__ << "Listening for services on port " << port; + return std::make_unique(sock, network_manager_, system_bus_); } From 433aa37a2d978270c8d752089f099b087fed8b41 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 14:00:18 +0530 Subject: [PATCH 065/201] Profile: Log profile object path after construction. --- .../platform/implementation/linux/bluetooth_bluez_profile.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index e6ea176c..a60003da 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -26,6 +26,7 @@ #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/implementation/linux/bluez_profile_glue.h" #include "internal/platform/implementation/linux/bluez_profile_manager_client_glue.h" +#include "internal/platform/logging.h" namespace nearby { namespace linux { @@ -36,6 +37,8 @@ public: : AdaptorInterfaces(system_bus, std::string(profile_object_path)), released_(false), devices_(devices) { registerAdaptor(); + NEARBY_LOGS(VERBOSE) << __func__ << ": Created a new BlueZ profile at :" + << getObjectPath(); } ~Profile() { unregisterAdaptor(); } From ac48b8e0eed2d77ee8b38448bfc327bbbd6f580e Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 14:02:03 +0530 Subject: [PATCH 066/201] Register: Create a BlueZ profile object before registering it. --- .../implementation/linux/bluetooth_bluez_profile.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 8503c503..7f3ef9a6 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -104,13 +104,17 @@ bool ProfileManager::Register(std::optional name, return true; } - auto profile_object_path = bluez::profile_object_path(service_uuid); + auto profile = std::make_shared( + getProxy().getConnection(), bluez::profile_object_path(service_uuid), + devices_); + try { std::map options; if (name.has_value()) { options["Name"] = std::string(*name); } - RegisterProfile(profile_object_path, std::string(service_uuid), options); + RegisterProfile(profile->getObjectPath(), std::string(service_uuid), + options); } catch (const sdbus::Error &e) { BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "RegisterProfile", e); return false; @@ -118,10 +122,7 @@ bool ProfileManager::Register(std::optional name, { absl::MutexLock l(®istered_service_uuids_lock_); - registered_services_.emplace( - std::string(service_uuid), - std::make_shared(getProxy().getConnection(), - profile_object_path, devices_)); + registered_services_.emplace(service_uuid, profile); } NEARBY_LOGS(INFO) << __func__ From d7d22684f4f5b846253cfaaba90d029a4da037aa Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 14:02:32 +0530 Subject: [PATCH 067/201] Start the thread pool on construction. --- internal/platform/implementation/linux/thread_pool.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/thread_pool.cc b/internal/platform/implementation/linux/thread_pool.cc index dcbc72ef..fdcf2466 100644 --- a/internal/platform/implementation/linux/thread_pool.cc +++ b/internal/platform/implementation/linux/thread_pool.cc @@ -26,6 +26,7 @@ namespace linux { ThreadPool::ThreadPool(size_t max_pool_size) : max_pool_size_(max_pool_size), shut_down_(false) { threads_.reserve(max_pool_size); + Start(); } ThreadPool::~ThreadPool() { ShutDown(); } @@ -55,6 +56,9 @@ bool ThreadPool::Start() { } }; + NEARBY_LOGS(INFO) << __func__ << ": Starting thread pool with " + << max_pool_size_ << " threads"; + for (size_t i = 0; i < max_pool_size_; i++) { threads_.emplace_back(runner); } @@ -70,7 +74,7 @@ bool ThreadPool::Run(Runnable &&task) { absl::MutexLock l(&mutex_); if (threads_.empty()) { - NEARBY_LOGS(ERROR) << __func__ << "thread pool is not active"; + NEARBY_LOGS(ERROR) << __func__ << ": thread pool is not active"; return false; } From 2887eedb3ef5b3c66a29e236479a384d9505358a Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 14:02:44 +0530 Subject: [PATCH 068/201] profile_object_path: Ensure the object name is valid. --- internal/platform/implementation/linux/bluez.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index 736a6c49..426ff73d 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -14,7 +14,8 @@ std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, } sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) { - return absl::Substitute("/com/google/nearby/profiles/$0", service_uuid); + return absl::Substitute("/com/google/nearby/profiles/$0", + absl::StrReplaceAll(service_uuid, {{"-", "_"}})); } sdbus::ObjectPath adapter_object_path(absl::string_view name) { From fbf7512a6a956e8844118b61aee7190e0eff015d Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 14:03:16 +0530 Subject: [PATCH 069/201] Add dummy implementations for BLE. --- internal/platform/implementation/linux/platform.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index fb33b1f2..84ff676d 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -15,6 +15,8 @@ #include "internal/platform/implementation/input_file.h" #include "internal/platform/implementation/linux/atomic_boolean.h" #include "internal/platform/implementation/linux/atomic_uint32.h" +#include "internal/platform/implementation/linux/ble_medium.h" +#include "internal/platform/implementation/linux/ble_v2_medium.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_classic_medium.h" #include "internal/platform/implementation/linux/bluez.h" @@ -183,12 +185,12 @@ ImplementationPlatform::CreateBluetoothClassicMedium( std::unique_ptr ImplementationPlatform::CreateBleMedium(BluetoothAdapter &) { - return nullptr; + return std::make_unique(); } std::unique_ptr ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { - return nullptr; + return std::make_unique(); } static std::unique_ptr From 9130c37b4f76aeb37c2182d91ba61a9f9d48c5f6 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 14:03:28 +0530 Subject: [PATCH 070/201] Add ble headers. --- internal/platform/implementation/linux/BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 9de52edd..98c174f4 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -48,6 +48,8 @@ cc_library( "avahi_entrygroup_client_glue.h", "avahi_server_client_glue.h", "avahi_servicebrowser_client_glue.h", + "ble_medium.h", + "ble_v2_medium.h", "bluetooth_adapter.h", "bluetooth_bluez_profile.h", "bluetooth_classic_device.h", From 0ca9a2f022b5936e3826b924bc571e8e7415993b Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 14:08:58 +0530 Subject: [PATCH 071/201] BluetoothServerSocket: Fix lifetime issues with service_uuid. --- .../implementation/linux/bluetooth_classic_server_socket.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h index 817c33ed..821a850d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -4,13 +4,14 @@ #include "internal/platform/exception.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" +#include "absl/strings/string_view.h" namespace nearby { namespace linux { class BluetoothServerSocket : public api::BluetoothServerSocket { public: BluetoothServerSocket(ProfileManager &profile_manager, - const std::string &service_uuid) + absl::string_view service_uuid) : profile_manager_(profile_manager), service_uuid_(service_uuid) {} ~BluetoothServerSocket() = default; @@ -32,7 +33,7 @@ public: private: ProfileManager &profile_manager_; - const std::string &service_uuid_; + std::string service_uuid_; }; } // namespace linux } // namespace nearby From 3fc41d70c34cc511083f630aabfaeaa968da44d5 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 15:09:14 +0530 Subject: [PATCH 072/201] Free resources on destruction. --- .../platform/implementation/linux/avahi.h | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index a0ed8cec..eff5f233 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -8,6 +8,7 @@ #include "internal/platform/implementation/linux/avahi_entrygroup_client_glue.h" #include "internal/platform/implementation/linux/avahi_server_client_glue.h" #include "internal/platform/implementation/linux/avahi_servicebrowser_client_glue.h" +#include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/wifi_lan.h" namespace nearby { @@ -36,7 +37,15 @@ public: entry_group_object_path) { registerProxy(); } - ~EntryGroup() { unregisterProxy(); } + ~EntryGroup() { + 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 { @@ -54,7 +63,14 @@ public: discovery_cb_(std::move(callback)) { registerProxy(); } - ~ServiceBrowser() { unregisterProxy(); } + ~ServiceBrowser() { + unregisterProxy(); + try { + Free(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "Free", e); + } + } protected: void onItemNew(const int32_t &interface, const int32_t &protocol, From 47057e068da4cb2e0168d03e6797d646c3115500 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 15:09:28 +0530 Subject: [PATCH 073/201] Allow advertising multiple services. --- .../platform/implementation/linux/wifi_lan.cc | 130 ++++++++++-------- .../platform/implementation/linux/wifi_lan.h | 34 +++-- 2 files changed, 90 insertions(+), 74 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index c094ddee..3ebf1250 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -9,6 +9,7 @@ #include #include +#include #include "absl/strings/substitute.h" #include "internal/platform/implementation/linux/avahi.h" @@ -25,41 +26,45 @@ namespace linux { WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus) : system_bus_(system_bus), network_manager_(std::make_shared(system_bus)), - avahi_(std::make_shared(system_bus)), - entry_group_(nullptr) {} - -WifiLanMedium::~WifiLanMedium() { - if (entry_group_ != nullptr) { - entry_group_->Free(); - } -} + avahi_(std::make_unique(system_bus)) {} bool WifiLanMedium::IsNetworkConnected() const { auto state = network_manager_->getState(); return state >= 50; // NM_STATE_CONNECTED_LOCAL } -bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { - if (entry_group_ == nullptr) { - try { - auto object_path = avahi_->EntryGroupNew(); - entry_group_ = - std::make_unique(system_bus_, object_path); - NEARBY_LOGS(VERBOSE) << __func__ << "Created a new entry group at " - << entry_group_->getObjectPath(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(avahi_, "EntryGroupNew", e); - NEARBY_LOGS(ERROR) << __func__ << ": Could not create a new entry group."; - return false; - } +std::optional> +entry_group_key(const NsdServiceInfo &nsd_service_info) { + auto name = nsd_service_info.GetServiceName(); + if (name.empty()) { + NEARBY_LOGS(ERROR) << __func__ << ": service name cannot be empty"; + return std::nullopt; } - if (advertising_) { - NEARBY_LOGS(ERROR) << __func__ - << ": Cannot advertise while we are already advertising"; + auto type = nsd_service_info.GetServiceType(); + if (type.empty()) { + NEARBY_LOGS(ERROR) << __func__ << ": service type cannot be empty"; + return std::nullopt; + } + + return std::make_pair(std::move(name), std::move(type)); +} + +bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { + auto key = entry_group_key(nsd_service_info); + if (!key.has_value()) { return false; } + { + absl::ReaderMutexLock l(&entry_groups_mutex_); + if (entry_groups_.count(*key) == 1) { + NEARBY_LOGS(ERROR) << __func__ + << ": advertising is already active for this service"; + return false; + } + } + auto txt_records_map = nsd_service_info.GetTxtRecords(); std::vector> txt_records(txt_records_map.size()); std::size_t i = 0; @@ -69,13 +74,24 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { txt_records[i++] = std::vector(entry.begin(), entry.end()); } + sdbus::ObjectPath entry_group_path; try { - entry_group_->AddService( + entry_group_path = avahi_->EntryGroupNew(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(avahi_, "EntryGroupNew", e); + return false; + } + + auto entry_group = + std::make_unique(system_bus_, entry_group_path); + + try { + entry_group->AddService( -1, // AVAHI_IF_UNSPEC -1, // AVAHI_PROTO_UNSPED 0, nsd_service_info.GetServiceName(), nsd_service_info.GetServiceType(), std::string(), std::string(), nsd_service_info.GetPort(), txt_records); - entry_group_->Commit(); + entry_group->Commit(); } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() @@ -83,48 +99,42 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { return false; } - advertising_ = true; + absl::MutexLock l(&entry_groups_mutex_); + entry_groups_.insert({*key, std::move(entry_group)}); + return true; } bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) { - if (!advertising_) { - NEARBY_LOGS(ERROR) << __func__ << ": Advertising is already stopped."; - return false; - } - if (entry_group_ == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": No entry group registered."; + auto key = entry_group_key(nsd_service_info); + if (!key.has_value()) { return false; } - try { - if (entry_group_->IsEmpty()) { - NEARBY_LOGS(ERROR) - << __func__ << ": Cannot stop advertising on an empty entry group."; - return false; - } - entry_group_->Reset(); - entry_group_->Commit(); - } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while removing service"; + absl::MutexLock l(&entry_groups_mutex_); + if (entry_groups_.count(*key) == 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Advertising is already inactive for this service."; return false; } - advertising_ = false; + entry_groups_.erase(*key); return true; } bool WifiLanMedium::StartDiscovery( const std::string &service_type, api::WifiLanMedium::DiscoveredServiceCallback callback) { - if (service_browsers_.count(service_type) != 0) { - auto &object = service_browsers_[service_type]; - NEARBY_LOGS(ERROR) << __func__ << ": A service browser for service type " - << service_type << " already exists at " - << object->getObjectPath(); - return false; + + { + absl::ReaderMutexLock l(&service_browsers_mutex_); + if (service_browsers_.count(service_type) != 0) { + auto &object = service_browsers_[service_type]; + NEARBY_LOGS(ERROR) << __func__ << ": A service browser for service type " + << service_type << " already exists at " + << object->getObjectPath(); + return false; + } } try { @@ -136,6 +146,8 @@ bool WifiLanMedium::StartDiscovery( << __func__ << ": Created a new org.freedesktop.Avahi.ServiceBrowser object at " << browser_object_path; + + absl::MutexLock l(&service_browsers_mutex_); service_browsers_.emplace( service_type, std::make_unique( @@ -145,7 +157,10 @@ bool WifiLanMedium::StartDiscovery( return false; } + service_browsers_mutex_.ReaderLock(); auto &browser = service_browsers_[service_type]; + service_browsers_mutex_.ReaderUnlock(); + try { NEARBY_LOGS(VERBOSE) << __func__ << ": Starting service discovery for " << browser->getObjectPath(); @@ -159,20 +174,13 @@ bool WifiLanMedium::StartDiscovery( } bool WifiLanMedium::StopDiscovery(const std::string &service_type) { + absl::MutexLock l(&service_browsers_mutex_); + if (service_browsers_.count(service_type) == 0) { NEARBY_LOGS(ERROR) << __func__ << ": Service type " << service_type << " has not been registered for discovery"; return false; } - - auto &browser = service_browsers_[service_type]; - try { - browser->Free(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(browser, "Free", e); - return false; - } - service_browsers_.erase(service_type); return true; diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 3600f500..856cfc7a 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -1,9 +1,9 @@ #ifndef PLATFORM_IMPL_LINUX_WIFI_LAN_H_ #define PLATFORM_IMPL_LINUX_WIFI_LAN_H_ #include -#include #include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/avahi.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_lan.h" @@ -14,14 +14,21 @@ namespace linux { class WifiLanMedium : public api::WifiLanMedium { public: WifiLanMedium(sdbus::IConnection &system_bus); - ~WifiLanMedium() override; + ~WifiLanMedium() override = default; bool IsNetworkConnected() const override; - bool StartAdvertising(const NsdServiceInfo &nsd_service_info) override; - bool StopAdvertising(const NsdServiceInfo &nsd_service_info) override; + + bool StartAdvertising(const NsdServiceInfo &nsd_service_info) override + ABSL_LOCKS_EXCLUDED(entry_groups_mutex_); + bool StopAdvertising(const NsdServiceInfo &nsd_service_info) override + ABSL_LOCKS_EXCLUDED(entry_groups_mutex_); + bool StartDiscovery(const std::string &service_type, - DiscoveredServiceCallback callback) override; - bool StopDiscovery(const std::string &service_type) override; + DiscoveredServiceCallback callback) override + ABSL_LOCKS_EXCLUDED(service_browsers_mutex_); + bool StopDiscovery(const std::string &service_type) override + ABSL_LOCKS_EXCLUDED(service_browsers_mutex_); + std::unique_ptr ConnectToService(const NsdServiceInfo &remote_service_info, CancellationFlag *cancellation_flag) override { @@ -39,19 +46,20 @@ public: } private: - DiscoveredServiceCallback discovery_cb_; - sdbus::IConnection &system_bus_; std::shared_ptr network_manager_; - std::shared_ptr avahi_; - std::unique_ptr entry_group_; + std::unique_ptr avahi_; + absl::Mutex entry_groups_mutex_; + absl::flat_hash_map, + std::unique_ptr> + entry_groups_ ABSL_GUARDED_BY(entry_groups_mutex_); + + absl::Mutex service_browsers_mutex_; absl::flat_hash_map> - service_browsers_; - - bool advertising_; + service_browsers_ ABSL_GUARDED_BY(service_browsers_mutex_); }; } // namespace linux } // namespace nearby From 6abeac91cedb86434ed13504a44861f9f77fdf5b Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 15:14:07 +0530 Subject: [PATCH 074/201] Add log messages for freeing service browsers and entry groups. --- internal/platform/implementation/linux/avahi.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index eff5f233..7c60c961 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -38,6 +38,9 @@ public: registerProxy(); } ~EntryGroup() { + NEARBY_LOGS(VERBOSE) << __func__ << ": Freeing entry group " + << getObjectPath(); + try { Free(); } catch (const sdbus::Error &e) { @@ -64,12 +67,15 @@ public: registerProxy(); } ~ServiceBrowser() { - unregisterProxy(); + 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: From adb1e1d235c1212c386a31cd2a0456693953bf04 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 15:47:13 +0530 Subject: [PATCH 075/201] Separate BluetoothAdapter into Adapter and BluezAdapter classes. --- .../implementation/linux/bluetooth_adapter.cc | 70 +++++-------------- .../implementation/linux/bluetooth_adapter.h | 49 +++++++++++-- .../linux/bluetooth_classic_medium.cc | 22 +++--- .../implementation/linux/bluetooth_pairing.cc | 6 +- .../implementation/linux/bluetooth_pairing.h | 5 +- .../platform/implementation/linux/platform.cc | 2 +- 6 files changed, 78 insertions(+), 76 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index 5d30dc0f..41ec999b 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -5,6 +5,7 @@ #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" +#include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/logging.h" namespace nearby { @@ -13,29 +14,19 @@ namespace linux { bool BluetoothAdapter::SetStatus(Status status) { try { bool val = status == api::BluetoothAdapter::Status::kEnabled; - Powered(val); + bluez_adapter_->Powered(val); return true; } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to set Powered status for adapter " - << getObjectPath(); + DBUS_LOG_PROPERTY_SET_ERROR(bluez_adapter_, "Powered", e); return false; } } bool BluetoothAdapter::IsEnabled() const { - auto proxy = sdbus::createProxy(getProxy().getConnection(), - bluez::SERVICE_DEST, getObjectPath()); - proxy->finishRegistration(); - try { - return proxy->getProperty("Powered").onInterface(INTERFACE_NAME); + return bluez_adapter_->Powered(); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get Powered status for adapter " - << getObjectPath(); + DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Powered", e); return false; } } @@ -47,20 +38,11 @@ BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const { } try { - auto proxy = sdbus::createProxy(getProxy().getConnection(), - bluez::SERVICE_DEST, getObjectPath()); - proxy->finishRegistration(); - - bool discoverable = - proxy->getProperty("Discoverable").onInterface(INTERFACE_NAME); + bool discoverable = bluez_adapter_->Discoverable(); return discoverable ? ScanMode::kConnectableDiscoverable : ScanMode::kConnectable; } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) - << __func__ << ": Got error '" << e.getName() << "' with message '" - << e.getMessage() - << "' while trying to get Discoverable status for adapter " - << getObjectPath(); + DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Discoverable", e); return ScanMode::kUnknown; } } @@ -75,13 +57,9 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { } try { - Discoverable(true); + bluez_adapter_->Discoverable(true); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) - << __func__ << ": Got error '" << e.getName() << "' with message '" - << e.getMessage() - << "' while trying to set Discoverable status for adapter " - << getObjectPath(); + DBUS_LOG_PROPERTY_SET_ERROR(bluez_adapter_, "Discoverable", e); return false; } @@ -95,50 +73,34 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) { } std::string BluetoothAdapter::GetName() const { - auto proxy = sdbus::createProxy(getProxy().getConnection(), - bluez::SERVICE_DEST, getObjectPath()); - proxy->finishRegistration(); - try { - return proxy->getProperty("Alias").onInterface(INTERFACE_NAME); + return bluez_adapter_->Alias(); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get Alias for adapter " - << getObjectPath(); + DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Alias", e); return std::string(); } } bool BluetoothAdapter::SetName(absl::string_view name, bool persist) { + persist_name_ = persist; return SetName(name); } bool BluetoothAdapter::SetName(absl::string_view name) { try { - Alias(std::string(name)); + bluez_adapter_->Alias(std::string(name)); return true; } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to set Alias for adapter " - << getObjectPath(); + DBUS_LOG_PROPERTY_SET_ERROR(bluez_adapter_, "Alias", e); return false; } } std::string BluetoothAdapter::GetMacAddress() const { - auto proxy = sdbus::createProxy(getProxy().getConnection(), - bluez::SERVICE_DEST, getObjectPath()); - proxy->finishRegistration(); - try { - return proxy->getProperty("Address").onInterface(INTERFACE_NAME); + return bluez_adapter_->Address(); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get Address for adapter " - << getObjectPath(); + DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Address", e); return std::string(); } } diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index 0bfe5f99..94d9291a 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -7,20 +7,37 @@ #include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" +#include "internal/platform/implementation/linux/dbus.h" namespace nearby { namespace linux { -class BluetoothAdapter - : public api::BluetoothAdapter, - public sdbus::ProxyInterfaces { +class BluezAdapter : public sdbus::ProxyInterfaces { public: - BluetoothAdapter(sdbus::IConnection &system_bus, - const sdbus::ObjectPath &adapter_object_path) + BluezAdapter(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path) : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, adapter_object_path) { registerProxy(); } + ~BluezAdapter() { unregisterProxy(); } +}; - ~BluetoothAdapter() override { unregisterProxy(); } +class BluetoothAdapter : public api::BluetoothAdapter { +public: + BluetoothAdapter(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path) + : bluez_adapter_( + std::make_unique(system_bus, adapter_object_path)) {} + + ~BluetoothAdapter() override { + if (!persist_name_) { + NEARBY_LOGS(INFO) << __func__ << "Resetting adapter Alias"; + try { + bluez_adapter_->Alias(""); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_SET_ERROR(bluez_adapter_, "Alias", e); + } + } + } bool SetStatus(Status status) override; bool IsEnabled() const override; @@ -33,6 +50,26 @@ public: 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_; } + +private: + std::unique_ptr bluez_adapter_; + bool persist_name_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 40ecf848..97348242 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -40,7 +40,8 @@ void BluetoothClassicMedium::onInterfacesAdded( &interfacesAndProperties) { NEARBY_LOGS(VERBOSE) << __func__ << "New intefaces added at " << object; - auto path_prefix = absl::Substitute("$0/dev_", adapter_->getObjectPath()); + auto path_prefix = absl::Substitute( + "$0/dev_", adapter_->GetBluezAdapterObject().getObjectPath()); if (object.find(path_prefix) != 0) { return; } @@ -78,7 +79,7 @@ void BluetoothClassicMedium::onInterfacesRemoved( const std::vector &interfaces) { NEARBY_LOGS(VERBOSE) << __func__ << ": Intefaces removed at " << object; - auto path_prefix = absl::Substitute("$0/dev_", adapter_->getObjectPath()); + auto path_prefix = absl::Substitute("$0/dev_", adapter_->GetObjectPath()); if (object.find(path_prefix) != 0) { return; } @@ -120,10 +121,11 @@ bool BluetoothClassicMedium::StartDiscovery( try { NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on " - << adapter_->getObjectPath(); - adapter_->StartDiscovery(); + << adapter_->GetObjectPath(); + adapter_->GetBluezAdapterObject().StartDiscovery(); } catch (const sdbus::Error &e) { - BLUEZ_LOG_METHOD_CALL_ERROR(adapter_, "StartDiscovery", e); + DBUS_LOG_METHOD_CALL_ERROR(&adapter_->GetBluezAdapterObject(), + "StartDiscovery", e); return false; } @@ -131,15 +133,17 @@ bool BluetoothClassicMedium::StartDiscovery( } bool BluetoothClassicMedium::StopDiscovery() { + auto &adapter = adapter_->GetBluezAdapterObject(); + try { NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " - << adapter_->getObjectPath(); + << adapter.getObjectPath(); absl::MutexLock l(&this->discovery_cb_lock_); - adapter_->StopDiscovery(); + adapter.StopDiscovery(); this->discovery_cb_.reset(); } catch (const sdbus::Error &e) { - BLUEZ_LOG_METHOD_CALL_ERROR(adapter_, "StopDiscovery", e); + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); return false; } @@ -151,7 +155,7 @@ BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, const std::string &service_uuid, CancellationFlag *cancellation_flag) { auto device_object_path = bluez::device_object_path( - adapter_->getObjectPath(), remote_device.GetMacAddress()); + adapter_->GetObjectPath(), remote_device.GetMacAddress()); if (!profile_manager_->ProfileRegistered(service_uuid)) { if (!profile_manager_->Register("", service_uuid)) { NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 81bdbb89..ccd730ad 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -100,15 +100,15 @@ bool BluetoothPairing::CancelPairing() { } bool BluetoothPairing::Unpair() { - try { - adapter_.RemoveDevice(device_.getObjectPath()); + try { + adapter_.RemoveDeviceByObjectPath(device_.getObjectPath()); return true; } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while trying to unpair device " << device_.getObjectPath() << " on adapter " - << adapter_.getObjectPath(); + << adapter_.GetObjectPath(); return false; } } diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 80fce60c..1610477a 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -17,8 +17,7 @@ namespace nearby { namespace linux { class BluetoothPairing : public api::BluetoothPairing { public: - BluetoothPairing(BluetoothAdapter &adapter, - BluetoothDevice &remote_device); + BluetoothPairing(BluetoothAdapter &adapter, BluetoothDevice &remote_device); ~BluetoothPairing() override = default; bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; @@ -33,7 +32,7 @@ private: sdbus::PendingAsyncCall pair_async_call_; BluetoothDevice &device_; - BluetoothAdapter &adapter_; + linux::BluetoothAdapter &adapter_; api::BluetoothPairingCallback pairing_cb_; }; diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 84ff676d..eb10edfc 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -178,7 +178,7 @@ ImplementationPlatform::CreateBluetoothAdapter() { std::unique_ptr ImplementationPlatform::CreateBluetoothClassicMedium( BluetoothAdapter &adapter) { - auto path = static_cast(&adapter)->getObjectPath(); + auto path = static_cast(&adapter)->GetObjectPath(); return std::make_unique( linux::getSystemBusConnection(), path); } From 6b4c8446bce60c30c3df9071959bb1c325b6a3b5 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 16:14:33 +0530 Subject: [PATCH 076/201] Provide Avahi Server object to ServiceBrowser objects. --- internal/platform/implementation/linux/avahi.h | 5 +++-- internal/platform/implementation/linux/wifi_lan.cc | 4 ++-- internal/platform/implementation/linux/wifi_lan.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index 7c60c961..51002bfe 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -60,10 +60,11 @@ class ServiceBrowser : public sdbus::ProxyInterfaces< public: ServiceBrowser(sdbus::IConnection &system_bus, const sdbus::ObjectPath &service_browser_object_path, - api::WifiLanMedium::DiscoveredServiceCallback callback) + api::WifiLanMedium::DiscoveredServiceCallback callback, + std::shared_ptr avahi_server) : ProxyInterfaces(system_bus, "org.freedesktop.Avahi", service_browser_object_path), - discovery_cb_(std::move(callback)) { + discovery_cb_(std::move(callback)), server_(avahi_server) { registerProxy(); } ~ServiceBrowser() { diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 3ebf1250..0c482816 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -26,7 +26,7 @@ namespace linux { WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus) : system_bus_(system_bus), network_manager_(std::make_shared(system_bus)), - avahi_(std::make_unique(system_bus)) {} + avahi_(std::make_shared(system_bus)) {} bool WifiLanMedium::IsNetworkConnected() const { auto state = network_manager_->getState(); @@ -151,7 +151,7 @@ bool WifiLanMedium::StartDiscovery( service_browsers_.emplace( service_type, std::make_unique( - system_bus_, browser_object_path, std::move(callback))); + system_bus_, browser_object_path, std::move(callback), avahi_)); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(avahi_, "ServiceBrowserPrepare", e); return false; diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 856cfc7a..04a736e8 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -50,7 +50,7 @@ private: std::shared_ptr network_manager_; - std::unique_ptr avahi_; + std::shared_ptr avahi_; absl::Mutex entry_groups_mutex_; absl::flat_hash_map, From d17c49deae9e3e45f9cd493b0aa8ea537eefedbe Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 16:36:33 +0530 Subject: [PATCH 077/201] Pass the correct flags to ResolveService. --- internal/platform/implementation/linux/avahi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/avahi.cc b/internal/platform/implementation/linux/avahi.cc index c762ccce..8384e205 100644 --- a/internal/platform/implementation/linux/avahi.cc +++ b/internal/platform/implementation/linux/avahi.cc @@ -24,7 +24,7 @@ void ServiceBrowser::onItemNew(const int32_t &interface, r_address, r_port, r_txt, r_flags] = server_->ResolveService(interface, protocol, name, type, domain, 0, // AVAHI_PROTO_INET - flags); + 0); info.SetServiceName(r_name); info.SetIPAddress(r_address); info.SetPort(r_port); From bbde0a58597cbacbd08461010399524bc30d3070 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 16:36:50 +0530 Subject: [PATCH 078/201] Remove discovery_cb_lock_, as it can cause deadlocks. --- .../implementation/linux/bluetooth_classic_medium.cc | 12 ++++-------- .../implementation/linux/bluetooth_classic_medium.h | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 97348242..d0b404db 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -60,12 +60,10 @@ void BluetoothClassicMedium::onInterfacesAdded( auto &device = devices_->add_new_device(object); - discovery_cb_lock_.ReaderLock(); if (discovery_cb_.has_value() && discovery_cb_->device_discovered_cb != nullptr) { discovery_cb_->device_discovered_cb(device); } - discovery_cb_lock_.ReaderUnlock(); for (auto &observer : observers_.GetObservers()) { observer->DeviceAdded(device); @@ -101,12 +99,11 @@ void BluetoothClassicMedium::onInterfacesRemoved( for (auto &observer : observers_.GetObservers()) { observer->DeviceRemoved(*device); } - discovery_cb_lock_.ReaderLock(); + if (discovery_cb_.has_value() && discovery_cb_->device_lost_cb != nullptr) { discovery_cb_->device_lost_cb(*device); } - discovery_cb_lock_.ReaderUnlock(); } devices_->remove_device_by_path(object); } @@ -115,9 +112,8 @@ void BluetoothClassicMedium::onInterfacesRemoved( bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { - discovery_cb_lock_.Lock(); + discovery_cb_ = std::move(discovery_callback); - discovery_cb_lock_.Unlock(); try { NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on " @@ -126,6 +122,7 @@ bool BluetoothClassicMedium::StartDiscovery( } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(&adapter_->GetBluezAdapterObject(), "StartDiscovery", e); + discovery_cb_.reset(); return false; } @@ -134,12 +131,11 @@ bool BluetoothClassicMedium::StartDiscovery( bool BluetoothClassicMedium::StopDiscovery() { auto &adapter = adapter_->GetBluezAdapterObject(); - + try { NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " << adapter.getObjectPath(); - absl::MutexLock l(&this->discovery_cb_lock_); adapter.StopDiscovery(); this->discovery_cb_.reset(); } catch (const sdbus::Error &e) { diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 27165b14..21ca3a2d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -105,7 +105,6 @@ private: std::unique_ptr adapter_; std::unique_ptr devices_; - absl::Mutex discovery_cb_lock_; std::optional discovery_cb_; std::unique_ptr profile_manager_; From 78c1714e8ea0908186574565c5a76d40a70dedfb Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 16:46:24 +0530 Subject: [PATCH 079/201] ServiceBrowser: Ignore local services. --- .../platform/implementation/linux/avahi.cc | 21 +++++++++++++------ .../platform/implementation/linux/avahi.h | 9 ++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/avahi.cc b/internal/platform/implementation/linux/avahi.cc index 8384e205..8538459b 100644 --- a/internal/platform/implementation/linux/avahi.cc +++ b/internal/platform/implementation/linux/avahi.cc @@ -17,6 +17,10 @@ void ServiceBrowser::onItemNew(const int32_t &interface, << protocol << ", name: '" << name << "', type: '" << type << "', domain: '" << domain << "', flags: " << flags; + if (flags & kAvahiLookupResultLocal) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Ignoring local service."; + return; + } NsdServiceInfo info; try { @@ -45,9 +49,9 @@ void ServiceBrowser::onItemNew(const int32_t &interface, 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) { +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: " @@ -55,6 +59,11 @@ void ServiceBrowser::onItemRemove(const int32_t &interface, const int32_t &proto << 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, @@ -89,13 +98,13 @@ void ServiceBrowser::onFailure(const std::string &error) { void ServiceBrowser::onAllForNow() { NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() - << ": notified via ServiceBrowser that all records have " - "been added for now"; + << ": 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"; + << ": notified via ServiceBrowser of cache exhaustion"; } } // namespace avahi diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index 51002bfe..e1ca2d06 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -91,6 +91,15 @@ protected: 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_; }; From f0a12c40a01e9a5dc42b019dba8a1c88f992ef99 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 17:01:35 +0530 Subject: [PATCH 080/201] Add ble_medium.h, ble_v2_medium.h. --- .../implementation/linux/ble_medium.h | 59 +++++++++++++++ .../implementation/linux/ble_v2_medium.h | 75 +++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 internal/platform/implementation/linux/ble_medium.h create mode 100644 internal/platform/implementation/linux/ble_v2_medium.h diff --git a/internal/platform/implementation/linux/ble_medium.h b/internal/platform/implementation/linux/ble_medium.h new file mode 100644 index 00000000..3fe8155d --- /dev/null +++ b/internal/platform/implementation/linux/ble_medium.h @@ -0,0 +1,59 @@ +#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; + + // 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 + Connect(api::BlePeripheral &peripheral, const std::string &service_id, + CancellationFlag *cancellation_flag) override { + return nullptr; + } +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h new file mode 100644 index 00000000..03dafe8b --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -0,0 +1,75 @@ +#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_ +#define PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_ + +#include "internal/platform/implementation/ble_v2.h" + +namespace nearby { +namespace linux { +class BleV2Medium : public api::ble_v2::BleMedium { + bool StartAdvertising( + const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters) override { + return false; + } + std::unique_ptr + StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters, + AdvertisingCallback callback) override { + return nullptr; + } + bool StopAdvertising() override {return false;} + + bool StartScanning(const Uuid &service_uuid, + api::ble_v2::TxPowerLevel tx_power_level, + ScanCallback callback) override { + return false; + } + bool StopScanning() override { return false; } + + std::unique_ptr + StartScanning(const Uuid &service_uuid, + api::ble_v2::TxPowerLevel tx_power_level, + ScanningCallback callback) override { + return nullptr; + }; + + std::unique_ptr + StartGattServer(api::ble_v2::ServerGattConnectionCallback callback) override { + return nullptr; + } + + std::unique_ptr ConnectToGattServer( + api::ble_v2::BlePeripheral &peripheral, + api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::ClientGattConnectionCallback callback) override { + return nullptr; + } + + std::unique_ptr + OpenServerSocket(const std::string &service_id) override { + return nullptr; + } + + std::unique_ptr + 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 { + return false; + } + bool GetRemotePeripheral(const std::string &mac_address, + GetRemotePeripheralCallback callback) override { + return false; + } + bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, + GetRemotePeripheralCallback callback) override { + return false; + } +}; +} // namespace linux +} // namespace nearby + +#endif From e4786e4cc9dd826e823b704b2b50f5d252b24b01 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 18:01:46 +0530 Subject: [PATCH 081/201] Print: Avoid memory leaks. --- .../platform/implementation/linux/log_message.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index 06fa54e9..9fc6402d 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -89,6 +89,7 @@ void LogControl::send(google::LogSeverity severity, const char *full_filename, auto str = LogSink::ToString(severity, base_filename, line, tm_time, message, message_len); syslog(ConvertSeverityToSyslog(severity), "%s", str.c_str()); + break; } case kConsole: default: @@ -101,12 +102,17 @@ void LogControl::send(google::LogSeverity severity, const char *full_filename, } void LogMessage::Print(const char *format, ...) { + char *buf = nullptr; + va_list ap; va_start(ap, format); - char *buf = nullptr; - vasprintf(&buf, format, ap); + auto ret = vasprintf(&buf, format, ap); va_end(ap); - log_streamer_.stream() << std::string(buf); + + if (ret >= 0) { + free(buf); + log_streamer_.stream() << std::string(buf); + } } std::ostream &LogMessage::Stream() { return log_streamer_.stream(); } From 3e4cffccf842a0922522f69ecdb51b0848ca09fa Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 18:06:14 +0530 Subject: [PATCH 082/201] Use the correct syslog identifier. --- .../platform/implementation/linux/log_message.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h index 0a473e3a..aef04a90 100644 --- a/internal/platform/implementation/linux/log_message.h +++ b/internal/platform/implementation/linux/log_message.h @@ -1,12 +1,12 @@ #ifndef PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ #define PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ -#include "absl/synchronization/mutex.h" +#include +#include + #include "glog/logging.h" #include "internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h" #include "internal/platform/implementation/log_message.h" -#include -#include namespace nearby { namespace linux { @@ -16,7 +16,7 @@ namespace linux { class LogMessage : public api::LogMessage { public: LogMessage(const char *file, int line, Severity severity); - ~LogMessage() override {}; + ~LogMessage() override{}; void Print(const char *format, ...) override; @@ -32,8 +32,9 @@ class LogControl public google::LogSink { public: LogControl(sdbus::IConnection &system_bus) - : AdaptorInterfaces(system_bus, "/com/google/nearby"), - severity_(api::LogMessage::LogMessage::Severity::kVerbose) { + : AdaptorInterfaces(system_bus, "/org/freedesktop/LogControl1"), + severity_(api::LogMessage::LogMessage::Severity::kVerbose), + log_target_(kConsole) { registerAdaptor(); } ~LogControl() { unregisterAdaptor(); } @@ -99,9 +100,7 @@ protected: log_target_ = kSyslog; } - std::string SyslogIdentifier() override { - return "com.github.com.google.nearby"; - } + std::string SyslogIdentifier() override { return "com.google.nearby"; } void send(google::LogSeverity severity, const char *full_filename, const char *base_filename, int line, const struct ::tm *tm_time, From 366c57fe12319201e866cc4a10ed5dea5841390c Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 20:26:45 +0530 Subject: [PATCH 083/201] Use the correct object name for LoginManager. --- internal/platform/implementation/linux/device_info.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 4c7b0596..7cf2e850 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -69,7 +69,7 @@ class LoginManager public: LoginManager(sdbus::IConnection &system_bus) : ProxyInterfaces("org.freedesktop.login1", - "/org/freedesktop/hostname1") { + "/org/freedesktop/login1") { registerProxy(); } ~LoginManager() { unregisterProxy(); } From 429e60cdd594a8a771ac07c3b1ed5e08fcd5e04c Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 20:27:23 +0530 Subject: [PATCH 084/201] Store a copy of the last known name and address to use for lost devices. --- .../linux/bluetooth_classic_device.cc | 38 +++++++++++++++++-- .../linux/bluetooth_classic_device.h | 4 ++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index b9df13e9..0fcd088d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -5,6 +5,7 @@ #include "absl/strings/string_view.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/logging.h" namespace nearby { @@ -14,6 +15,16 @@ BluetoothDevice::BluetoothDevice(sdbus::IConnection &system_bus, : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, std::string(device_object_path)) { registerProxy(); + try { + last_known_name_ = Alias(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "Alias", e); + } + try { + last_known_address_ = Address(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "Address", e); + } } std::string BluetoothDevice::GetName() const { @@ -24,8 +35,19 @@ std::string BluetoothDevice::GetName() const { try { std::string alias = bluez_device->getProperty("Alias").onInterface(bluez::DEVICE_INTERFACE); + { + absl::MutexLock l(&properties_mutex_); + last_known_name_ = alias; + } return alias; } catch (const sdbus::Error &e) { + if (e.getName() == "org.freedesktop.DBus.Error.UnknownObject") { + NEARBY_LOGS(VERBOSE) + << __func__ << ": " << getObjectPath() + << ": device is no longer known, returning last known name"; + absl::ReaderMutexLock l(&properties_mutex_); + return last_known_name_; + } NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while trying to get Alias for device " @@ -42,8 +64,20 @@ std::string BluetoothDevice::GetMacAddress() const { try { std::string addr = bluez_device->getProperty("Address").onInterface( bluez::DEVICE_INTERFACE); + { + absl::MutexLock l(&properties_mutex_); + last_known_address_ = addr; + } return addr; } catch (const sdbus::Error &e) { + if (e.getName() == "org.freedesktop.DBus.Error.UnknownObject") { + NEARBY_LOGS(VERBOSE) + << __func__ << ": " << getObjectPath() + << ": device is no longer known, returning last known address"; + absl::ReaderMutexLock l(&properties_mutex_); + return last_known_address_; + } + NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while trying to get Address for device " @@ -91,10 +125,6 @@ void MonitoredBluetoothDevice::onPropertiesChanged( return; } - NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() - << ": Received PropertiesChanged signal for interface " - << interfaceName; - for (auto it = changedProperties.begin(); it != changedProperties.end(); it++) { if (it->first == bluez::DEVICE_PROP_ADDRESS) { diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index cab3058a..861859ac 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -53,6 +53,10 @@ private: absl::Mutex pair_callback_lock_; absl::AnyInvocable on_pair_reply_cb_ = DefaultCallback(); + + 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_); }; class MonitoredBluetoothDevice From bf84a1fdac07af60e221e3dce54a5af17f34c905 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 20:27:49 +0530 Subject: [PATCH 085/201] Simplify ObjectManager listener code. --- .../linux/bluetooth_classic_medium.cc | 44 ++++++++----------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index d0b404db..8a4cef22 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -15,6 +15,7 @@ #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" #include "internal/platform/implementation/linux/bluetooth_pairing.h" #include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/implementation/linux/bluez_device_client_glue.h" #include "internal/platform/logging.h" namespace nearby { @@ -37,9 +38,7 @@ BluetoothClassicMedium::~BluetoothClassicMedium() { unregisterProxy(); } void BluetoothClassicMedium::onInterfacesAdded( const sdbus::ObjectPath &object, const std::map> - &interfacesAndProperties) { - NEARBY_LOGS(VERBOSE) << __func__ << "New intefaces added at " << object; - + &interfaces) { auto path_prefix = absl::Substitute( "$0/dev_", adapter_->GetBluezAdapterObject().getObjectPath()); if (object.find(path_prefix) != 0) { @@ -51,23 +50,18 @@ void BluetoothClassicMedium::onInterfacesAdded( return; } - for (auto it = interfacesAndProperties.begin(); - it != interfacesAndProperties.end(); it++) { - auto interface = it->first; + if (interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1) { + NEARBY_LOGS(INFO) << __func__ << ": Encountered new device at " << object; - if (interface == "org.bluez.Device1") { - NEARBY_LOGS(INFO) << __func__ << ": Encountered new device at " << object; + auto &device = devices_->add_new_device(object); - auto &device = devices_->add_new_device(object); + if (discovery_cb_.has_value() && + discovery_cb_->device_discovered_cb != nullptr) { + discovery_cb_->device_discovered_cb(device); + } - if (discovery_cb_.has_value() && - discovery_cb_->device_discovered_cb != nullptr) { - discovery_cb_->device_discovered_cb(device); - } - - for (auto &observer : observers_.GetObservers()) { - observer->DeviceAdded(device); - } + for (auto &observer : observers_.GetObservers()) { + observer->DeviceAdded(device); } } } @@ -75,16 +69,13 @@ void BluetoothClassicMedium::onInterfacesAdded( void BluetoothClassicMedium::onInterfacesRemoved( const sdbus::ObjectPath &object, const std::vector &interfaces) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Intefaces removed at " << object; - auto path_prefix = absl::Substitute("$0/dev_", adapter_->GetObjectPath()); if (object.find(path_prefix) != 0) { return; } for (auto &interface : interfaces) { - if (interface == bluez::DEVICE_INTERFACE) { - + if (interface == org::bluez::Device1_proxy::INTERFACE_NAME) { { auto device = devices_->get_device_by_path(object); if (!device.has_value()) { @@ -95,15 +86,16 @@ void BluetoothClassicMedium::onInterfacesRemoved( return; } - NEARBY_LOGS(INFO) << __func__ << ": " << object << " has been removed"; - for (auto &observer : observers_.GetObservers()) { - observer->DeviceRemoved(*device); - } - + NEARBY_LOGS(INFO) << __func__ << ": Device " << object + << " has been removed"; if (discovery_cb_.has_value() && discovery_cb_->device_lost_cb != nullptr) { discovery_cb_->device_lost_cb(*device); } + + for (auto &observer : observers_.GetObservers()) { + observer->DeviceRemoved(*device); + } } devices_->remove_device_by_path(object); } From 6c198fc2d2ab978d330e73adee991ab5d923558a Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 22:06:30 +0530 Subject: [PATCH 086/201] Add copyright notice headers. --- .../implementation/linux/atomic_boolean.h | 14 ++++++++++++++ .../implementation/linux/atomic_uint32.h | 14 ++++++++++++++ internal/platform/implementation/linux/avahi.cc | 14 ++++++++++++++ internal/platform/implementation/linux/avahi.h | 14 ++++++++++++++ .../platform/implementation/linux/ble_medium.h | 14 ++++++++++++++ .../implementation/linux/ble_v2_medium.h | 14 ++++++++++++++ .../implementation/linux/bluetooth_adapter.cc | 14 ++++++++++++++ .../implementation/linux/bluetooth_adapter.h | 14 ++++++++++++++ .../linux/bluetooth_bluez_profile.cc | 14 ++++++++++++++ .../linux/bluetooth_bluez_profile.h | 14 ++++++++++++++ .../linux/bluetooth_classic_device.cc | 14 ++++++++++++++ .../linux/bluetooth_classic_device.h | 14 ++++++++++++++ .../linux/bluetooth_classic_medium.cc | 14 ++++++++++++++ .../linux/bluetooth_classic_medium.h | 14 ++++++++++++++ .../linux/bluetooth_classic_server_socket.cc | 14 ++++++++++++++ .../linux/bluetooth_classic_server_socket.h | 14 ++++++++++++++ .../linux/bluetooth_classic_socket.cc | 17 ++++++++++++++--- .../linux/bluetooth_classic_socket.h | 14 ++++++++++++++ .../implementation/linux/bluetooth_devices.cc | 14 ++++++++++++++ .../implementation/linux/bluetooth_devices.h | 14 ++++++++++++++ .../implementation/linux/bluetooth_pairing.cc | 14 ++++++++++++++ .../implementation/linux/bluetooth_pairing.h | 14 ++++++++++++++ internal/platform/implementation/linux/bluez.cc | 14 ++++++++++++++ internal/platform/implementation/linux/bluez.h | 14 ++++++++++++++ .../implementation/linux/condition_variable.h | 14 ++++++++++++++ .../implementation/linux/credential_storage.h | 14 ++++++++++++++ internal/platform/implementation/linux/dbus.cc | 14 ++++++++++++++ internal/platform/implementation/linux/dbus.h | 14 ++++++++++++++ .../implementation/linux/device_info.cc | 14 ++++++++++++++ .../platform/implementation/linux/device_info.h | 14 ++++++++++++++ .../implementation/linux/log_message.cc | 14 ++++++++++++++ .../platform/implementation/linux/log_message.h | 14 ++++++++++++++ internal/platform/implementation/linux/mutex.h | 14 ++++++++++++++ .../platform/implementation/linux/platform.cc | 14 ++++++++++++++ internal/platform/implementation/linux/stream.h | 14 ++++++++++++++ .../implementation/linux/wifi_direct.cc | 14 ++++++++++++++ .../platform/implementation/linux/wifi_direct.h | 14 ++++++++++++++ .../linux/wifi_direct_server_socket.cc | 14 ++++++++++++++ .../linux/wifi_direct_server_socket.h | 14 ++++++++++++++ .../implementation/linux/wifi_direct_socket.h | 14 ++++++++++++++ .../implementation/linux/wifi_hotspot.cc | 14 ++++++++++++++ .../implementation/linux/wifi_hotspot.h | 14 ++++++++++++++ .../linux/wifi_hotspot_server_socket.cc | 14 ++++++++++++++ .../linux/wifi_hotspot_server_socket.h | 14 ++++++++++++++ .../implementation/linux/wifi_hotspot_socket.h | 14 ++++++++++++++ .../platform/implementation/linux/wifi_lan.cc | 14 ++++++++++++++ .../platform/implementation/linux/wifi_lan.h | 14 ++++++++++++++ .../linux/wifi_lan_server_socket.cc | 14 ++++++++++++++ .../linux/wifi_lan_server_socket.h | 14 ++++++++++++++ .../implementation/linux/wifi_lan_socket.h | 14 ++++++++++++++ .../implementation/linux/wifi_medium.cc | 14 ++++++++++++++ .../platform/implementation/linux/wifi_medium.h | 14 ++++++++++++++ .../platform/implementation/linux/wifi_socket.h | 14 ++++++++++++++ 53 files changed, 742 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/atomic_boolean.h b/internal/platform/implementation/linux/atomic_boolean.h index 1cd1787e..85e835cb 100644 --- a/internal/platform/implementation/linux/atomic_boolean.h +++ b/internal/platform/implementation/linux/atomic_boolean.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/atomic_uint32.h b/internal/platform/implementation/linux/atomic_uint32.h index f5fbf88b..81c9468f 100644 --- a/internal/platform/implementation/linux/atomic_uint32.h +++ b/internal/platform/implementation/linux/atomic_uint32.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/avahi.cc b/internal/platform/implementation/linux/avahi.cc index 8538459b..bc3df9f1 100644 --- a/internal/platform/implementation/linux/avahi.cc +++ b/internal/platform/implementation/linux/avahi.cc @@ -1,3 +1,17 @@ +// 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" diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index e1ca2d06..121ac3c4 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/ble_medium.h b/internal/platform/implementation/linux/ble_medium.h index 3fe8155d..501c96a1 100644 --- a/internal/platform/implementation/linux/ble_medium.h +++ b/internal/platform/implementation/linux/ble_medium.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index 03dafe8b..51723032 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index 41ec999b..21822efd 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -1,3 +1,17 @@ +// 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 #include diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index 94d9291a..405931bc 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -1,3 +1,17 @@ +// 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 diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 7f3ef9a6..af0ec0a8 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index a60003da..588322ed 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 0fcd088d..8170c7f9 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 861859ac..35fc3d6c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 8a4cef22..79ccfc80 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -1,3 +1,17 @@ +// 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 #include diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 21ca3a2d..913a91fe 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc index e6bc2e75..ce0b59b0 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc @@ -1,3 +1,17 @@ +// 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 "absl/strings/str_replace.h" #include "absl/strings/substitute.h" #include "internal/platform/exception.h" diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h index 821a850d..d898794e 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 68877889..859f9014 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -1,14 +1,25 @@ +// 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 #include #include #include -#include - #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 { diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index fefe55e7..18266236 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 549ae5f0..24a0787b 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -1,3 +1,17 @@ +// 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 #include diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index a1d9d46c..67ef813a 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index ccd730ad..da612a3b 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -1,3 +1,17 @@ +// 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 #include diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 1610477a..48558a4e 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -1,3 +1,17 @@ +// 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_PROFILE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_ diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index 426ff73d..1347c317 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -1,3 +1,17 @@ +// 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 "absl/strings/substitute.h" #include "absl/strings/string_view.h" #include "absl/strings/str_replace.h" diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index ace3a142..c008ae0e 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/condition_variable.h b/internal/platform/implementation/linux/condition_variable.h index 13cdb23f..356b72f4 100644 --- a/internal/platform/implementation/linux/condition_variable.h +++ b/internal/platform/implementation/linux/condition_variable.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/credential_storage.h b/internal/platform/implementation/linux/credential_storage.h index 8730dd1b..802f0e04 100644 --- a/internal/platform/implementation/linux/credential_storage.h +++ b/internal/platform/implementation/linux/credential_storage.h @@ -1,3 +1,17 @@ +// 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 diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index bec2244e..d134b5c7 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -1,3 +1,17 @@ +// 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 #include diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h index 547cd2b9..73bbffbd 100644 --- a/internal/platform/implementation/linux/dbus.h +++ b/internal/platform/implementation/linux/dbus.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index a3ec5668..c8894843 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 7cf2e850..edbefd4d 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -1,3 +1,17 @@ +// 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_ diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index 9fc6402d..aeb2b612 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h index aef04a90..46b1084c 100644 --- a/internal/platform/implementation/linux/log_message.h +++ b/internal/platform/implementation/linux/log_message.h @@ -1,3 +1,17 @@ +// 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_LOG_MESSAGE_H_ #define PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ diff --git a/internal/platform/implementation/linux/mutex.h b/internal/platform/implementation/linux/mutex.h index 7007aee4..52619b6d 100644 --- a/internal/platform/implementation/linux/mutex.h +++ b/internal/platform/implementation/linux/mutex.h @@ -1,3 +1,17 @@ +// 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_MUTEX_H_ #define PLATFORM_IMPL_LINUX_MUTEX_H_ diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index eb10edfc..53080360 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/stream.h b/internal/platform/implementation/linux/stream.h index e761442f..ecf9f6ea 100644 --- a/internal/platform/implementation/linux/stream.h +++ b/internal/platform/implementation/linux/stream.h @@ -1,3 +1,17 @@ +// 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_STREAM_H_ #define PLATFORM_IMPL_LINUX_STREAM_H_ diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index 9ff6fde2..6b550109 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/wifi_direct.h b/internal/platform/implementation/linux/wifi_direct.h index 1346fc60..3e5025ad 100644 --- a/internal/platform/implementation/linux/wifi_direct.h +++ b/internal/platform/implementation/linux/wifi_direct.h @@ -1,3 +1,17 @@ +// 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_WIFI_DIRECT_H_ #define PLATFORM_IMPL_LINUX_WIFI_DIRECT_H_ #include diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.cc b/internal/platform/implementation/linux/wifi_direct_server_socket.cc index 65f4de96..ed351b4d 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.cc @@ -1,3 +1,17 @@ +// 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/wifi_direct_server_socket.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/linux/wifi_direct_socket.h" diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.h b/internal/platform/implementation/linux/wifi_direct_server_socket.h index 713f5e07..f0261667 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.h @@ -1,3 +1,17 @@ +// 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_WIFI_DIRECT_SERVER_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_DIRECT_SERVER_SOCKET_H_ diff --git a/internal/platform/implementation/linux/wifi_direct_socket.h b/internal/platform/implementation/linux/wifi_direct_socket.h index 932b3257..069eb0c2 100644 --- a/internal/platform/implementation/linux/wifi_direct_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_socket.h @@ -1,3 +1,17 @@ +// 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_WIFI_DIRECT_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_DIRECT_SOCKET_H_ diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 4640db2b..55716242 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/wifi_hotspot.h b/internal/platform/implementation/linux/wifi_hotspot.h index 18daf48f..9873ea3d 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.h +++ b/internal/platform/implementation/linux/wifi_hotspot.h @@ -1,3 +1,17 @@ +// 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_WIFI_HOTSPOT_H_ #define PLATFORM_IMPL_LINUX_WIFI_HOTSPOT_H_ diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc index 531dd7e0..847a20a5 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc @@ -1,3 +1,17 @@ +// 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 #include diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h index 7a8f2ac3..2097df01 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h @@ -1,3 +1,17 @@ +// 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_WIFI_SERVER_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_SERVER_SOCKET_H_ diff --git a/internal/platform/implementation/linux/wifi_hotspot_socket.h b/internal/platform/implementation/linux/wifi_hotspot_socket.h index 7e0d2d56..2a62668a 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_socket.h @@ -1,3 +1,17 @@ +// 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_WIFI_HOTSPOT_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_HOTSPOT_SOCKET_H_ diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 0c482816..c047366b 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 04a736e8..dc52fb30 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -1,3 +1,17 @@ +// 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_WIFI_LAN_H_ #define PLATFORM_IMPL_LINUX_WIFI_LAN_H_ #include diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index 89ac1ca6..4490b8f2 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.h b/internal/platform/implementation/linux/wifi_lan_server_socket.h index 3e139721..27de3785 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.h @@ -1,3 +1,17 @@ +// 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_WIFI_LAN_SERVER_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_LAN_SERVER_SOCKET_H_ diff --git a/internal/platform/implementation/linux/wifi_lan_socket.h b/internal/platform/implementation/linux/wifi_lan_socket.h index 198c97da..f2ec43a0 100644 --- a/internal/platform/implementation/linux/wifi_lan_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_socket.h @@ -1,3 +1,17 @@ +// 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_WIFI_LAN_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_ diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 945cca13..a5ee580b 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -1,3 +1,17 @@ +// 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 #include #include diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index e8ffcbdf..c06fe1bb 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -1,3 +1,17 @@ +// 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_WIFI_MEDIUM_H_ #define PLATFORM_IMPL_LINUX_WIFI_MEDIUM_H_ diff --git a/internal/platform/implementation/linux/wifi_socket.h b/internal/platform/implementation/linux/wifi_socket.h index 0d70b4c7..040093df 100644 --- a/internal/platform/implementation/linux/wifi_socket.h +++ b/internal/platform/implementation/linux/wifi_socket.h @@ -1,3 +1,17 @@ +// 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_WIFI_LAN_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_ From be5fcba2d29748cd265f10a864949378bdf4e46f Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 22:12:10 +0530 Subject: [PATCH 087/201] Add copyright headers. --- internal/platform/implementation/linux/BUILD | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 98c174f4..d8ad0213 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -1,3 +1,17 @@ +# 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( From 86cffae21f74fa52f1449257a9a8752af8a000aa Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 29 Aug 2023 23:56:15 +0530 Subject: [PATCH 088/201] Move dbus stubs to generated package. --- internal/platform/implementation/linux/BUILD | 19 ++-------------- .../platform/implementation/linux/avahi.h | 6 ++--- .../implementation/linux/bluetooth_adapter.cc | 2 +- .../implementation/linux/bluetooth_adapter.h | 2 +- .../linux/bluetooth_bluez_profile.h | 4 ++-- .../linux/bluetooth_classic_device.h | 2 +- .../linux/bluetooth_classic_medium.cc | 2 +- .../implementation/linux/bluetooth_pairing.h | 2 +- .../implementation/linux/device_info.h | 10 ++++----- .../implementation/linux/generated/BUILD | 22 +++++++++++++++++++ .../dbus/avahi/entrygroup_client.h} | 0 .../org.freedesktop.Avahi.EntryGroup.xml | 0 .../avahi}/org.freedesktop.Avahi.Server.xml | 0 .../org.freedesktop.Avahi.ServiceBrowser.xml | 0 .../org.freedesktop.Avahi.ServiceResolver.xml | 0 .../dbus/avahi/server2_client.h} | 0 .../dbus/avahi/servicebrowser_client.h} | 0 .../dbus/bluez/adapter_client.h} | 0 .../dbus/bluez/device_client.h} | 0 .../dbus/bluez}/org.bluez.Adapter1.xml | 0 .../dbus/bluez}/org.bluez.Device1.xml | 0 .../dbus/bluez}/org.bluez.Profile1.xml | 0 .../dbus/bluez}/org.bluez.ProfileManager1.xml | 0 .../dbus/bluez/profile_manager_client.h} | 0 .../dbus/bluez/profile_server.h} | 0 .../dbus/hostname/hostname_client.h} | 0 .../hostname}/org.freedesktop.hostname1.xml | 0 .../dbus/logcontrol/logcontrol_server.h} | 0 .../org.freedesktop.LogControl1.xml | 0 .../dbus/login/login_manager_client.h} | 0 .../dbus/login/login_session_client.h} | 0 .../login}/org.freedesktop.login1.Manager.xml | 0 .../login}/org.freedesktop.login1.Session.xml | 0 .../networkmanager/access_point_client.h} | 0 .../connection_active_client.h} | 0 .../networkmanager/device_wifip2p_client.h} | 0 .../networkmanager/device_wireless_client.h} | 0 .../dbus/networkmanager/ip4config_client.h} | 0 .../networkmanager/networkmanager_client.h} | 0 ...freedesktop.NetworkManager.AccessPoint.xml | 0 ...sktop.NetworkManager.Connection.Active.xml | 0 ...edesktop.NetworkManager.Device.WifiP2P.xml | 0 ...desktop.NetworkManager.Device.Wireless.xml | 0 ...g.freedesktop.NetworkManager.IP4Config.xml | 0 .../org.freedesktop.NetworkManager.xml | 0 .../implementation/linux/log_message.h | 2 +- .../platform/implementation/linux/platform.cc | 2 +- .../implementation/linux/wifi_medium.cc | 4 ++-- .../implementation/linux/wifi_medium.h | 10 ++++----- 49 files changed, 48 insertions(+), 41 deletions(-) create mode 100644 internal/platform/implementation/linux/generated/BUILD rename internal/platform/implementation/linux/{avahi_entrygroup_client_glue.h => generated/dbus/avahi/entrygroup_client.h} (100%) rename internal/platform/implementation/linux/{ => generated/dbus/avahi}/org.freedesktop.Avahi.EntryGroup.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/avahi}/org.freedesktop.Avahi.Server.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/avahi}/org.freedesktop.Avahi.ServiceBrowser.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/avahi}/org.freedesktop.Avahi.ServiceResolver.xml (100%) rename internal/platform/implementation/linux/{avahi_server_client_glue.h => generated/dbus/avahi/server2_client.h} (100%) rename internal/platform/implementation/linux/{avahi_servicebrowser_client_glue.h => generated/dbus/avahi/servicebrowser_client.h} (100%) rename internal/platform/implementation/linux/{bluez_adapter_client_glue.h => generated/dbus/bluez/adapter_client.h} (100%) rename internal/platform/implementation/linux/{bluez_device_client_glue.h => generated/dbus/bluez/device_client.h} (100%) rename internal/platform/implementation/linux/{ => generated/dbus/bluez}/org.bluez.Adapter1.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/bluez}/org.bluez.Device1.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/bluez}/org.bluez.Profile1.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/bluez}/org.bluez.ProfileManager1.xml (100%) rename internal/platform/implementation/linux/{bluez_profile_manager_client_glue.h => generated/dbus/bluez/profile_manager_client.h} (100%) rename internal/platform/implementation/linux/{bluez_profile_glue.h => generated/dbus/bluez/profile_server.h} (100%) rename internal/platform/implementation/linux/{hostname_client_glue.h => generated/dbus/hostname/hostname_client.h} (100%) rename internal/platform/implementation/linux/{ => generated/dbus/hostname}/org.freedesktop.hostname1.xml (100%) rename internal/platform/implementation/linux/{org_freedesktop_logcontrol_server_glue.h => generated/dbus/logcontrol/logcontrol_server.h} (100%) rename internal/platform/implementation/linux/{ => generated/dbus/logcontrol}/org.freedesktop.LogControl1.xml (100%) rename internal/platform/implementation/linux/{login_manager_client_glue.h => generated/dbus/login/login_manager_client.h} (100%) rename internal/platform/implementation/linux/{login_session_client_glue.h => generated/dbus/login/login_session_client.h} (100%) rename internal/platform/implementation/linux/{ => generated/dbus/login}/org.freedesktop.login1.Manager.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/login}/org.freedesktop.login1.Session.xml (100%) rename internal/platform/implementation/linux/{networkmanager_accesspoint_client_glue.h => generated/dbus/networkmanager/access_point_client.h} (100%) rename internal/platform/implementation/linux/{networkmanager_connection_active_client_glue.h => generated/dbus/networkmanager/connection_active_client.h} (100%) rename internal/platform/implementation/linux/{networkmanager_device_wifip2p_client_glue.h => generated/dbus/networkmanager/device_wifip2p_client.h} (100%) rename internal/platform/implementation/linux/{networkmanager_device_wireless_client_glue.h => generated/dbus/networkmanager/device_wireless_client.h} (100%) rename internal/platform/implementation/linux/{networkmanager_ip4config_client_glue.h => generated/dbus/networkmanager/ip4config_client.h} (100%) rename internal/platform/implementation/linux/{networkmanager_client_glue.h => generated/dbus/networkmanager/networkmanager_client.h} (100%) rename internal/platform/implementation/linux/{ => generated/dbus/networkmanager}/org.freedesktop.NetworkManager.AccessPoint.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/networkmanager}/org.freedesktop.NetworkManager.Connection.Active.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/networkmanager}/org.freedesktop.NetworkManager.Device.WifiP2P.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/networkmanager}/org.freedesktop.NetworkManager.Device.Wireless.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/networkmanager}/org.freedesktop.NetworkManager.IP4Config.xml (100%) rename internal/platform/implementation/linux/{ => generated/dbus/networkmanager}/org.freedesktop.NetworkManager.xml (100%) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index d8ad0213..6d647607 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -33,10 +33,6 @@ cc_library( "timer.h", "thread_pool.h", "log_message.h", - "org_freedesktop_logcontrol_server_glue.h", - "hostname_client_glue.h", - "login_manager_client_glue.h", - "login_session_client_glue.h", "utils.h", ], srcs = [ @@ -59,9 +55,6 @@ cc_library( name = "comm", hdrs = [ "avahi.h", - "avahi_entrygroup_client_glue.h", - "avahi_server_client_glue.h", - "avahi_servicebrowser_client_glue.h", "ble_medium.h", "ble_v2_medium.h", "bluetooth_adapter.h", @@ -73,17 +66,7 @@ cc_library( "bluetooth_devices.h", "bluetooth_pairing.h", "bluez.h", - "bluez_adapter_client_glue.h", - "bluez_device_client_glue.h", - "bluez_profile_glue.h", - "bluez_profile_manager_client_glue.h", "dbus.h", - "networkmanager_accesspoint_client_glue.h", - "networkmanager_client_glue.h", - "networkmanager_connection_active_client_glue.h", - "networkmanager_device_wifip2p_client_glue.h", - "networkmanager_device_wireless_client_glue.h", - "networkmanager_ip4config_client_glue.h", "stream.h", "wifi_direct.h", "wifi_direct_server_socket.h", @@ -104,6 +87,7 @@ cc_library( "//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", @@ -188,6 +172,7 @@ cc_library( "//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", diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index 121ac3c4..208eaa52 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -19,9 +19,9 @@ #include #include -#include "internal/platform/implementation/linux/avahi_entrygroup_client_glue.h" -#include "internal/platform/implementation/linux/avahi_server_client_glue.h" -#include "internal/platform/implementation/linux/avahi_servicebrowser_client_glue.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/linux/dbus.h" #include "internal/platform/implementation/wifi_lan.h" diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index 21822efd..fb83b31c 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -18,7 +18,7 @@ #include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluez.h" -#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h" #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/logging.h" diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index 405931bc..d03309e9 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -20,7 +20,7 @@ #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/bluez_adapter_client_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h" #include "internal/platform/implementation/linux/dbus.h" namespace nearby { diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index 588322ed..ff447480 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -38,8 +38,8 @@ #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" -#include "internal/platform/implementation/linux/bluez_profile_glue.h" -#include "internal/platform/implementation/linux/bluez_profile_manager_client_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/profile_server.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/profile_manager_client.h" #include "internal/platform/logging.h" namespace nearby { diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 35fc3d6c..c5d5073e 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -25,7 +25,7 @@ #include "absl/strings/string_view.h" #include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" -#include "internal/platform/implementation/linux/bluez_device_client_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/device_client.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 79ccfc80..91d7cb67 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -29,7 +29,7 @@ #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" #include "internal/platform/implementation/linux/bluetooth_pairing.h" #include "internal/platform/implementation/linux/bluez.h" -#include "internal/platform/implementation/linux/bluez_device_client_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/device_client.h" #include "internal/platform/logging.h" namespace nearby { diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 48558a4e..917a7278 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PROFILE_H_ +#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_PAIRING_H_ #include diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index edbefd4d..139885fe 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -16,20 +16,20 @@ #define PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ #include -#include -#include #include #include #include +#include +#include #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/hostname_client_glue.h" -#include "internal/platform/implementation/linux/login_manager_client_glue.h" -#include "internal/platform/implementation/linux/login_session_client_glue.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 { diff --git a/internal/platform/implementation/linux/generated/BUILD b/internal/platform/implementation/linux/generated/BUILD new file mode 100644 index 00000000..7bb5ea35 --- /dev/null +++ b/internal/platform/implementation/linux/generated/BUILD @@ -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__", + ], +) diff --git a/internal/platform/implementation/linux/avahi_entrygroup_client_glue.h b/internal/platform/implementation/linux/generated/dbus/avahi/entrygroup_client.h similarity index 100% rename from internal/platform/implementation/linux/avahi_entrygroup_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/avahi/entrygroup_client.h diff --git a/internal/platform/implementation/linux/org.freedesktop.Avahi.EntryGroup.xml b/internal/platform/implementation/linux/generated/dbus/avahi/org.freedesktop.Avahi.EntryGroup.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.Avahi.EntryGroup.xml rename to internal/platform/implementation/linux/generated/dbus/avahi/org.freedesktop.Avahi.EntryGroup.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.Avahi.Server.xml b/internal/platform/implementation/linux/generated/dbus/avahi/org.freedesktop.Avahi.Server.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.Avahi.Server.xml rename to internal/platform/implementation/linux/generated/dbus/avahi/org.freedesktop.Avahi.Server.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceBrowser.xml b/internal/platform/implementation/linux/generated/dbus/avahi/org.freedesktop.Avahi.ServiceBrowser.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceBrowser.xml rename to internal/platform/implementation/linux/generated/dbus/avahi/org.freedesktop.Avahi.ServiceBrowser.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceResolver.xml b/internal/platform/implementation/linux/generated/dbus/avahi/org.freedesktop.Avahi.ServiceResolver.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.Avahi.ServiceResolver.xml rename to internal/platform/implementation/linux/generated/dbus/avahi/org.freedesktop.Avahi.ServiceResolver.xml diff --git a/internal/platform/implementation/linux/avahi_server_client_glue.h b/internal/platform/implementation/linux/generated/dbus/avahi/server2_client.h similarity index 100% rename from internal/platform/implementation/linux/avahi_server_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/avahi/server2_client.h diff --git a/internal/platform/implementation/linux/avahi_servicebrowser_client_glue.h b/internal/platform/implementation/linux/generated/dbus/avahi/servicebrowser_client.h similarity index 100% rename from internal/platform/implementation/linux/avahi_servicebrowser_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/avahi/servicebrowser_client.h diff --git a/internal/platform/implementation/linux/bluez_adapter_client_glue.h b/internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h similarity index 100% rename from internal/platform/implementation/linux/bluez_adapter_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h diff --git a/internal/platform/implementation/linux/bluez_device_client_glue.h b/internal/platform/implementation/linux/generated/dbus/bluez/device_client.h similarity index 100% rename from internal/platform/implementation/linux/bluez_device_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/bluez/device_client.h diff --git a/internal/platform/implementation/linux/org.bluez.Adapter1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Adapter1.xml similarity index 100% rename from internal/platform/implementation/linux/org.bluez.Adapter1.xml rename to internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Adapter1.xml diff --git a/internal/platform/implementation/linux/org.bluez.Device1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Device1.xml similarity index 100% rename from internal/platform/implementation/linux/org.bluez.Device1.xml rename to internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Device1.xml diff --git a/internal/platform/implementation/linux/org.bluez.Profile1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Profile1.xml similarity index 100% rename from internal/platform/implementation/linux/org.bluez.Profile1.xml rename to internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Profile1.xml diff --git a/internal/platform/implementation/linux/org.bluez.ProfileManager1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.ProfileManager1.xml similarity index 100% rename from internal/platform/implementation/linux/org.bluez.ProfileManager1.xml rename to internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.ProfileManager1.xml diff --git a/internal/platform/implementation/linux/bluez_profile_manager_client_glue.h b/internal/platform/implementation/linux/generated/dbus/bluez/profile_manager_client.h similarity index 100% rename from internal/platform/implementation/linux/bluez_profile_manager_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/bluez/profile_manager_client.h diff --git a/internal/platform/implementation/linux/bluez_profile_glue.h b/internal/platform/implementation/linux/generated/dbus/bluez/profile_server.h similarity index 100% rename from internal/platform/implementation/linux/bluez_profile_glue.h rename to internal/platform/implementation/linux/generated/dbus/bluez/profile_server.h diff --git a/internal/platform/implementation/linux/hostname_client_glue.h b/internal/platform/implementation/linux/generated/dbus/hostname/hostname_client.h similarity index 100% rename from internal/platform/implementation/linux/hostname_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/hostname/hostname_client.h diff --git a/internal/platform/implementation/linux/org.freedesktop.hostname1.xml b/internal/platform/implementation/linux/generated/dbus/hostname/org.freedesktop.hostname1.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.hostname1.xml rename to internal/platform/implementation/linux/generated/dbus/hostname/org.freedesktop.hostname1.xml diff --git a/internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h b/internal/platform/implementation/linux/generated/dbus/logcontrol/logcontrol_server.h similarity index 100% rename from internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h rename to internal/platform/implementation/linux/generated/dbus/logcontrol/logcontrol_server.h diff --git a/internal/platform/implementation/linux/org.freedesktop.LogControl1.xml b/internal/platform/implementation/linux/generated/dbus/logcontrol/org.freedesktop.LogControl1.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.LogControl1.xml rename to internal/platform/implementation/linux/generated/dbus/logcontrol/org.freedesktop.LogControl1.xml diff --git a/internal/platform/implementation/linux/login_manager_client_glue.h b/internal/platform/implementation/linux/generated/dbus/login/login_manager_client.h similarity index 100% rename from internal/platform/implementation/linux/login_manager_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/login/login_manager_client.h diff --git a/internal/platform/implementation/linux/login_session_client_glue.h b/internal/platform/implementation/linux/generated/dbus/login/login_session_client.h similarity index 100% rename from internal/platform/implementation/linux/login_session_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/login/login_session_client.h diff --git a/internal/platform/implementation/linux/org.freedesktop.login1.Manager.xml b/internal/platform/implementation/linux/generated/dbus/login/org.freedesktop.login1.Manager.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.login1.Manager.xml rename to internal/platform/implementation/linux/generated/dbus/login/org.freedesktop.login1.Manager.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.login1.Session.xml b/internal/platform/implementation/linux/generated/dbus/login/org.freedesktop.login1.Session.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.login1.Session.xml rename to internal/platform/implementation/linux/generated/dbus/login/org.freedesktop.login1.Session.xml diff --git a/internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h b/internal/platform/implementation/linux/generated/dbus/networkmanager/access_point_client.h similarity index 100% rename from internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/networkmanager/access_point_client.h diff --git a/internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h b/internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h similarity index 100% rename from internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h diff --git a/internal/platform/implementation/linux/networkmanager_device_wifip2p_client_glue.h b/internal/platform/implementation/linux/generated/dbus/networkmanager/device_wifip2p_client.h similarity index 100% rename from internal/platform/implementation/linux/networkmanager_device_wifip2p_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/networkmanager/device_wifip2p_client.h diff --git a/internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h b/internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h similarity index 100% rename from internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h diff --git a/internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h b/internal/platform/implementation/linux/generated/dbus/networkmanager/ip4config_client.h similarity index 100% rename from internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/networkmanager/ip4config_client.h diff --git a/internal/platform/implementation/linux/networkmanager_client_glue.h b/internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h similarity index 100% rename from internal/platform/implementation/linux/networkmanager_client_glue.h rename to internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.AccessPoint.xml b/internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.AccessPoint.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.NetworkManager.AccessPoint.xml rename to internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.AccessPoint.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Connection.Active.xml b/internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.Connection.Active.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.NetworkManager.Connection.Active.xml rename to internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.Connection.Active.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.WifiP2P.xml b/internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.Device.WifiP2P.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.WifiP2P.xml rename to internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.Device.WifiP2P.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.Wireless.xml b/internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.Device.Wireless.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.NetworkManager.Device.Wireless.xml rename to internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.Device.Wireless.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.IP4Config.xml b/internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.IP4Config.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.NetworkManager.IP4Config.xml rename to internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.IP4Config.xml diff --git a/internal/platform/implementation/linux/org.freedesktop.NetworkManager.xml b/internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.xml similarity index 100% rename from internal/platform/implementation/linux/org.freedesktop.NetworkManager.xml rename to internal/platform/implementation/linux/generated/dbus/networkmanager/org.freedesktop.NetworkManager.xml diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h index 46b1084c..13122565 100644 --- a/internal/platform/implementation/linux/log_message.h +++ b/internal/platform/implementation/linux/log_message.h @@ -19,7 +19,7 @@ #include #include "glog/logging.h" -#include "internal/platform/implementation/linux/org_freedesktop_logcontrol_server_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/logcontrol/logcontrol_server.h" #include "internal/platform/implementation/log_message.h" namespace nearby { diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 53080360..2d97faa7 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -34,7 +34,7 @@ #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_classic_medium.h" #include "internal/platform/implementation/linux/bluez.h" -#include "internal/platform/implementation/linux/bluez_adapter_client_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h" #include "internal/platform/implementation/linux/condition_variable.h" #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/mutex.h" diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index a5ee580b..4a96cf7c 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -25,8 +25,8 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/dbus.h" -#include "internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h" -#include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi.h" diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index c06fe1bb..4b395310 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -29,11 +29,11 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/dbus.h" -#include "internal/platform/implementation/linux/networkmanager_accesspoint_client_glue.h" -#include "internal/platform/implementation/linux/networkmanager_client_glue.h" -#include "internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h" -#include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h" -#include "internal/platform/implementation/linux/networkmanager_ip4config_client_glue.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/access_point_client.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/ip4config_client.h" #include "internal/platform/implementation/wifi.h" #include "internal/platform/logging.h" From cb83656eabc88fd6f875c640ae6ee843c8597495 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 01:19:00 +0530 Subject: [PATCH 089/201] Minor refactoring. --- .../implementation/linux/bluetooth_adapter.cc | 4 +- .../linux/bluetooth_bluez_profile.cc | 36 +++-- .../linux/bluetooth_bluez_profile.h | 72 ++++++---- .../linux/bluetooth_classic_device.cc | 4 +- .../linux/bluetooth_classic_device.h | 37 +++-- .../linux/bluetooth_classic_medium.cc | 17 ++- .../linux/bluetooth_classic_medium.h | 109 +++++++-------- .../linux/bluetooth_classic_server_socket.h | 37 +++-- .../linux/bluetooth_classic_socket.cc | 2 +- .../linux/bluetooth_classic_socket.h | 14 +- .../implementation/linux/bluetooth_devices.h | 7 +- .../implementation/linux/bluetooth_pairing.cc | 8 +- .../implementation/linux/bluetooth_pairing.h | 3 +- .../implementation/linux/device_info.cc | 10 +- .../implementation/linux/device_info.h | 64 +++++---- .../implementation/linux/thread_pool.h | 19 +-- .../implementation/linux/wifi_direct.h | 3 +- .../linux/wifi_direct_server_socket.h | 41 +++--- .../implementation/linux/wifi_direct_socket.h | 5 +- .../implementation/linux/wifi_hotspot.h | 56 ++++---- .../linux/wifi_hotspot_server_socket.h | 7 +- .../linux/wifi_hotspot_socket.h | 3 +- .../platform/implementation/linux/wifi_lan.h | 3 +- .../linux/wifi_lan_server_socket.h | 5 +- .../implementation/linux/wifi_lan_socket.h | 3 +- .../implementation/linux/wifi_medium.h | 128 +++++++++++------- 26 files changed, 392 insertions(+), 305 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index fb83b31c..d57dc56f 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -91,7 +91,7 @@ std::string BluetoothAdapter::GetName() const { return bluez_adapter_->Alias(); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Alias", e); - return std::string(); + return {}; } } @@ -115,7 +115,7 @@ std::string BluetoothAdapter::GetMacAddress() const { return bluez_adapter_->Address(); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(bluez_adapter_, "Address", e); - return std::string(); + return {}; } } diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index af0ec0a8..c88026ab 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -37,9 +37,9 @@ namespace nearby { namespace linux { bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { - registered_service_uuids_lock_.ReaderLock(); + registered_service_uuids_mutex_.ReaderLock(); bool registered = registered_services_.count(std::string(service_uuid)) == 1; - registered_service_uuids_lock_.ReaderUnlock(); + registered_service_uuids_mutex_.ReaderUnlock(); return registered; } @@ -78,9 +78,9 @@ void Profile::NewConnection( absl::MutexLock l(&connections_lock_); if (connections_.count(mac_addr) != 0) { - connections_[mac_addr].push_back(std::pair(fd, std::move(props))); + connections_[mac_addr].push_back(std::pair(fd, props)); } else { - connections_[mac_addr] = std::vector{std::pair(fd, std::move(props))}; + connections_[mac_addr] = std::vector{std::pair(fd, props)}; } } @@ -135,7 +135,7 @@ bool ProfileManager::Register(std::optional name, } { - absl::MutexLock l(®istered_service_uuids_lock_); + absl::MutexLock l(®istered_service_uuids_mutex_); registered_services_.emplace(service_uuid, profile); } @@ -165,7 +165,7 @@ void ProfileManager::Unregister(absl::string_view service_uuid) { } { - absl::MutexLock l(®istered_service_uuids_lock_); + absl::MutexLock l(®istered_service_uuids_mutex_); registered_services_.erase(std::string(service_uuid)); } } @@ -184,9 +184,9 @@ ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device, auto mac_addr = remote_device.GetMacAddress(); - registered_service_uuids_lock_.ReaderLock(); + registered_service_uuids_mutex_.ReaderLock(); auto profile = registered_services_[std::string(service_uuid)]; - registered_service_uuids_lock_.ReaderUnlock(); + registered_service_uuids_mutex_.ReaderUnlock(); NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() << ": Attempting to get a FD for service " @@ -226,16 +226,19 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { return std::nullopt; } - registered_service_uuids_lock_.ReaderLock(); + registered_service_uuids_mutex_.ReaderLock(); auto profile = registered_services_[std::string(service_uuid)]; - registered_service_uuids_lock_.ReaderUnlock(); + registered_service_uuids_mutex_.ReaderUnlock(); NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() << ": Attempting to get a FD for service " - << profile->getObjectPath(); + << service_uuid; profile->connections_lock_.Lock(); - auto cond = [profile]() { return !profile->connections_.empty(); }; + auto cond = [profile]() { + profile->connections_lock_.AssertReaderHeld(); + return !profile->connections_.empty(); + }; profile->connections_lock_.Await(absl::Condition(&cond)); auto it = profile->connections_.begin(); @@ -246,7 +249,14 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { profile->connections_.erase(it); profile->connections_lock_.Unlock(); - return std::pair(devices_.get_device_by_address(mac_addr).value(), fd); + auto maybe_device = devices_.get_device_by_address(mac_addr); + if (!maybe_device.has_value()) { + NEARBY_LOGS(ERROR) << __func__ << ": Device " << mac_addr + << " is no longer available"; + return std::nullopt; + } + + return std::pair(*maybe_device, fd); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index ff447480..06ee742e 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -38,26 +38,38 @@ #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_server.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 Profile : public sdbus::AdaptorInterfaces { -public: +class ProfileManager; + +class Profile final + : public sdbus::AdaptorInterfaces { + public: + Profile(const Profile &) = delete; + Profile(Profile &&) = delete; + Profile &operator=(const Profile &) = delete; + Profile &operator=(Profile &&) = delete; Profile(sdbus::IConnection &system_bus, absl::string_view profile_object_path, BluetoothDevices &devices) : AdaptorInterfaces(system_bus, std::string(profile_object_path)), - released_(false), devices_(devices) { + released_(false), + devices_(devices) { registerAdaptor(); NEARBY_LOGS(VERBOSE) << __func__ << ": Created a new BlueZ profile at :" << getObjectPath(); } ~Profile() { unregisterAdaptor(); } + private: + friend class ProfileManager; + struct FDProperties { - FDProperties(const std::map &fd_props) { + explicit FDProperties(const std::map &fd_props) + : version(std::nullopt), features(std::nullopt) { if (fd_props.count("Version") == 1) { version = fd_props.at("Version"); } @@ -72,21 +84,27 @@ public: void Release() override; void NewConnection(const sdbus::ObjectPath &, const sdbus::UnixFd &, - const std::map &) override; - void RequestDisconnection(const sdbus::ObjectPath &) override; + const std::map &) 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>> - connections_; + connections_ ABSL_GUARDED_BY(connections_lock_); BluetoothDevices &devices_; }; -class ProfileManager +class ProfileManager final : private sdbus::ProxyInterfaces { -public: + 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) { @@ -94,29 +112,35 @@ public: } ~ProfileManager() { unregisterProxy(); } - bool ProfileRegistered(absl::string_view service_uuid); + bool ProfileRegistered(absl::string_view service_uuid) + ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); bool Register(std::optional service_name, - absl::string_view service_uuid); - bool Register(absl::string_view service_uuid) { + 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); + void Unregister(absl::string_view service_uuid) + ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); - std::optional - GetServiceRecordFD(api::BluetoothDevice &remote_device, - absl::string_view service_uuid, - CancellationFlag *cancellation_flag); + std::optional GetServiceRecordFD( + api::BluetoothDevice &remote_device, absl::string_view service_uuid, + CancellationFlag *cancellation_flag) + ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); std::optional< std::pair, sdbus::UnixFd>> - GetServiceRecordFD(absl::string_view service_uuid); + GetServiceRecordFD(absl::string_view service_uuid) + ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); -private: + private: BluetoothDevices &devices_; // Maps service UUIDs to RegisteredService - std::map> registered_services_; - absl::Mutex registered_service_uuids_lock_; + absl::Mutex registered_service_uuids_mutex_; + std::map> registered_services_ + ABSL_GUARDED_BY(registered_service_uuids_mutex_); }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 8170c7f9..2d1f9d36 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -25,9 +25,9 @@ namespace nearby { namespace linux { BluetoothDevice::BluetoothDevice(sdbus::IConnection &system_bus, - const sdbus::ObjectPath &device_object_path) + sdbus::ObjectPath device_object_path) : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, - std::string(device_object_path)) { + std::move(device_object_path)) { registerProxy(); try { last_known_name_ = Alias(); diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index c5d5073e..7f7f5aa2 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -34,21 +34,27 @@ class BluetoothDevice : public api::BluetoothDevice, public sdbus::ProxyInterfaces { public: - BluetoothDevice(sdbus::IConnection &system_bus, const sdbus::ObjectPath &); - ~BluetoothDevice() = default; + BluetoothDevice(const BluetoothDevice &) = delete; + BluetoothDevice(BluetoothDevice &&) = delete; + BluetoothDevice &operator=(const BluetoothDevice &) = delete; + BluetoothDevice &operator=(BluetoothDevice &&) = delete; + BluetoothDevice(sdbus::IConnection &system_bus, sdbus::ObjectPath device_object_path); + ~BluetoothDevice() override { + unregisterProxy(); + } - // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() - std::string GetName() const override; + // 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; + // Returns BT MAC address assigned to this device. + std::string GetMacAddress() const override; - bool ConnectToProfile(absl::string_view service_uuid); + bool ConnectToProfile(absl::string_view service_uuid); - void - set_pair_reply_callback(absl::AnyInvocable cb) { - absl::MutexLock l(&pair_callback_lock_); - on_pair_reply_cb_ = std::move(cb); + void set_pair_reply_callback( + absl::AnyInvocable cb) { + absl::MutexLock l(&pair_callback_lock_); + on_pair_reply_cb_ = std::move(cb); } void reset_pair_reply_callback() { @@ -73,7 +79,7 @@ private: mutable std::string last_known_address_ ABSL_GUARDED_BY(properties_mutex_); }; -class MonitoredBluetoothDevice +class MonitoredBluetoothDevice final : public BluetoothDevice, public sdbus::ProxyInterfaces { public: @@ -81,10 +87,15 @@ public: using sdbus::ProxyInterfaces::unregisterProxy; using sdbus::ProxyInterfaces::getObjectPath; + MonitoredBluetoothDevice(const MonitoredBluetoothDevice &) = delete; + MonitoredBluetoothDevice(MonitoredBluetoothDevice &&) = delete; + MonitoredBluetoothDevice &operator=(const MonitoredBluetoothDevice &) = + delete; + MonitoredBluetoothDevice &operator=(MonitoredBluetoothDevice &&) = delete; MonitoredBluetoothDevice( sdbus::IConnection &system_bus, const sdbus::ObjectPath &, ObserverList &observers); - ~MonitoredBluetoothDevice() { unregisterProxy(); } + ~MonitoredBluetoothDevice() override { unregisterProxy(); } protected: void onPropertiesChanged( diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 91d7cb67..8b2b7f0d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -47,8 +47,6 @@ BluetoothClassicMedium::BluetoothClassicMedium( registerProxy(); } -BluetoothClassicMedium::~BluetoothClassicMedium() { unregisterProxy(); } - void BluetoothClassicMedium::onInterfacesAdded( const sdbus::ObjectPath &object, const std::map> @@ -74,7 +72,7 @@ void BluetoothClassicMedium::onInterfacesAdded( discovery_cb_->device_discovered_cb(device); } - for (auto &observer : observers_.GetObservers()) { + for (const auto &observer : observers_.GetObservers()) { observer->DeviceAdded(device); } } @@ -88,7 +86,7 @@ void BluetoothClassicMedium::onInterfacesRemoved( return; } - for (auto &interface : interfaces) { + for (const auto &interface : interfaces) { if (interface == org::bluez::Device1_proxy::INTERFACE_NAME) { { auto device = devices_->get_device_by_path(object); @@ -107,7 +105,7 @@ void BluetoothClassicMedium::onInterfacesRemoved( discovery_cb_->device_lost_cb(*device); } - for (auto &observer : observers_.GetObservers()) { + for (const auto &observer : observers_.GetObservers()) { observer->DeviceRemoved(*device); } } @@ -166,7 +164,10 @@ BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, } } - auto &device = devices_->get_device_by_path(device_object_path).value().get(); + auto maybe_device = devices_->get_device_by_path(device_object_path); + if (!maybe_device.has_value()) return nullptr; + + auto &device = maybe_device->get(); device.ConnectToProfile(service_uuid); auto fd = profile_manager_->GetServiceRecordFD(remote_device, service_uuid, @@ -202,7 +203,7 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, api::BluetoothDevice * BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { auto device = devices_->get_device_by_address(mac_address); - if (device.has_value()) + if (!device.has_value()) return nullptr; return &(device->get()); @@ -211,6 +212,8 @@ BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { std::unique_ptr BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) { auto device = devices_->get_device_by_address(remote_device.GetMacAddress()); + if (!device.has_value()) return nullptr; + return std::unique_ptr( new BluetoothPairing(*adapter_, *device)); } diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 913a91fe..68cd26b3 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -39,69 +39,70 @@ namespace nearby { namespace linux { // Container of operations that can be performed over the Bluetooth Classic // medium. -class BluetoothClassicMedium +class BluetoothClassicMedium final : public api::BluetoothClassicMedium, sdbus::ProxyInterfaces { public: - BluetoothClassicMedium(sdbus::IConnection &system_bus, - const sdbus::ObjectPath &adapter_object_path); - ~BluetoothClassicMedium() override; + BluetoothClassicMedium(const BluetoothClassicMedium &) = delete; + BluetoothClassicMedium(BluetoothClassicMedium &&) = delete; + BluetoothClassicMedium &operator=(const BluetoothClassicMedium &) = delete; + BluetoothClassicMedium &operator=(BluetoothClassicMedium &&) = delete; + BluetoothClassicMedium(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path); + ~BluetoothClassicMedium() override { unregisterProxy(); }; - // 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; + // 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 - ConnectToService(api::BluetoothDevice &remote_device, - const std::string &service_uuid, - CancellationFlag *cancellation_flag) 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 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 - ListenForService(const std::string &service_name, - const std::string &service_uuid) 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 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 - CreatePairing(api::BluetoothDevice &remote_device) 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 CreatePairing( + api::BluetoothDevice &remote_device) override; - api::BluetoothDevice * - GetRemoteDevice(const std::string &mac_address) override; + api::BluetoothDevice *GetRemoteDevice(const std::string &mac_address) override; - void AddObserver(Observer *observer) override { - observers_.AddObserver(observer); + void AddObserver(Observer *observer) override { + observers_.AddObserver(observer); }; void RemoveObserver(Observer *observer) override { observers_.RemoveObserver(observer); diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h index d898794e..b503b3ec 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -22,28 +22,27 @@ namespace nearby { namespace linux { -class BluetoothServerSocket : public api::BluetoothServerSocket { +class BluetoothServerSocket final : public api::BluetoothServerSocket { public: - BluetoothServerSocket(ProfileManager &profile_manager, - absl::string_view service_uuid) - : profile_manager_(profile_manager), service_uuid_(service_uuid) {} - ~BluetoothServerSocket() = default; + 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 Accept() override; + // 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 Accept() override; - // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close() - // - // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override; + // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close() + // + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + Exception Close() override; private: ProfileManager &profile_manager_; diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 859f9014..2f79ef5c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -55,7 +55,7 @@ Exception OutputStream::Write(const ByteArray &data) { if (!fd_.has_value()) return Exception{Exception::kIo}; - ssize_t written = 0; + size_t written = 0; while (written < data.size()) { ssize_t ret = write(fd_->get(), data.data(), data.size()); if (ret < 1) { diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index 18266236..dcefc4e5 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -27,15 +27,15 @@ namespace nearby { namespace linux { -class BluetoothSocket : public api::BluetoothSocket { +class BluetoothSocket final : public api::BluetoothSocket { public: - BluetoothSocket(api::BluetoothDevice &device, sdbus::UnixFd fd) - : device_(device), output_stream_(fd), input_stream_(fd) {} + BluetoothSocket(api::BluetoothDevice &device, sdbus::UnixFd fd) + : device_(device), output_stream_(fd), input_stream_(fd) {} - nearby::InputStream &GetInputStream() override { return input_stream_; } - nearby::OutputStream &GetOutputStream() override { return output_stream_; } - Exception Close() override; - api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; + nearby::InputStream &GetInputStream() override { return input_stream_; } + nearby::OutputStream &GetOutputStream() override { return output_stream_; } + Exception Close() override; + api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; private: api::BluetoothDevice &device_; diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 67ef813a..49804517 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -28,15 +28,14 @@ namespace nearby { namespace linux { -class BluetoothDevices { +class BluetoothDevices final { public: BluetoothDevices( sdbus::IConnection &system_bus, - const sdbus::ObjectPath &adapter_object_path, + sdbus::ObjectPath adapter_object_path, ObserverList &observers) : system_bus_(system_bus), observers_(observers), - adapter_object_path_(adapter_object_path) {} - ~BluetoothDevices() = default; + adapter_object_path_(std::move(adapter_object_path)) {} std::optional> get_device_by_path(const sdbus::ObjectPath &); diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index da612a3b..d4ec92c6 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -29,8 +29,9 @@ namespace linux { void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { if (error != nullptr && error->isValid()) { - auto name = error->getName(); - api::BluetoothPairingCallback::PairingError err; + const auto &name = error->getName(); + api::BluetoothPairingCallback::PairingError err = + api::BluetoothPairingCallback::PairingError::kAuthFailed; NEARBY_LOGS(ERROR) << __func__ << ": " << "Got error '" << error->getName() @@ -46,8 +47,6 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { err = api::BluetoothPairingCallback::PairingError::kAuthRejected; } else if (name == "org.bluez.Error.AuthenticationTimeout") { err = api::BluetoothPairingCallback::PairingError::kAuthTimeout; - } else { - err = api::BluetoothPairingCallback::PairingError::kAuthFailed; } if (pairing_cb_.on_pairing_error_cb != nullptr) { @@ -59,7 +58,6 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { if (pairing_cb_.on_paired_cb != nullptr) { pairing_cb_.on_paired_cb(); } - return; } BluetoothPairing::BluetoothPairing(BluetoothAdapter &adapter, diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 917a7278..2c2fbac2 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -29,10 +29,9 @@ namespace nearby { namespace linux { -class BluetoothPairing : public api::BluetoothPairing { +class BluetoothPairing final : public api::BluetoothPairing { public: BluetoothPairing(BluetoothAdapter &adapter, BluetoothDevice &remote_device); - ~BluetoothPairing() override = default; bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; bool FinishPairing(std::optional pin_code) override; diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index c8894843..17287dbd 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -108,7 +108,7 @@ std::optional DeviceInfo::GetFullName() const { std::optional DeviceInfo::GetProfileUserName() const { struct passwd *pwd = getpwuid(getuid()); - if (!pwd) { + if (pwd == nullptr) { return std::nullopt; } char *name = strtok(pwd->pw_gecos, ","); @@ -122,7 +122,7 @@ std::optional DeviceInfo::GetDownloadPath() const { std::optional DeviceInfo::GetLocalAppDataPath() const { char *dir = getenv("XDG_CONFIG_HOME"); - if (dir == NULL) { + if (dir == nullptr) { return std::filesystem::path("/tmp"); } return std::filesystem::path(std::string(dir)) / "Google Nearby"; @@ -130,7 +130,7 @@ std::optional DeviceInfo::GetLocalAppDataPath() const { std::optional DeviceInfo::GetTemporaryPath() const { char *dir = getenv("XDG_RUNTIME_PATH"); - if (dir == NULL) { + if (dir == nullptr) { return std::filesystem::path("/tmp"); } return std::filesystem::path(std::string(dir)) / "Google Nearby"; @@ -138,7 +138,7 @@ std::optional DeviceInfo::GetTemporaryPath() const { std::optional DeviceInfo::GetLogPath() const { char *dir = getenv("XDG_STATE_HOME"); - if (dir == NULL) { + if (dir == nullptr) { return std::filesystem::path("/tmp"); } return std::filesystem::path(std::string(dir)) / "Google Nearby" / "logs"; @@ -146,7 +146,7 @@ std::optional DeviceInfo::GetLogPath() const { std::optional DeviceInfo::GetCrashDumpPath() const { char *dir = getenv("XDG_STATE_HOME"); - if (dir == NULL) { + if (dir == nullptr) { return std::filesystem::path("/tmp"); } return std::filesystem::path(std::string(dir)) / "Google Nearby" / "crashes"; diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 139885fe..281884fd 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -34,15 +34,19 @@ namespace nearby { namespace linux { -class CurrentUserSession +class CurrentUserSession final : public sdbus::ProxyInterfaces { -public: - CurrentUserSession(sdbus::IConnection &system_bus) + 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(); } - ~CurrentUserSession() { unregisterProxy(); } void RegisterScreenLockedListener( absl::string_view listener_name, @@ -51,7 +55,7 @@ public: void UnregisterScreenLockedListener(absl::string_view listener_name) ABSL_LOCKS_EXCLUDED(screen_lock_listeners_mutex_); -protected: + 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, @@ -60,7 +64,7 @@ protected: void onLock() override ABSL_LOCKS_EXCLUDED(screen_lock_listeners_mutex_); void onUnlock() override ABSL_LOCKS_EXCLUDED(screen_lock_listeners_mutex_); -private: + private: absl::Mutex screen_lock_listeners_mutex_; absl::flat_hash_map> @@ -69,26 +73,33 @@ private: class Hostnamed : public sdbus::ProxyInterfaces { -public: - Hostnamed(sdbus::IConnection &system_bus) + 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(); } + ~Hostnamed() { unregisterProxy(); } }; -class LoginManager +class LoginManager final : public sdbus::ProxyInterfaces { -public: - LoginManager(sdbus::IConnection &system_bus) - : ProxyInterfaces("org.freedesktop.login1", - "/org/freedesktop/login1") { + 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: + protected: void onSessionNew(const std::string &session_id, const sdbus::ObjectPath &object_path) override {} void onSessionRemoved(const std::string &session_id, @@ -105,15 +116,14 @@ protected: void onPrepareForSleep(const bool &start) override {} }; -class DeviceInfo : public api::DeviceInfo { -public: - DeviceInfo(sdbus::IConnection &system_bus); - ~DeviceInfo() override = default; +class DeviceInfo final : public api::DeviceInfo { + public: + explicit DeviceInfo(sdbus::IConnection &system_bus); std::optional GetOsDeviceName() const override; api::DeviceInfo::DeviceType GetDeviceType() const override; api::DeviceInfo::OsType GetOsType() const override { - return api::DeviceInfo::OsType::kWindows; // Or ChromeOS? + return api::DeviceInfo::OsType::kWindows; // Or ChromeOS? } std::optional GetFullName() const override; std::optional GetGivenName() const override { @@ -138,23 +148,23 @@ public: absl::string_view listener_name, std::function callback) override { current_user_session_->RegisterScreenLockedListener(listener_name, - std::move(callback)); + std::move(callback)); } - void - UnregisterScreenLockedListener(absl::string_view listener_name) override { + void UnregisterScreenLockedListener( + absl::string_view listener_name) override { current_user_session_->UnregisterScreenLockedListener(listener_name); } bool PreventSleep() override; bool AllowSleep() override; -private: + private: sdbus::IConnection &system_bus_; std::unique_ptr current_user_session_; std::unique_ptr login_manager_; std::optional inhibit_fd_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby -#endif // PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ +#endif // PLATFORM_IMPL_LINUX_DEVICE_INFO_H_ diff --git a/internal/platform/implementation/linux/thread_pool.h b/internal/platform/implementation/linux/thread_pool.h index a5a9aa42..7f2b0fc1 100644 --- a/internal/platform/implementation/linux/thread_pool.h +++ b/internal/platform/implementation/linux/thread_pool.h @@ -31,21 +31,24 @@ namespace linux { class ThreadPool { public: - ThreadPool(size_t max_pool_size); - ~ThreadPool(); + ThreadPool(const ThreadPool &) = delete; + ThreadPool(ThreadPool &&) = delete; + ThreadPool &operator=(const ThreadPool &) = delete; + ThreadPool &operator=(ThreadPool &&) = delete; + explicit ThreadPool(size_t max_pool_size); + ~ThreadPool(); - bool Start() ABSL_LOCKS_EXCLUDED(mutex_); + bool Start() ABSL_LOCKS_EXCLUDED(mutex_); - // Runs a task on thread pool. The result indicates whether the task is put - // into the thread pool. - bool Run(Runnable &&task) ABSL_LOCKS_EXCLUDED(mutex_); + // Runs a task on thread pool. The result indicates whether the task is put + // into the thread pool. + bool Run(Runnable &&task) ABSL_LOCKS_EXCLUDED(mutex_); - void ShutDown() ABSL_LOCKS_EXCLUDED(mutex_); + void ShutDown() ABSL_LOCKS_EXCLUDED(mutex_); private: Runnable NextTask() ABSL_LOCKS_EXCLUDED(mutex_); -private: size_t max_pool_size_; std::atomic_bool shut_down_; diff --git a/internal/platform/implementation/linux/wifi_direct.h b/internal/platform/implementation/linux/wifi_direct.h index 3e5025ad..bbaf720c 100644 --- a/internal/platform/implementation/linux/wifi_direct.h +++ b/internal/platform/implementation/linux/wifi_direct.h @@ -30,9 +30,8 @@ public: sdbus::IConnection &system_bus, std::shared_ptr network_manager, std::unique_ptr wireless_device) - : system_bus_(system_bus), network_manager_(network_manager), + : system_bus_(system_bus), network_manager_(std::move(network_manager)), wireless_device_(std::move(wireless_device)) {} - ~NetworkManagerWifiDirectMedium() {} bool IsInterfaceValid() const override { return true; } std::unique_ptr diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.h b/internal/platform/implementation/linux/wifi_direct_server_socket.h index f0261667..1f5fe879 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.h @@ -15,30 +15,35 @@ #ifndef PLATFORM_IMPL_LINUX_WIFI_DIRECT_SERVER_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_DIRECT_SERVER_SOCKET_H_ +#include #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_direct.h" -#include namespace nearby { - namespace linux { - class NetworkManagerWifiDirectServerSocket - : public api::WifiDirectServerSocket { -public: - NetworkManagerWifiDirectServerSocket(int socket, sdbus::IConnection &system_bus, - const sdbus::ObjectPath &active_connection_path, - std::shared_ptr network_manager) : fd_(socket), system_bus_(system_bus), active_connection_path_(active_connection_path), network_manager_(network_manager) {} - ~NetworkManagerWifiDirectServerSocket() {} +namespace linux { +class NetworkManagerWifiDirectServerSocket + : public api::WifiDirectServerSocket { + public: + NetworkManagerWifiDirectServerSocket( + int socket, sdbus::IConnection &system_bus, + sdbus::ObjectPath active_connection_path, + std::shared_ptr network_manager) + : fd_(socket), + system_bus_(system_bus), + active_connection_path_(std::move(active_connection_path)), + network_manager_(std::move(network_manager)) {} - std::string GetIPAddress() const override; - int GetPort() const override; - std::unique_ptr Accept() override; - Exception Close() override; -private: + std::string GetIPAddress() const override; + int GetPort() const override; + std::unique_ptr Accept() override; + Exception Close() override; + + private: sdbus::UnixFd fd_; sdbus::IConnection &system_bus_; sdbus::ObjectPath active_connection_path_; - std::shared_ptr network_manager_ ; - }; - } -} + std::shared_ptr network_manager_; +}; +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_direct_socket.h b/internal/platform/implementation/linux/wifi_direct_socket.h index 069eb0c2..25472d8f 100644 --- a/internal/platform/implementation/linux/wifi_direct_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_socket.h @@ -23,9 +23,8 @@ namespace nearby { namespace linux { class WifiDirectSocket : public api::WifiDirectSocket { public: - WifiDirectSocket(int socket) - : fd_(sdbus::UnixFd(socket)), output_stream_(fd_), input_stream_(fd_) {} - ~WifiDirectSocket() = default; + explicit WifiDirectSocket(int socket) + : fd_(sdbus::UnixFd(socket)), output_stream_(fd_), input_stream_(fd_) {} InputStream &GetInputStream() override { return input_stream_; }; OutputStream &GetOutputStream() override { return output_stream_; }; diff --git a/internal/platform/implementation/linux/wifi_hotspot.h b/internal/platform/implementation/linux/wifi_hotspot.h index 9873ea3d..d1061e47 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.h +++ b/internal/platform/implementation/linux/wifi_hotspot.h @@ -25,38 +25,38 @@ namespace nearby { namespace linux { class NetworkManagerWifiHotspotMedium : public api::WifiHotspotMedium { public: - NetworkManagerWifiHotspotMedium( - sdbus::IConnection &system_bus, - std::shared_ptr network_manager, - const sdbus::ObjectPath &wireless_device_object_path) - : system_bus_(system_bus), - wireless_device_(std::make_unique( - network_manager, system_bus, wireless_device_object_path)), - network_manager_(network_manager) {} - NetworkManagerWifiHotspotMedium( - sdbus::IConnection &system_bus, - std::shared_ptr network_manager, - std::unique_ptr wireless_device) - : system_bus_(system_bus), wireless_device_(std::move(wireless_device)), - network_manager_(network_manager) {} - ~NetworkManagerWifiHotspotMedium() {} + NetworkManagerWifiHotspotMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + sdbus::ObjectPath wireless_device_object_path) + : system_bus_(system_bus), + wireless_device_(std::make_unique( + network_manager, system_bus, std::move(wireless_device_object_path))), + network_manager_(std::move(network_manager)) {} + NetworkManagerWifiHotspotMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + std::unique_ptr wireless_device) + : system_bus_(system_bus), + wireless_device_(std::move(wireless_device)), + network_manager_(std::move(network_manager)) {} - bool IsInterfaceValid() const override { return true; } - std::unique_ptr - ConnectToService(absl::string_view ip_address, int port, - CancellationFlag *cancellation_flag) override; - std::unique_ptr - ListenForService(int port) override; + bool IsInterfaceValid() const override { return true; } + std::unique_ptr ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr ListenForService( + int port) override; - bool StartWifiHotspot(HotspotCredentials *hotspot_credentials) override; - bool StopWifiHotspot() override; + bool StartWifiHotspot(HotspotCredentials *hotspot_credentials) override; + bool StopWifiHotspot() override; - bool ConnectWifiHotspot(HotspotCredentials *hotspot_credentials) override; - bool DisconnectWifiHotspot() override; + bool ConnectWifiHotspot(HotspotCredentials *hotspot_credentials) override; + bool DisconnectWifiHotspot() override; - absl::optional> - GetDynamicPortRange() override { - return absl::nullopt; + absl::optional> GetDynamicPortRange() + override { + return absl::nullopt; } private: diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h index 2097df01..77746040 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h @@ -27,12 +27,11 @@ class NetworkManagerWifiHotspotServerSocket public: NetworkManagerWifiHotspotServerSocket( int socket, sdbus::IConnection &system_bus, - const sdbus::ObjectPath &active_connection_path, + sdbus::ObjectPath active_connection_path, std::shared_ptr network_manager) : fd_(socket), system_bus_(system_bus), - active_connection_path_(active_connection_path), - network_manager_(network_manager) {} - ~NetworkManagerWifiHotspotServerSocket() {} + active_connection_path_(std::move(active_connection_path)), + network_manager_(std::move(network_manager)) {} std::string GetIPAddress() const override; int GetPort() const override; diff --git a/internal/platform/implementation/linux/wifi_hotspot_socket.h b/internal/platform/implementation/linux/wifi_hotspot_socket.h index 2a62668a..0d208cc1 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_socket.h @@ -22,10 +22,9 @@ namespace nearby { namespace linux { class WifiHotspotSocket : public api::WifiHotspotSocket { public: - WifiHotspotSocket(int connection_fd) + explicit WifiHotspotSocket(int connection_fd) : fd_(sdbus::UnixFd(connection_fd)), output_stream_(fd_), input_stream_(fd_) {} - ~WifiHotspotSocket() {} nearby::InputStream &GetInputStream() override { return input_stream_; }; nearby::OutputStream &GetOutputStream() override { return output_stream_; }; diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index dc52fb30..6cee1102 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -27,8 +27,7 @@ namespace nearby { namespace linux { class WifiLanMedium : public api::WifiLanMedium { public: - WifiLanMedium(sdbus::IConnection &system_bus); - ~WifiLanMedium() override = default; + explicit WifiLanMedium(sdbus::IConnection &system_bus); bool IsNetworkConnected() const override; diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.h b/internal/platform/implementation/linux/wifi_lan_server_socket.h index 27de3785..32ec7bca 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.h @@ -28,12 +28,11 @@ namespace nearby { namespace linux { class WifiLanServerSocket : public api::WifiLanServerSocket { public: - WifiLanServerSocket(int socket, + explicit WifiLanServerSocket(int socket, std::shared_ptr network_manager, sdbus::IConnection &system_bus) - : fd_(sdbus::UnixFd(socket)), network_manager_(network_manager), + : fd_(sdbus::UnixFd(socket)), network_manager_(std::move(network_manager)), system_bus_(system_bus) {} - ~WifiLanServerSocket() override = default; std::string GetIPAddress() const override; int GetPort() const override; diff --git a/internal/platform/implementation/linux/wifi_lan_socket.h b/internal/platform/implementation/linux/wifi_lan_socket.h index f2ec43a0..276c8d2c 100644 --- a/internal/platform/implementation/linux/wifi_lan_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_socket.h @@ -28,9 +28,8 @@ namespace nearby { namespace linux { class WifiLanSocket : public api::WifiLanSocket { public: - WifiLanSocket(sdbus::UnixFd fd) + explicit WifiLanSocket(sdbus::UnixFd fd) : fd_(fd), output_stream_(fd), input_stream_(fd) {} - ~WifiLanSocket() = default; nearby::InputStream &GetInputStream() override { return input_stream_; diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 4b395310..065cb406 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -21,30 +21,35 @@ #include #include -#include #include #include #include #include +#include #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/access_point_client.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/ip4config_client.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h" #include "internal/platform/implementation/wifi.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { -class NetworkManager +class NetworkManager final : public sdbus::ProxyInterfaces { -public: - NetworkManager(sdbus::IConnection &system_bus) + public: + NetworkManager(const NetworkManager &) = delete; + NetworkManager(NetworkManager &&) = delete; + NetworkManager &operator=(const NetworkManager &) = delete; + NetworkManager &operator=(NetworkManager &&) = delete; + explicit NetworkManager(sdbus::IConnection &system_bus) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - "/org/freedesktop/NetworkManager") { + "/org/freedesktop/NetworkManager"), + state_(0) { registerProxy(); try { state_ = State(); @@ -56,20 +61,24 @@ public: std::uint32_t getState() const { return state_; } -protected: + protected: void onCheckPermissions() override {} void onStateChanged(const uint32_t &state) override { state_ = state; } void onDeviceAdded(const sdbus::ObjectPath &device_path) override {} void onDeviceRemoved(const sdbus::ObjectPath &device_path) override {} -private: + private: std::atomic_uint32_t state_; }; class NetworkManagerIP4Config : public sdbus::ProxyInterfaces< org::freedesktop::NetworkManager::IP4Config_proxy> { -public: + public: + NetworkManagerIP4Config(const NetworkManagerIP4Config &) = delete; + NetworkManagerIP4Config(NetworkManagerIP4Config &&) = delete; + NetworkManagerIP4Config &operator=(const NetworkManagerIP4Config &) = delete; + NetworkManagerIP4Config &operator=(NetworkManagerIP4Config &&) = delete; NetworkManagerIP4Config(sdbus::IConnection &system_bus, const sdbus::ObjectPath &config_object_path) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", @@ -82,11 +91,16 @@ public: class NetworkManagerAccessPoint : public sdbus::ProxyInterfaces< org::freedesktop::NetworkManager::AccessPoint_proxy> { -public: + public: + NetworkManagerAccessPoint(const NetworkManagerAccessPoint &) = delete; + NetworkManagerAccessPoint(NetworkManagerAccessPoint &&) = delete; + NetworkManagerAccessPoint &operator=(const NetworkManagerAccessPoint &) = + delete; + NetworkManagerAccessPoint &operator=(NetworkManagerAccessPoint &&) = delete; NetworkManagerAccessPoint(sdbus::IConnection &system_bus, - const sdbus::ObjectPath &access_point_object_path) + sdbus::ObjectPath access_point_object_path) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - access_point_object_path) { + std::move(access_point_object_path)) { registerProxy(); } ~NetworkManagerAccessPoint() { unregisterProxy(); } @@ -123,12 +137,20 @@ extern std::ostream &operator<<(std::ostream &s, class NetworkManagerActiveConnection : public sdbus::ProxyInterfaces< org::freedesktop::NetworkManager::Connection::Active_proxy> { -public: - NetworkManagerActiveConnection( - sdbus::IConnection &system_bus, - const sdbus::ObjectPath &active_connection_path) + public: + NetworkManagerActiveConnection(const NetworkManagerActiveConnection &) = + delete; + NetworkManagerActiveConnection(NetworkManagerActiveConnection &&) = delete; + NetworkManagerActiveConnection &operator=( + const NetworkManagerActiveConnection &) = delete; + NetworkManagerActiveConnection &operator=(NetworkManagerActiveConnection &&) = + delete; + explicit NetworkManagerActiveConnection( + sdbus::IConnection &system_bus, sdbus::ObjectPath active_connection_path) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - active_connection_path) { + std::move(active_connection_path)), + state_(kStateUnknown), + reason_(kStateReasonUnknown) { registerProxy(); try { auto state = State(); @@ -139,9 +161,9 @@ public: DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); } } - ~NetworkManagerActiveConnection() { unregisterProxy(); } + virtual ~NetworkManagerActiveConnection() { unregisterProxy(); } -protected: + protected: void onStateChanged(const uint32_t &state, const uint32_t &reason) override ABSL_LOCKS_EXCLUDED(state_mutex_) { absl::MutexLock l(&state_mutex_); @@ -153,9 +175,9 @@ protected: } } -public: - std::pair, bool> - WaitForConnection(absl::Duration timeout = absl::Seconds(10)) + public: + std::pair, bool> WaitForConnection( + absl::Duration timeout = absl::Seconds(10)) ABSL_LOCKS_EXCLUDED(state_mutex_) { NEARBY_LOGS(VERBOSE) << __func__ << ": Waiting for an update to " << getObjectPath() << "'s state"; @@ -208,36 +230,42 @@ public: return ip4addresses; } -private: + private: absl::Mutex state_mutex_; ActiveConnectionState state_ ABSL_GUARDED_BY(state_mutex_); ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_); }; -class NetworkManagerObjectManager +class NetworkManagerObjectManager final : public sdbus::ProxyInterfaces { -public: - NetworkManagerObjectManager(sdbus::IConnection &system_bus) + public: + NetworkManagerObjectManager(const NetworkManagerObjectManager &) = delete; + NetworkManagerObjectManager(NetworkManagerObjectManager &&) = delete; + NetworkManagerObjectManager &operator=(const NetworkManagerObjectManager &) = + delete; + NetworkManagerObjectManager &operator=(NetworkManagerObjectManager &&) = + delete; + explicit NetworkManagerObjectManager(sdbus::IConnection &system_bus) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", "/org/freedesktop") { registerProxy(); } ~NetworkManagerObjectManager() { unregisterProxy(); } - std::unique_ptr - GetIp4Config(const sdbus::ObjectPath &access_point); + std::unique_ptr GetIp4Config( + const sdbus::ObjectPath &access_point); std::unique_ptr GetActiveConnectionForAccessPoint(const sdbus::ObjectPath &access_point_path, const sdbus::ObjectPath &device_path); -protected: + protected: void onInterfacesAdded( const sdbus::ObjectPath &objectPath, const std::map> &interfacesAndProperties) override {} - void - onInterfacesRemoved(const sdbus::ObjectPath &objectPath, - const std::vector &interfaces) override {} + void onInterfacesRemoved( + const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override {} }; class NetworkManagerWifiMedium @@ -245,21 +273,26 @@ class NetworkManagerWifiMedium public sdbus::ProxyInterfaces< org::freedesktop::NetworkManager::Device::Wireless_proxy, sdbus::Properties_proxy> { -public: + public: + NetworkManagerWifiMedium(const NetworkManagerWifiMedium &) = delete; + NetworkManagerWifiMedium(NetworkManagerWifiMedium &&) = delete; + NetworkManagerWifiMedium &operator=(const NetworkManagerWifiMedium &) = + delete; + NetworkManagerWifiMedium &operator=(NetworkManagerWifiMedium &&) = delete; NetworkManagerWifiMedium(std::shared_ptr network_manager, sdbus::IConnection &system_bus, const sdbus::ObjectPath &wireless_device_object_path) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", wireless_device_object_path), - network_manager_(std::move(network_manager)) { + network_manager_(std::move(network_manager)), + last_scan_(-1) { registerProxy(); } ~NetworkManagerWifiMedium() override { unregisterProxy(); } class ScanResultCallback : public api::WifiMedium::ScanResultCallback { - public: - ~ScanResultCallback() override = default; + public: void OnScanResults( const std::vector &scan_results) override { // TODO: Add implementation at some point @@ -272,21 +305,20 @@ public: bool Scan( const api::WifiMedium::ScanResultCallback &scan_result_callback) override; - std::shared_ptr - SearchBySSID(absl::string_view ssid, - absl::Duration scan_timeout = absl::Seconds(15)) + std::shared_ptr SearchBySSID( + absl::string_view ssid, absl::Duration scan_timeout = absl::Seconds(15)) ABSL_LOCKS_EXCLUDED(known_access_points_lock_); - api::WifiConnectionStatus - ConnectToNetwork(absl::string_view ssid, absl::string_view password, - api::WifiAuthType auth_type) override; + api::WifiConnectionStatus ConnectToNetwork( + absl::string_view ssid, absl::string_view password, + api::WifiAuthType auth_type) override; bool VerifyInternetConnectivity() override; std::string GetIpAddress() override; std::unique_ptr GetActiveConnection(); -protected: + protected: void onPropertiesChanged( const std::string &interfaceName, const std::map &changedProperties, @@ -306,9 +338,9 @@ protected: known_access_points_.erase(access_point); } -private: - std::shared_ptr - SearchBySSIDNoScan(std::vector &ssid) + private: + std::shared_ptr SearchBySSIDNoScan( + std::vector &ssid) ABSL_LOCKS_EXCLUDED(known_access_points_lock_); std::shared_ptr network_manager_; @@ -329,7 +361,7 @@ private: std::int64_t last_scan_ ABSL_GUARDED_BY(last_scan_lock_); }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif From c742bd3a375d2d2789503fb43010125b03625011 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 13:21:30 +0530 Subject: [PATCH 090/201] clang-format --- .../implementation/linux/atomic_boolean.h | 12 +- .../implementation/linux/atomic_uint32.h | 10 +- .../platform/implementation/linux/avahi.cc | 10 +- .../platform/implementation/linux/avahi.h | 27 +- .../implementation/linux/ble_medium.h | 12 +- .../implementation/linux/ble_v2_medium.h | 42 ++- .../implementation/linux/bluetooth_adapter.cc | 42 +-- .../implementation/linux/bluetooth_adapter.h | 14 +- .../linux/bluetooth_bluez_profile.cc | 16 +- .../linux/bluetooth_classic_device.cc | 4 +- .../linux/bluetooth_classic_device.h | 49 ++- .../linux/bluetooth_classic_medium.cc | 23 +- .../linux/bluetooth_classic_medium.h | 120 ++++---- .../linux/bluetooth_classic_server_socket.cc | 7 +- .../linux/bluetooth_classic_server_socket.h | 44 +-- .../linux/bluetooth_classic_socket.cc | 18 +- .../linux/bluetooth_classic_socket.h | 20 +- .../implementation/linux/bluetooth_devices.cc | 8 +- .../implementation/linux/bluetooth_devices.h | 22 +- .../implementation/linux/bluetooth_pairing.cc | 8 +- .../implementation/linux/bluetooth_pairing.h | 8 +- .../platform/implementation/linux/bluez.cc | 12 +- .../platform/implementation/linux/bluez.h | 37 ++- .../implementation/linux/condition_variable.h | 10 +- .../linux/condition_variable_test.cc | 8 +- .../linux/count_down_latch_test.cc | 11 +- .../implementation/linux/credential_storage.h | 14 +- .../platform/implementation/linux/dbus.cc | 11 +- internal/platform/implementation/linux/dbus.h | 42 +-- .../implementation/linux/device_info.cc | 10 +- .../implementation/linux/device_info.h | 5 +- .../implementation/linux/device_info_test.cc | 2 +- .../platform/implementation/linux/executor.cc | 4 +- .../implementation/linux/executor_test.cc | 4 +- .../platform/implementation/linux/file.cc | 8 +- .../implementation/linux/file_path.cc | 17 +- .../implementation/linux/file_path_test.cc | 27 +- .../implementation/linux/http_loader.cc | 284 ++++++++++-------- .../implementation/linux/http_loader.h | 9 +- .../implementation/linux/input_file.h | 2 +- .../implementation/linux/input_file_test.cc | 8 +- .../implementation/linux/log_message.cc | 86 +++--- .../implementation/linux/log_message.h | 56 ++-- .../platform/implementation/linux/mutex.h | 12 +- .../implementation/linux/output_file.h | 2 +- .../implementation/linux/output_file_test.cc | 8 +- .../platform/implementation/linux/platform.cc | 68 ++--- .../linux/preferences_manager.cc | 7 +- .../linux/preferences_manager.h | 4 +- .../linux/preferences_manager_test.cc | 14 +- .../linux/preferences_repository.cc | 5 +- .../linux/preferences_repository_test.cc | 7 +- .../linux/scheduled_executor.cc | 8 +- .../implementation/linux/scheduled_executor.h | 2 +- .../linux/scheduled_executor_test.cc | 5 +- .../platform/implementation/linux/stream.h | 12 +- .../linux/submittable_executor.h | 2 +- .../linux/submittable_executor_test.cc | 4 +- .../implementation/linux/system_clock.cc | 8 +- .../platform/implementation/linux/test_data.h | 1 - .../implementation/linux/test_utils.cc | 11 +- .../implementation/linux/thread_pool.cc | 4 +- .../implementation/linux/thread_pool.h | 32 +- .../implementation/linux/thread_pool_test.cc | 5 +- .../platform/implementation/linux/timer.cc | 26 +- .../platform/implementation/linux/timer.h | 10 +- .../platform/implementation/linux/utils.cc | 118 ++++---- .../implementation/linux/wifi_direct.cc | 13 +- .../implementation/linux/wifi_direct.h | 30 +- .../linux/wifi_direct_server_socket.cc | 11 +- .../implementation/linux/wifi_direct_socket.h | 10 +- .../implementation/linux/wifi_hotspot.cc | 14 +- .../implementation/linux/wifi_hotspot.h | 65 ++-- .../linux/wifi_hotspot_server_socket.cc | 14 +- .../linux/wifi_hotspot_server_socket.h | 11 +- .../linux/wifi_hotspot_socket.h | 11 +- .../platform/implementation/linux/wifi_lan.cc | 37 ++- .../platform/implementation/linux/wifi_lan.h | 28 +- .../linux/wifi_lan_server_socket.cc | 16 +- .../linux/wifi_lan_server_socket.h | 15 +- .../implementation/linux/wifi_lan_socket.h | 16 +- .../implementation/linux/wifi_medium.cc | 102 +++---- .../implementation/linux/wifi_socket.h | 18 +- 83 files changed, 983 insertions(+), 986 deletions(-) diff --git a/internal/platform/implementation/linux/atomic_boolean.h b/internal/platform/implementation/linux/atomic_boolean.h index 85e835cb..e7e2a82d 100644 --- a/internal/platform/implementation/linux/atomic_boolean.h +++ b/internal/platform/implementation/linux/atomic_boolean.h @@ -15,13 +15,13 @@ #ifndef PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_ #define PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_ -#include "internal/platform/implementation/atomic_boolean.h" #include +#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: + public: AtomicBoolean(bool initial_value) : atomic_boolean_(initial_value) {} ~AtomicBoolean() override = default; @@ -31,11 +31,11 @@ public: // Atomically exchange original value with a new one. Return previous value. bool Set(bool value) override { return atomic_boolean_.exchange(value); }; -private: + private: std::atomic_bool atomic_boolean_ = false; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby -#endif // PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_ +#endif // PLATFORM_IMPL_LINUX_ATOMIC_BOOLEAN_H_ diff --git a/internal/platform/implementation/linux/atomic_uint32.h b/internal/platform/implementation/linux/atomic_uint32.h index 81c9468f..28ce3016 100644 --- a/internal/platform/implementation/linux/atomic_uint32.h +++ b/internal/platform/implementation/linux/atomic_uint32.h @@ -15,15 +15,15 @@ #ifndef PLATFORM_IMPL_LINUX_ATOMIC_UINT32_H_ #define PLATFORM_IMPL_LINUX_ATOMIC_UINT32_H_ -#include "internal/platform/implementation/atomic_reference.h" #include #include +#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: + public: AtomicUint32(std::uint32_t initial_value) : atomic_uint_(initial_value) {} ~AtomicUint32() override = default; @@ -33,10 +33,10 @@ public: // Atomically exchange original value with a new one. Return previous value. void Set(std::uint32_t value) override { atomic_uint_ = value; }; -private: + private: std::atomic_bool atomic_uint_ = false; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/avahi.cc b/internal/platform/implementation/linux/avahi.cc index bc3df9f1..b9c5b068 100644 --- a/internal/platform/implementation/linux/avahi.cc +++ b/internal/platform/implementation/linux/avahi.cc @@ -41,7 +41,7 @@ void ServiceBrowser::onItemNew(const int32_t &interface, 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, // AVAHI_PROTO_INET 0); info.SetServiceName(r_name); info.SetIPAddress(r_address); @@ -83,7 +83,7 @@ void ServiceBrowser::onItemRemove( 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, // AVAHI_PROTO_INET flags); info.SetServiceName(r_name); info.SetIPAddress(r_address); @@ -121,6 +121,6 @@ void ServiceBrowser::onCacheExhausted() { << ": notified via ServiceBrowser of cache exhaustion"; } -} // namespace avahi -} // namespace linux -} // namespace nearby +} // namespace avahi +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index 208eaa52..5ba38b4e 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -15,14 +15,14 @@ #ifndef PLATFORM_IMPL_LINUX_AVAHI_H_ #define PLATFORM_IMPL_LINUX_AVAHI_H_ -#include #include #include +#include +#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/linux/dbus.h" #include "internal/platform/implementation/wifi_lan.h" namespace nearby { @@ -30,21 +30,21 @@ namespace linux { namespace avahi { class Server : public sdbus::ProxyInterfaces { -public: + public: Server(sdbus::IConnection &system_bus) : ProxyInterfaces(system_bus, "org.freedesktop.Avahi", "/") { registerProxy(); } ~Server() { unregisterProxy(); } -protected: + protected: void onStateChanged(const int32_t &state, const std::string &error) override { } }; class EntryGroup : public sdbus::ProxyInterfaces { -public: + public: EntryGroup(sdbus::IConnection &system_bus, const sdbus::ObjectPath &entry_group_object_path) : ProxyInterfaces(system_bus, "org.freedesktop.Avahi", @@ -64,21 +64,22 @@ public: unregisterProxy(); } -protected: + protected: void onStateChanged(const int32_t &state, const std::string &error) override { } }; class ServiceBrowser : public sdbus::ProxyInterfaces< org::freedesktop::Avahi::ServiceBrowser_proxy> { -public: + public: ServiceBrowser(sdbus::IConnection &system_bus, const sdbus::ObjectPath &service_browser_object_path, api::WifiLanMedium::DiscoveredServiceCallback callback, std::shared_ptr avahi_server) : ProxyInterfaces(system_bus, "org.freedesktop.Avahi", service_browser_object_path), - discovery_cb_(std::move(callback)), server_(avahi_server) { + discovery_cb_(std::move(callback)), + server_(avahi_server) { registerProxy(); } ~ServiceBrowser() { @@ -93,7 +94,7 @@ public: unregisterProxy(); } -protected: + 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; @@ -104,7 +105,7 @@ protected: void onAllForNow() override; void onCacheExhausted() override; -private: + private: enum LookupResultFlags { kAvahiLookupResultFlagCached = 1, kAvahiLookupResultFlagWideArea = 2, @@ -117,8 +118,8 @@ private: api::WifiLanMedium::DiscoveredServiceCallback discovery_cb_; std::shared_ptr server_; }; -} // namespace avahi -} // namespace linux -} // namespace nearby +} // namespace avahi +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/ble_medium.h b/internal/platform/implementation/linux/ble_medium.h index 501c96a1..84c474a5 100644 --- a/internal/platform/implementation/linux/ble_medium.h +++ b/internal/platform/implementation/linux/ble_medium.h @@ -21,7 +21,7 @@ namespace nearby { namespace linux { // Container of operations that can be performed over the BLE medium. class BleMedium : public api::BleMedium { -public: + public: BleMedium() {} ~BleMedium() = default; @@ -61,13 +61,13 @@ public: // Connects to a BLE peripheral. // On success, returns a new BleSocket. // On error, returns nullptr. - std::unique_ptr - Connect(api::BlePeripheral &peripheral, const std::string &service_id, - CancellationFlag *cancellation_flag) override { + std::unique_ptr Connect( + api::BlePeripheral &peripheral, const std::string &service_id, + CancellationFlag *cancellation_flag) override { return nullptr; } }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index 51723032..ee0d1d7d 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -25,13 +25,13 @@ class BleV2Medium : public api::ble_v2::BleMedium { api::ble_v2::AdvertiseParameters advertise_set_parameters) override { return false; } - std::unique_ptr - StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data, - api::ble_v2::AdvertiseParameters advertise_set_parameters, - AdvertisingCallback callback) override { + std::unique_ptr StartAdvertising( + const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters, + AdvertisingCallback callback) override { return nullptr; } - bool StopAdvertising() override {return false;} + bool StopAdvertising() override { return false; } bool StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, @@ -40,15 +40,14 @@ class BleV2Medium : public api::ble_v2::BleMedium { } bool StopScanning() override { return false; } - std::unique_ptr - StartScanning(const Uuid &service_uuid, - api::ble_v2::TxPowerLevel tx_power_level, - ScanningCallback callback) override { + std::unique_ptr StartScanning( + const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, + ScanningCallback callback) override { return nullptr; }; - std::unique_ptr - StartGattServer(api::ble_v2::ServerGattConnectionCallback callback) override { + std::unique_ptr StartGattServer( + api::ble_v2::ServerGattConnectionCallback callback) override { return nullptr; } @@ -59,21 +58,18 @@ class BleV2Medium : public api::ble_v2::BleMedium { return nullptr; } - std::unique_ptr - OpenServerSocket(const std::string &service_id) override { + std::unique_ptr OpenServerSocket( + const std::string &service_id) override { return nullptr; } - std::unique_ptr - Connect(const std::string &service_id, - api::ble_v2::TxPowerLevel tx_power_level, - api::ble_v2::BlePeripheral &peripheral, - CancellationFlag *cancellation_flag) override { + std::unique_ptr 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 { - return false; - } + bool IsExtendedAdvertisementsAvailable() override { return false; } bool GetRemotePeripheral(const std::string &mac_address, GetRemotePeripheralCallback callback) override { return false; @@ -83,7 +79,7 @@ class BleV2Medium : public api::ble_v2::BleMedium { return false; } }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index d57dc56f..3dba14f6 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -18,8 +18,8 @@ #include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluez.h" -#include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.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 { @@ -63,26 +63,26 @@ BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const { 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; - } + 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; - } + 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; + return true; + } + case ScanMode::kNone: + return SetStatus(Status::kDisabled); + default: + return false; } } @@ -119,5 +119,5 @@ std::string BluetoothAdapter::GetMacAddress() const { } } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index d03309e9..e2573a8e 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -20,13 +20,13 @@ #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/generated/dbus/bluez/adapter_client.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 { -public: + public: BluezAdapter(sdbus::IConnection &system_bus, const sdbus::ObjectPath &adapter_object_path) : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, adapter_object_path) { @@ -36,7 +36,7 @@ public: }; class BluetoothAdapter : public api::BluetoothAdapter { -public: + public: BluetoothAdapter(sdbus::IConnection &system_bus, const sdbus::ObjectPath &adapter_object_path) : bluez_adapter_( @@ -81,11 +81,11 @@ public: BluezAdapter &GetBluezAdapterObject() { return *bluez_adapter_; } -private: + private: std::unique_ptr bluez_adapter_; bool persist_name_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby -#endif // PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ +#endif // PLATFORM_IMPL_LINUX_BLUETOOTH_ADAPTER_H_ diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index c88026ab..dfe1a880 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -16,11 +16,11 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -172,10 +172,9 @@ void ProfileManager::Unregister(absl::string_view service_uuid) { // Get a service record FD for a connected profile (identified by service_uuid) // to the given device. -std::optional -ProfileManager::GetServiceRecordFD(api::BluetoothDevice &remote_device, - absl::string_view service_uuid, - CancellationFlag *cancellation_flag) { +std::optional ProfileManager::GetServiceRecordFD( + api::BluetoothDevice &remote_device, absl::string_view service_uuid, + CancellationFlag *cancellation_flag) { if (!ProfileRegistered(service_uuid)) { NEARBY_LOGS(ERROR) << __func__ << ": Service " << service_uuid << " is not registered"; @@ -245,8 +244,7 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { auto mac_addr = it->first; auto [fd, properties] = it->second.back(); it->second.pop_back(); - if (it->second.empty()) - profile->connections_.erase(it); + if (it->second.empty()) profile->connections_.erase(it); profile->connections_lock_.Unlock(); auto maybe_device = devices_.get_device_by_address(mac_addr); @@ -259,5 +257,5 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { return std::pair(*maybe_device, fd); } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 2d1f9d36..d1cc4425 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -165,5 +165,5 @@ void MonitoredBluetoothDevice::onPropertiesChanged( } } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 7f7f5aa2..60fc280b 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -33,28 +33,27 @@ namespace linux { class BluetoothDevice : public api::BluetoothDevice, public sdbus::ProxyInterfaces { -public: - BluetoothDevice(const BluetoothDevice &) = delete; - BluetoothDevice(BluetoothDevice &&) = delete; - BluetoothDevice &operator=(const BluetoothDevice &) = delete; - BluetoothDevice &operator=(BluetoothDevice &&) = delete; - BluetoothDevice(sdbus::IConnection &system_bus, sdbus::ObjectPath device_object_path); - ~BluetoothDevice() override { - unregisterProxy(); - } + public: + BluetoothDevice(const BluetoothDevice &) = delete; + BluetoothDevice(BluetoothDevice &&) = delete; + BluetoothDevice &operator=(const BluetoothDevice &) = delete; + BluetoothDevice &operator=(BluetoothDevice &&) = delete; + BluetoothDevice(sdbus::IConnection &system_bus, + sdbus::ObjectPath device_object_path); + ~BluetoothDevice() override { unregisterProxy(); } - // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() - std::string GetName() const override; + // 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; + // Returns BT MAC address assigned to this device. + std::string GetMacAddress() const override; - bool ConnectToProfile(absl::string_view service_uuid); + bool ConnectToProfile(absl::string_view service_uuid); - void set_pair_reply_callback( - absl::AnyInvocable cb) { - absl::MutexLock l(&pair_callback_lock_); - on_pair_reply_cb_ = std::move(cb); + void set_pair_reply_callback( + absl::AnyInvocable cb) { + absl::MutexLock l(&pair_callback_lock_); + on_pair_reply_cb_ = std::move(cb); } void reset_pair_reply_callback() { @@ -62,14 +61,14 @@ public: on_pair_reply_cb_ = DefaultCallback(); } -protected: + protected: void onConnectProfileReply(const sdbus::Error *error) override; void onPairReply(const sdbus::Error *error) override { absl::ReaderMutexLock l(&pair_callback_lock_); on_pair_reply_cb_(error); }; -private: + private: absl::Mutex pair_callback_lock_; absl::AnyInvocable on_pair_reply_cb_ = DefaultCallback(); @@ -82,7 +81,7 @@ private: class MonitoredBluetoothDevice final : public BluetoothDevice, public sdbus::ProxyInterfaces { -public: + public: using sdbus::ProxyInterfaces::registerProxy; using sdbus::ProxyInterfaces::unregisterProxy; using sdbus::ProxyInterfaces::getObjectPath; @@ -97,17 +96,17 @@ public: ObserverList &observers); ~MonitoredBluetoothDevice() override { unregisterProxy(); } -protected: + protected: void onPropertiesChanged( const std::string &interfaceName, const std::map &changedProperties, const std::vector &invalidatedProperties) override; -private: + private: ObserverList &observers_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 8b2b7f0d..bcabd7e3 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -116,7 +116,6 @@ void BluetoothClassicMedium::onInterfacesRemoved( bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { - discovery_cb_ = std::move(discovery_callback); try { @@ -150,10 +149,9 @@ bool BluetoothClassicMedium::StopDiscovery() { return true; } -std::unique_ptr -BluetoothClassicMedium::ConnectToService(api::BluetoothDevice &remote_device, - const std::string &service_uuid, - CancellationFlag *cancellation_flag) { +std::unique_ptr BluetoothClassicMedium::ConnectToService( + api::BluetoothDevice &remote_device, const std::string &service_uuid, + CancellationFlag *cancellation_flag) { auto device_object_path = bluez::device_object_path( adapter_->GetObjectPath(), remote_device.GetMacAddress()); if (!profile_manager_->ProfileRegistered(service_uuid)) { @@ -200,17 +198,16 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, new BluetoothServerSocket(*profile_manager_, service_uuid)); } -api::BluetoothDevice * -BluetoothClassicMedium::GetRemoteDevice(const std::string &mac_address) { +api::BluetoothDevice *BluetoothClassicMedium::GetRemoteDevice( + const std::string &mac_address) { auto device = devices_->get_device_by_address(mac_address); - if (!device.has_value()) - return nullptr; + if (!device.has_value()) return nullptr; return &(device->get()); } -std::unique_ptr -BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) { +std::unique_ptr BluetoothClassicMedium::CreatePairing( + api::BluetoothDevice &remote_device) { auto device = devices_->get_device_by_address(remote_device.GetMacAddress()); if (!device.has_value()) return nullptr; @@ -218,5 +215,5 @@ BluetoothClassicMedium::CreatePairing(api::BluetoothDevice &remote_device) { new BluetoothPairing(*adapter_, *device)); } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 68cd26b3..6d9240ad 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -42,73 +42,75 @@ namespace linux { class BluetoothClassicMedium final : public api::BluetoothClassicMedium, sdbus::ProxyInterfaces { -public: - BluetoothClassicMedium(const BluetoothClassicMedium &) = delete; - BluetoothClassicMedium(BluetoothClassicMedium &&) = delete; - BluetoothClassicMedium &operator=(const BluetoothClassicMedium &) = delete; - BluetoothClassicMedium &operator=(BluetoothClassicMedium &&) = delete; - BluetoothClassicMedium(sdbus::IConnection &system_bus, - const sdbus::ObjectPath &adapter_object_path); - ~BluetoothClassicMedium() override { unregisterProxy(); }; + public: + BluetoothClassicMedium(const BluetoothClassicMedium &) = delete; + BluetoothClassicMedium(BluetoothClassicMedium &&) = delete; + BluetoothClassicMedium &operator=(const BluetoothClassicMedium &) = delete; + BluetoothClassicMedium &operator=(BluetoothClassicMedium &&) = delete; + BluetoothClassicMedium(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &adapter_object_path); + ~BluetoothClassicMedium() override { unregisterProxy(); }; - // 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; + // 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 ConnectToService( - api::BluetoothDevice &remote_device, const std::string &service_uuid, - CancellationFlag *cancellation_flag) 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 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 ListenForService( - const std::string &service_name, const std::string &service_uuid) 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 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 CreatePairing( - api::BluetoothDevice &remote_device) 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 CreatePairing( + api::BluetoothDevice &remote_device) override; - api::BluetoothDevice *GetRemoteDevice(const std::string &mac_address) override; + api::BluetoothDevice *GetRemoteDevice( + const std::string &mac_address) override; - void AddObserver(Observer *observer) override { - observers_.AddObserver(observer); + void AddObserver(Observer *observer) override { + observers_.AddObserver(observer); }; void RemoveObserver(Observer *observer) override { observers_.RemoveObserver(observer); }; -protected: + protected: void onInterfacesAdded( const sdbus::ObjectPath &objectPath, const std::map> @@ -116,7 +118,7 @@ protected: void onInterfacesRemoved(const sdbus::ObjectPath &objectPath, const std::vector &interfaces) override; -private: + private: std::unique_ptr adapter_; std::unique_ptr devices_; @@ -126,7 +128,7 @@ private: ObserverList observers_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc index ce0b59b0..ec6d868c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc @@ -12,16 +12,15 @@ // 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 "absl/strings/str_replace.h" #include "absl/strings/substitute.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_server_socket.h" #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" -#include namespace nearby { namespace linux { @@ -46,5 +45,5 @@ Exception BluetoothServerSocket::Close() { return {Exception::kSuccess}; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h index b503b3ec..7efdd817 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -15,40 +15,40 @@ #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/exception.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" -#include "absl/strings/string_view.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) {} + 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 Accept() override; + // 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 Accept() override; - // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close() - // - // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override; + // https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close() + // + // Returns Exception::kIo on error, Exception::kSuccess otherwise. + Exception Close() override; -private: + private: ProfileManager &profile_manager_; std::string service_uuid_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 2f79ef5c..35c4d921 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include -#include #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" @@ -25,8 +25,7 @@ namespace nearby { namespace linux { ExceptionOr InputStream::Read(std::int64_t size) { - if (!fd_.has_value()) - return Exception::kIo; + if (!fd_.has_value()) return Exception::kIo; char *data = new char[size]; ssize_t ret = read(fd_->get(), data, size); @@ -42,8 +41,7 @@ ExceptionOr InputStream::Read(std::int64_t size) { } Exception InputStream::Close() { - if (!fd_.has_value()) - return Exception{Exception::kIo}; + if (!fd_.has_value()) return Exception{Exception::kIo}; auto ret = close(fd_->get()) < 0 ? Exception{Exception::kIo} : Exception{Exception::kSuccess}; @@ -52,8 +50,7 @@ Exception InputStream::Close() { } Exception OutputStream::Write(const ByteArray &data) { - if (!fd_.has_value()) - return Exception{Exception::kIo}; + if (!fd_.has_value()) return Exception{Exception::kIo}; size_t written = 0; while (written < data.size()) { @@ -69,8 +66,7 @@ Exception OutputStream::Write(const ByteArray &data) { Exception OutputStream::Flush() { return Exception{Exception::kSuccess}; } Exception OutputStream::Close() { - if (!fd_.has_value()) - return Exception{Exception::kIo}; + if (!fd_.has_value()) return Exception{Exception::kIo}; auto ret = close(fd_->get()) < 0 ? Exception{Exception::kIo} : Exception{Exception::kSuccess}; @@ -85,5 +81,5 @@ Exception BluetoothSocket::Close() { return Exception{Exception::kSuccess}; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index dcefc4e5..d69676a4 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -28,20 +28,20 @@ namespace nearby { namespace linux { class BluetoothSocket final : public api::BluetoothSocket { -public: - BluetoothSocket(api::BluetoothDevice &device, sdbus::UnixFd fd) - : device_(device), output_stream_(fd), input_stream_(fd) {} + public: + BluetoothSocket(api::BluetoothDevice &device, sdbus::UnixFd fd) + : device_(device), output_stream_(fd), input_stream_(fd) {} - nearby::InputStream &GetInputStream() override { return input_stream_; } - nearby::OutputStream &GetOutputStream() override { return output_stream_; } - Exception Close() override; - api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; + nearby::InputStream &GetInputStream() override { return input_stream_; } + nearby::OutputStream &GetOutputStream() override { return output_stream_; } + Exception Close() override; + api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; -private: + private: api::BluetoothDevice &device_; OutputStream output_stream_; InputStream input_stream_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 24a0787b..06e24166 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -51,8 +51,8 @@ void BluetoothDevices::remove_device_by_path( devices_by_path_.erase(device_object_path); } -BluetoothDevice & -BluetoothDevices::add_new_device(sdbus::ObjectPath device_object_path) { +BluetoothDevice &BluetoothDevices::add_new_device( + sdbus::ObjectPath device_object_path) { absl::MutexLock l(&devices_by_path_lock_); auto pair = devices_by_path_.emplace( std::string(device_object_path), @@ -60,5 +60,5 @@ BluetoothDevices::add_new_device(sdbus::ObjectPath device_object_path) { system_bus_, std::move(device_object_path), observers_)); return *pair.first->second; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 49804517..e002c63f 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -29,22 +29,22 @@ namespace nearby { namespace linux { class BluetoothDevices final { -public: + public: BluetoothDevices( - sdbus::IConnection &system_bus, - sdbus::ObjectPath adapter_object_path, + sdbus::IConnection &system_bus, sdbus::ObjectPath adapter_object_path, ObserverList &observers) - : system_bus_(system_bus), observers_(observers), + : system_bus_(system_bus), + observers_(observers), adapter_object_path_(std::move(adapter_object_path)) {} - std::optional> - get_device_by_path(const sdbus::ObjectPath &); - std::optional> - get_device_by_address(const std::string &); + std::optional> get_device_by_path( + const sdbus::ObjectPath &); + std::optional> get_device_by_address( + const std::string &); void remove_device_by_path(const sdbus::ObjectPath &); BluetoothDevice &add_new_device(sdbus::ObjectPath); -private: + private: absl::Mutex devices_by_path_lock_; std::map> devices_by_path_; @@ -53,7 +53,7 @@ private: ObserverList &observers_; sdbus::ObjectPath adapter_object_path_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index d4ec92c6..50ea4203 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -61,7 +61,7 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { } BluetoothPairing::BluetoothPairing(BluetoothAdapter &adapter, - BluetoothDevice &remote_device) + BluetoothDevice &remote_device) : device_(remote_device), adapter_(adapter) {} bool BluetoothPairing::InitiatePairing( @@ -112,7 +112,7 @@ bool BluetoothPairing::CancelPairing() { } bool BluetoothPairing::Unpair() { - try { + try { adapter_.RemoveDeviceByObjectPath(device_.getObjectPath()); return true; } catch (const sdbus::Error &e) { @@ -137,5 +137,5 @@ bool BluetoothPairing::IsPaired() { return false; } } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 2c2fbac2..d1b2230d 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -30,7 +30,7 @@ namespace nearby { namespace linux { class BluetoothPairing final : public api::BluetoothPairing { -public: + public: BluetoothPairing(BluetoothAdapter &adapter, BluetoothDevice &remote_device); bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; @@ -39,7 +39,7 @@ public: bool Unpair() override; bool IsPaired() override; -private: + private: void pairing_reply_handler(const sdbus::Error *e); sdbus::PendingAsyncCall pair_async_call_; @@ -49,7 +49,7 @@ private: api::BluetoothPairingCallback pairing_cb_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index 1347c317..61bf0a02 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/substitute.h" -#include "absl/strings/string_view.h" -#include "absl/strings/str_replace.h" #include "internal/platform/implementation/linux/bluez.h" #include +#include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" namespace nearby { namespace linux { @@ -36,6 +36,6 @@ sdbus::ObjectPath adapter_object_path(absl::string_view name) { return absl::Substitute("/org/bluez/$0", name); } -} // namespace bluez -} // namespace linux -} // namespace nearby +} // namespace bluez +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index c008ae0e..3be9eb7b 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -23,12 +23,12 @@ #include -#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(); \ +#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 { @@ -44,35 +44,34 @@ static constexpr const char *DEVICE_PROP_ALIAS = "Alias"; static constexpr const char *DEVICE_PROP_PAIRED = "Paired"; static constexpr const char *DEVICE_PROP_CONNECTED = "Connected"; - std::string -device_object_path(const sdbus::ObjectPath &adapter_object_path, - absl::string_view mac_address); +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 profile_object_path(absl::string_view service_uuid); - sdbus::ObjectPath adapter_object_path(absl::string_view name); +sdbus::ObjectPath adapter_object_path(absl::string_view name); class BluezObjectManager : public sdbus::ProxyInterfaces { -public: + public: BluezObjectManager(sdbus::IConnection &system_bus) : ProxyInterfaces(system_bus, "org.bluez", "/") { registerProxy(); } ~BluezObjectManager() { unregisterProxy(); } -protected: + protected: void onInterfacesAdded( const sdbus::ObjectPath &objectPath, const std::map> &interfacesAndProperties) override {} - void - onInterfacesRemoved(const sdbus::ObjectPath &objectPath, - const std::vector &interfaces) override {} + void onInterfacesRemoved( + const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override {} }; -} // namespace bluez -} // namespace linux -} // namespace nearby +} // namespace bluez +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/condition_variable.h b/internal/platform/implementation/linux/condition_variable.h index 356b72f4..03cdd17d 100644 --- a/internal/platform/implementation/linux/condition_variable.h +++ b/internal/platform/implementation/linux/condition_variable.h @@ -23,7 +23,7 @@ namespace nearby { namespace linux { class ConditionVariable : public api::ConditionVariable { -public: + public: explicit ConditionVariable(api::Mutex *mutex) : mutex_(static_cast(mutex)->GetRegularMutex()) {} ~ConditionVariable() = default; @@ -40,11 +40,11 @@ public: void Notify() override { cond_var_.SignalAll(); } -private: + private: absl::Mutex *mutex_; absl::CondVar cond_var_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby -#endif // PLATFORM_IMPL_LINUX_CONDITION_VARIABLE_H_ +#endif // PLATFORM_IMPL_LINUX_CONDITION_VARIABLE_H_ diff --git a/internal/platform/implementation/linux/condition_variable_test.cc b/internal/platform/implementation/linux/condition_variable_test.cc index a45aae8e..b25b47e4 100644 --- a/internal/platform/implementation/linux/condition_variable_test.cc +++ b/internal/platform/implementation/linux/condition_variable_test.cc @@ -14,7 +14,7 @@ #include "internal/platform/implementation/linux/condition_variable.h" -#include // NOLINT +#include // NOLINT #include "absl/time/clock.h" #include "internal/platform/exception.h" @@ -28,12 +28,10 @@ class ConditionVariableTests : public testing::Test { public: ConditionVariableTest() {} - std::future WaitForEvent(bool timedWait, // NOLINT + std::future WaitForEvent(bool timedWait, // NOLINT const absl::Duration* timeout) { return std::async( - std::launch::async, - [this, timedWait, timeout]() mutable -> bool { - + 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) { diff --git a/internal/platform/implementation/linux/count_down_latch_test.cc b/internal/platform/implementation/linux/count_down_latch_test.cc index 6f4caccd..08147a1f 100644 --- a/internal/platform/implementation/linux/count_down_latch_test.cc +++ b/internal/platform/implementation/linux/count_down_latch_test.cc @@ -31,7 +31,7 @@ class CountDownLatchTests : public testing::Test { class CountDownLatchTest { public: - static unsigned int ThreadProcCountDown(void *lpParam) { + static unsigned int ThreadProcCountDown(void* lpParam) { TestData* testData = static_cast(lpParam); sleep(1); @@ -42,7 +42,7 @@ class CountDownLatchTests : public testing::Test { return 0; } - static unsigned int ThreadProcAwait(void *lpParam) { + static unsigned int ThreadProcAwait(void* lpParam) { TestData* testData = static_cast(lpParam); sleep(1); @@ -125,7 +125,7 @@ TEST_F(CountDownLatchTests, CountDownLatchAwaitNoTimeoutSucceeds) { threads.emplace_back(CountDownLatchTest::ThreadProcAwait, &testData); } - for (auto &thread : threads) { + for (auto& thread : threads) { thread.join(); } // Act @@ -139,8 +139,8 @@ TEST_F(CountDownLatchTests, CountDownLatchAwaitNoTimeoutSucceeds) { } void test(std::string str) { - std::cout << str << std::endl; - return; + std::cout << str << std::endl; + return; } TEST_F(CountDownLatchTests, CountDownLatchCountDownBeforeAwaitSucceeds) { @@ -158,4 +158,3 @@ TEST_F(CountDownLatchTests, CountDownLatchCountDownBeforeAwaitSucceeds) { // Assert EXPECT_EQ(count, 1); } - diff --git a/internal/platform/implementation/linux/credential_storage.h b/internal/platform/implementation/linux/credential_storage.h index 802f0e04..0ef5cd32 100644 --- a/internal/platform/implementation/linux/credential_storage.h +++ b/internal/platform/implementation/linux/credential_storage.h @@ -50,15 +50,15 @@ class CredentialStorage : public api::CredentialStorage { 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; + void GetPublicCredentials( + const CredentialSelector &credential_selector, + PublicCredentialType public_credential_type, + GetPublicCredentialsResultCallback callback) override; -private: + private: std::unique_ptr proxy; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index d134b5c7..755d25e4 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include +#include #include -#include "internal/platform/implementation/linux/dbus.h" #include "absl/base/call_once.h" +#include "internal/platform/implementation/linux/dbus.h" namespace nearby { namespace linux { @@ -29,8 +29,7 @@ static std::unique_ptr global_default_bus_connection = static absl::once_flag bus_connection_init_; static void initBusConnections() { - global_system_bus_connection = - sdbus::createSystemBusConnection(); + global_system_bus_connection = sdbus::createSystemBusConnection(); global_system_bus_connection->enterEventLoopAsync(); global_default_bus_connection = sdbus::createDefaultBusConnection("com.google.nearby"); @@ -47,5 +46,5 @@ sdbus::IConnection &getDefaultBusConnection() { assert(global_default_bus_connection != nullptr); return *global_default_bus_connection; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h index 73bbffbd..7df2770c 100644 --- a/internal/platform/implementation/linux/dbus.h +++ b/internal/platform/implementation/linux/dbus.h @@ -15,37 +15,37 @@ #ifndef PLATFORM_IMPL_LINUX_DBUS_H_ #define PLATFORM_IMPL_LINUX_DBUS_H_ -#include "internal/platform/logging.h" #include +#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(); \ +#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(); \ +#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(); \ +#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 sdbus::IConnection &getSystemBusConnection(); extern sdbus::IConnection &getDefaultBusConnection(); -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 17287dbd..0d431426 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include #include #include #include -#include #include -#include #include #include @@ -166,7 +166,7 @@ bool DeviceInfo::PreventSleep() { inhibit_fd_ = login_manager_->Inhibit("sleep", "Google Nearby", "Google Nearby", "block"); return true; - } catch (const sdbus::Error& e) { + } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(login_manager_, "Inhibit", e); return false; } @@ -183,5 +183,5 @@ bool DeviceInfo::AllowSleep() { return true; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 281884fd..67b54b30 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -83,7 +83,7 @@ class Hostnamed "/org/freedesktop/hostname1") { registerProxy(); } - ~Hostnamed() { unregisterProxy(); } + ~Hostnamed() { unregisterProxy(); } }; class LoginManager final @@ -94,7 +94,8 @@ class LoginManager final LoginManager &operator=(const LoginManager &) = delete; LoginManager &operator=(LoginManager &&) = delete; explicit LoginManager(sdbus::IConnection &system_bus) - : ProxyInterfaces(system_bus, "org.freedesktop.login1", "/org/freedesktop/login1") { + : ProxyInterfaces(system_bus, "org.freedesktop.login1", + "/org/freedesktop/login1") { registerProxy(); } ~LoginManager() { unregisterProxy(); } diff --git a/internal/platform/implementation/linux/device_info_test.cc b/internal/platform/implementation/linux/device_info_test.cc index 9168a7b4..ad8713d9 100644 --- a/internal/platform/implementation/linux/device_info_test.cc +++ b/internal/platform/implementation/linux/device_info_test.cc @@ -17,8 +17,8 @@ #include #include -#include "gtest/gtest.h" #include "absl/synchronization/notification.h" +#include "gtest/gtest.h" #include "internal/platform/implementation/device_info.h" namespace nearby { diff --git a/internal/platform/implementation/linux/executor.cc b/internal/platform/implementation/linux/executor.cc index c222d1b2..c4b22d37 100644 --- a/internal/platform/implementation/linux/executor.cc +++ b/internal/platform/implementation/linux/executor.cc @@ -48,5 +48,5 @@ void Executor::Shutdown() { thread_pool_ = nullptr; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/executor_test.cc b/internal/platform/implementation/linux/executor_test.cc index 858c7fc2..8cfadfa4 100644 --- a/internal/platform/implementation/linux/executor_test.cc +++ b/internal/platform/implementation/linux/executor_test.cc @@ -15,14 +15,14 @@ #include "internal/platform/implementation/linux/executor.h" #include -#include #include +#include -#include "gtest/gtest.h" #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 { diff --git a/internal/platform/implementation/linux/file.cc b/internal/platform/implementation/linux/file.cc index acb5fd0c..0c3b9d2b 100644 --- a/internal/platform/implementation/linux/file.cc +++ b/internal/platform/implementation/linux/file.cc @@ -17,11 +17,11 @@ #include #include #include +#include #include #include #include #include -#include #include "absl/memory/memory.h" #include "absl/strings/string_view.h" @@ -40,7 +40,8 @@ std::unique_ptr IOFile::CreateInputFile( 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); + 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); @@ -54,7 +55,8 @@ 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> converter; - file_.open(std::filesystem::path(converter.from_bytes(path_)), std::ios::binary | std::ios::out); + file_.open(std::filesystem::path(converter.from_bytes(path_)), + std::ios::binary | std::ios::out); } ExceptionOr IOFile::Read(std::int64_t size) { diff --git a/internal/platform/implementation/linux/file_path.cc b/internal/platform/implementation/linux/file_path.cc index 9e31b880..57a49860 100644 --- a/internal/platform/implementation/linux/file_path.cc +++ b/internal/platform/implementation/linux/file_path.cc @@ -23,8 +23,8 @@ #include "absl/strings/str_cat.h" #include "internal/platform/implementation/linux/dbus.h" -#include "internal/platform/implementation/linux/utils.h" #include "internal/platform/implementation/linux/device_info.h" +#include "internal/platform/implementation/linux/utils.h" #include "internal/platform/logging.h" namespace nearby { @@ -63,9 +63,8 @@ std::wstring FilePath::GetDownloadPathInternal(std::wstring parent_folder, // 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(); + } else { + base_path = download_path.value(); } // If parent_folder starts with a \\ or /, then strip it @@ -152,7 +151,8 @@ std::wstring FilePath::CreateOutputFileWithRename(std::wstring path) { file_name2); file.clear(); - file.open(wstring_to_string(target), std::fstream::binary | std::fstream::in); + file.open(wstring_to_string(target), + std::fstream::binary | std::fstream::in); } if (count > 0) { @@ -186,13 +186,12 @@ void FilePath::SanitizePath(std::wstring& path) { char kIllegalFileCharacters[] = {'/'}; void FilePath::ReplaceInvalidCharacters(std::wstring& path) { - - for (auto &character : 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); + << " replaced \'" << std::string(1, character) + << "\' with \'" << std::string(1, kReplacementChar); character = kReplacementChar; } for (auto illegal_character : kIllegalFileCharacters) { diff --git a/internal/platform/implementation/linux/file_path_test.cc b/internal/platform/implementation/linux/file_path_test.cc index a9c7e878..e7fe44e0 100644 --- a/internal/platform/implementation/linux/file_path_test.cc +++ b/internal/platform/implementation/linux/file_path_test.cc @@ -20,9 +20,9 @@ #include #include -#include "gtest/gtest.h" #include #include +#include "gtest/gtest.h" namespace nearby { namespace linux { @@ -54,7 +54,9 @@ 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"))); + default_download_path_ = + string_to_wstring(DeviceInfo().GetDownloadPath().value_or( + std::string(getenv("HOME")).append("/Downloads"))); } std::wstring default_download_path_; }; @@ -563,7 +565,8 @@ FileWithIncrementedName) { // 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); + input_file.open(wstring_to_string(output_file_path), + std::ifstream::binary | std::ifstream::in); ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); } @@ -615,7 +618,8 @@ ReturnsNextIncrementedFileName) { 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); + input_file.open(wstring_to_string(output_file2_path), + std::ifstream::binary | std::ifstream::in); ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); } @@ -649,7 +653,8 @@ MultipleDotsReturnsIncrementBeforeFirstDot) { 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); + input_file.open(wstring_to_string(output_file1_path), + std::ifstream::binary | std::ifstream::in); ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); } @@ -683,7 +688,8 @@ DotsReturnsWithIncrementAtEnd) { 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); + input_file.open(wstring_to_string(output_file1_path), + std::ifstream::binary | std::ifstream::in); ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit); } @@ -751,19 +757,22 @@ AHoleBetweenRenamedFiles) { // 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); + 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); + 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); + 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 diff --git a/internal/platform/implementation/linux/http_loader.cc b/internal/platform/implementation/linux/http_loader.cc index 8cc4abcb..2d6a7262 100644 --- a/internal/platform/implementation/linux/http_loader.cc +++ b/internal/platform/implementation/linux/http_loader.cc @@ -35,16 +35,14 @@ using ::nearby::api::WebResponse; } // namespace -HttpLoader::HttpLoader(const nearby::api::WebRequest &request) : - request_(request), - header_data_(open_memstream(&header_strings_, &header_sizeloc_)), - our_header_data_(nullptr), - response_data_(open_memstream(&response_strings_, &response_sizeloc_)), - curl_(curl_easy_init()) {} +HttpLoader::HttpLoader(const nearby::api::WebRequest &request) + : request_(request), + header_data_(open_memstream(&header_strings_, &header_sizeloc_)), + our_header_data_(nullptr), + response_data_(open_memstream(&response_strings_, &response_sizeloc_)), + curl_(curl_easy_init()) {} -HttpLoader::~HttpLoader() { - DisconnectWebServer(); -} +HttpLoader::~HttpLoader() { DisconnectWebServer(); } absl::StatusOr HttpLoader::GetResponse() { absl::Status status; @@ -90,8 +88,7 @@ absl::StatusOr HttpLoader::QueryStatusCode(CURL *file_handle) { return status_code; } -absl::StatusOr HttpLoader::QueryStatusText( - CURL *request_handle) { +absl::StatusOr HttpLoader::QueryStatusText(CURL *request_handle) { absl::StatusOr status; std::string status_text; @@ -102,129 +99,129 @@ absl::StatusOr HttpLoader::QueryStatusText( switch (status.value()) { case 100: - return "Continue"; + return "Continue"; case 101: - return "Switching Protocols"; + return "Switching Protocols"; case 102: - return "Processing"; + return "Processing"; case 103: - return "Early Hints"; + return "Early Hints"; case 200: - return "OK"; + return "OK"; case 201: - return "Created"; + return "Created"; case 202: - return "Accepted"; + return "Accepted"; case 203: - return "Non-Authoritative Information"; + return "Non-Authoritative Information"; case 204: - return "No Content"; + return "No Content"; case 205: - return "Reset Content"; + return "Reset Content"; case 206: - return "Partial Content"; + return "Partial Content"; case 207: - return "Multi-Status"; + return "Multi-Status"; case 208: - return "Already Reported"; + return "Already Reported"; case 226: - return "IM Used"; + return "IM Used"; case 300: - return "Multiple Choices"; + return "Multiple Choices"; case 301: - return "Moved Permanently"; + return "Moved Permanently"; case 302: - return "Found"; + return "Found"; case 303: - return "See Other"; + return "See Other"; case 304: - return "Not Modified"; + return "Not Modified"; case 305: - return "Use Proxy"; + return "Use Proxy"; case 307: - return "Temporary Redirect"; + return "Temporary Redirect"; case 308: - return "Permanent Redirect"; + return "Permanent Redirect"; case 400: - return "Bad Request"; + return "Bad Request"; case 401: - return "Unauthorized"; + return "Unauthorized"; case 402: - return "Payment Required"; + return "Payment Required"; case 403: - return "Forbidden"; + return "Forbidden"; case 404: - return "Not Found"; + return "Not Found"; case 405: - return "Method Not Allowed"; + return "Method Not Allowed"; case 406: - return "Not Acceptable"; + return "Not Acceptable"; case 407: - return "Proxy Authentication Required"; + return "Proxy Authentication Required"; case 408: - return "Request Timeout"; + return "Request Timeout"; case 409: - return "Conflict"; + return "Conflict"; case 410: - return "Gone"; + return "Gone"; case 411: - return "Lenth Required"; + return "Lenth Required"; case 412: - return "Precondition Failed"; + return "Precondition Failed"; case 413: - return "Payload Too Large"; + return "Payload Too Large"; case 414: - return "URI Too Long"; + return "URI Too Long"; case 415: - return "Unsupported Media Type"; + return "Unsupported Media Type"; case 416: - return "Range Not Satisfiable"; + return "Range Not Satisfiable"; case 417: - return "Expectation Failed"; + return "Expectation Failed"; case 418: - return "I'm a teapot!"; + return "I'm a teapot!"; case 421: - return "Misdirected Request"; + return "Misdirected Request"; case 422: - return "Unprocessable Content"; + return "Unprocessable Content"; case 423: - return "Locked"; + return "Locked"; case 424: - return "Failed Dependency"; + return "Failed Dependency"; case 425: - return "Too Early"; + return "Too Early"; case 426: - return "Upgrade Required"; + return "Upgrade Required"; case 428: - return "Precondition Required"; + return "Precondition Required"; case 429: - return "Too Many Requests"; + return "Too Many Requests"; case 431: - return "Request Header Fields Too Large"; + return "Request Header Fields Too Large"; case 451: - return "Unavailable For Legal Reasons"; + return "Unavailable For Legal Reasons"; case 500: - return "Internal Server Error"; + return "Internal Server Error"; case 501: - return "Not Implemented"; + return "Not Implemented"; case 502: - return "Bad Gateway"; + return "Bad Gateway"; case 503: - return "Service Unavailable"; + return "Service Unavailable"; case 504: - return "Gateway Timeout"; + return "Gateway Timeout"; case 505: - return "HTTP Version Not Supported"; + return "HTTP Version Not Supported"; case 506: - return "Variant Also Negotiates"; + return "Variant Also Negotiates"; case 507: - return "Insufficient Storage"; + return "Insufficient Storage"; case 508: - return "Loop Detected"; + return "Loop Detected"; case 509: - return "Network Authentication Required"; + return "Network Authentication Required"; default: - return absl::InternalError("Invalid status code."); + return absl::InternalError("Invalid status code."); } } @@ -234,7 +231,7 @@ HttpLoader::QueryResponseHeaders(CURL *request_handle) { long header_size; status = QueryResponseInfo(curl_, CURLINFO_HEADER_SIZE, &header_size); - + if (!status.ok()) { return status; } @@ -261,16 +258,16 @@ HttpLoader::QueryResponseHeaders(CURL *request_handle) { return headers; } -const nearby::api::WebRequest& HttpLoader::GetRequest() { - return request_; -} +const nearby::api::WebRequest &HttpLoader::GetRequest() { return request_; } -size_t HttpLoader::CurlReadCallback(char *buffer, size_t size, size_t nitems, void *userdata) { +size_t HttpLoader::CurlReadCallback(char *buffer, size_t size, size_t nitems, + void *userdata) { size_t write_size_max = size * nitems; size_t write_amount = 0; - for (const auto &str : reinterpret_cast(userdata)->GetRequest().body) { + for (const auto &str : + reinterpret_cast(userdata)->GetRequest().body) { if (write_amount == write_size_max) { - break; + break; } *(buffer + write_amount) = str; write_amount++; @@ -279,19 +276,21 @@ size_t HttpLoader::CurlReadCallback(char *buffer, size_t size, size_t nitems, vo return write_amount; } -// This function uses the CURL getinfo function to grab info. Each info_level has a different -// type it can return. It would not be feasable to determine the type and return it. -// IT IS UP TO THE CALLER OF THE FUNCTION TO USE THE void* CORRECTLY. +// This function uses the CURL getinfo function to grab info. Each info_level +// has a different type it can return. It would not be feasable to determine the +// type and return it. IT IS UP TO THE CALLER OF THE FUNCTION TO USE THE void* +// CORRECTLY. absl::Status HttpLoader::QueryResponseInfo(CURL *request_handle, - CURLINFO info_level, - void *info) { + CURLINFO info_level, void *info) { CURLcode query_result = curl_easy_getinfo(request_handle, info_level, &info); if (query_result == CURLE_OK) { return absl::OkStatus(); } - return absl::InvalidArgumentError("Failed to query HTTP information: " + std::string(curl_easy_strerror(query_result))); + return absl::InvalidArgumentError( + "Failed to query HTTP information: " + + std::string(curl_easy_strerror(query_result))); } absl::Status HttpLoader::ParseUrl() { @@ -300,7 +299,8 @@ absl::Status HttpLoader::ParseUrl() { char *host_name; char *path; - CURLUcode ret = curl_url_set(url_components, CURLUPART_URL, request_.url.c_str(), CURLU_NON_SUPPORT_SCHEME); + CURLUcode ret = curl_url_set(url_components, CURLUPART_URL, + request_.url.c_str(), CURLU_NON_SUPPORT_SCHEME); if (ret) { curl_url_cleanup(url_components); curl_free(schema); @@ -310,10 +310,13 @@ absl::Status HttpLoader::ParseUrl() { schema = nullptr; host_name = nullptr; path = nullptr; - return absl::InvalidArgumentError("Invalid URL format: " + std::string(curl_url_strerror(ret))); + return absl::InvalidArgumentError("Invalid URL format: " + + std::string(curl_url_strerror(ret))); } - ret = curl_url_get(url_components, CURLUPART_SCHEME, &schema, CURLU_URLDECODE | CURLU_URLENCODE | CURLU_DEFAULT_PORT | CURLU_DEFAULT_SCHEME); + ret = curl_url_get(url_components, CURLUPART_SCHEME, &schema, + CURLU_URLDECODE | CURLU_URLENCODE | CURLU_DEFAULT_PORT | + CURLU_DEFAULT_SCHEME); if (ret) { curl_url_cleanup(url_components); curl_free(schema); @@ -323,10 +326,13 @@ absl::Status HttpLoader::ParseUrl() { schema = nullptr; host_name = nullptr; path = nullptr; - return absl::InvalidArgumentError("Could not parse URL schema: " + std::string(curl_url_strerror(ret))); + return absl::InvalidArgumentError("Could not parse URL schema: " + + std::string(curl_url_strerror(ret))); } - ret = curl_url_get(url_components, CURLUPART_PATH, &path, CURLU_URLDECODE | CURLU_URLENCODE | CURLU_DEFAULT_PORT | CURLU_DEFAULT_SCHEME); + ret = curl_url_get(url_components, CURLUPART_PATH, &path, + CURLU_URLDECODE | CURLU_URLENCODE | CURLU_DEFAULT_PORT | + CURLU_DEFAULT_SCHEME); if (ret) { curl_url_cleanup(url_components); curl_free(schema); @@ -336,7 +342,8 @@ absl::Status HttpLoader::ParseUrl() { schema = nullptr; host_name = nullptr; path = nullptr; - return absl::InvalidArgumentError("Could not parse URL path: " + std::string(curl_url_strerror(ret))); + return absl::InvalidArgumentError("Could not parse URL path: " + + std::string(curl_url_strerror(ret))); } if (!(schema_ == "http" || schema_ == "https")) { @@ -378,53 +385,71 @@ absl::Status HttpLoader::ConnectWebServer() { response_data_ = open_memstream(&response_strings_, &response_sizeloc_); } - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L)); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_URL, request_.url.c_str())); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L)); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_URL, request_.url.c_str())); option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_PORT, port_)); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_AUTOREFERER, 1L)); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L)); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_USERAGENT, "Mozilla/5.0")); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_HEADERDATA, header_data_)); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_WRITEDATA, response_data_)); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_AUTOREFERER, 1L)); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L)); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_USERAGENT, "Mozilla/5.0")); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_HEADERDATA, header_data_)); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_WRITEDATA, response_data_)); // Prepare headers std::string request_headers; - for (const auto& header : request_.headers) { - struct curl_slist *list = curl_slist_append(our_header_data_, std::string(header.first + ": " + header.second).c_str()); + for (const auto &header : request_.headers) { + struct curl_slist *list = curl_slist_append( + our_header_data_, + std::string(header.first + ": " + header.second).c_str()); if (list) { our_header_data_ = list; } } if (!request_headers.empty()) { - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, our_header_data_)); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, our_header_data_)); } if (request_.method == "GET") { option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L)); - } - else if (request_.method == "POST") { - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, static_cast(request_.body.size()))); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, request_.body.c_str())); - } - else if (request_.method == "PUT") { + } else if (request_.method == "POST") { + option_return_codes.push_back(curl_easy_setopt( + curl_, CURLOPT_POSTFIELDSIZE, static_cast(request_.body.size()))); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, request_.body.c_str())); + } else if (request_.method == "PUT") { option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_UPLOAD, 1L)); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_READFUNCTION, CurlReadCallback)); - option_return_codes.push_back(curl_easy_setopt(curl_, CURLOPT_READDATA, this)); - option_return_codes.push_back(curl_easy_setopt(curl_, (request_.body.size() < std::numeric_limits::max() ? CURLOPT_INFILESIZE : CURLOPT_INFILESIZE_LARGE), request_.body.size())); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_READFUNCTION, CurlReadCallback)); + option_return_codes.push_back( + curl_easy_setopt(curl_, CURLOPT_READDATA, this)); + option_return_codes.push_back(curl_easy_setopt( + curl_, + (request_.body.size() < std::numeric_limits::max() + ? CURLOPT_INFILESIZE + : CURLOPT_INFILESIZE_LARGE), + request_.body.size())); - } - else { - NEARBY_LOGS(ERROR) << "Failed to open internet with error " - << "Invalid request method: " << request_.method << "."; - return absl::FailedPreconditionError("Failed to open internet: Invalid request method."); + } else { + NEARBY_LOGS(ERROR) << "Failed to open internet with error " + << "Invalid request method: " << request_.method << "."; + return absl::FailedPreconditionError( + "Failed to open internet: Invalid request method."); } for (const auto &ret : option_return_codes) { if (ret) { NEARBY_LOGS(ERROR) << "Failed to open internet with error " << curl_easy_strerror(ret) << "."; - return absl::FailedPreconditionError(absl::StrCat(curl_easy_strerror(ret))); + return absl::FailedPreconditionError( + absl::StrCat(curl_easy_strerror(ret))); } } @@ -432,7 +457,6 @@ absl::Status HttpLoader::ConnectWebServer() { } absl::Status HttpLoader::SendRequest() { - CURLcode ret = curl_easy_perform(curl_); if (ret != CURLE_OK) { @@ -468,18 +492,20 @@ absl::StatusOr HttpLoader::ProcessResponse() { curl_off_t download_size; - CURLcode ret = curl_easy_getinfo(curl_, CURLINFO_SIZE_DOWNLOAD_T, &download_size); + CURLcode ret = + curl_easy_getinfo(curl_, CURLINFO_SIZE_DOWNLOAD_T, &download_size); - if (ret) { - if (download_size != 0) { - // Append data to response - web_response.body.assign(response_strings_, download_size); - } else { - NEARBY_LOGS(ERROR) - << "Failed to read response from remote web server with error " - << curl_easy_strerror(ret) << "."; - return absl::FailedPreconditionError(absl::StrCat(curl_easy_strerror(ret))); - } + if (ret) { + if (download_size != 0) { + // Append data to response + web_response.body.assign(response_strings_, download_size); + } else { + NEARBY_LOGS(ERROR) + << "Failed to read response from remote web server with error " + << curl_easy_strerror(ret) << "."; + return absl::FailedPreconditionError( + absl::StrCat(curl_easy_strerror(ret))); + } } status = HTTPCodeToStatus(web_response.status_code, web_response.status_text); diff --git a/internal/platform/implementation/linux/http_loader.h b/internal/platform/implementation/linux/http_loader.h index 97ca5507..02d68f72 100644 --- a/internal/platform/implementation/linux/http_loader.h +++ b/internal/platform/implementation/linux/http_loader.h @@ -15,8 +15,8 @@ #ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_LINUX_HTTP_LOADER_H_ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_LINUX_HTTP_LOADER_H_ -#include #include +#include #include "absl/status/status.h" #include "absl/status/statusor.h" @@ -32,18 +32,19 @@ namespace linux { // WinInet APIs to get HTTP response. The platform handles HTTP/HTTPS sessions. class HttpLoader { public: - explicit HttpLoader(const nearby::api::WebRequest& request); + explicit HttpLoader(const nearby::api::WebRequest &request); ~HttpLoader(); absl::StatusOr GetResponse(); - const nearby::api::WebRequest& GetRequest(); + const nearby::api::WebRequest &GetRequest(); private: // Defines the buffer size. It is used to init a buffer for receiving HTTP // response. The unit is byte. static constexpr int kReceiveBufferSize = 8 * 1024; - static size_t CurlReadCallback(char *buffer, size_t size, size_t nitems, void *userdata); + static size_t CurlReadCallback(char *buffer, size_t size, size_t nitems, + void *userdata); absl::Status ConnectWebServer(); absl::Status SendRequest(); diff --git a/internal/platform/implementation/linux/input_file.h b/internal/platform/implementation/linux/input_file.h index 7d4df48a..955baccf 100644 --- a/internal/platform/implementation/linux/input_file.h +++ b/internal/platform/implementation/linux/input_file.h @@ -15,9 +15,9 @@ #ifndef PLATFORM_IMPL_LINUX_INPUT_FILE_H_ #define PLATFORM_IMPL_LINUX_INPUT_FILE_H_ -#include "internal/platform/implementation/input_file.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" +#include "internal/platform/implementation/input_file.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/input_file_test.cc b/internal/platform/implementation/linux/input_file_test.cc index 63268b0c..e7cbdd87 100644 --- a/internal/platform/implementation/linux/input_file_test.cc +++ b/internal/platform/implementation/linux/input_file_test.cc @@ -18,9 +18,9 @@ #include "gtest/gtest.h" #include "internal/platform/exception.h" -#include "internal/platform/payload_id.h" #include "internal/platform/implementation/linux/test_utils.h" #include "internal/platform/logging.h" +#include "internal/platform/payload_id.h" class InputFileTests : public testing::Test { protected: @@ -32,9 +32,9 @@ class InputFileTests : public testing::Test { file_.open(path, std::ios::out); if (!file_) { - NEARBY_LOG(ERROR, - "Failed to create OutputFile with payloadId: %s and error: %d", - test_utils::GetPayloadPath(payloadId).c_str(), std::strerror(errno)); + NEARBY_LOG( + ERROR, "Failed to create OutputFile with payloadId: %s and error: %d", + test_utils::GetPayloadPath(payloadId).c_str(), std::strerror(errno)); } const char* buffer = TEST_STRING; diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index aeb2b612..b8f898dd 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #define SD_JOURNAL_SUPPRESS_LOCATION true #include @@ -51,34 +51,34 @@ bool LogMessage::ShouldCreateLogMessage(Severity severity) { return severity >= global_log_control_->GetLogLevel(); } -} // namespace api +} // namespace api namespace linux { -static inline google::LogSeverity -ConvertSeverity(api::LogMessage::Severity severity) { +static inline google::LogSeverity ConvertSeverity( + api::LogMessage::Severity severity) { switch (severity) { - case api::LogMessage::Severity::kWarning: - return google::GLOG_WARNING; - case api::LogMessage::Severity::kError: - return google::GLOG_ERROR; - case api::LogMessage::Severity::kFatal: - return google::GLOG_FATAL; - case api::LogMessage::Severity::kVerbose: - case api::LogMessage::Severity::kInfo: - default: - return google::GLOG_INFO; + case api::LogMessage::Severity::kWarning: + return google::GLOG_WARNING; + case api::LogMessage::Severity::kError: + return google::GLOG_ERROR; + case api::LogMessage::Severity::kFatal: + return google::GLOG_FATAL; + case api::LogMessage::Severity::kVerbose: + case api::LogMessage::Severity::kInfo: + default: + return google::GLOG_INFO; } } static inline int ConvertSeverityToSyslog(google::LogSeverity severity) { switch (severity) { - case google::GLOG_WARNING: - return LOG_WARNING; - case google::GLOG_ERROR: - return LOG_ERR; - case google::GLOG_FATAL: - return LOG_EMERG; - case google::GLOG_INFO: - default: - return LOG_INFO; + case google::GLOG_WARNING: + return LOG_WARNING; + case google::GLOG_ERROR: + return LOG_ERR; + case google::GLOG_FATAL: + return LOG_EMERG; + case google::GLOG_INFO: + default: + return LOG_INFO; } } @@ -94,24 +94,24 @@ void LogControl::send(google::LogSeverity severity, const char *full_filename, const struct ::tm *tm_time, const char *message, size_t message_len) { switch (log_target_) { - case kJournal: - sd_journal_send("MESSAGE=%s", message, "PRIORITY=%d", - ConvertSeverityToSyslog(severity), "CODE_FILE=%s", - base_filename, "CODE_LINE=%d", line, NULL); - break; - case kSyslog: { - auto str = LogSink::ToString(severity, base_filename, line, tm_time, - message, message_len); - syslog(ConvertSeverityToSyslog(severity), "%s", str.c_str()); - break; - } - case kConsole: - default: - absl::MutexLock l(&cout_mutex); - std::cout << LogSink::ToString(severity, base_filename, line, tm_time, - message, message_len) - << "\n"; - break; + case kJournal: + sd_journal_send("MESSAGE=%s", message, "PRIORITY=%d", + ConvertSeverityToSyslog(severity), "CODE_FILE=%s", + base_filename, "CODE_LINE=%d", line, NULL); + break; + case kSyslog: { + auto str = LogSink::ToString(severity, base_filename, line, tm_time, + message, message_len); + syslog(ConvertSeverityToSyslog(severity), "%s", str.c_str()); + break; + } + case kConsole: + default: + absl::MutexLock l(&cout_mutex); + std::cout << LogSink::ToString(severity, base_filename, line, tm_time, + message, message_len) + << "\n"; + break; } } @@ -131,5 +131,5 @@ void LogMessage::Print(const char *format, ...) { std::ostream &LogMessage::Stream() { return log_streamer_.stream(); } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h index 13122565..07ef773c 100644 --- a/internal/platform/implementation/linux/log_message.h +++ b/internal/platform/implementation/linux/log_message.h @@ -28,7 +28,7 @@ namespace linux { // See documentation in // cpp/platform/api/log_message.h class LogMessage : public api::LogMessage { -public: + public: LogMessage(const char *file, int line, Severity severity); ~LogMessage() override{}; @@ -36,7 +36,7 @@ public: std::ostream &Stream() override; -private: + private: google::LogMessage log_streamer_; static api::LogMessage::Severity min_log_severity_; }; @@ -44,7 +44,7 @@ private: class LogControl : public sdbus::AdaptorInterfaces, public google::LogSink { -public: + public: LogControl(sdbus::IConnection &system_bus) : AdaptorInterfaces(system_bus, "/org/freedesktop/LogControl1"), severity_(api::LogMessage::LogMessage::Severity::kVerbose), @@ -57,20 +57,20 @@ public: LogMessage::Severity GetLogLevel() { return severity_; } -protected: + protected: std::string LogLevel() override { switch (severity_) { - case api::LogMessage::Severity::kInfo: - return "info"; - case api::LogMessage::Severity::kWarning: - return "warning"; - case api::LogMessage::Severity::kError: - return "err"; - case api::LogMessage::Severity::kFatal: - return "emerg"; - case api::LogMessage::Severity::kVerbose: - default: - return "debug"; + case api::LogMessage::Severity::kInfo: + return "info"; + case api::LogMessage::Severity::kWarning: + return "warning"; + case api::LogMessage::Severity::kError: + return "err"; + case api::LogMessage::Severity::kFatal: + return "emerg"; + case api::LogMessage::Severity::kVerbose: + default: + return "debug"; } } @@ -91,15 +91,15 @@ protected: std::string LogTarget() override { switch (log_target_) { - case kKernel: - return "kmsg"; - case kJournal: - return "journal"; - case kSyslog: - return "syslog"; - case kConsole: - default: - return "console"; + case kKernel: + return "kmsg"; + case kJournal: + return "journal"; + case kSyslog: + return "syslog"; + case kConsole: + default: + return "console"; } } @@ -120,11 +120,11 @@ protected: const char *base_filename, int line, const struct ::tm *tm_time, const char *message, size_t message_len) override; -private: + private: std::atomic severity_; std::atomic log_target_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby -#endif // PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ +#endif // PLATFORM_IMPL_LINUX_LOG_MESSAGE_H_ diff --git a/internal/platform/implementation/linux/mutex.h b/internal/platform/implementation/linux/mutex.h index 52619b6d..86f10d36 100644 --- a/internal/platform/implementation/linux/mutex.h +++ b/internal/platform/implementation/linux/mutex.h @@ -24,7 +24,7 @@ namespace nearby { namespace linux { class ABSL_LOCKABLE Mutex : public api::Mutex { -public: + public: explicit Mutex(Mode mode) : mode_(mode) { if (mode == Mode::kRecursive) mutex_.emplace(); @@ -57,14 +57,12 @@ public: } } - absl::Mutex *GetRegularMutex() { - return std::get_if(&mutex_); - } + absl::Mutex *GetRegularMutex() { return std::get_if(&mutex_); } -private: + private: std::variant mutex_; Mode mode_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/output_file.h b/internal/platform/implementation/linux/output_file.h index 53bcbddb..54ebe127 100644 --- a/internal/platform/implementation/linux/output_file.h +++ b/internal/platform/implementation/linux/output_file.h @@ -15,9 +15,9 @@ #ifndef PLATFORM_IMPL_LINUX_OUTPUT_FILE_H_ #define PLATFORM_IMPL_LINUX_OUTPUT_FILE_H_ -#include "internal/platform/implementation/output_file.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" +#include "internal/platform/implementation/output_file.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/output_file_test.cc b/internal/platform/implementation/linux/output_file_test.cc index bf490d27..95a87329 100644 --- a/internal/platform/implementation/linux/output_file_test.cc +++ b/internal/platform/implementation/linux/output_file_test.cc @@ -13,12 +13,11 @@ // limitations under the License. #include "internal/platform/implementation/linux/output_file.h" - #include "gtest/gtest.h" -#include "internal/platform/implementation/platform.h" #include "internal/platform/exception.h" -#include "internal/platform/payload_id.h" +#include "internal/platform/implementation/platform.h" #include "internal/platform/implementation/windows/test_utils.h" +#include "internal/platform/payload_id.h" class OutputFileTests : public testing::Test { protected: @@ -33,7 +32,8 @@ class OutputFileTests : public testing::Test { // You can define per-test tear-down logic as usual. void TearDown() override { nearby::PayloadId payloadId(TEST_PAYLOAD_ID); - if (std::filesystem::exists(test_utils::GetPayloadPath(payloadId).c_str())) { + if (std::filesystem::exists( + test_utils::GetPayloadPath(payloadId).c_str())) { std::filesystem::remove(test_utils::GetPayloadPath(payloadId).c_str()); } } diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 2d97faa7..9e22395b 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -34,9 +34,9 @@ #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_classic_medium.h" #include "internal/platform/implementation/linux/bluez.h" -#include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h" #include "internal/platform/implementation/linux/condition_variable.h" #include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h" #include "internal/platform/implementation/linux/mutex.h" #include "internal/platform/implementation/linux/preferences_manager.h" #include "internal/platform/implementation/linux/submittable_executor.h" @@ -57,41 +57,41 @@ namespace nearby { namespace api { -std::string -ImplementationPlatform::GetCustomSavePath(const std::string &parent_folder, - const std::string &file_name) { +std::string ImplementationPlatform::GetCustomSavePath( + const std::string &parent_folder, const std::string &file_name) { auto fs = std::filesystem::path(parent_folder); return fs / file_name; } -std::string -ImplementationPlatform::GetDownloadPath(const std::string &parent_folder, - const std::string &file_name) { +std::string ImplementationPlatform::GetDownloadPath( + const std::string &parent_folder, const std::string &file_name) { auto downloads = std::filesystem::path(getenv("XDG_DOWNLOAD_DIR")); return downloads / std::filesystem::path(parent_folder).filename() / std::filesystem::path(file_name).filename(); } -std::string -ImplementationPlatform::GetDownloadPath(const std::string &file_name) { +std::string ImplementationPlatform::GetDownloadPath( + const std::string &file_name) { auto downloads = std::filesystem::path(getenv("XDG_DOWNLOAD_DIR")); return downloads / std::filesystem::path(file_name).filename(); } -std::string -ImplementationPlatform::GetAppDataPath(const std::string &file_name) { +std::string ImplementationPlatform::GetAppDataPath( + const std::string &file_name) { auto state = std::filesystem::path(getenv("XDG_STATE_HOME")); return state / std::filesystem::path(file_name).filename(); } OSName ImplementationPlatform::GetCurrentOS() { return OSName::kWindows; } -std::unique_ptr ImplementationPlatform::CreateAtomicBoolean(bool initial_value) { +std::unique_ptr ImplementationPlatform::CreateAtomicBoolean( + bool initial_value) { return std::make_unique(initial_value); } -std::unique_ptr ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) { +std::unique_ptr ImplementationPlatform::CreateAtomicUint32( + std::uint32_t value) { return std::make_unique(value); } @@ -102,8 +102,8 @@ ImplementationPlatform::CreateCountDownLatch(std::int32_t count) { #pragma push_macro("CreateMutex") #undef CreateMutex -std::unique_ptr -ImplementationPlatform::CreateMutex(Mutex::Mode mode) { +std::unique_ptr ImplementationPlatform::CreateMutex( + Mutex::Mode mode) { return std::make_unique(mode); } #pragma pop_macro("CreateMutex") @@ -113,26 +113,25 @@ ImplementationPlatform::CreateConditionVariable(api::Mutex *mutex) { return std::make_unique(mutex); } -std::unique_ptr -ImplementationPlatform::CreateInputFile(PayloadId id, std::int64_t total_size) { +std::unique_ptr ImplementationPlatform::CreateInputFile( + PayloadId id, std::int64_t total_size) { auto path = GetDownloadPath(std::to_string(id)); return nearby::shared::IOFile::CreateInputFile(path, total_size); } -std::unique_ptr -ImplementationPlatform::CreateInputFile(const std::string &file_path, - size_t size) { +std::unique_ptr ImplementationPlatform::CreateInputFile( + const std::string &file_path, size_t size) { return nearby::shared::IOFile::CreateInputFile(file_path, size); } -std::unique_ptr -ImplementationPlatform::CreateOutputFile(PayloadId payload_id) { +std::unique_ptr ImplementationPlatform::CreateOutputFile( + PayloadId payload_id) { return nearby::shared::IOFile::CreateOutputFile( GetDownloadPath("", std::to_string(payload_id))); } -std::unique_ptr -ImplementationPlatform::CreateOutputFile(const std::string &file_path) { +std::unique_ptr ImplementationPlatform::CreateOutputFile( + const std::string &file_path) { std::filesystem::path path(file_path); try { std::filesystem::create_directories(path.parent_path()); @@ -144,9 +143,8 @@ ImplementationPlatform::CreateOutputFile(const std::string &file_path) { return nearby::shared::IOFile::CreateOutputFile(path.string()); } -std::unique_ptr -ImplementationPlatform::CreateLogMessage(const char *file, int line, - LogMessage::Severity severity) { +std::unique_ptr ImplementationPlatform::CreateLogMessage( + const char *file, int line, LogMessage::Severity severity) { return std::make_unique(file, line, severity); } @@ -197,8 +195,8 @@ ImplementationPlatform::CreateBluetoothClassicMedium( linux::getSystemBusConnection(), path); } -std::unique_ptr -ImplementationPlatform::CreateBleMedium(BluetoothAdapter &) { +std::unique_ptr ImplementationPlatform::CreateBleMedium( + BluetoothAdapter &) { return std::make_unique(); } @@ -207,8 +205,8 @@ ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { return std::make_unique(); } -static std::unique_ptr -createWifiMedium(std::shared_ptr nm) { +static std::unique_ptr createWifiMedium( + std::shared_ptr nm) { std::vector device_paths; try { @@ -299,8 +297,8 @@ std::unique_ptr ImplementationPlatform::CreateDeviceInfo() { return std::make_unique(linux::getSystemBusConnection()); } -absl::StatusOr -ImplementationPlatform::SendRequest(const WebRequest &request) { +absl::StatusOr ImplementationPlatform::SendRequest( + const WebRequest &request) { if (request.body.size() >= (8 * 1024 * 1024)) { return absl::Status(absl::StatusCode::kResourceExhausted, "request body too large"); @@ -375,5 +373,5 @@ ImplementationPlatform::CreatePreferencesManager(absl::string_view path) { } #endif -} // namespace api -} // namespace nearby +} // namespace api +} // namespace nearby diff --git a/internal/platform/implementation/linux/preferences_manager.cc b/internal/platform/implementation/linux/preferences_manager.cc index 9d174c09..f0a8d8ee 100644 --- a/internal/platform/implementation/linux/preferences_manager.cc +++ b/internal/platform/implementation/linux/preferences_manager.cc @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/preferences_manager.h" - #include // NOLINT(build/c++17) #include #include @@ -22,10 +20,11 @@ #include #include "absl/strings/string_view.h" -#include "nlohmann/json.hpp" -#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/linux/preferences_manager.h" #include "internal/platform/implementation/linux/preferences_repository.h" #include "internal/platform/logging.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/preferences_manager.h b/internal/platform/implementation/linux/preferences_manager.h index 9aaa3006..860fdb04 100644 --- a/internal/platform/implementation/linux/preferences_manager.h +++ b/internal/platform/implementation/linux/preferences_manager.h @@ -26,10 +26,10 @@ #include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "absl/types/span.h" +#include "internal/platform/implementation/linux/preferences_repository.h" +#include "internal/platform/implementation/preferences_manager.h" #include "nlohmann/json.hpp" #include "nlohmann/json_fwd.hpp" -#include "internal/platform/implementation/preferences_manager.h" -#include "internal/platform/implementation/linux/preferences_repository.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/preferences_manager_test.cc b/internal/platform/implementation/linux/preferences_manager_test.cc index 064e4acf..d1aa5393 100644 --- a/internal/platform/implementation/linux/preferences_manager_test.cc +++ b/internal/platform/implementation/linux/preferences_manager_test.cc @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/preferences_manager.h" - #include #include @@ -24,14 +22,15 @@ #include #include -#include "gtest/gtest.h" #include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" #include "absl/types/span.h" +#include "gtest/gtest.h" +#include "internal/platform/implementation/linux/preferences_manager.h" +#include "internal/platform/logging.h" #include "nlohmann/json.hpp" #include "nlohmann/json_fwd.hpp" -#include "internal/platform/logging.h" namespace nearby { namespace linux { @@ -41,10 +40,8 @@ constexpr absl::Duration kTimeOut = absl::Milliseconds(200); constexpr char kPreferencesFilePath[] = "Google/Nearby/Sharing"; } // namespace - TEST(PreferencesManager, CorruptedConfigFile) { - std::filesystem::path settingsPath = - std::filesystem::temp_directory_path(); + std::filesystem::path settingsPath = std::filesystem::temp_directory_path(); std::ofstream output_stream{settingsPath / "preferences.json"}; output_stream << "CORRUPTED" << std::endl; @@ -54,8 +51,7 @@ TEST(PreferencesManager, CorruptedConfigFile) { } TEST(PreferencesManager, ValidConfigFile) { - std::filesystem::path settingsPath = - std::filesystem::temp_directory_path(); + std::filesystem::path settingsPath = std::filesystem::temp_directory_path(); std::ofstream output_stream{settingsPath / "preferences.json"}; output_stream << "{\"data\":8, \"name\": \"Valid\"}" << std::endl; output_stream.close(); diff --git a/internal/platform/implementation/linux/preferences_repository.cc b/internal/platform/implementation/linux/preferences_repository.cc index c6e3d2f3..5732414c 100644 --- a/internal/platform/implementation/linux/preferences_repository.cc +++ b/internal/platform/implementation/linux/preferences_repository.cc @@ -11,16 +11,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/preferences_repository.h" - #include #include // NOLINT(build/c++17) #include #include +#include "internal/platform/implementation/linux/preferences_repository.h" +#include "internal/platform/logging.h" #include "nlohmann/json.hpp" #include "nlohmann/json_fwd.hpp" -#include "internal/platform/logging.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/preferences_repository_test.cc b/internal/platform/implementation/linux/preferences_repository_test.cc index 3e380bb9..143d6a58 100644 --- a/internal/platform/implementation/linux/preferences_repository_test.cc +++ b/internal/platform/implementation/linux/preferences_repository_test.cc @@ -12,17 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/preferences_repository.h" - #include // NOLINT(build/c++17) #include #include #include "gtest/gtest.h" -#include "nlohmann/json.hpp" -#include "nlohmann/json_fwd.hpp" #include "internal/platform/implementation/device_info.h" #include "internal/platform/implementation/platform.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/linux/preferences_repository.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/scheduled_executor.cc b/internal/platform/implementation/linux/scheduled_executor.cc index e8a0be76..57d153a3 100644 --- a/internal/platform/implementation/linux/scheduled_executor.cc +++ b/internal/platform/implementation/linux/scheduled_executor.cc @@ -32,8 +32,8 @@ ScheduledExecutor::ScheduledExecutor() // We want Cancelable to live until both caller and executor are done with it. // Exclusive ownership model does not work for this case; // using std:shared_ptr<> instead of std::unique_ptr<>. -std::shared_ptr -ScheduledExecutor::Schedule(Runnable &&runnable, absl::Duration duration) { +std::shared_ptr ScheduledExecutor::Schedule( + Runnable &&runnable, absl::Duration duration) { if (shut_down_) { NEARBY_LOGS(ERROR) << __func__ << ": Attempt to Schedule on a shut down executor."; @@ -80,5 +80,5 @@ void ScheduledExecutor::Shutdown() { NEARBY_LOGS(ERROR) << __func__ << ": Attempt to Shutdown on a shut down executor."; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/scheduled_executor.h b/internal/platform/implementation/linux/scheduled_executor.h index 4dffef8b..90257c8c 100644 --- a/internal/platform/implementation/linux/scheduled_executor.h +++ b/internal/platform/implementation/linux/scheduled_executor.h @@ -22,8 +22,8 @@ #include "absl/synchronization/notification.h" #include "absl/time/time.h" #include "internal/platform/implementation/cancelable.h" -#include "internal/platform/implementation/scheduled_executor.h" #include "internal/platform/implementation/linux/executor.h" +#include "internal/platform/implementation/scheduled_executor.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/scheduled_executor_test.cc b/internal/platform/implementation/linux/scheduled_executor_test.cc index 2c9e804f..1b0a5722 100644 --- a/internal/platform/implementation/linux/scheduled_executor_test.cc +++ b/internal/platform/implementation/linux/scheduled_executor_test.cc @@ -12,16 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/scheduled_executor.h" - #include #include -#include "gtest/gtest.h" #include "absl/synchronization/notification.h" #include "absl/time/clock.h" #include "absl/time/time.h" +#include "gtest/gtest.h" #include "internal/platform/implementation/linux/test_data.h" +#include "internal/platform/implementation/linux/scheduled_executor.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/stream.h b/internal/platform/implementation/linux/stream.h index ecf9f6ea..a205faee 100644 --- a/internal/platform/implementation/linux/stream.h +++ b/internal/platform/implementation/linux/stream.h @@ -25,30 +25,30 @@ namespace nearby { namespace linux { class InputStream : public nearby::InputStream { -public: + public: InputStream(sdbus::UnixFd &fd) : fd_(fd){}; ExceptionOr Read(std::int64_t size) override; Exception Close() override; -private: + private: std::optional fd_; }; class OutputStream : public nearby::OutputStream { -public: + public: OutputStream(sdbus::UnixFd &fd) : fd_(fd){}; Exception Write(const ByteArray &data) override; Exception Flush() override; Exception Close() override; -private: + private: std::optional fd_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/submittable_executor.h b/internal/platform/implementation/linux/submittable_executor.h index 133c144e..85d1a3ba 100644 --- a/internal/platform/implementation/linux/submittable_executor.h +++ b/internal/platform/implementation/linux/submittable_executor.h @@ -15,8 +15,8 @@ #ifndef PLATFORM_IMPL_LINUX_SUBMITTABLE_EXECUTOR_H_ #define PLATFORM_IMPL_LINUX_SUBMITTABLE_EXECUTOR_H_ -#include "internal/platform/implementation/submittable_executor.h" #include "internal/platform/implementation/linux/executor.h" +#include "internal/platform/implementation/submittable_executor.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/submittable_executor_test.cc b/internal/platform/implementation/linux/submittable_executor_test.cc index b3cf11d6..c6162607 100644 --- a/internal/platform/implementation/linux/submittable_executor_test.cc +++ b/internal/platform/implementation/linux/submittable_executor_test.cc @@ -14,13 +14,13 @@ #include "internal/platform/implementation/linux/submittable_executor.h" -#include #include +#include -#include "gtest/gtest.h" #include "absl/synchronization/blocking_counter.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 { diff --git a/internal/platform/implementation/linux/system_clock.cc b/internal/platform/implementation/linux/system_clock.cc index ea1edd85..f2cc2793 100644 --- a/internal/platform/implementation/linux/system_clock.cc +++ b/internal/platform/implementation/linux/system_clock.cc @@ -20,14 +20,14 @@ namespace nearby { // Initialize global system state. -void SystemClock::Init() { } +void SystemClock::Init() {} // Returns current absolute time. It is guaranteed to be monotonic. absl::Time SystemClock::ElapsedRealtime() { return absl::FromUnixNanos( - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count()); + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count()); } // Pauses current thread for the specified duration. diff --git a/internal/platform/implementation/linux/test_data.h b/internal/platform/implementation/linux/test_data.h index 7cdddf9b..fe0189ce 100644 --- a/internal/platform/implementation/linux/test_data.h +++ b/internal/platform/implementation/linux/test_data.h @@ -31,4 +31,3 @@ RUNNABLE_SEPARATOR_TEXT) #endif // PLATFORM_IMPL_LINUX_TEST_DATA_H_ - diff --git a/internal/platform/implementation/linux/test_utils.cc b/internal/platform/implementation/linux/test_utils.cc index 209a8904..91cc2447 100644 --- a/internal/platform/implementation/linux/test_utils.cc +++ b/internal/platform/implementation/linux/test_utils.cc @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/test_utils.h" -#include "internal/platform/implementation/linux/device_info.h" - #include -#include #include +#include #include "absl/strings/str_format.h" #include "absl/strings/str_replace.h" +#include "internal/platform/implementation/linux/device_info.h" +#include "internal/platform/implementation/linux/test_utils.h" namespace test_utils { std::wstring StringToWideString(const std::string& s) { @@ -29,7 +28,9 @@ std::wstring StringToWideString(const std::string& s) { } std::string GetPayloadPath(nearby::PayloadId payload_id) { - std::filesystem::path path = nearby::linux::DeviceInfo().GetDownloadPath().value_or(std::string(getenv("HOME")).append("Downloads")); + std::filesystem::path path = + nearby::linux::DeviceInfo().GetDownloadPath().value_or( + std::string(getenv("HOME")).append("Downloads")); return path.string(); } diff --git a/internal/platform/implementation/linux/thread_pool.cc b/internal/platform/implementation/linux/thread_pool.cc index fdcf2466..209e2122 100644 --- a/internal/platform/implementation/linux/thread_pool.cc +++ b/internal/platform/implementation/linux/thread_pool.cc @@ -117,5 +117,5 @@ Runnable ThreadPool::NextTask() { return task; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/thread_pool.h b/internal/platform/implementation/linux/thread_pool.h index 7f2b0fc1..13f35cf6 100644 --- a/internal/platform/implementation/linux/thread_pool.h +++ b/internal/platform/implementation/linux/thread_pool.h @@ -30,23 +30,23 @@ namespace nearby { namespace linux { class ThreadPool { -public: - ThreadPool(const ThreadPool &) = delete; - ThreadPool(ThreadPool &&) = delete; - ThreadPool &operator=(const ThreadPool &) = delete; - ThreadPool &operator=(ThreadPool &&) = delete; - explicit ThreadPool(size_t max_pool_size); - ~ThreadPool(); + public: + ThreadPool(const ThreadPool &) = delete; + ThreadPool(ThreadPool &&) = delete; + ThreadPool &operator=(const ThreadPool &) = delete; + ThreadPool &operator=(ThreadPool &&) = delete; + explicit ThreadPool(size_t max_pool_size); + ~ThreadPool(); - bool Start() ABSL_LOCKS_EXCLUDED(mutex_); + bool Start() ABSL_LOCKS_EXCLUDED(mutex_); - // Runs a task on thread pool. The result indicates whether the task is put - // into the thread pool. - bool Run(Runnable &&task) ABSL_LOCKS_EXCLUDED(mutex_); + // Runs a task on thread pool. The result indicates whether the task is put + // into the thread pool. + bool Run(Runnable &&task) ABSL_LOCKS_EXCLUDED(mutex_); - void ShutDown() ABSL_LOCKS_EXCLUDED(mutex_); + void ShutDown() ABSL_LOCKS_EXCLUDED(mutex_); -private: + private: Runnable NextTask() ABSL_LOCKS_EXCLUDED(mutex_); size_t max_pool_size_; @@ -56,7 +56,7 @@ private: std::vector threads_ ABSL_GUARDED_BY(mutex_); std::queue tasks_ ABSL_GUARDED_BY(mutex_); }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby -#endif // PLATFORM_IMPL_LINUX_THREAD_POOL_H_ +#endif // PLATFORM_IMPL_LINUX_THREAD_POOL_H_ diff --git a/internal/platform/implementation/linux/thread_pool_test.cc b/internal/platform/implementation/linux/thread_pool_test.cc index f2c8327a..b0ff996c 100644 --- a/internal/platform/implementation/linux/thread_pool_test.cc +++ b/internal/platform/implementation/linux/thread_pool_test.cc @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/thread_pool.h" - #include -#include "gtest/gtest.h" #include "absl/synchronization/blocking_counter.h" #include "absl/synchronization/notification.h" #include "absl/time/clock.h" #include "absl/time/time.h" +#include "gtest/gtest.h" +#include "internal/platform/implementation/linux/thread_pool.h" namespace nearby { namespace linux { diff --git a/internal/platform/implementation/linux/timer.cc b/internal/platform/implementation/linux/timer.cc index 21e54788..ab4cf74e 100644 --- a/internal/platform/implementation/linux/timer.cc +++ b/internal/platform/implementation/linux/timer.cc @@ -13,16 +13,15 @@ // limitations under the License. #include +#include +#include #include #include #include -#include -#include - -#include "internal/platform/implementation/linux/submittable_executor.h" -#include "internal/platform/implementation/linux/timer.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/submittable_executor.h" +#include "internal/platform/implementation/linux/timer.h" #include "internal/platform/logging.h" namespace nearby { @@ -31,8 +30,7 @@ namespace linux { static void timer_callback(union sigval val) { absl::AnyInvocable *callback = reinterpret_cast *>(val.sival_ptr); - if (*callback != nullptr) - (*callback)(); + if (*callback != nullptr) (*callback)(); } Timer::~Timer() { @@ -60,11 +58,11 @@ bool Timer::Create(int delay, int interval, } callback_ = std::move(callback); - + struct sigevent ev; ev.sigev_value.sival_ptr = &callback_; ev.sigev_notify_function = timer_callback; - + timer_t timerid; struct itimerspec spec; @@ -86,7 +84,7 @@ bool Timer::Create(int delay, int interval, << std::strerror(errno); if (!timer_delete(&timerid)) { NEARBY_LOGS(ERROR) << __func__ << ": error deleting POSIX timer: " - << std::strerror(errno); + << std::strerror(errno); } return false; } @@ -108,7 +106,7 @@ bool Timer::Stop() { return false; } - timerid_.reset(); + timerid_.reset(); return true; } @@ -127,10 +125,10 @@ bool Timer::FireNow() { task_executor_ = std::make_unique(); } - task_executor_->Execute([&]() {callback_();}); + task_executor_->Execute([&]() { callback_(); }); return true; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/timer.h b/internal/platform/implementation/linux/timer.h index 444dfab9..b19ecbe2 100644 --- a/internal/platform/implementation/linux/timer.h +++ b/internal/platform/implementation/linux/timer.h @@ -15,22 +15,22 @@ #ifndef PLATFORM_IMPL_LINUX_TIMER_H_ #define PLATFORM_IMPL_LINUX_TIMER_H_ +#include +#include #include #include -#include -#include #include "absl/base/thread_annotations.h" #include "absl/synchronization/mutex.h" -#include "internal/platform/implementation/timer.h" #include "internal/platform/implementation/linux/submittable_executor.h" +#include "internal/platform/implementation/timer.h" namespace nearby { namespace linux { class Timer : public api::Timer { public: - Timer() : timerid_(nullptr) {} ; + Timer() : timerid_(nullptr){}; ~Timer() override; bool Create(int delay, int interval, @@ -39,7 +39,7 @@ class Timer : public api::Timer { bool Stop() override ABSL_LOCKS_EXCLUDED(mutex_); bool FireNow() override ABSL_LOCKS_EXCLUDED(mutex_); -private: + private: absl::Mutex mutex_; std::optional timerid_ ABSL_GUARDED_BY(mutex_); absl::AnyInvocable callback_; diff --git a/internal/platform/implementation/linux/utils.cc b/internal/platform/implementation/linux/utils.cc index 0660b9b8..58c95ba5 100644 --- a/internal/platform/implementation/linux/utils.cc +++ b/internal/platform/implementation/linux/utils.cc @@ -37,10 +37,10 @@ #include "internal/platform/uuid.h" // Linux headers -#include #include #include #include +#include namespace nearby { namespace linux { @@ -69,10 +69,9 @@ uint64_t mac_address_string_to_uint64(absl::string_view mac_address) { std::string ipaddr_4bytes_to_dotdecimal_string( absl::string_view ipaddr_4bytes) { - union addrs { - in_addr_t addr; - uint8_t bits[4]; + in_addr_t addr; + uint8_t bits[4]; } address; address.bits[0] = ipaddr_4bytes[0]; @@ -99,7 +98,7 @@ std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s) { struct in_addr addr; if (inet_aton(ipv4_s.c_str(), &addr) != 0) { - return {}; + return {}; } std::string ipv4_b = std::to_string(addr.s_addr); @@ -120,75 +119,66 @@ std::string wstring_to_string(std::wstring wstr) { std::vector GetIpv4Addresses() { std::vector result; - struct ifaddrs *interface = nullptr; + struct ifaddrs* interface = nullptr; char host[NI_MAXHOST]; if (getifaddrs(&interface) != 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Failed to get interfaces. Error: " + NEARBY_LOGS(ERROR) << __func__ << ": Failed to get interfaces. Error: " << strerror(errno); freeifaddrs(interface); return {}; } int status = 0; - for (struct ifaddrs *ifa = interface; ifa != nullptr; ifa = ifa->ifa_next) { + for (struct ifaddrs* ifa = interface; ifa != nullptr; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family == AF_INET) { - status = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST); + status = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, + NI_MAXHOST, nullptr, 0, NI_NUMERICHOST); } switch (status) { - case EAI_AGAIN: - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get IP for interface: " - << ifa->ifa_name - << " : The name could not be resolved at this time. " - << "Try again later."; - break; - case EAI_BADFLAGS: - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get IP for interface: " - << ifa->ifa_name - << " : The flags argument has an invalid value."; - break; - case EAI_FAIL: - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get IP for interface: " - << ifa->ifa_name - << " : A nonrecoverable error occured."; - break; - case EAI_FAMILY: - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get IP for interface: " - << ifa->ifa_name - << " : The address family was not recognized, " - << "or the address length was invalid for the " - << "specified family."; - break; - case EAI_MEMORY: - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get IP for interface: " - << ifa->ifa_name - << " : Out of memory."; - break; - case EAI_NONAME: - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get IP for interface: " - << ifa->ifa_name - << " : The name does not resolve for the suplied arguments." - << " NI_NAMEREQD is set and the host's name cannot be located, " - << "or neither hostname nor service name were requsted."; - break; - case EAI_OVERFLOW: - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get IP for interface: " - << ifa->ifa_name - << " : The bugger pointed to by `host` or `serv` was too small."; - break; - case EAI_SYSTEM: - NEARBY_LOGS(ERROR) << __func__ - << "A system error occured. Error code: " - << errno - << ": " << strerror(errno); - break; + case EAI_AGAIN: + NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " + << ifa->ifa_name + << " : The name could not be resolved at this time. " + << "Try again later."; + break; + case EAI_BADFLAGS: + NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " + << ifa->ifa_name + << " : The flags argument has an invalid value."; + break; + case EAI_FAIL: + NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " + << ifa->ifa_name + << " : A nonrecoverable error occured."; + break; + case EAI_FAMILY: + NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " + << ifa->ifa_name + << " : The address family was not recognized, " + << "or the address length was invalid for the " + << "specified family."; + break; + case EAI_MEMORY: + NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " + << ifa->ifa_name << " : Out of memory."; + break; + case EAI_NONAME: + NEARBY_LOGS(ERROR) + << __func__ << "Failed to get IP for interface: " << ifa->ifa_name + << " : The name does not resolve for the suplied arguments." + << " NI_NAMEREQD is set and the host's name cannot be located, " + << "or neither hostname nor service name were requsted."; + break; + case EAI_OVERFLOW: + NEARBY_LOGS(ERROR) + << __func__ << "Failed to get IP for interface: " << ifa->ifa_name + << " : The bugger pointed to by `host` or `serv` was too small."; + break; + case EAI_SYSTEM: + NEARBY_LOGS(ERROR) << __func__ + << "A system error occured. Error code: " << errno + << ": " << strerror(errno); + break; } } freeifaddrs(interface); @@ -358,6 +348,6 @@ std::vector InspectableReader::ReadStringArray( return result; } */ -} +} // namespace } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index 6b550109..f772f296 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -13,9 +13,9 @@ // limitations under the License. #include -#include #include #include +#include #include "internal/platform/implementation/linux/wifi_direct.h" #include "internal/platform/implementation/linux/wifi_direct_server_socket.h" @@ -146,7 +146,7 @@ bool NetworkManagerWifiDirectMedium::DisconnectWifiDirect() { bool NetworkManagerWifiDirectMedium::ConnectedToWifi() { try { auto mode = wireless_device_->Mode(); - return mode == 2; // NM_802_11_MODE_INFRA + return mode == 2; // NM_802_11_MODE_INFRA } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e); return false; @@ -156,15 +156,14 @@ bool NetworkManagerWifiDirectMedium::ConnectedToWifi() { bool NetworkManagerWifiDirectMedium::StartWifiDirect( WifiDirectCredentials *wifi_direct_credentials) { // According to the comments in the windows implementation, the wifi direct - // medium is currently just a regular wifi hotspot. + // medium is currently just a regular wifi hotspot. auto wireless_device = std::make_unique( network_manager_, system_bus_, wireless_device_->getObjectPath()); auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, std::move(wireless_device)); HotspotCredentials hotspot_creds; - if (!hotspot.StartWifiHotspot(&hotspot_creds)) - return false; + if (!hotspot.StartWifiHotspot(&hotspot_creds)) return false; wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID()); wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword()); @@ -180,5 +179,5 @@ bool NetworkManagerWifiDirectMedium::StopWifiDirect() { return hotspot.DisconnectWifiHotspot(); } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_direct.h b/internal/platform/implementation/linux/wifi_direct.h index bbaf720c..3d376080 100644 --- a/internal/platform/implementation/linux/wifi_direct.h +++ b/internal/platform/implementation/linux/wifi_direct.h @@ -17,6 +17,7 @@ #include #include + #include #include "internal/platform/implementation/linux/wifi_medium.h" @@ -25,40 +26,41 @@ namespace nearby { namespace linux { class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium { -public: + public: NetworkManagerWifiDirectMedium( sdbus::IConnection &system_bus, std::shared_ptr network_manager, std::unique_ptr wireless_device) - : system_bus_(system_bus), network_manager_(std::move(network_manager)), + : system_bus_(system_bus), + network_manager_(std::move(network_manager)), wireless_device_(std::move(wireless_device)) {} bool IsInterfaceValid() const override { return true; } - std::unique_ptr - ConnectToService(absl::string_view ip_address, int port, - CancellationFlag *cancellation_flag) override; - std::unique_ptr - ListenForService(int port) override; - bool - ConnectWifiDirect(WifiDirectCredentials *wifi_direct_credentials) override; + std::unique_ptr ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr ListenForService( + int port) override; + bool ConnectWifiDirect( + WifiDirectCredentials *wifi_direct_credentials) override; bool DisconnectWifiDirect() override; bool StartWifiDirect(WifiDirectCredentials *wifi_direct_credentials) override; bool StopWifiDirect() override; - absl::optional> - GetDynamicPortRange() override { + absl::optional> GetDynamicPortRange() + override { return std::nullopt; } -private: + private: bool ConnectedToWifi(); sdbus::IConnection &system_bus_; std::shared_ptr network_manager_; std::unique_ptr wireless_device_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.cc b/internal/platform/implementation/linux/wifi_direct_server_socket.cc index ed351b4d..b2c9495f 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.cc @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/wifi_direct_server_socket.h" -#include "internal/platform/exception.h" -#include "internal/platform/implementation/linux/wifi_direct_socket.h" #include #include +#include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/wifi_direct_server_socket.h" +#include "internal/platform/implementation/linux/wifi_direct_socket.h" + namespace nearby { namespace linux { std::string NetworkManagerWifiDirectServerSocket::GetIPAddress() const { @@ -76,5 +77,5 @@ Exception NetworkManagerWifiDirectServerSocket::Close() { return {Exception::kSuccess}; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_direct_socket.h b/internal/platform/implementation/linux/wifi_direct_socket.h index 25472d8f..011b0617 100644 --- a/internal/platform/implementation/linux/wifi_direct_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_socket.h @@ -22,9 +22,9 @@ namespace nearby { namespace linux { class WifiDirectSocket : public api::WifiDirectSocket { -public: + public: explicit WifiDirectSocket(int socket) - : fd_(sdbus::UnixFd(socket)), output_stream_(fd_), input_stream_(fd_) {} + : fd_(sdbus::UnixFd(socket)), output_stream_(fd_), input_stream_(fd_) {} InputStream &GetInputStream() override { return input_stream_; }; OutputStream &GetOutputStream() override { return output_stream_; }; @@ -36,12 +36,12 @@ public: return Exception{Exception::kSuccess}; }; -private: + private: sdbus::UnixFd fd_; OutputStream output_stream_; InputStream input_stream_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 55716242..7e1f80aa 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -13,12 +13,12 @@ // limitations under the License. #include +#include +#include #include #include - -#include #include -#include + #include #include "internal/platform/implementation/linux/dbus.h" @@ -313,7 +313,7 @@ bool NetworkManagerWifiHotspotMedium::DisconnectWifiHotspot() { bool NetworkManagerWifiHotspotMedium::WifiHotspotActive() { try { auto mode = wireless_device_->Mode(); - return mode == 3; // NM_802_11_MODE_AP + return mode == 3; // NM_802_11_MODE_AP } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e); return false; @@ -323,12 +323,12 @@ bool NetworkManagerWifiHotspotMedium::WifiHotspotActive() { bool NetworkManagerWifiHotspotMedium::ConnectedToWifi() { try { auto mode = wireless_device_->Mode(); - return mode == 2; // NM_802_11_MODE_INFRA + return mode == 2; // NM_802_11_MODE_INFRA } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e); return false; } } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot.h b/internal/platform/implementation/linux/wifi_hotspot.h index d1061e47..f00c9b7a 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.h +++ b/internal/platform/implementation/linux/wifi_hotspot.h @@ -24,42 +24,43 @@ namespace nearby { namespace linux { class NetworkManagerWifiHotspotMedium : public api::WifiHotspotMedium { -public: - NetworkManagerWifiHotspotMedium( - sdbus::IConnection &system_bus, - std::shared_ptr network_manager, - sdbus::ObjectPath wireless_device_object_path) - : system_bus_(system_bus), - wireless_device_(std::make_unique( - network_manager, system_bus, std::move(wireless_device_object_path))), - network_manager_(std::move(network_manager)) {} - NetworkManagerWifiHotspotMedium( - sdbus::IConnection &system_bus, - std::shared_ptr network_manager, - std::unique_ptr wireless_device) - : system_bus_(system_bus), - wireless_device_(std::move(wireless_device)), - network_manager_(std::move(network_manager)) {} + public: + NetworkManagerWifiHotspotMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + sdbus::ObjectPath wireless_device_object_path) + : system_bus_(system_bus), + wireless_device_(std::make_unique( + network_manager, system_bus, + std::move(wireless_device_object_path))), + network_manager_(std::move(network_manager)) {} + NetworkManagerWifiHotspotMedium( + sdbus::IConnection &system_bus, + std::shared_ptr network_manager, + std::unique_ptr wireless_device) + : system_bus_(system_bus), + wireless_device_(std::move(wireless_device)), + network_manager_(std::move(network_manager)) {} - bool IsInterfaceValid() const override { return true; } - std::unique_ptr ConnectToService( - absl::string_view ip_address, int port, - CancellationFlag *cancellation_flag) override; - std::unique_ptr ListenForService( - int port) override; + bool IsInterfaceValid() const override { return true; } + std::unique_ptr ConnectToService( + absl::string_view ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr ListenForService( + int port) override; - bool StartWifiHotspot(HotspotCredentials *hotspot_credentials) override; - bool StopWifiHotspot() override; + bool StartWifiHotspot(HotspotCredentials *hotspot_credentials) override; + bool StopWifiHotspot() override; - bool ConnectWifiHotspot(HotspotCredentials *hotspot_credentials) override; - bool DisconnectWifiHotspot() override; + bool ConnectWifiHotspot(HotspotCredentials *hotspot_credentials) override; + bool DisconnectWifiHotspot() override; - absl::optional> GetDynamicPortRange() - override { - return absl::nullopt; + absl::optional> GetDynamicPortRange() + override { + return absl::nullopt; } -private: + private: bool WifiHotspotActive(); bool ConnectedToWifi(); @@ -67,7 +68,7 @@ private: std::unique_ptr wireless_device_; std::shared_ptr network_manager_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc index 847a20a5..a6041f98 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc @@ -26,11 +26,11 @@ std::string NetworkManagerWifiHotspotServerSocket::GetIPAddress() const { active_connection_path_); auto ip4addresses = active_conn.GetIP4Addresses(); if (ip4addresses.empty()) { - NEARBY_LOGS(ERROR) - << __func__ - << ": Could not find any IPv4 addresses for active connection " - << active_connection_path_; - return std::string(); + NEARBY_LOGS(ERROR) + << __func__ + << ": Could not find any IPv4 addresses for active connection " + << active_connection_path_; + return std::string(); } return ip4addresses[0]; } @@ -77,5 +77,5 @@ Exception NetworkManagerWifiHotspotServerSocket::Close() { return {Exception::kSuccess}; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h index 77746040..db4ff7f9 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h @@ -24,12 +24,13 @@ namespace nearby { namespace linux { class NetworkManagerWifiHotspotServerSocket : public api::WifiHotspotServerSocket { -public: + public: NetworkManagerWifiHotspotServerSocket( int socket, sdbus::IConnection &system_bus, sdbus::ObjectPath active_connection_path, std::shared_ptr network_manager) - : fd_(socket), system_bus_(system_bus), + : fd_(socket), + system_bus_(system_bus), active_connection_path_(std::move(active_connection_path)), network_manager_(std::move(network_manager)) {} @@ -38,13 +39,13 @@ public: std::unique_ptr Accept() override; Exception Close() override; -private: + private: sdbus::UnixFd fd_; sdbus::IConnection &system_bus_; sdbus::ObjectPath active_connection_path_; std::shared_ptr network_manager_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_hotspot_socket.h b/internal/platform/implementation/linux/wifi_hotspot_socket.h index 0d208cc1..e94587ff 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_socket.h @@ -21,9 +21,10 @@ namespace nearby { namespace linux { class WifiHotspotSocket : public api::WifiHotspotSocket { -public: + public: explicit WifiHotspotSocket(int connection_fd) - : fd_(sdbus::UnixFd(connection_fd)), output_stream_(fd_), + : fd_(sdbus::UnixFd(connection_fd)), + output_stream_(fd_), input_stream_(fd_) {} nearby::InputStream &GetInputStream() override { return input_stream_; }; @@ -35,12 +36,12 @@ public: return Exception{Exception::kSuccess}; }; -private: + private: sdbus::UnixFd fd_; OutputStream output_stream_; InputStream input_stream_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index c047366b..ce8b0026 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -13,17 +13,17 @@ // limitations under the License. #include +#include +#include #include #include #include #include -#include -#include -#include +#include #include #include -#include +#include #include "absl/strings/substitute.h" #include "internal/platform/implementation/linux/avahi.h" @@ -44,11 +44,11 @@ WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus) bool WifiLanMedium::IsNetworkConnected() const { auto state = network_manager_->getState(); - return state >= 50; // NM_STATE_CONNECTED_LOCAL + return state >= 50; // NM_STATE_CONNECTED_LOCAL } -std::optional> -entry_group_key(const NsdServiceInfo &nsd_service_info) { +std::optional> entry_group_key( + const NsdServiceInfo &nsd_service_info) { auto name = nsd_service_info.GetServiceName(); if (name.empty()) { NEARBY_LOGS(ERROR) << __func__ << ": service name cannot be empty"; @@ -101,8 +101,8 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { try { entry_group->AddService( - -1, // AVAHI_IF_UNSPEC - -1, // AVAHI_PROTO_UNSPED + -1, // AVAHI_IF_UNSPEC + -1, // AVAHI_PROTO_UNSPED 0, nsd_service_info.GetServiceName(), nsd_service_info.GetServiceType(), std::string(), std::string(), nsd_service_info.GetPort(), txt_records); entry_group->Commit(); @@ -139,7 +139,6 @@ bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) { bool WifiLanMedium::StartDiscovery( const std::string &service_type, api::WifiLanMedium::DiscoveredServiceCallback callback) { - { absl::ReaderMutexLock l(&service_browsers_mutex_); if (service_browsers_.count(service_type) != 0) { @@ -153,8 +152,8 @@ bool WifiLanMedium::StartDiscovery( try { sdbus::ObjectPath browser_object_path = - avahi_->ServiceBrowserPrepare(-1, // AVAHI_IF_UNSPEC - -1, // AVAHI_PROTO_UNSPED + avahi_->ServiceBrowserPrepare(-1, // AVAHI_IF_UNSPEC + -1, // AVAHI_PROTO_UNSPED service_type, std::string(), 0); NEARBY_LOGS(VERBOSE) << __func__ @@ -200,9 +199,9 @@ bool WifiLanMedium::StopDiscovery(const std::string &service_type) { return true; } -std::unique_ptr -WifiLanMedium::ConnectToService(const std::string &ip_address, int port, - CancellationFlag *cancellation_flag) { +std::unique_ptr WifiLanMedium::ConnectToService( + const std::string &ip_address, int port, + CancellationFlag *cancellation_flag) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -229,8 +228,8 @@ WifiLanMedium::ConnectToService(const std::string &ip_address, int port, return std::make_unique(std::move(fd)); } -std::unique_ptr -WifiLanMedium::ListenForService(int port) { +std::unique_ptr WifiLanMedium::ListenForService( + int port) { auto sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { NEARBY_LOGS(ERROR) << __func__ @@ -268,5 +267,5 @@ absl::optional> GetDynamicPortRange() { return absl::nullopt; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 6cee1102..60c56fae 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -26,7 +26,7 @@ namespace nearby { namespace linux { class WifiLanMedium : public api::WifiLanMedium { -public: + public: explicit WifiLanMedium(sdbus::IConnection &system_bus); bool IsNetworkConnected() const override; @@ -42,23 +42,23 @@ public: bool StopDiscovery(const std::string &service_type) override ABSL_LOCKS_EXCLUDED(service_browsers_mutex_); - std::unique_ptr - ConnectToService(const NsdServiceInfo &remote_service_info, - CancellationFlag *cancellation_flag) override { + std::unique_ptr ConnectToService( + const NsdServiceInfo &remote_service_info, + CancellationFlag *cancellation_flag) override { return ConnectToService(remote_service_info.GetIPAddress(), remote_service_info.GetPort(), cancellation_flag); }; - std::unique_ptr - ConnectToService(const std::string &ip_address, int port, - CancellationFlag *cancellation_flag) override; - std::unique_ptr - ListenForService(int port = 0) override; - absl::optional> - GetDynamicPortRange() override { + std::unique_ptr ConnectToService( + const std::string &ip_address, int port, + CancellationFlag *cancellation_flag) override; + std::unique_ptr ListenForService( + int port = 0) override; + absl::optional> GetDynamicPortRange() + override { return std::nullopt; } -private: + private: sdbus::IConnection &system_bus_; std::shared_ptr network_manager_; @@ -74,7 +74,7 @@ private: absl::flat_hash_map> service_browsers_ ABSL_GUARDED_BY(service_browsers_mutex_); }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index 4490b8f2..52f54334 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -13,13 +13,13 @@ // limitations under the License. #include -#include -#include #include -#include #include #include #include +#include +#include +#include #include @@ -60,17 +60,17 @@ std::string WifiLanServerSocket::GetIPAddress() const { address_data = ip4config.AddressData(); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "IP4Config", e); - continue; + continue; } if (address_data.size() > 0) { - return address_data[0]["address"]; + return address_data[0]["address"]; } } } NEARBY_LOGS(ERROR) - << __func__ << ": Could not find any active IP addresses for this device"; + << __func__ << ": Could not find any active IP addresses for this device"; return std::string(); } @@ -115,5 +115,5 @@ Exception WifiLanServerSocket::Close() { return {Exception::kSuccess}; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.h b/internal/platform/implementation/linux/wifi_lan_server_socket.h index 32ec7bca..3b5a75fe 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.h @@ -27,11 +27,12 @@ namespace nearby { namespace linux { class WifiLanServerSocket : public api::WifiLanServerSocket { -public: + public: explicit WifiLanServerSocket(int socket, - std::shared_ptr network_manager, - sdbus::IConnection &system_bus) - : fd_(sdbus::UnixFd(socket)), network_manager_(std::move(network_manager)), + std::shared_ptr network_manager, + sdbus::IConnection &system_bus) + : fd_(sdbus::UnixFd(socket)), + network_manager_(std::move(network_manager)), system_bus_(system_bus) {} std::string GetIPAddress() const override; @@ -40,11 +41,11 @@ public: std::unique_ptr Accept() override; Exception Close() override; -private: + private: sdbus::UnixFd fd_; std::shared_ptr network_manager_; sdbus::IConnection &system_bus_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_lan_socket.h b/internal/platform/implementation/linux/wifi_lan_socket.h index 276c8d2c..016b7190 100644 --- a/internal/platform/implementation/linux/wifi_lan_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_socket.h @@ -27,16 +27,12 @@ namespace nearby { namespace linux { class WifiLanSocket : public api::WifiLanSocket { -public: + public: explicit WifiLanSocket(sdbus::UnixFd fd) : fd_(fd), output_stream_(fd), input_stream_(fd) {} - nearby::InputStream &GetInputStream() override { - return input_stream_; - }; - nearby::OutputStream &GetOutputStream() override { - return output_stream_; - }; + nearby::InputStream &GetInputStream() override { return input_stream_; }; + nearby::OutputStream &GetOutputStream() override { return output_stream_; }; Exception Close() override { input_stream_.Close(); output_stream_.Close(); @@ -44,12 +40,12 @@ public: return Exception{Exception::kSuccess}; }; -private: + private: sdbus::UnixFd fd_; OutputStream output_stream_; InputStream input_stream_; }; -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby #endif diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 4a96cf7c..9ff06cf2 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -13,9 +13,9 @@ // limitations under the License. #include +#include #include #include -#include #include #include @@ -36,39 +36,41 @@ namespace linux { std::ostream &operator<<(std::ostream &s, const ActiveConnectionStateReason &reason) { switch (reason) { - case kStateReasonUnknown: - return s << "The reason for the active connection state change is unknown."; - case kStateReasonNone: - return s << "No reason was given for the active connection state change."; - case kStateReasonUserDisconnected: - return s << "The active connection changed state because the user " - "disconnected it."; - case kStateReasonDeviceDisconnected: - return s << "The active connection changed state because the device it was " + case kStateReasonUnknown: + return s + << "The reason for the active connection state change is unknown."; + case kStateReasonNone: + return s << "No reason was given for the active connection state change."; + case kStateReasonUserDisconnected: + return s << "The active connection changed state because the user " + "disconnected it."; + case kStateReasonDeviceDisconnected: + return s + << "The active connection changed state because the device it was " "using was disconnected."; - case kStateReasonServiceStopped: - return s << "The service providing the VPN connection was stopped."; - case kStateReasonIPConfigInvalid: - return s << "The IP config of the active connection was invalid."; - case kStateReasonConnectTimeout: - return s << "The connection attempt to the VPN service timed out."; - case kStateReasonServiceStartTimeout: - return s << "A timeout occurred while starting the service providing the " - "VPN connection."; - case kStateReasonServiceStartFailed: - return s << "Starting the service providing the VPN connection failed."; - case kStateReasonNoSecrets: - return s << "Necessary secrets for the connection were not provided."; - case kStateReasonLoginFailed: - return s << "Authentication to the server failed."; - case kStateReasonConnectionRemoved: - return s << "The connection was deleted from settings."; - case kStateReasonDependencyFailed: - return s << "Master connection of this connection failed to activate."; - case kStateReasonDeviceRealizeFailed: - return s << "Could not create the software device link."; - case kStateReasonDeviceRemoved: - return s << "The device this connection depended on disappeared."; + case kStateReasonServiceStopped: + return s << "The service providing the VPN connection was stopped."; + case kStateReasonIPConfigInvalid: + return s << "The IP config of the active connection was invalid."; + case kStateReasonConnectTimeout: + return s << "The connection attempt to the VPN service timed out."; + case kStateReasonServiceStartTimeout: + return s << "A timeout occurred while starting the service providing the " + "VPN connection."; + case kStateReasonServiceStartFailed: + return s << "Starting the service providing the VPN connection failed."; + case kStateReasonNoSecrets: + return s << "Necessary secrets for the connection were not provided."; + case kStateReasonLoginFailed: + return s << "Authentication to the server failed."; + case kStateReasonConnectionRemoved: + return s << "The connection was deleted from settings."; + case kStateReasonDependencyFailed: + return s << "Master connection of this connection failed to activate."; + case kStateReasonDeviceRealizeFailed: + return s << "Could not create the software device link."; + case kStateReasonDeviceRemoved: + return s << "The device this connection depended on disappeared."; } } @@ -312,25 +314,23 @@ NetworkManagerWifiMedium::SearchBySSID(absl::string_view ssid, return ap; } -static inline std::pair -AuthAlgAndKeyMgmt(api::WifiAuthType auth_type) { +static inline std::pair AuthAlgAndKeyMgmt( + api::WifiAuthType auth_type) { switch (auth_type) { - case api::WifiAuthType::kUnknown: - return {"open", "none"}; - case api::WifiAuthType::kOpen: - return {"open", "none"}; - case api::WifiAuthType::kWpaPsk: - return {"shared", "wpa-psk"}; - case api::WifiAuthType::kWep: - return {"none", "wep"}; + case api::WifiAuthType::kUnknown: + return {"open", "none"}; + case api::WifiAuthType::kOpen: + return {"open", "none"}; + case api::WifiAuthType::kWpaPsk: + return {"shared", "wpa-psk"}; + case api::WifiAuthType::kWep: + return {"none", "wep"}; } } -api::WifiConnectionStatus -NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid, - absl::string_view password, - api::WifiAuthType auth_type) { - +api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( + absl::string_view ssid, absl::string_view password, + api::WifiAuthType auth_type) { auto ap = SearchBySSID(ssid); if (ap == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() @@ -424,7 +424,7 @@ NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid, bool NetworkManagerWifiMedium::VerifyInternetConnectivity() { try { std::uint32_t connectivity = network_manager_->CheckConnectivity(); - return connectivity == 4; // NM_CONNECTIVITY_FULL + return connectivity == 4; // NM_CONNECTIVITY_FULL } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "CheckConnectivity", e); return false; @@ -465,5 +465,5 @@ NetworkManagerWifiMedium::GetActiveConnection() { return conn; } -} // namespace linux -} // namespace nearby +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_socket.h b/internal/platform/implementation/linux/wifi_socket.h index 040093df..fbc0e9a4 100644 --- a/internal/platform/implementation/linux/wifi_socket.h +++ b/internal/platform/implementation/linux/wifi_socket.h @@ -16,15 +16,15 @@ #define PLATFORM_IMPL_LINUX_WIFI_LAN_SOCKET_H_ namespace nearby { - namespace api { - class WifiLanSocket { - public: - ~WifiLanSocket() = default; +namespace api { +class WifiLanSocket { + public: + ~WifiLanSocket() = default; - private: - int fd; - }; - } -} + private: + int fd; +}; +} // namespace api +} // namespace nearby #endif From dbbd9e043cde12d0266f0a6e83069bf17da447a4 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 16:46:17 +0530 Subject: [PATCH 091/201] Rewrite NetworkManager state to use an enum type for clarity. --- .../platform/implementation/linux/wifi_lan.cc | 4 +- .../implementation/linux/wifi_medium.h | 44 ++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index ce8b0026..53413a3c 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -44,7 +44,9 @@ WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus) bool WifiLanMedium::IsNetworkConnected() const { auto state = network_manager_->getState(); - return state >= 50; // NM_STATE_CONNECTED_LOCAL + return state == NetworkManager::kNMStateConnectedLocal || + state == NetworkManager::kNMStateConnectedSite || + state == NetworkManager::kNMStateConnectedGlobal; } std::optional> entry_group_key( diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 065cb406..53821eb3 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -49,26 +49,60 @@ class NetworkManager final explicit NetworkManager(sdbus::IConnection &system_bus) : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager"), - state_(0) { + state_(kNMStateUnknown) { registerProxy(); try { - state_ = State(); + setState(State()); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); } } ~NetworkManager() { unregisterProxy(); } - std::uint32_t getState() const { return state_; } + // https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMState + enum NMState { + kNMStateUnknown = 0, + kNMStateAsleep = 10, + kNMStateDisconnected = 20, + kNMStateDisconnecting = 30, + kNMStateConnecting = 40, + kNMStateConnectedLocal = 50, + kNMStateConnectedSite = 60, + kNMStateConnectedGlobal = 70, + }; + + NMState getState() const { return state_; } protected: void onCheckPermissions() override {} - void onStateChanged(const uint32_t &state) override { state_ = state; } + void onStateChanged(const uint32_t &state) override { setState(state); } void onDeviceAdded(const sdbus::ObjectPath &device_path) override {} void onDeviceRemoved(const sdbus::ObjectPath &device_path) override {} private: - std::atomic_uint32_t state_; + void inline setState(std::uint32_t val) { +#define NM_STATE_CASE_SET(k) \ + case (k): \ + state_ = (k); \ + break + + switch (val) { + NM_STATE_CASE_SET(kNMStateAsleep); + NM_STATE_CASE_SET(kNMStateDisconnected); + NM_STATE_CASE_SET(kNMStateDisconnecting); + NM_STATE_CASE_SET(kNMStateConnecting); + NM_STATE_CASE_SET(kNMStateConnectedLocal); + NM_STATE_CASE_SET(kNMStateConnectedSite); + NM_STATE_CASE_SET(kNMStateConnectedGlobal); + default: + NEARBY_LOGS(ERROR) << __func__ << "invalid NMState value: " << val + << ", setting state to unknown"; + NM_STATE_CASE_SET(kNMStateUnknown); + } +#undef NM_STATE_CASE_SET + }; + + std::atomic state_; }; class NetworkManagerIP4Config From 1de5123935201ca4750cdc013dcfdef9c00b2a65 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 16:46:41 +0530 Subject: [PATCH 092/201] Minor refactoring. --- .../platform/implementation/linux/wifi_hotspot.cc | 2 +- .../linux/wifi_hotspot_server_socket.cc | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 7e1f80aa..58891d76 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -51,7 +51,7 @@ NetworkManagerWifiHotspotMedium::ConnectToService( NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" << port; - struct sockaddr_in addr; + struct sockaddr_in addr{}; addr.sin_addr.s_addr = inet_addr(std::string(ip_address).c_str()); addr.sin_family = AF_INET; addr.sin_port = htons(port); diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc index a6041f98..e4e880bb 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc @@ -30,13 +30,13 @@ std::string NetworkManagerWifiHotspotServerSocket::GetIPAddress() const { << __func__ << ": Could not find any IPv4 addresses for active connection " << active_connection_path_; - return std::string(); + return {}; } return ip4addresses[0]; } int NetworkManagerWifiHotspotServerSocket::GetPort() const { - struct sockaddr_in sin; + struct sockaddr_in sin{}; socklen_t len = sizeof(sin); auto ret = getsockname(fd_.get(), reinterpret_cast(&sin), &len); @@ -51,7 +51,7 @@ int NetworkManagerWifiHotspotServerSocket::GetPort() const { std::unique_ptr NetworkManagerWifiHotspotServerSocket::Accept() { - struct sockaddr_in addr; + struct sockaddr_in addr{}; socklen_t len = sizeof(addr); auto conn = @@ -67,10 +67,9 @@ NetworkManagerWifiHotspotServerSocket::Accept() { } Exception NetworkManagerWifiHotspotServerSocket::Close() { - int fd = fd_.release(); - auto ret = close(fd); + auto ret = close(fd_.release()); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " + NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket: " << std::strerror(errno); return {Exception::kFailed}; } From b4fd1e0ced4efefd8aa8bae320a3284c0825d668 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 18:48:10 +0530 Subject: [PATCH 093/201] Split off most of NetworkManager code into their own files. --- internal/platform/implementation/linux/BUILD | 5 + .../implementation/linux/network_manager.cc | 93 ++++++ .../implementation/linux/network_manager.h | 147 ++++++++++ .../linux/network_manager_access_point.h | 43 +++ .../network_manager_active_connection.cc | 124 ++++++++ .../linux/network_manager_active_connection.h | 113 ++++++++ .../implementation/linux/wifi_medium.cc | 131 +-------- .../implementation/linux/wifi_medium.h | 274 +----------------- 8 files changed, 535 insertions(+), 395 deletions(-) create mode 100644 internal/platform/implementation/linux/network_manager.cc create mode 100644 internal/platform/implementation/linux/network_manager.h create mode 100644 internal/platform/implementation/linux/network_manager_access_point.h create mode 100644 internal/platform/implementation/linux/network_manager_active_connection.cc create mode 100644 internal/platform/implementation/linux/network_manager_active_connection.h diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 6d647607..b387c3e9 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -67,6 +67,9 @@ cc_library( "bluetooth_pairing.h", "bluez.h", "dbus.h", + "network_manager.h", + "network_manager_active_connection.h", + "network_manager_access_point.h", "stream.h", "wifi_direct.h", "wifi_direct_server_socket.h", @@ -133,6 +136,8 @@ cc_library( "bluez.cc", "dbus.cc", "executor.cc", + "network_manager.cc", + "network_manager_active_connection.cc", "platform.cc", "preferences_manager.cc", "preferences_repository.cc", diff --git a/internal/platform/implementation/linux/network_manager.cc b/internal/platform/implementation/linux/network_manager.cc new file mode 100644 index 00000000..32297138 --- /dev/null +++ b/internal/platform/implementation/linux/network_manager.cc @@ -0,0 +1,93 @@ +// 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 + +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/network_manager.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" + +namespace nearby { +namespace linux { +std::unique_ptr +NetworkManagerObjectManager::GetActiveConnectionForAccessPoint( + const sdbus::ObjectPath &access_point, + const sdbus::ObjectPath &device_path) { + std::map>> + objects; + try { + objects = GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); + return nullptr; + } + + for (auto &[object_path, interfaces] : objects) { + if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/") == + 0) { + if (interfaces.count(org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME) == 1) { + auto props = interfaces[org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME]; + sdbus::ObjectPath specific_object = props["SpecificObject"]; + if (specific_object == access_point) { + std::vector devices = props["Devices"]; + for (auto &path : devices) { + if (path == device_path) { + return std::make_unique( + getProxy().getConnection(), object_path); + } + } + } + } + } + } + return nullptr; +} + +std::unique_ptr +NetworkManagerObjectManager::GetIp4Config( + const sdbus::ObjectPath &active_connection) { + std::map>> + objects; + try { + objects = GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); + return nullptr; + } + + for (auto &[object_path, interfaces] : objects) { + if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/", + 0) == 0) { + if (interfaces.count(org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME) == 1) { + auto props = interfaces[org::freedesktop::NetworkManager::Connection:: + Active_proxy::INTERFACE_NAME]; + sdbus::ObjectPath specific_object = props["SpecificObject"]; + sdbus::ObjectPath ip4config = props["Ip4Config"]; + + if (specific_object == active_connection) + return std::make_unique( + getProxy().getConnection(), ip4config); + } + } + } + + return nullptr; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/network_manager.h b/internal/platform/implementation/linux/network_manager.h new file mode 100644 index 00000000..1c7c51af --- /dev/null +++ b/internal/platform/implementation/linux/network_manager.h @@ -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_NETWORK_MANAGER_H_ +#define PLATFORM_IMPL_LINUX_NETWORK_MANAGER_H_ + +#include + +#include +#include + +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/ip4config_client.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" + +namespace nearby { +namespace linux { +class NetworkManager final + : public sdbus::ProxyInterfaces { + public: + NetworkManager(const NetworkManager &) = delete; + NetworkManager(NetworkManager &&) = delete; + NetworkManager &operator=(const NetworkManager &) = delete; + NetworkManager &operator=(NetworkManager &&) = delete; + explicit NetworkManager(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager"), + state_(kNMStateUnknown) { + registerProxy(); + try { + setState(State()); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); + } + } + ~NetworkManager() { unregisterProxy(); } + + // https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMState + enum NMState { + kNMStateUnknown = 0, + kNMStateAsleep = 10, + kNMStateDisconnected = 20, + kNMStateDisconnecting = 30, + kNMStateConnecting = 40, + kNMStateConnectedLocal = 50, + kNMStateConnectedSite = 60, + kNMStateConnectedGlobal = 70, + }; + + NMState getState() const { return state_; } + + protected: + void onCheckPermissions() override {} + void onStateChanged(const uint32_t &state) override { setState(state); } + void onDeviceAdded(const sdbus::ObjectPath &device_path) override {} + void onDeviceRemoved(const sdbus::ObjectPath &device_path) override {} + + private: + void inline setState(std::uint32_t val) { +#define NM_STATE_CASE_SET(k) \ + case (k): \ + state_ = (k); \ + break + + switch (val) { + NM_STATE_CASE_SET(kNMStateAsleep); + NM_STATE_CASE_SET(kNMStateDisconnected); + NM_STATE_CASE_SET(kNMStateDisconnecting); + NM_STATE_CASE_SET(kNMStateConnecting); + NM_STATE_CASE_SET(kNMStateConnectedLocal); + NM_STATE_CASE_SET(kNMStateConnectedSite); + NM_STATE_CASE_SET(kNMStateConnectedGlobal); + default: + NEARBY_LOGS(ERROR) << __func__ << "invalid NMState value: " << val + << ", setting state to unknown"; + NM_STATE_CASE_SET(kNMStateUnknown); + } +#undef NM_STATE_CASE_SET + }; + + std::atomic state_; +}; + +class NetworkManagerIP4Config + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::IP4Config_proxy> { + public: + NetworkManagerIP4Config(const NetworkManagerIP4Config &) = delete; + NetworkManagerIP4Config(NetworkManagerIP4Config &&) = delete; + NetworkManagerIP4Config &operator=(const NetworkManagerIP4Config &) = delete; + NetworkManagerIP4Config &operator=(NetworkManagerIP4Config &&) = delete; + NetworkManagerIP4Config(sdbus::IConnection &system_bus, + const sdbus::ObjectPath &config_object_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + config_object_path) { + registerProxy(); + } + ~NetworkManagerIP4Config() { unregisterProxy(); } +}; + +class NetworkManagerObjectManager final + : public sdbus::ProxyInterfaces { + public: + NetworkManagerObjectManager(const NetworkManagerObjectManager &) = delete; + NetworkManagerObjectManager(NetworkManagerObjectManager &&) = delete; + NetworkManagerObjectManager &operator=(const NetworkManagerObjectManager &) = + delete; + NetworkManagerObjectManager &operator=(NetworkManagerObjectManager &&) = + delete; + explicit NetworkManagerObjectManager(sdbus::IConnection &system_bus) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + "/org/freedesktop") { + registerProxy(); + } + ~NetworkManagerObjectManager() { unregisterProxy(); } + + std::unique_ptr GetIp4Config( + const sdbus::ObjectPath &access_point); + std::unique_ptr + GetActiveConnectionForAccessPoint(const sdbus::ObjectPath &access_point_path, + const sdbus::ObjectPath &device_path); + + protected: + void onInterfacesAdded( + const sdbus::ObjectPath &objectPath, + const std::map> + &interfacesAndProperties) override {} + void onInterfacesRemoved( + const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override {} +}; + +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/network_manager_access_point.h b/internal/platform/implementation/linux/network_manager_access_point.h new file mode 100644 index 00000000..131e4f6f --- /dev/null +++ b/internal/platform/implementation/linux/network_manager_access_point.h @@ -0,0 +1,43 @@ +// 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_NETWORK_MANAGER_ACCESS_POINT_H_ +#define PLATFORM_IMPL_LINUX_NETWORK_MANAGER_ACCESS_POINT_H_ +#include + +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/access_point_client.h" + +namespace nearby { +namespace linux { +class NetworkManagerAccessPoint + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::AccessPoint_proxy> { + public: + NetworkManagerAccessPoint(const NetworkManagerAccessPoint &) = delete; + NetworkManagerAccessPoint(NetworkManagerAccessPoint &&) = delete; + NetworkManagerAccessPoint &operator=(const NetworkManagerAccessPoint &) = + delete; + NetworkManagerAccessPoint &operator=(NetworkManagerAccessPoint &&) = delete; + NetworkManagerAccessPoint(sdbus::IConnection &system_bus, + sdbus::ObjectPath access_point_object_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + std::move(access_point_object_path)) { + registerProxy(); + } + ~NetworkManagerAccessPoint() { unregisterProxy(); } +}; +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/network_manager_active_connection.cc b/internal/platform/implementation/linux/network_manager_active_connection.cc new file mode 100644 index 00000000..b97c2f2d --- /dev/null +++ b/internal/platform/implementation/linux/network_manager_active_connection.cc @@ -0,0 +1,124 @@ +// 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 + +#include +#include + +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/network_manager.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" + +namespace nearby { +namespace linux { +std::ostream &operator<<( + std::ostream &stream, + const NetworkManagerActiveConnection::ActiveConnectionStateReason &reason) { + switch (reason) { + case NetworkManagerActiveConnection::kStateReasonUnknown: + return stream + << "The reason for the active connection state change is unknown."; + case NetworkManagerActiveConnection::kStateReasonNone: + return stream + << "No reason was given for the active connection state change."; + case NetworkManagerActiveConnection::kStateReasonUserDisconnected: + return stream << "The active connection changed state because the user " + "disconnected it."; + case NetworkManagerActiveConnection::kStateReasonDeviceDisconnected: + return stream + << "The active connection changed state because the device it was " + "using was disconnected."; + case NetworkManagerActiveConnection::kStateReasonServiceStopped: + return stream << "The service providing the VPN connection was stopped."; + case NetworkManagerActiveConnection::kStateReasonIPConfigInvalid: + return stream << "The IP config of the active connection was invalid."; + case NetworkManagerActiveConnection::kStateReasonConnectTimeout: + return stream << "The connection attempt to the VPN service timed out."; + case NetworkManagerActiveConnection::kStateReasonServiceStartTimeout: + return stream + << "A timeout occurred while starting the service providing the " + "VPN connection."; + case NetworkManagerActiveConnection::kStateReasonServiceStartFailed: + return stream + << "Starting the service providing the VPN connection failed."; + case NetworkManagerActiveConnection::kStateReasonNoSecrets: + return stream + << "Necessary secrets for the connection were not provided."; + case NetworkManagerActiveConnection::kStateReasonLoginFailed: + return stream << "Authentication to the server failed."; + case NetworkManagerActiveConnection::kStateReasonConnectionRemoved: + return stream << "The connection was deleted from settings."; + case NetworkManagerActiveConnection::kStateReasonDependencyFailed: + return stream + << "Master connection of this connection failed to activate."; + case NetworkManagerActiveConnection::kStateReasonDeviceRealizeFailed: + return stream << "Could not create the software device link."; + case NetworkManagerActiveConnection::kStateReasonDeviceRemoved: + return stream << "The device this connection depended on disappeared."; + } +} + +std::vector NetworkManagerActiveConnection::GetIP4Addresses() { + sdbus::ObjectPath ip4config_path; + try { + ip4config_path = Ip4Config(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "Ip4Config", e); + return {}; + } + + NetworkManagerIP4Config ip4config(getProxy().getConnection(), ip4config_path); + std::vector> address_data; + try { + address_data = ip4config.AddressData(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "AddressData", e); + return {}; + } + + std::vector ip4addresses; + for (auto &data : address_data) { + if (data.count("address") == 1) { + ip4addresses.push_back(data["address"]); + } + } + return ip4addresses; +} + +std::pair, bool> +NetworkManagerActiveConnection::WaitForConnection(absl::Duration timeout) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Waiting for an update to " + << getObjectPath() << "'s state"; + + auto state_changed = [this]() { + this->state_mutex_.AssertReaderHeld(); + return this->state_ == kStateActivated || this->state_ == kStateDeactivated; + }; + + absl::Condition cond(&state_changed); + auto success = state_mutex_.ReaderLockWhenWithTimeout(cond, timeout); + auto reason = reason_; + auto state = state_; + state_mutex_.ReaderUnlock(); + + if (!success) { + return {reason, true}; + } + + return state == kStateActivated ? std::pair{std::nullopt, false} + : std::pair{std::optional(reason), false}; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/network_manager_active_connection.h b/internal/platform/implementation/linux/network_manager_active_connection.h new file mode 100644 index 00000000..1d4aeb91 --- /dev/null +++ b/internal/platform/implementation/linux/network_manager_active_connection.h @@ -0,0 +1,113 @@ +// 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_NETWORK_MANAGER_ACTIVE_CONNECTION_H_ +#define PLATFORM_IMPL_LINUX_NETWORK_MANAGER_ACTIVE_CONNECTION_H_ + +#include + +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" + +namespace nearby { +namespace linux { +class NetworkManagerActiveConnection + : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::Connection::Active_proxy> { + public: + enum ActiveConnectionState { + kStateUnknown = 0, + kStateActivating = 1, + kStateActivated = 2, + kStateDeactivating = 3, + kStateDeactivated = 4 + }; + enum ActiveConnectionStateReason { + kStateReasonUnknown = 0, + kStateReasonNone = 1, + kStateReasonUserDisconnected = 2, + kStateReasonDeviceDisconnected = 3, + kStateReasonServiceStopped = 4, + kStateReasonIPConfigInvalid = 5, + kStateReasonConnectTimeout = 6, + kStateReasonServiceStartTimeout = 7, + kStateReasonServiceStartFailed = 8, + kStateReasonNoSecrets = 9, + kStateReasonLoginFailed = 10, + kStateReasonConnectionRemoved = 11, + kStateReasonDependencyFailed = 12, + kStateReasonDeviceRealizeFailed = 13, + kStateReasonDeviceRemoved = 14, + }; + + NetworkManagerActiveConnection(const NetworkManagerActiveConnection &) = + delete; + NetworkManagerActiveConnection(NetworkManagerActiveConnection &&) = delete; + NetworkManagerActiveConnection &operator=( + const NetworkManagerActiveConnection &) = delete; + NetworkManagerActiveConnection &operator=(NetworkManagerActiveConnection &&) = + delete; + explicit NetworkManagerActiveConnection( + sdbus::IConnection &system_bus, sdbus::ObjectPath active_connection_path) + : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + std::move(active_connection_path)), + state_(kStateUnknown), + reason_(kStateReasonUnknown) { + registerProxy(); + try { + auto state = State(); + if (state >= kStateUnknown && state <= kStateDeactivated) { + state_ = static_cast(state); + } + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); + } + } + virtual ~NetworkManagerActiveConnection() { unregisterProxy(); } + + protected: + void onStateChanged(const uint32_t &state, const uint32_t &reason) override + ABSL_LOCKS_EXCLUDED(state_mutex_) { + absl::MutexLock l(&state_mutex_); + if (state >= kStateUnknown && state <= kStateDeactivated) { + state_ = static_cast(state); + } + if (reason >= kStateReasonUnknown && reason <= kStateReasonDeviceRemoved) { + reason_ = static_cast(reason); + } + } + + public: + std::pair, bool> WaitForConnection( + absl::Duration timeout = absl::Seconds(10)) + ABSL_LOCKS_EXCLUDED(state_mutex_); + std::vector GetIP4Addresses(); + + private: + absl::Mutex state_mutex_; + ActiveConnectionState state_ ABSL_GUARDED_BY(state_mutex_); + ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_); +}; + +extern std::ostream &operator<<( + std::ostream &stream, + const NetworkManagerActiveConnection::ActiveConnectionStateReason &reason); + +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 9ff06cf2..33bdcce5 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -27,124 +27,12 @@ #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi.h" namespace nearby { namespace linux { - -std::ostream &operator<<(std::ostream &s, - const ActiveConnectionStateReason &reason) { - switch (reason) { - case kStateReasonUnknown: - return s - << "The reason for the active connection state change is unknown."; - case kStateReasonNone: - return s << "No reason was given for the active connection state change."; - case kStateReasonUserDisconnected: - return s << "The active connection changed state because the user " - "disconnected it."; - case kStateReasonDeviceDisconnected: - return s - << "The active connection changed state because the device it was " - "using was disconnected."; - case kStateReasonServiceStopped: - return s << "The service providing the VPN connection was stopped."; - case kStateReasonIPConfigInvalid: - return s << "The IP config of the active connection was invalid."; - case kStateReasonConnectTimeout: - return s << "The connection attempt to the VPN service timed out."; - case kStateReasonServiceStartTimeout: - return s << "A timeout occurred while starting the service providing the " - "VPN connection."; - case kStateReasonServiceStartFailed: - return s << "Starting the service providing the VPN connection failed."; - case kStateReasonNoSecrets: - return s << "Necessary secrets for the connection were not provided."; - case kStateReasonLoginFailed: - return s << "Authentication to the server failed."; - case kStateReasonConnectionRemoved: - return s << "The connection was deleted from settings."; - case kStateReasonDependencyFailed: - return s << "Master connection of this connection failed to activate."; - case kStateReasonDeviceRealizeFailed: - return s << "Could not create the software device link."; - case kStateReasonDeviceRemoved: - return s << "The device this connection depended on disappeared."; - } -} - -std::unique_ptr -NetworkManagerObjectManager::GetIp4Config( - const sdbus::ObjectPath &active_connection) { - std::map>> - objects; - try { - objects = GetManagedObjects(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); - return nullptr; - } - - for (auto &[object_path, interfaces] : objects) { - if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/", - 0) == 0) { - if (interfaces.count(org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME) == 1) { - auto props = interfaces[org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME]; - sdbus::ObjectPath specific_object = props["SpecificObject"]; - sdbus::ObjectPath ip4config = props["Ip4Config"]; - - if (specific_object == active_connection) - return std::make_unique( - getProxy().getConnection(), ip4config); - } - } - } - - return nullptr; -} - -std::unique_ptr -NetworkManagerObjectManager::GetActiveConnectionForAccessPoint( - const sdbus::ObjectPath &access_point, - const sdbus::ObjectPath &device_path) { - std::map>> - objects; - try { - objects = GetManagedObjects(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); - return nullptr; - } - - for (auto &[object_path, interfaces] : objects) { - if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/") == - 0) { - if (interfaces.count(org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME) == 1) { - auto props = interfaces[org::freedesktop::NetworkManager::Connection:: - Active_proxy::INTERFACE_NAME]; - sdbus::ObjectPath specific_object = props["SpecificObject"]; - if (specific_object == access_point) { - std::vector devices = props["Devices"]; - for (auto &path : devices) { - if (path == device_path) { - return std::make_unique( - getProxy().getConnection(), object_path); - } - } - } - } - } - } - - return nullptr; -} - api::WifiCapability &NetworkManagerWifiMedium::GetCapability() { try { auto cap_mask = WirelessCapabilities(); @@ -222,16 +110,9 @@ void NetworkManagerWifiMedium::onPropertiesChanged( return; } - for (auto &[property, val] : changedProperties) { - if (property == "LastScan") { - { - absl::MutexLock l(&last_scan_lock_); - last_scan_ = val; - } - // absl::ReaderMutexLock l(&scan_result_callback_lock_); - // if (scan_result_callback_.has_value()) { - // } - } + if (changedProperties.count("LastScan") == 1) { + absl::MutexLock l(&last_scan_lock_); + last_scan_ = changedProperties.at("LastScan"); } } @@ -413,8 +294,8 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( << active_conn_path << " failed to activate, NMActiveConnectionStateReason:" << *reason; - if (*reason == ActiveConnectionStateReason::kStateReasonNoSecrets || - *reason == ActiveConnectionStateReason::kStateReasonLoginFailed) + if (*reason == NetworkManagerActiveConnection::kStateReasonNoSecrets || + *reason == NetworkManagerActiveConnection::kStateReasonLoginFailed) return api::WifiConnectionStatus::kAuthFailure; } diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 53821eb3..788741c9 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -20,288 +20,22 @@ #include #include #include +#include #include #include #include #include -#include #include "absl/synchronization/mutex.h" -#include "internal/platform/implementation/linux/dbus.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/access_point_client.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/ip4config_client.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/networkmanager_client.h" +#include "internal/platform/implementation/linux/network_manager.h" +#include "internal/platform/implementation/linux/network_manager_access_point.h" +#include "internal/platform/implementation/linux/network_manager_active_connection.h" #include "internal/platform/implementation/wifi.h" -#include "internal/platform/logging.h" namespace nearby { namespace linux { -class NetworkManager final - : public sdbus::ProxyInterfaces { - public: - NetworkManager(const NetworkManager &) = delete; - NetworkManager(NetworkManager &&) = delete; - NetworkManager &operator=(const NetworkManager &) = delete; - NetworkManager &operator=(NetworkManager &&) = delete; - explicit NetworkManager(sdbus::IConnection &system_bus) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - "/org/freedesktop/NetworkManager"), - state_(kNMStateUnknown) { - registerProxy(); - try { - setState(State()); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); - } - } - ~NetworkManager() { unregisterProxy(); } - - // https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMState - enum NMState { - kNMStateUnknown = 0, - kNMStateAsleep = 10, - kNMStateDisconnected = 20, - kNMStateDisconnecting = 30, - kNMStateConnecting = 40, - kNMStateConnectedLocal = 50, - kNMStateConnectedSite = 60, - kNMStateConnectedGlobal = 70, - }; - - NMState getState() const { return state_; } - - protected: - void onCheckPermissions() override {} - void onStateChanged(const uint32_t &state) override { setState(state); } - void onDeviceAdded(const sdbus::ObjectPath &device_path) override {} - void onDeviceRemoved(const sdbus::ObjectPath &device_path) override {} - - private: - void inline setState(std::uint32_t val) { -#define NM_STATE_CASE_SET(k) \ - case (k): \ - state_ = (k); \ - break - - switch (val) { - NM_STATE_CASE_SET(kNMStateAsleep); - NM_STATE_CASE_SET(kNMStateDisconnected); - NM_STATE_CASE_SET(kNMStateDisconnecting); - NM_STATE_CASE_SET(kNMStateConnecting); - NM_STATE_CASE_SET(kNMStateConnectedLocal); - NM_STATE_CASE_SET(kNMStateConnectedSite); - NM_STATE_CASE_SET(kNMStateConnectedGlobal); - default: - NEARBY_LOGS(ERROR) << __func__ << "invalid NMState value: " << val - << ", setting state to unknown"; - NM_STATE_CASE_SET(kNMStateUnknown); - } -#undef NM_STATE_CASE_SET - }; - - std::atomic state_; -}; - -class NetworkManagerIP4Config - : public sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::IP4Config_proxy> { - public: - NetworkManagerIP4Config(const NetworkManagerIP4Config &) = delete; - NetworkManagerIP4Config(NetworkManagerIP4Config &&) = delete; - NetworkManagerIP4Config &operator=(const NetworkManagerIP4Config &) = delete; - NetworkManagerIP4Config &operator=(NetworkManagerIP4Config &&) = delete; - NetworkManagerIP4Config(sdbus::IConnection &system_bus, - const sdbus::ObjectPath &config_object_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - config_object_path) { - registerProxy(); - } - ~NetworkManagerIP4Config() { unregisterProxy(); } -}; - -class NetworkManagerAccessPoint - : public sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::AccessPoint_proxy> { - public: - NetworkManagerAccessPoint(const NetworkManagerAccessPoint &) = delete; - NetworkManagerAccessPoint(NetworkManagerAccessPoint &&) = delete; - NetworkManagerAccessPoint &operator=(const NetworkManagerAccessPoint &) = - delete; - NetworkManagerAccessPoint &operator=(NetworkManagerAccessPoint &&) = delete; - NetworkManagerAccessPoint(sdbus::IConnection &system_bus, - sdbus::ObjectPath access_point_object_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - std::move(access_point_object_path)) { - registerProxy(); - } - ~NetworkManagerAccessPoint() { unregisterProxy(); } -}; - -enum ActiveConnectionState { - kStateUnknown = 0, - kStateActivating = 1, - kStateActivated = 2, - kStateDeactivating = 3, - kStateDeactivated = 4 -}; -enum ActiveConnectionStateReason { - kStateReasonUnknown = 0, - kStateReasonNone = 1, - kStateReasonUserDisconnected = 2, - kStateReasonDeviceDisconnected = 3, - kStateReasonServiceStopped = 4, - kStateReasonIPConfigInvalid = 5, - kStateReasonConnectTimeout = 6, - kStateReasonServiceStartTimeout = 7, - kStateReasonServiceStartFailed = 8, - kStateReasonNoSecrets = 9, - kStateReasonLoginFailed = 10, - kStateReasonConnectionRemoved = 11, - kStateReasonDependencyFailed = 12, - kStateReasonDeviceRealizeFailed = 13, - kStateReasonDeviceRemoved = 14, -}; - -extern std::ostream &operator<<(std::ostream &s, - const ActiveConnectionStateReason &reason); - -class NetworkManagerActiveConnection - : public sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::Connection::Active_proxy> { - public: - NetworkManagerActiveConnection(const NetworkManagerActiveConnection &) = - delete; - NetworkManagerActiveConnection(NetworkManagerActiveConnection &&) = delete; - NetworkManagerActiveConnection &operator=( - const NetworkManagerActiveConnection &) = delete; - NetworkManagerActiveConnection &operator=(NetworkManagerActiveConnection &&) = - delete; - explicit NetworkManagerActiveConnection( - sdbus::IConnection &system_bus, sdbus::ObjectPath active_connection_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - std::move(active_connection_path)), - state_(kStateUnknown), - reason_(kStateReasonUnknown) { - registerProxy(); - try { - auto state = State(); - if (state >= kStateUnknown && state <= kStateDeactivated) { - state_ = static_cast(state); - } - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); - } - } - virtual ~NetworkManagerActiveConnection() { unregisterProxy(); } - - protected: - void onStateChanged(const uint32_t &state, const uint32_t &reason) override - ABSL_LOCKS_EXCLUDED(state_mutex_) { - absl::MutexLock l(&state_mutex_); - if (state >= kStateUnknown && state <= kStateDeactivated) { - state_ = static_cast(state); - } - if (reason >= kStateReasonUnknown && reason <= kStateReasonDeviceRemoved) { - reason_ = static_cast(reason); - } - } - - public: - std::pair, bool> WaitForConnection( - absl::Duration timeout = absl::Seconds(10)) - ABSL_LOCKS_EXCLUDED(state_mutex_) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Waiting for an update to " - << getObjectPath() << "'s state"; - - auto state_changed = [this]() { - this->state_mutex_.AssertReaderHeld(); - return this->state_ == kStateActivated || - this->state_ == kStateDeactivated; - }; - - absl::Condition cond(&state_changed); - auto success = state_mutex_.ReaderLockWhenWithTimeout(cond, timeout); - auto reason = reason_; - auto state = state_; - state_mutex_.ReaderUnlock(); - - if (!success) { - return {reason, true}; - } - - return state == kStateActivated ? std::pair{std::nullopt, false} - : std::pair{std::optional(reason), false}; - } - - std::vector GetIP4Addresses() { - sdbus::ObjectPath ip4config_path; - try { - ip4config_path = Ip4Config(); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(this, "Ip4Config", e); - return {}; - } - - NetworkManagerIP4Config ip4config(getProxy().getConnection(), - ip4config_path); - std::vector> address_data; - try { - address_data = ip4config.AddressData(); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(&ip4config, "AddressData", e); - return {}; - } - - std::vector ip4addresses; - for (auto &data : address_data) { - if (data.count("address") == 1) { - ip4addresses.push_back(data["address"]); - } - } - return ip4addresses; - } - - private: - absl::Mutex state_mutex_; - ActiveConnectionState state_ ABSL_GUARDED_BY(state_mutex_); - ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_); -}; - -class NetworkManagerObjectManager final - : public sdbus::ProxyInterfaces { - public: - NetworkManagerObjectManager(const NetworkManagerObjectManager &) = delete; - NetworkManagerObjectManager(NetworkManagerObjectManager &&) = delete; - NetworkManagerObjectManager &operator=(const NetworkManagerObjectManager &) = - delete; - NetworkManagerObjectManager &operator=(NetworkManagerObjectManager &&) = - delete; - explicit NetworkManagerObjectManager(sdbus::IConnection &system_bus) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - "/org/freedesktop") { - registerProxy(); - } - ~NetworkManagerObjectManager() { unregisterProxy(); } - - std::unique_ptr GetIp4Config( - const sdbus::ObjectPath &access_point); - std::unique_ptr - GetActiveConnectionForAccessPoint(const sdbus::ObjectPath &access_point_path, - const sdbus::ObjectPath &device_path); - - protected: - void onInterfacesAdded( - const sdbus::ObjectPath &objectPath, - const std::map> - &interfacesAndProperties) override {} - void onInterfacesRemoved( - const sdbus::ObjectPath &objectPath, - const std::vector &interfaces) override {} -}; - class NetworkManagerWifiMedium : public api::WifiMedium, public sdbus::ProxyInterfaces< From faea2a395a33a84fb09b2264ae335098365c0fc4 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 19:06:04 +0530 Subject: [PATCH 094/201] Refactor --- .../implementation/linux/wifi_medium.cc | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 33bdcce5..982c1072 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -37,7 +37,7 @@ api::WifiCapability &NetworkManagerWifiMedium::GetCapability() { try { auto cap_mask = WirelessCapabilities(); // https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMDeviceWifiCapabilities - capability_.supports_5_ghz = (cap_mask & 0x00000400); + capability_.supports_5_ghz = (cap_mask & 0x00000400) != 0; capability_.supports_6_ghz = false; capability_.support_wifi_direct = true; } catch (const sdbus::Error &e) { @@ -121,13 +121,13 @@ bool NetworkManagerWifiMedium::Scan( // absl::MutexLock l(&scan_result_callback_lock_); // scan_result_callback_ = scan_result_callback; - // try { - // RequestScan(std::map()); - // } catch (const sdbus::Error &e) { - // scan_result_callback_ = std::nullopt; - // DBUS_LOG_METHOD_CALL_ERROR(&getProxy(), "RequestScan", e); - // return false; - // } + try { + RequestScan({}); + } catch (const sdbus::Error &e) { + scan_result_callback_ = std::nullopt; + DBUS_LOG_METHOD_CALL_ERROR(&getProxy(), "RequestScan", e); + return false; + } return false; } @@ -136,8 +136,12 @@ NetworkManagerWifiMedium::SearchBySSIDNoScan( std::vector &ssid_bytes) { absl::ReaderMutexLock l(&known_access_points_lock_); for (auto &[object_path, ap] : known_access_points_) { - if (ap->Ssid() == ssid_bytes) { - return ap; + try { + if (ap->Ssid() == ssid_bytes) { + return ap; + } + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(ap, "Ssid", e); } } From 5b5eb953e09513480eca062d6d754e0e72e4c35a Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 19:06:12 +0530 Subject: [PATCH 095/201] Use absl::flat_hash_map for known_access_points_. --- internal/platform/implementation/linux/wifi_medium.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 788741c9..b4ef095b 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -97,7 +97,7 @@ class NetworkManagerWifiMedium absl::MutexLock l(&known_access_points_lock_); known_access_points_.erase(access_point); known_access_points_.emplace(access_point, - std::make_unique( + std::make_shared( getProxy().getConnection(), access_point)); } void onAccessPointRemoved(const sdbus::ObjectPath &access_point) override @@ -117,7 +117,8 @@ class NetworkManagerWifiMedium api::WifiInformation information_{false}; absl::Mutex known_access_points_lock_; - std::map> + absl::flat_hash_map> known_access_points_ ABSL_GUARDED_BY(known_access_points_lock_); absl::Mutex scan_result_callback_lock_; From 1376173a9ed8de46d6dc11f2d13597cfba08bd1e Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 19:20:36 +0530 Subject: [PATCH 096/201] GetInformation: Prevent potential UB while getting AP frequency --- .../implementation/linux/wifi_medium.cc | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 982c1072..da49c599 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,13 @@ api::WifiCapability &NetworkManagerWifiMedium::GetCapability() { return capability_; } +inline std::int32_t to_signed(std::uint32_t v) { + if (v <= INT_MAX) return static_cast(v); + if (v >= INT_MIN) return static_cast(v - INT_MIN) + INT_MIN; + + return INT_MAX; +} + api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { std::unique_ptr active_access_point; @@ -68,17 +76,17 @@ api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { information_ = api::WifiInformation{true, ssid, active_access_point->HwAddress(), - (int32_t)(active_access_point->Frequency())}; + to_signed(active_access_point->Frequency())}; NetworkManagerObjectManager manager(getProxy().getConnection()); auto ip4config = manager.GetIp4Config(active_access_point->getObjectPath()); if (ip4config != nullptr) { auto address_data = ip4config->AddressData(); - if (address_data.size() > 0) { + if (!address_data.empty()) { std::string address = address_data[0]["address"]; information_.ip_address_dot_decimal = address; - struct in_addr addr; + struct in_addr addr {}; inet_aton(address.c_str(), &addr); char addr_bytes[4]; @@ -176,9 +184,9 @@ NetworkManagerWifiMedium::SearchBySSID(absl::string_view ssid, DBUS_LOG_METHOD_CALL_ERROR(this, "RequestScan", e); } - auto scan_finish = [cur_last_scan, this]() { - this->last_scan_lock_.AssertReaderHeld(); - return cur_last_scan != this->last_scan_; + auto scan_finish = [&, cur_last_scan]() { + last_scan_lock_.AssertReaderHeld(); + return cur_last_scan != last_scan_; }; absl::Condition cond(&scan_finish); From e691cee79ad0ee78ee2012e6ecbef87aaba76812 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 30 Aug 2023 19:24:11 +0530 Subject: [PATCH 097/201] GetIP4Config: Avoid unnecessary lookups for unrelated connections. --- internal/platform/implementation/linux/network_manager.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/network_manager.cc b/internal/platform/implementation/linux/network_manager.cc index 32297138..4c10a96f 100644 --- a/internal/platform/implementation/linux/network_manager.cc +++ b/internal/platform/implementation/linux/network_manager.cc @@ -78,11 +78,11 @@ NetworkManagerObjectManager::GetIp4Config( auto props = interfaces[org::freedesktop::NetworkManager::Connection:: Active_proxy::INTERFACE_NAME]; sdbus::ObjectPath specific_object = props["SpecificObject"]; - sdbus::ObjectPath ip4config = props["Ip4Config"]; - - if (specific_object == active_connection) + if (specific_object == active_connection) { + sdbus::ObjectPath ip4config = props["Ip4Config"]; return std::make_unique( getProxy().getConnection(), ip4config); + } } } } From 0858eb9c84353b4c83edd7cd6644d2fe517cec07 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 31 Aug 2023 01:43:15 +0530 Subject: [PATCH 098/201] Print: Fix crash because of the buffer being freed incorrectly. --- internal/platform/implementation/linux/log_message.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index b8f898dd..c542b454 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -121,12 +121,11 @@ void LogMessage::Print(const char *format, ...) { va_list ap; va_start(ap, format); auto ret = vasprintf(&buf, format, ap); - va_end(ap); - - if (ret >= 0) { - free(buf); - log_streamer_.stream() << std::string(buf); + if (ret > 0) { + log_streamer_.stream() << std::string(buf, ret); } + if (buf != nullptr) free(buf); + va_end(ap); } std::ostream &LogMessage::Stream() { return log_streamer_.stream(); } From 30fe002422ab6d33c5eb8591be1885f217156cbb Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 31 Aug 2023 20:58:27 +0530 Subject: [PATCH 099/201] Reuse the Windows mutex implementation. --- .../implementation/linux/condition_variable.h | 2 +- .../platform/implementation/linux/mutex.h | 39 ++++++++----------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/internal/platform/implementation/linux/condition_variable.h b/internal/platform/implementation/linux/condition_variable.h index 03cdd17d..afde337e 100644 --- a/internal/platform/implementation/linux/condition_variable.h +++ b/internal/platform/implementation/linux/condition_variable.h @@ -25,7 +25,7 @@ namespace linux { class ConditionVariable : public api::ConditionVariable { public: explicit ConditionVariable(api::Mutex *mutex) - : mutex_(static_cast(mutex)->GetRegularMutex()) {} + : mutex_(&(static_cast(mutex)->GetMutex())) {} ~ConditionVariable() = default; Exception Wait() override { diff --git a/internal/platform/implementation/linux/mutex.h b/internal/platform/implementation/linux/mutex.h index 86f10d36..07df42aa 100644 --- a/internal/platform/implementation/linux/mutex.h +++ b/internal/platform/implementation/linux/mutex.h @@ -25,42 +25,37 @@ namespace nearby { namespace linux { class ABSL_LOCKABLE Mutex : public api::Mutex { public: - explicit Mutex(Mode mode) : mode_(mode) { - if (mode == Mode::kRecursive) - mutex_.emplace(); - else - mutex_.emplace(); - } - + explicit Mutex(Mode mode) : mode_(mode) {} ~Mutex() override = default; - Mutex(Mutex &&) = delete; - Mutex &operator=(Mutex &&) = delete; - Mutex(const Mutex &) = delete; - Mutex &operator=(const Mutex &) = delete; + Mutex(Mutex&&) = delete; + Mutex& operator=(Mutex&&) = delete; + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override { - if (auto mutex = std::get_if(&mutex_); mutex != nullptr) { - if (mode_ == Mode::kRegularNoCheck) { - mutex->ForgetDeadlockInfo(); - } - mutex->Lock(); + if (mode_ == Mode::kRegularNoCheck) mutex_.ForgetDeadlockInfo(); + if (mode_ == Mode::kRegular || mode_ == Mode::kRegularNoCheck) { + mutex_.Lock(); } else { - std::get_if(&mutex_)->lock(); + recursive_mutex_.lock(); } } void Unlock() ABSL_UNLOCK_FUNCTION() override { - if (auto mutex = std::get_if(&mutex_); mutex != nullptr) { - mutex->Unlock(); + if (mode_ == Mode::kRegular || mode_ == Mode::kRegularNoCheck) { + mutex_.Unlock(); } else { - std::get_if(&mutex_)->unlock(); + recursive_mutex_.unlock(); } } - absl::Mutex *GetRegularMutex() { return std::get_if(&mutex_); } + absl::Mutex& GetMutex() { return mutex_; } + std::recursive_mutex& GetRecursiveMutex() { return recursive_mutex_; } private: - std::variant mutex_; + friend class ConditionVariable; + absl::Mutex mutex_; + std::recursive_mutex recursive_mutex_; // The actual mutex allocation Mode mode_; }; } // namespace linux From 474b7833e4c0aa4ffc76d84c542db68cd6a1ee09 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Thu, 31 Aug 2023 21:00:01 +0530 Subject: [PATCH 100/201] Disable Start/StopWifiDirect for now. --- .../implementation/linux/wifi_direct.cc | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index f772f296..8aa605e2 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -157,26 +157,28 @@ bool NetworkManagerWifiDirectMedium::StartWifiDirect( WifiDirectCredentials *wifi_direct_credentials) { // According to the comments in the windows implementation, the wifi direct // medium is currently just a regular wifi hotspot. - auto wireless_device = std::make_unique( - network_manager_, system_bus_, wireless_device_->getObjectPath()); - auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, - std::move(wireless_device)); + // auto wireless_device = std::make_unique( + // network_manager_, system_bus_, wireless_device_->getObjectPath()); + // auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, + // std::move(wireless_device)); - HotspotCredentials hotspot_creds; - if (!hotspot.StartWifiHotspot(&hotspot_creds)) return false; + // HotspotCredentials hotspot_creds; + // if (!hotspot.StartWifiHotspot(&hotspot_creds)) return false; - wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID()); - wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword()); - return true; + // wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID()); + // wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword()); + // return true; + return false; } bool NetworkManagerWifiDirectMedium::StopWifiDirect() { - auto wireless_device = std::make_unique( - network_manager_, system_bus_, wireless_device_->getObjectPath()); - auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, - std::move(wireless_device)); + // auto wireless_device = std::make_unique( + // network_manager_, system_bus_, wireless_device_->getObjectPath()); + // auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, + // std::move(wireless_device)); - return hotspot.DisconnectWifiHotspot(); + // return hotspot.DisconnectWifiHotspot(); + return false; } } // namespace linux From b6b9d3b005de63a73f7d550c289f6877b04b800e Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 17:03:06 +0530 Subject: [PATCH 101/201] Move stream implementation to its own file. --- .../linux/bluetooth_classic_socket.h | 7 +++- ...{bluetooth_classic_socket.cc => stream.cc} | 41 ++++++++----------- .../platform/implementation/linux/stream.h | 8 ++-- 3 files changed, 26 insertions(+), 30 deletions(-) rename internal/platform/implementation/linux/{bluetooth_classic_socket.cc => stream.cc} (61%) diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index d69676a4..b7e49606 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -34,7 +34,12 @@ class BluetoothSocket final : public api::BluetoothSocket { nearby::InputStream &GetInputStream() override { return input_stream_; } nearby::OutputStream &GetOutputStream() override { return output_stream_; } - Exception Close() override; + Exception Close() override { + input_stream_.Close(); + output_stream_.Close(); + + return Exception{Exception::kSuccess}; + } api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; private: diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/stream.cc similarity index 61% rename from internal/platform/implementation/linux/bluetooth_classic_socket.cc rename to internal/platform/implementation/linux/stream.cc index 35c4d921..2f389fab 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/stream.cc @@ -19,42 +19,40 @@ #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" -#include "internal/platform/implementation/linux/bluetooth_classic_socket.h" +#include "internal/platform/implementation/linux/stream.h" namespace nearby { namespace linux { ExceptionOr InputStream::Read(std::int64_t size) { - if (!fd_.has_value()) return Exception::kIo; + if (!fd_.isValid()) return {Exception::kIo}; - char *data = new char[size]; - ssize_t ret = read(fd_->get(), data, size); + std::string buffer; + buffer.resize(size); + ssize_t ret = read(fd_.get(), buffer.data(), buffer.size()); if (ret == 0) { - delete[] data; return ExceptionOr(ByteArray()); - } else if (ret < 0) { - delete[] data; - return Exception::kIo; } + if (ret < 0) { + return {Exception::kIo}; + } + buffer.resize(ret); - return ExceptionOr(ByteArray(data, size)); + return ExceptionOr(ByteArray(std::move(buffer))); } Exception InputStream::Close() { - if (!fd_.has_value()) return Exception{Exception::kIo}; - - auto ret = close(fd_->get()) < 0 ? Exception{Exception::kIo} - : Exception{Exception::kSuccess}; + if (!fd_.isValid()) return Exception{Exception::kIo}; fd_.reset(); - return ret; + return {}; } Exception OutputStream::Write(const ByteArray &data) { - if (!fd_.has_value()) return Exception{Exception::kIo}; + if (!fd_.isValid()) return Exception{Exception::kIo}; size_t written = 0; while (written < data.size()) { - ssize_t ret = write(fd_->get(), data.data(), data.size()); + ssize_t ret = write(fd_.get(), data.data(), data.size()); if (ret < 1) { return Exception{Exception::kIo}; } @@ -66,20 +64,13 @@ Exception OutputStream::Write(const ByteArray &data) { Exception OutputStream::Flush() { return Exception{Exception::kSuccess}; } Exception OutputStream::Close() { - if (!fd_.has_value()) return Exception{Exception::kIo}; + if (!fd_.isValid()) return Exception{Exception::kIo}; - auto ret = close(fd_->get()) < 0 ? Exception{Exception::kIo} + auto ret = close(fd_.get()) < 0 ? Exception{Exception::kIo} : Exception{Exception::kSuccess}; fd_.reset(); return ret; } -Exception BluetoothSocket::Close() { - input_stream_.Close(); - output_stream_.Close(); - - return Exception{Exception::kSuccess}; -} - } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/stream.h b/internal/platform/implementation/linux/stream.h index a205faee..8034fa87 100644 --- a/internal/platform/implementation/linux/stream.h +++ b/internal/platform/implementation/linux/stream.h @@ -26,26 +26,26 @@ namespace nearby { namespace linux { class InputStream : public nearby::InputStream { public: - InputStream(sdbus::UnixFd &fd) : fd_(fd){}; + explicit InputStream(sdbus::UnixFd fd) : fd_(std::move(fd)){}; ExceptionOr Read(std::int64_t size) override; Exception Close() override; private: - std::optional fd_; + sdbus::UnixFd fd_; }; class OutputStream : public nearby::OutputStream { public: - OutputStream(sdbus::UnixFd &fd) : fd_(fd){}; + explicit OutputStream(sdbus::UnixFd fd) : fd_(std::move(fd)){}; Exception Write(const ByteArray &data) override; Exception Flush() override; Exception Close() override; private: - std::optional fd_; + sdbus::UnixFd fd_; }; } // namespace linux From 1f08f1ab33bd9cae2db3872cde18cb16f1ef8869 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 17:03:23 +0530 Subject: [PATCH 102/201] Register: Set options to allow RFCOMM socket creation. --- .../platform/implementation/linux/bluetooth_bluez_profile.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index dfe1a880..9ae63ddb 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -126,6 +126,10 @@ bool ProfileManager::Register(std::optional name, std::map options; if (name.has_value()) { options["Name"] = std::string(*name); + options["RequireAuthorization"] = false; + options["RequireAuthentication"] = false; + options["Channel"] = static_cast(0); + options["PSM"] = static_cast(0); } RegisterProfile(profile->getObjectPath(), std::string(service_uuid), options); From 10f606ee5175ea89eda8dc4b012b698c6efb670f Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 19:58:05 +0530 Subject: [PATCH 103/201] Add BluetoothInputStream, BluetoothOutputStream. --- internal/platform/implementation/linux/BUILD | 39 +++--- .../linux/bluetooth_classic_socket.cc | 123 ++++++++++++++++++ .../linux/bluetooth_classic_socket.h | 57 +++++++- .../platform/implementation/linux/stream.cc | 12 +- 4 files changed, 203 insertions(+), 28 deletions(-) create mode 100644 internal/platform/implementation/linux/bluetooth_classic_socket.cc diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index b387c3e9..60e094a7 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -127,9 +127,9 @@ cc_library( "avahi.cc", "bluetooth_adapter.cc", "bluetooth_bluez_profile.cc", + "bluetooth_classic_socket.cc", "bluetooth_classic_device.cc", "bluetooth_classic_medium.cc", - "bluetooth_classic_socket.cc", "bluetooth_classic_server_socket.cc", "bluetooth_devices.cc", "bluetooth_pairing.cc", @@ -142,6 +142,7 @@ cc_library( "preferences_manager.cc", "preferences_repository.cc", "scheduled_executor.cc", + "stream.cc", "submittable_executor.cc", "system_clock.cc", "thread_pool.cc", @@ -212,6 +213,7 @@ cc_library( deps = [ "//internal/platform:base", "@nlohmann_json//:json", + ":types", ], ) @@ -221,25 +223,20 @@ cc_test( srcs = [ "atomic_boolean_test.cc", "atomic_reference_test.cc", - "ble_gatt_server_test.cc", - "ble_medium_test.cc", - "ble_v2_peripheral_test.cc", - "ble_v2_test.cc", - "bluetooth_adapter_test.cc", - "count_down_latch_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", - "utils_test.cc", - "webrtc_test.cc", + "mutex_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", + # "utils_test.cc", ], tags = ["notap"], deps = [ @@ -247,7 +244,7 @@ cc_test( ":crypto", ":test_utils", ":types", - ":windows", + ":linux", "//internal/platform:base", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc new file mode 100644 index 00000000..325cce9f --- /dev/null +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -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 +#include +#include +#include +#include +#include +#include + +#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 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 diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index b7e49606..7833aaa2 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -19,17 +19,66 @@ #include #include +#include #include #include "internal/platform/exception.h" #include "internal/platform/implementation/bluetooth_classic.h" -#include "internal/platform/implementation/linux/stream.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 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(api::BluetoothDevice &device, sdbus::UnixFd fd) + BluetoothSocket(api::BluetoothDevice &device, const sdbus::UnixFd &fd) : device_(device), output_stream_(fd), input_stream_(fd) {} nearby::InputStream &GetInputStream() override { return input_stream_; } @@ -44,8 +93,8 @@ class BluetoothSocket final : public api::BluetoothSocket { private: api::BluetoothDevice &device_; - OutputStream output_stream_; - InputStream input_stream_; + BluetoothOutputStream output_stream_; + BluetoothInputStream input_stream_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/stream.cc b/internal/platform/implementation/linux/stream.cc index 2f389fab..edfb1da2 100644 --- a/internal/platform/implementation/linux/stream.cc +++ b/internal/platform/implementation/linux/stream.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include @@ -20,6 +21,7 @@ #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/linux/stream.h" +#include "internal/platform/logging.h" namespace nearby { namespace linux { @@ -29,11 +31,13 @@ ExceptionOr InputStream::Read(std::int64_t size) { std::string buffer; buffer.resize(size); - ssize_t ret = read(fd_.get(), buffer.data(), buffer.size()); + ssize_t ret = recv(fd_.get(), buffer.data(), buffer.size(), MSG_WAITALL); if (ret == 0) { return ExceptionOr(ByteArray()); } if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": error reading from fd: " << std::strerror(errno); return {Exception::kIo}; } buffer.resize(ret); @@ -53,7 +57,9 @@ Exception OutputStream::Write(const ByteArray &data) { size_t written = 0; while (written < data.size()) { ssize_t ret = write(fd_.get(), data.data(), data.size()); - if (ret < 1) { + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": error writing to fd: " << std::strerror(errno); return Exception{Exception::kIo}; } written += ret; @@ -67,7 +73,7 @@ Exception OutputStream::Close() { if (!fd_.isValid()) return Exception{Exception::kIo}; auto ret = close(fd_.get()) < 0 ? Exception{Exception::kIo} - : Exception{Exception::kSuccess}; + : Exception{Exception::kSuccess}; fd_.reset(); return ret; } From 1449dc402d6318e9cee2c52870bcf7f3f7e1be19 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 19:58:44 +0530 Subject: [PATCH 104/201] StartWifiHotspot: Generate connection UUID in the correct format. --- internal/platform/implementation/linux/wifi_hotspot.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 58891d76..3fdf4599 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -141,7 +141,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( return false; } - char id_cstr[SD_ID128_STRING_MAX]; + char id_cstr[SD_ID128_UUID_STRING_MAX]; sd_id128_to_string(id, id_cstr); std::string ssid = absl::StrCat("DIRECT-", id_cstr); @@ -163,7 +163,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( << std::strerror(ret); return false; } - sd_id128_to_string(id, id_cstr); + sd_id128_to_uuid_string(id, id_cstr); std::vector ssid_bytes(ssid.begin(), ssid.end()); std::map> From 3a22a870742d04699f9c3f54656327c0b79d51e7 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 19:59:08 +0530 Subject: [PATCH 105/201] WiFiLanSocket: Don't store an extra copy of the FD. --- internal/platform/implementation/linux/wifi_lan_socket.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_lan_socket.h b/internal/platform/implementation/linux/wifi_lan_socket.h index 016b7190..63c29b63 100644 --- a/internal/platform/implementation/linux/wifi_lan_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_socket.h @@ -29,7 +29,7 @@ namespace linux { class WifiLanSocket : public api::WifiLanSocket { public: explicit WifiLanSocket(sdbus::UnixFd fd) - : fd_(fd), output_stream_(fd), input_stream_(fd) {} + : output_stream_(fd), input_stream_(fd) {} nearby::InputStream &GetInputStream() override { return input_stream_; }; nearby::OutputStream &GetOutputStream() override { return output_stream_; }; @@ -41,7 +41,6 @@ class WifiLanSocket : public api::WifiLanSocket { }; private: - sdbus::UnixFd fd_; OutputStream output_stream_; InputStream input_stream_; }; From 14b12e9afc7c1386ab871002ec47b66fa0cbc656 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 19:59:38 +0530 Subject: [PATCH 106/201] Add support for request cancellation to GetServiceRecordFD. --- .../linux/bluetooth_bluez_profile.cc | 31 ++++++++++++------- .../linux/bluetooth_bluez_profile.h | 7 +++-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 9ae63ddb..2f51f187 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -196,19 +196,20 @@ std::optional ProfileManager::GetServiceRecordFD( << 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()); }; - profile->connections_lock_.Lock(); - profile->connections_lock_.Await(absl::Condition(&cond)); + + absl::MutexLock connections_lock(&profile->connections_lock_, + absl::Condition(&cond)); if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) { - NEARBY_LOGS(WARNING) + NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() << ": " << remote_device.GetMacAddress() - << ": Cancelled waiting for a service record for profile " + << ": Cancelled waiting for a new connection on profile " << service_uuid; - profile->connections_lock_.Unlock(); return std::nullopt; } @@ -216,15 +217,15 @@ std::optional ProfileManager::GetServiceRecordFD( profile->connections_[mac_addr].pop_back(); if (profile->connections_[mac_addr].empty()) profile->connections_.erase(mac_addr); - profile->connections_lock_.Unlock(); - return fd; + return std::move(fd); } // Listen for a connected profile on any device, returning the connected device // with its FD. std::optional, sdbus::UnixFd>> -ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { +ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, + const CancellationFlag &cancellation_flag) { if (!ProfileRegistered(service_uuid)) { return std::nullopt; } @@ -238,12 +239,20 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { << service_uuid; profile->connections_lock_.Lock(); - auto cond = [profile]() { + auto cond = [profile, &cancellation_flag]() { profile->connections_lock_.AssertReaderHeld(); - return !profile->connections_.empty(); + return !profile->connections_.empty() || cancellation_flag.Cancelled(); }; profile->connections_lock_.Await(absl::Condition(&cond)); + if (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(); @@ -258,7 +267,7 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid) { return std::nullopt; } - return std::pair(*maybe_device, fd); + return std::pair(*maybe_device, std::move(fd)); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index 06ee742e..c9cda470 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -53,9 +53,9 @@ class Profile final Profile(Profile &&) = delete; Profile &operator=(const Profile &) = delete; Profile &operator=(Profile &&) = delete; - Profile(sdbus::IConnection &system_bus, absl::string_view profile_object_path, + Profile(sdbus::IConnection &system_bus, sdbus::ObjectPath profile_object_path, BluetoothDevices &devices) - : AdaptorInterfaces(system_bus, std::string(profile_object_path)), + : AdaptorInterfaces(system_bus, std::move(profile_object_path)), released_(false), devices_(devices) { registerAdaptor(); @@ -130,7 +130,8 @@ class ProfileManager final ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); std::optional< std::pair, sdbus::UnixFd>> - GetServiceRecordFD(absl::string_view service_uuid) + GetServiceRecordFD(absl::string_view service_uuid, + const CancellationFlag &cancellation_flag) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); private: From 2e58a81cfc63da4a336fde3df1d2710aa9c769fe Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 20:00:27 +0530 Subject: [PATCH 107/201] BluetoothServerSocket: Cancel an ongoing Accept request on Close. --- .../linux/bluetooth_classic_server_socket.cc | 23 +++++++++++-------- .../linux/bluetooth_classic_server_socket.h | 2 ++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc index ec6d868c..d06741ca 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc @@ -13,34 +13,39 @@ // limitations under the License. #include "internal/platform/implementation/linux/bluetooth_classic_server_socket.h" -#include "absl/strings/str_replace.h" -#include "absl/strings/substitute.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/implementation/linux/bluez.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { std::unique_ptr BluetoothServerSocket::Accept() { - auto pair = profile_manager_.GetServiceRecordFD(service_uuid_); + 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()) { NEARBY_LOGS(ERROR) << __func__ << "Failed to get a new connection for profile " - << service_uuid_ << " for device "; + << service_uuid_; return nullptr; } auto [device, fd] = *pair; - return std::unique_ptr(new BluetoothSocket(device, fd)); + return std::make_unique(device, std::move(fd)); } Exception BluetoothServerSocket::Close() { - auto profile_object_path = - absl::Substitute("/com/google/nearby/profiles/$0", service_uuid_); - + NEARBY_LOGS(ERROR) << __func__ << ": closing bluetooth server socket"; + stopped_.Cancel(); profile_manager_.Unregister(service_uuid_); return {Exception::kSuccess}; diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h index 7efdd817..7697eefb 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.h @@ -16,6 +16,7 @@ #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" @@ -45,6 +46,7 @@ class BluetoothServerSocket final : public api::BluetoothServerSocket { Exception Close() override; private: + CancellationFlag stopped_; ProfileManager &profile_manager_; std::string service_uuid_; }; From ef1df07ce44676c7e18f5caf2d4dad50befae911 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 20:00:50 +0530 Subject: [PATCH 108/201] Set the initial value for AtomicBoolean. --- internal/platform/implementation/linux/atomic_boolean.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/atomic_boolean.h b/internal/platform/implementation/linux/atomic_boolean.h index e7e2a82d..cb067bdc 100644 --- a/internal/platform/implementation/linux/atomic_boolean.h +++ b/internal/platform/implementation/linux/atomic_boolean.h @@ -22,7 +22,7 @@ namespace linux { // A boolean value that may be updated atomically. class AtomicBoolean : public api::AtomicBoolean { public: - AtomicBoolean(bool initial_value) : atomic_boolean_(initial_value) {} + AtomicBoolean(bool initial_value = false) : atomic_boolean_(initial_value) {} ~AtomicBoolean() override = default; // Atomically read and return current value. From 06c1cc52ab261fbd4939daf4337867564085cf24 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 20:01:13 +0530 Subject: [PATCH 109/201] Minor refactor. --- internal/platform/implementation/linux/device_info.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 0d431426..c91a4956 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -79,14 +79,12 @@ api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { try { std::string chasis = hostnamed.Chassis(); api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; - if (chasis == "phone") { + 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; - } else if (chasis == "handset") { - device = api::DeviceInfo::DeviceType::kPhone; } return device; } catch (const sdbus::Error &e) { @@ -97,20 +95,20 @@ api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { std::optional DeviceInfo::GetFullName() const { struct passwd *pwd = getpwuid(getuid()); - if (!pwd) { + if (pwd == nullptr) { return std::nullopt; } char *name = strtok(pwd->pw_gecos, ","); std::wstring_convert, char16_t> convert; - return convert.from_bytes(name ? name : pwd->pw_gecos); + return convert.from_bytes(name == nullptr ? name : pwd->pw_gecos); } std::optional DeviceInfo::GetProfileUserName() const { struct passwd *pwd = getpwuid(getuid()); if (pwd == nullptr) { return std::nullopt; - } + } char *name = strtok(pwd->pw_gecos, ","); return std::string(name); } From 8602ac9c26f19d37af8c2951482b4bfcfe2c5ed2 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 20:02:40 +0530 Subject: [PATCH 110/201] ConnectToProfile: log about the connection attempt. --- .../platform/implementation/linux/bluetooth_classic_device.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index d1cc4425..05f0b2c8 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -109,6 +109,8 @@ void BluetoothDevice::onConnectProfileReply(const sdbus::Error *error) { } bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { + NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + << ": Attempting to connect to profile " << service_uuid; try { ConnectProfile(std::string(service_uuid)); return true; From a8199cf5c51b615dd45a5039a3da2d2a40d86053 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 1 Sep 2023 21:38:25 +0530 Subject: [PATCH 111/201] Disable AP isolation for softAP --- internal/platform/implementation/linux/wifi_hotspot.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 3fdf4599..d1b1715f 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -51,7 +51,7 @@ NetworkManagerWifiHotspotMedium::ConnectToService( NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" << port; - struct sockaddr_in addr{}; + struct sockaddr_in addr {}; addr.sin_addr.s_addr = inet_addr(std::string(ip_address).c_str()); addr.sin_family = AF_INET; addr.sin_port = htons(port); @@ -179,6 +179,8 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( {"802-11-wireless", std::map{ {"assigned-mac-address", "random"}, + {"ap-isolation", + static_cast(0)}, // NM_TERNARY_FALSE {"mode", "ap"}, {"ssid", ssid_bytes}, {"security", "802-11-wireless-security"}}}, From e39b475a496eda506262714aa8584ebd5833a4e9 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 2 Sep 2023 13:01:20 +0530 Subject: [PATCH 112/201] Fix typo. --- internal/platform/implementation/linux/device_info.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index c91a4956..9c28208e 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -101,7 +101,7 @@ std::optional DeviceInfo::GetFullName() const { char *name = strtok(pwd->pw_gecos, ","); std::wstring_convert, char16_t> convert; - return convert.from_bytes(name == nullptr ? name : pwd->pw_gecos); + return convert.from_bytes(name != nullptr ? name : pwd->pw_gecos); } std::optional DeviceInfo::GetProfileUserName() const { From be0379a3de3488a8d537647807e1c851fce6030b Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 2 Sep 2023 13:32:37 +0530 Subject: [PATCH 113/201] GetOsDeviceName: Use avahi's GetHostNameFqdn --- .../platform/implementation/linux/device_info.cc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 9c28208e..8a97814e 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -24,6 +24,7 @@ #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" @@ -63,13 +64,13 @@ DeviceInfo::DeviceInfo(sdbus::IConnection &system_bus) login_manager_(std::make_unique(system_bus_)) {} std::optional DeviceInfo::GetOsDeviceName() const { - Hostnamed hostnamed(system_bus_); + avahi::Server avahi(system_bus_); try { - std::string hostname = hostnamed.PrettyHostname(); + std::string hostname = avahi.GetHostNameFqdn(); std::wstring_convert, char16_t> convert; return convert.from_bytes(hostname); } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(&hostnamed, "PrettyHostname", e); + DBUS_LOG_PROPERTY_GET_ERROR(&avahi, "GetHostNameFqdn", e); return std::nullopt; } } @@ -105,12 +106,9 @@ std::optional DeviceInfo::GetFullName() const { } std::optional DeviceInfo::GetProfileUserName() const { - struct passwd *pwd = getpwuid(getuid()); - if (pwd == nullptr) { - return std::nullopt; - } - char *name = strtok(pwd->pw_gecos, ","); - return std::string(name); + char *logname = secure_getenv("LOGNAME"); + return logname == nullptr ? std::nullopt + : std::optional(std::string(logname)); } std::optional DeviceInfo::GetDownloadPath() const { From e95710907f2da448902f581dd0e8eff384c768ce Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 2 Sep 2023 22:04:07 +0530 Subject: [PATCH 114/201] Use CancellationFlagListener to ensure that Accept exits. --- .../linux/bluetooth_bluez_profile.cc | 24 ++++++++++++++++--- .../linux/bluetooth_bluez_profile.h | 2 +- .../linux/bluetooth_classic_server_socket.cc | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 2f51f187..ac66837e 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -27,6 +27,7 @@ #include #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" @@ -191,6 +192,14 @@ std::optional ProfileManager::GetServiceRecordFD( auto profile = registered_services_[std::string(service_uuid)]; registered_service_uuids_mutex_.ReaderUnlock(); + std::unique_ptr cancel_listener; + if (cancellation_flag != nullptr) + cancel_listener = std::make_unique( + 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; @@ -225,7 +234,7 @@ std::optional ProfileManager::GetServiceRecordFD( // with its FD. std::optional, sdbus::UnixFd>> ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, - const CancellationFlag &cancellation_flag) { + CancellationFlag *cancellation_flag) { if (!ProfileRegistered(service_uuid)) { return std::nullopt; } @@ -238,14 +247,23 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, << ": Attempting to get a FD for service " << service_uuid; + std::unique_ptr cancel_listener; + if (cancellation_flag != nullptr) + cancel_listener = std::make_unique( + 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.Cancelled(); + return !profile->connections_.empty() || + (cancellation_flag != nullptr && cancellation_flag->Cancelled()); }; profile->connections_lock_.Await(absl::Condition(&cond)); - if (cancellation_flag.Cancelled()) { + if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) { NEARBY_LOGS(VERBOSE) << __func__ << "Cancelled waiting for new connections on profile " << profile->getObjectPath(); diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index c9cda470..c92ab821 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -131,7 +131,7 @@ class ProfileManager final std::optional< std::pair, sdbus::UnixFd>> GetServiceRecordFD(absl::string_view service_uuid, - const CancellationFlag &cancellation_flag) + CancellationFlag *cancellation_flag) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); private: diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc index d06741ca..489423cc 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc @@ -31,7 +31,7 @@ std::unique_ptr BluetoothServerSocket::Accept() { << ": accepting new connections for service uuid " << service_uuid_; - auto pair = profile_manager_.GetServiceRecordFD(service_uuid_, stopped_); + auto pair = profile_manager_.GetServiceRecordFD(service_uuid_, &stopped_); if (!pair.has_value()) { NEARBY_LOGS(ERROR) << __func__ << "Failed to get a new connection for profile " From 5e18c84b98876c0f454160cd017840eaf419aea4 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 2 Sep 2023 22:04:32 +0530 Subject: [PATCH 115/201] Use separate locks for the the thread vector and task queue. --- .../implementation/linux/thread_pool.cc | 53 +++++++++++-------- .../implementation/linux/thread_pool.h | 15 +++--- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/internal/platform/implementation/linux/thread_pool.cc b/internal/platform/implementation/linux/thread_pool.cc index 209e2122..fe2d3164 100644 --- a/internal/platform/implementation/linux/thread_pool.cc +++ b/internal/platform/implementation/linux/thread_pool.cc @@ -34,21 +34,14 @@ ThreadPool::~ThreadPool() { ShutDown(); } bool ThreadPool::Start() { shut_down_.store(false, std::memory_order_acquire); - absl::MutexLock l(&mutex_); - if (!threads_.empty()) { - NEARBY_LOGS(ERROR) << __func__ << "thread pool is already active"; - return false; - } - - auto runner = [&]() { + auto runner = [this]() { while (true) { - if (shut_down_) { - return; - } - auto task = NextTask(); if (task == nullptr) { + if (shut_down_) { + return; + } NEARBY_LOGS(WARNING) << __func__ << ": Tried to run a null task."; continue; } @@ -56,6 +49,12 @@ bool ThreadPool::Start() { } }; + absl::MutexLock l(&threads_mutex_); + if (!threads_.empty()) { + NEARBY_LOGS(ERROR) << __func__ << "thread pool is already active"; + return false; + } + NEARBY_LOGS(INFO) << __func__ << ": Starting thread pool with " << max_pool_size_ << " threads"; @@ -72,43 +71,51 @@ bool ThreadPool::Run(Runnable &&task) { return false; } - absl::MutexLock l(&mutex_); - if (threads_.empty()) { - NEARBY_LOGS(ERROR) << __func__ << ": thread pool is not active"; - return false; + { + absl::ReaderMutexLock l(&threads_mutex_); + if (threads_.empty()) { + NEARBY_LOGS(ERROR) << __func__ << ": thread pool is not active"; + return false; + } } + absl::MutexLock l(&tasks_mutex_); tasks_.push(std::move(task)); return true; } void ThreadPool::ShutDown() { - shut_down_.store(true, std::memory_order_acquire); - + { + absl::MutexLock l(&tasks_mutex_); + shut_down_.store(true, std::memory_order_acquire); + } NEARBY_LOGS(INFO) << __func__ << ": asked to shut down, waiting for active threads to stop"; { - absl::ReaderMutexLock l(&mutex_); + absl::ReaderMutexLock l(&threads_mutex_); for (auto &thread : threads_) { thread.join(); } } - absl::MutexLock l(&mutex_); + absl::MutexLock l(&threads_mutex_); threads_.clear(); NEARBY_LOGS(INFO) << __func__ << ": shut down thread pool"; } Runnable ThreadPool::NextTask() { Runnable task; - auto task_available = [&]() { - mutex_.AssertReaderHeld(); - return !tasks_.empty(); + auto task_available = [this]() { + this->tasks_mutex_.AssertReaderHeld(); + return !this->tasks_.empty() || this->shut_down_; }; { - absl::MutexLock l(&mutex_, absl::Condition(&task_available)); + absl::MutexLock l(&tasks_mutex_, absl::Condition(&task_available)); + if (shut_down_) { + return nullptr; + } task = std::move(tasks_.front()); tasks_.pop(); diff --git a/internal/platform/implementation/linux/thread_pool.h b/internal/platform/implementation/linux/thread_pool.h index 13f35cf6..45c0463c 100644 --- a/internal/platform/implementation/linux/thread_pool.h +++ b/internal/platform/implementation/linux/thread_pool.h @@ -38,23 +38,24 @@ class ThreadPool { explicit ThreadPool(size_t max_pool_size); ~ThreadPool(); - bool Start() ABSL_LOCKS_EXCLUDED(mutex_); + bool Start() ABSL_LOCKS_EXCLUDED(threads_mutex_); // Runs a task on thread pool. The result indicates whether the task is put // into the thread pool. - bool Run(Runnable &&task) ABSL_LOCKS_EXCLUDED(mutex_); + bool Run(Runnable &&task) ABSL_LOCKS_EXCLUDED(tasks_mutex_); - void ShutDown() ABSL_LOCKS_EXCLUDED(mutex_); + void ShutDown() ABSL_LOCKS_EXCLUDED(threads_mutex_); private: - Runnable NextTask() ABSL_LOCKS_EXCLUDED(mutex_); + Runnable NextTask() ABSL_LOCKS_EXCLUDED(tasks_mutex_); size_t max_pool_size_; std::atomic_bool shut_down_; - absl::Mutex mutex_; - std::vector threads_ ABSL_GUARDED_BY(mutex_); - std::queue tasks_ ABSL_GUARDED_BY(mutex_); + absl::Mutex threads_mutex_; + std::vector threads_ ABSL_GUARDED_BY(threads_mutex_); + absl::Mutex tasks_mutex_; + std::queue tasks_ ABSL_GUARDED_BY(tasks_mutex_); }; } // namespace linux } // namespace nearby From e8236aad625e1589f236ae07e30d989e23315112 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 3 Sep 2023 13:10:18 +0530 Subject: [PATCH 116/201] Use atexit to cleanup bus connections before exiting. --- internal/platform/implementation/linux/dbus.cc | 6 ++++++ internal/platform/implementation/linux/log_message.cc | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index 755d25e4..9bc9b775 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -28,12 +28,18 @@ static std::unique_ptr global_default_bus_connection = nullptr; static absl::once_flag bus_connection_init_; +static void disconnectBus() { + global_system_bus_connection = nullptr; + global_default_bus_connection = nullptr; +} + static void initBusConnections() { global_system_bus_connection = sdbus::createSystemBusConnection(); global_system_bus_connection->enterEventLoopAsync(); global_default_bus_connection = sdbus::createDefaultBusConnection("com.google.nearby"); global_default_bus_connection->enterEventLoopAsync(); + atexit(disconnectBus); } sdbus::IConnection &getSystemBusConnection() { diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index c542b454..0f2bc3b5 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -33,9 +33,14 @@ namespace nearby { static std::unique_ptr global_log_control_; static absl::once_flag log_control_init_; +static void cleanup_log_control() { + global_log_control_ = nullptr; +} + static void init_log_control(std::nullptr_t) { global_log_control_ = std::make_unique(linux::getDefaultBusConnection()); + atexit(cleanup_log_control); } namespace api { From ad7401616b2764e70a90346f807aa5fb55a532ae Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 5 Sep 2023 19:45:10 +0530 Subject: [PATCH 117/201] Refactor bluetooth code to use shared pointers instead of references. --- .../implementation/linux/bluetooth_adapter.cc | 4 +- .../implementation/linux/bluetooth_adapter.h | 21 +++----- .../linux/bluetooth_bluez_profile.cc | 20 ++++---- .../linux/bluetooth_bluez_profile.h | 3 +- .../linux/bluetooth_classic_medium.cc | 51 +++++++++---------- .../linux/bluetooth_classic_medium.h | 4 +- .../linux/bluetooth_classic_socket.h | 12 +++-- .../implementation/linux/bluetooth_devices.cc | 16 +++--- .../implementation/linux/bluetooth_devices.h | 18 ++++--- .../implementation/linux/bluetooth_pairing.cc | 26 +++++----- .../implementation/linux/bluetooth_pairing.h | 4 +- 11 files changed, 85 insertions(+), 94 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc index 3dba14f6..99f1bb0f 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ b/internal/platform/implementation/linux/bluetooth_adapter.cc @@ -17,7 +17,6 @@ #include "internal/platform/implementation/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" -#include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/generated/dbus/bluez/adapter_client.h" #include "internal/platform/logging.h" @@ -95,8 +94,7 @@ std::string BluetoothAdapter::GetName() const { } } -bool BluetoothAdapter::SetName(absl::string_view name, bool persist) { - persist_name_ = persist; +bool BluetoothAdapter::SetName(absl::string_view name, bool /*persist*/) { return SetName(name); } diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index e2573a8e..3d2bc900 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -37,21 +37,17 @@ class BluezAdapter : public sdbus::ProxyInterfaces { class BluetoothAdapter : public api::BluetoothAdapter { public: + BluetoothAdapter(const BluetoothAdapter &) = default; + BluetoothAdapter(BluetoothAdapter &&) = delete; + BluetoothAdapter &operator=(const BluetoothAdapter &) = default; + BluetoothAdapter &operator=(BluetoothAdapter &&) = delete; + BluetoothAdapter(sdbus::IConnection &system_bus, const sdbus::ObjectPath &adapter_object_path) : bluez_adapter_( - std::make_unique(system_bus, adapter_object_path)) {} + std::make_shared(system_bus, adapter_object_path)) {} - ~BluetoothAdapter() override { - if (!persist_name_) { - NEARBY_LOGS(INFO) << __func__ << "Resetting adapter Alias"; - try { - bluez_adapter_->Alias(""); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_SET_ERROR(bluez_adapter_, "Alias", e); - } - } - } + ~BluetoothAdapter() override = default; bool SetStatus(Status status) override; bool IsEnabled() const override; @@ -82,8 +78,7 @@ class BluetoothAdapter : public api::BluetoothAdapter { BluezAdapter &GetBluezAdapterObject() { return *bluez_adapter_; } private: - std::unique_ptr bluez_adapter_; - bool persist_name_; + std::shared_ptr bluez_adapter_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index ac66837e..f28128ae 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -62,7 +62,7 @@ void Profile::NewConnection( auto device = devices_.get_device_by_path(device_object_path); - if (!device.has_value()) { + if (device == nullptr) { NEARBY_LOGS(ERROR) << __func__ << "NewConection called with a device object we don't know about: " @@ -70,10 +70,10 @@ void Profile::NewConnection( throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); } - auto alias = device->get().Alias(); - auto mac_addr = device->get().Address(); + auto alias = device->Alias(); + auto mac_addr = device->Address(); NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() - << ": Connected to " << device->get().getObjectPath(); + << ": Connected to " << device->getObjectPath(); FDProperties props(fd_props); @@ -88,7 +88,7 @@ void Profile::NewConnection( void Profile::RequestDisconnection( const sdbus::ObjectPath &device_object_path) { auto device = devices_.get_device_by_path(device_object_path); - if (!device.has_value()) { + if (device == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() << ": RequestDisconnection called with a device object " "we don't know about: " @@ -96,7 +96,7 @@ void Profile::RequestDisconnection( throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); } - auto mac_addr = device->get().Address(); + auto mac_addr = device->Address(); NEARBY_LOGS(VERBOSE) << __func__ << ": Disconnection requested for device " << device_object_path; @@ -232,7 +232,7 @@ std::optional ProfileManager::GetServiceRecordFD( // Listen for a connected profile on any device, returning the connected device // with its FD. -std::optional, sdbus::UnixFd>> +std::optional, sdbus::UnixFd>> ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, CancellationFlag *cancellation_flag) { if (!ProfileRegistered(service_uuid)) { @@ -278,14 +278,14 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, if (it->second.empty()) profile->connections_.erase(it); profile->connections_lock_.Unlock(); - auto maybe_device = devices_.get_device_by_address(mac_addr); - if (!maybe_device.has_value()) { + 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(*maybe_device, std::move(fd)); + return std::pair(device, std::move(fd)); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index c92ab821..5e025b11 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -128,8 +128,7 @@ class ProfileManager final api::BluetoothDevice &remote_device, absl::string_view service_uuid, CancellationFlag *cancellation_flag) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); - std::optional< - std::pair, sdbus::UnixFd>> + std::optional, sdbus::UnixFd>> GetServiceRecordFD(absl::string_view service_uuid, CancellationFlag *cancellation_flag) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index bcabd7e3..4efb270e 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -34,14 +34,12 @@ namespace nearby { namespace linux { -BluetoothClassicMedium::BluetoothClassicMedium( - sdbus::IConnection &system_bus, - const sdbus::ObjectPath &adapter_object_path) +BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, + BluetoothAdapter &adapter) : ProxyInterfaces(system_bus, "org.bluez", "/"), - adapter_( - std::make_unique(system_bus, adapter_object_path)), + adapter_(adapter), devices_(std::make_unique( - system_bus, adapter_object_path, observers_)), + system_bus, adapter.GetObjectPath(), observers_)), profile_manager_( std::make_unique(system_bus, *devices_)) { registerProxy(); @@ -52,12 +50,12 @@ void BluetoothClassicMedium::onInterfacesAdded( const std::map> &interfaces) { auto path_prefix = absl::Substitute( - "$0/dev_", adapter_->GetBluezAdapterObject().getObjectPath()); + "$0/dev_", adapter_.GetBluezAdapterObject().getObjectPath()); if (object.find(path_prefix) != 0) { return; } - if (devices_->get_device_by_path(object).has_value()) { + if (devices_->get_device_by_path(object) != nullptr) { // Device already exists. return; } @@ -65,15 +63,15 @@ void BluetoothClassicMedium::onInterfacesAdded( if (interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1) { NEARBY_LOGS(INFO) << __func__ << ": Encountered new device at " << object; - auto &device = devices_->add_new_device(object); + auto device = devices_->add_new_device(object); if (discovery_cb_.has_value() && discovery_cb_->device_discovered_cb != nullptr) { - discovery_cb_->device_discovered_cb(device); + discovery_cb_->device_discovered_cb(*device); } for (const auto &observer : observers_.GetObservers()) { - observer->DeviceAdded(device); + observer->DeviceAdded(*device); } } } @@ -81,7 +79,7 @@ void BluetoothClassicMedium::onInterfacesAdded( void BluetoothClassicMedium::onInterfacesRemoved( const sdbus::ObjectPath &object, const std::vector &interfaces) { - auto path_prefix = absl::Substitute("$0/dev_", adapter_->GetObjectPath()); + auto path_prefix = absl::Substitute("$0/dev_", adapter_.GetObjectPath()); if (object.find(path_prefix) != 0) { return; } @@ -90,7 +88,7 @@ void BluetoothClassicMedium::onInterfacesRemoved( if (interface == org::bluez::Device1_proxy::INTERFACE_NAME) { { auto device = devices_->get_device_by_path(object); - if (!device.has_value()) { + if (device == nullptr) { NEARBY_LOGS(WARNING) << __func__ << ": received InterfacesRemoved for a device " "we don't know about: " @@ -120,10 +118,10 @@ bool BluetoothClassicMedium::StartDiscovery( try { NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on " - << adapter_->GetObjectPath(); - adapter_->GetBluezAdapterObject().StartDiscovery(); + << adapter_.GetObjectPath(); + adapter_.GetBluezAdapterObject().StartDiscovery(); } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter_->GetBluezAdapterObject(), + DBUS_LOG_METHOD_CALL_ERROR(&adapter_.GetBluezAdapterObject(), "StartDiscovery", e); discovery_cb_.reset(); return false; @@ -133,7 +131,7 @@ bool BluetoothClassicMedium::StartDiscovery( } bool BluetoothClassicMedium::StopDiscovery() { - auto &adapter = adapter_->GetBluezAdapterObject(); + auto &adapter = adapter_.GetBluezAdapterObject(); try { NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " @@ -153,7 +151,7 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( api::BluetoothDevice &remote_device, const std::string &service_uuid, CancellationFlag *cancellation_flag) { auto device_object_path = bluez::device_object_path( - adapter_->GetObjectPath(), remote_device.GetMacAddress()); + adapter_.GetObjectPath(), remote_device.GetMacAddress()); if (!profile_manager_->ProfileRegistered(service_uuid)) { if (!profile_manager_->Register("", service_uuid)) { NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " @@ -162,11 +160,10 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( } } - auto maybe_device = devices_->get_device_by_path(device_object_path); - if (!maybe_device.has_value()) return nullptr; + auto device = devices_->get_device_by_path(device_object_path); + if (device == nullptr) return nullptr; - auto &device = maybe_device->get(); - device.ConnectToProfile(service_uuid); + device->ConnectToProfile(service_uuid); auto fd = profile_manager_->GetServiceRecordFD(remote_device, service_uuid, cancellation_flag); @@ -179,7 +176,7 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( } return std::unique_ptr( - new BluetoothSocket(remote_device, fd.value())); + new BluetoothSocket(device, fd.value())); } std::unique_ptr @@ -201,18 +198,18 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, api::BluetoothDevice *BluetoothClassicMedium::GetRemoteDevice( const std::string &mac_address) { auto device = devices_->get_device_by_address(mac_address); - if (!device.has_value()) return nullptr; + if (device == nullptr) return nullptr; - return &(device->get()); + return device.get(); } std::unique_ptr BluetoothClassicMedium::CreatePairing( api::BluetoothDevice &remote_device) { auto device = devices_->get_device_by_address(remote_device.GetMacAddress()); - if (!device.has_value()) return nullptr; + if (device == nullptr) return nullptr; return std::unique_ptr( - new BluetoothPairing(*adapter_, *device)); + new BluetoothPairing(adapter_, device)); } } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 6d9240ad..96b511f0 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -48,7 +48,7 @@ class BluetoothClassicMedium final BluetoothClassicMedium &operator=(const BluetoothClassicMedium &) = delete; BluetoothClassicMedium &operator=(BluetoothClassicMedium &&) = delete; BluetoothClassicMedium(sdbus::IConnection &system_bus, - const sdbus::ObjectPath &adapter_object_path); + BluetoothAdapter &adapter); ~BluetoothClassicMedium() override { unregisterProxy(); }; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() @@ -119,7 +119,7 @@ class BluetoothClassicMedium final const std::vector &interfaces) override; private: - std::unique_ptr adapter_; + BluetoothAdapter adapter_; std::unique_ptr devices_; std::optional discovery_cb_; diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index 7833aaa2..58ffa2c8 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -24,6 +24,7 @@ #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" @@ -69,7 +70,7 @@ class BluetoothOutputStream : public nearby::OutputStream { explicit BluetoothOutputStream(sdbus::UnixFd fd) : fd_(std::move(fd)){}; Exception Write(const ByteArray &data) override; - Exception Flush() override {return {Exception::kSuccess};} + Exception Flush() override { return {Exception::kSuccess}; } Exception Close() override; private: @@ -78,8 +79,9 @@ class BluetoothOutputStream : public nearby::OutputStream { class BluetoothSocket final : public api::BluetoothSocket { public: - BluetoothSocket(api::BluetoothDevice &device, const sdbus::UnixFd &fd) - : device_(device), output_stream_(fd), input_stream_(fd) {} + BluetoothSocket(std::shared_ptr 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_; } @@ -89,10 +91,10 @@ class BluetoothSocket final : public api::BluetoothSocket { return Exception{Exception::kSuccess}; } - api::BluetoothDevice *GetRemoteDevice() override { return &device_; }; + api::BluetoothDevice *GetRemoteDevice() override { return device_.get(); }; private: - api::BluetoothDevice &device_; + std::shared_ptr device_; BluetoothOutputStream output_stream_; BluetoothInputStream input_stream_; }; diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 06e24166..e0aba216 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -24,21 +24,19 @@ namespace nearby { namespace linux { -std::optional> -BluetoothDevices::get_device_by_path( +std::shared_ptr BluetoothDevices::get_device_by_path( const sdbus::ObjectPath &device_object_path) { absl::ReaderMutexLock l(&devices_by_path_lock_); if (devices_by_path_.count(device_object_path) == 0) { - return std::nullopt; + return nullptr; } - auto &device = devices_by_path_.at(device_object_path); - return *device; + return devices_by_path_[device_object_path]; } -std::optional> -BluetoothDevices::get_device_by_address(const std::string &addr) { +std::shared_ptr 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); @@ -51,14 +49,14 @@ void BluetoothDevices::remove_device_by_path( devices_by_path_.erase(device_object_path); } -BluetoothDevice &BluetoothDevices::add_new_device( +std::shared_ptr BluetoothDevices::add_new_device( sdbus::ObjectPath device_object_path) { absl::MutexLock l(&devices_by_path_lock_); auto pair = devices_by_path_.emplace( std::string(device_object_path), std::make_unique( system_bus_, std::move(device_object_path), observers_)); - return *pair.first->second; + return pair.first->second; } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index e002c63f..feb190eb 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -21,6 +21,7 @@ #include #include +#include "absl/container/flat_hash_map.h" #include "absl/synchronization/mutex.h" #include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" @@ -37,17 +38,18 @@ class BluetoothDevices final { observers_(observers), adapter_object_path_(std::move(adapter_object_path)) {} - std::optional> get_device_by_path( - const sdbus::ObjectPath &); - std::optional> get_device_by_address( - const std::string &); - void remove_device_by_path(const sdbus::ObjectPath &); - BluetoothDevice &add_new_device(sdbus::ObjectPath); + std::shared_ptr get_device_by_path(const sdbus::ObjectPath &) + ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); + std::shared_ptr get_device_by_address(const std::string &); + void remove_device_by_path(const sdbus::ObjectPath &) + ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); + std::shared_ptr add_new_device(sdbus::ObjectPath) + ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); private: absl::Mutex devices_by_path_lock_; - std::map> - devices_by_path_; + absl::flat_hash_map> + devices_by_path_ ABSL_GUARDED_BY(devices_by_path_lock_); sdbus::IConnection &system_bus_; ObserverList &observers_; diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 50ea4203..9cc0b2f5 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -37,7 +37,7 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { << "Got error '" << error->getName() << "' with message '" << error->getMessage() << "' while pairing with device " - << device_.getObjectPath(); + << device_->getObjectPath(); if (name == "org.bluez.Error.AuthenticationCanceled") { err = api::BluetoothPairingCallback::PairingError::kAuthCanceled; @@ -60,9 +60,9 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { } } -BluetoothPairing::BluetoothPairing(BluetoothAdapter &adapter, - BluetoothDevice &remote_device) - : device_(remote_device), adapter_(adapter) {} +BluetoothPairing::BluetoothPairing( + BluetoothAdapter &adapter, std::shared_ptr remote_device) + : device_(std::move(remote_device)), adapter_(adapter) {} bool BluetoothPairing::InitiatePairing( api::BluetoothPairingCallback pairing_cb) { @@ -76,17 +76,17 @@ bool BluetoothPairing::InitiatePairing( bool BluetoothPairing::FinishPairing( std::optional pin_code) { - device_.set_pair_reply_callback([this](const sdbus::Error *error) { + device_->set_pair_reply_callback([this](const sdbus::Error *error) { this->pairing_reply_handler(error); }); try { - pair_async_call_ = device_.Pair(); + pair_async_call_ = device_->Pair(); } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while trying to initiate pairing for device " - << device_.getObjectPath(); + << device_->getObjectPath(); return false; } @@ -99,12 +99,12 @@ bool BluetoothPairing::CancelPairing() { pair_async_call_.cancel(); } - device_.CancelPairing(); + device_->CancelPairing(); } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while trying to cancel pairing for device " - << device_.getObjectPath(); + << device_->getObjectPath(); return false; } @@ -113,13 +113,13 @@ bool BluetoothPairing::CancelPairing() { bool BluetoothPairing::Unpair() { try { - adapter_.RemoveDeviceByObjectPath(device_.getObjectPath()); + adapter_.RemoveDeviceByObjectPath(device_->getObjectPath()); return true; } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while trying to unpair device " - << device_.getObjectPath() << " on adapter " + << device_->getObjectPath() << " on adapter " << adapter_.GetObjectPath(); return false; } @@ -127,13 +127,13 @@ bool BluetoothPairing::Unpair() { bool BluetoothPairing::IsPaired() { try { - bool bonded = device_.Bonded(); + bool bonded = device_->Bonded(); return bonded; } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while trying to get Bonded state for device " - << device_.getObjectPath(); + << device_->getObjectPath(); return false; } } diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index d1b2230d..768a43e0 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -31,7 +31,7 @@ namespace nearby { namespace linux { class BluetoothPairing final : public api::BluetoothPairing { public: - BluetoothPairing(BluetoothAdapter &adapter, BluetoothDevice &remote_device); + BluetoothPairing(BluetoothAdapter &adapter, std::shared_ptr remote_device); bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; bool FinishPairing(std::optional pin_code) override; @@ -44,7 +44,7 @@ class BluetoothPairing final : public api::BluetoothPairing { sdbus::PendingAsyncCall pair_async_call_; - BluetoothDevice &device_; + std::shared_ptr device_; linux::BluetoothAdapter &adapter_; api::BluetoothPairingCallback pairing_cb_; From 4042687b8d9ded5c71c2193561265fd49fc66070 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 5 Sep 2023 20:00:25 +0530 Subject: [PATCH 118/201] Add support for sharing DiscoveryCallbacks across BluetoothDevices. --- .../implementation/linux/bluetooth_classic_device.cc | 4 ++++ .../implementation/linux/bluetooth_classic_device.h | 7 +++++++ .../implementation/linux/bluetooth_classic_medium.cc | 9 +++++---- .../implementation/linux/bluetooth_classic_medium.h | 2 +- .../platform/implementation/linux/bluetooth_devices.cc | 2 +- .../platform/implementation/linux/bluetooth_devices.h | 2 +- internal/platform/implementation/linux/bluez.h | 1 + 7 files changed, 20 insertions(+), 7 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 05f0b2c8..b940d62d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -163,6 +163,10 @@ void MonitoredBluetoothDevice::onPropertiesChanged( for (auto &observer : observers_.GetObservers()) { observer->DeviceConnectedStateChanged(*this, it->second); } + } else if (it->first == bluez::DEVICE_NAME) { + auto callback = discovery_cb_.lock(); + if (callback != nullptr && callback->device_name_changed_cb != nullptr) + callback->device_name_changed_cb(*this); } } } diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 60fc280b..0226056f 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -96,6 +96,12 @@ class MonitoredBluetoothDevice final ObserverList &observers); ~MonitoredBluetoothDevice() override { unregisterProxy(); } + void SetDiscoveryCallback( + std::shared_ptr + &callback) { + discovery_cb_ = callback; + }; + protected: void onPropertiesChanged( const std::string &interfaceName, @@ -104,6 +110,7 @@ class MonitoredBluetoothDevice final private: ObserverList &observers_; + std::weak_ptr discovery_cb_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 4efb270e..3d3daa95 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -64,9 +64,9 @@ void BluetoothClassicMedium::onInterfacesAdded( NEARBY_LOGS(INFO) << __func__ << ": Encountered new device at " << object; auto device = devices_->add_new_device(object); - - if (discovery_cb_.has_value() && + if (discovery_cb_ != nullptr && discovery_cb_->device_discovered_cb != nullptr) { + device->SetDiscoveryCallback(discovery_cb_); discovery_cb_->device_discovered_cb(*device); } @@ -98,7 +98,7 @@ void BluetoothClassicMedium::onInterfacesRemoved( NEARBY_LOGS(INFO) << __func__ << ": Device " << object << " has been removed"; - if (discovery_cb_.has_value() && + if (discovery_cb_ != nullptr && discovery_cb_->device_lost_cb != nullptr) { discovery_cb_->device_lost_cb(*device); } @@ -114,7 +114,8 @@ void BluetoothClassicMedium::onInterfacesRemoved( bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { - discovery_cb_ = std::move(discovery_callback); + discovery_cb_ = + std::make_shared(std::move(discovery_callback)); try { NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on " diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 96b511f0..40d369a7 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -122,7 +122,7 @@ class BluetoothClassicMedium final BluetoothAdapter adapter_; std::unique_ptr devices_; - std::optional discovery_cb_; + std::shared_ptr discovery_cb_; std::unique_ptr profile_manager_; ObserverList observers_; diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index e0aba216..c50b7b93 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -49,7 +49,7 @@ void BluetoothDevices::remove_device_by_path( devices_by_path_.erase(device_object_path); } -std::shared_ptr BluetoothDevices::add_new_device( +std::shared_ptr BluetoothDevices::add_new_device( sdbus::ObjectPath device_object_path) { absl::MutexLock l(&devices_by_path_lock_); auto pair = devices_by_path_.emplace( diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index feb190eb..078dc0b2 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -43,7 +43,7 @@ class BluetoothDevices final { std::shared_ptr get_device_by_address(const std::string &); void remove_device_by_path(const sdbus::ObjectPath &) ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); - std::shared_ptr add_new_device(sdbus::ObjectPath) + std::shared_ptr add_new_device(sdbus::ObjectPath) ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); private: diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 3be9eb7b..049503ae 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -43,6 +43,7 @@ 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"; std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, absl::string_view mac_address); From 608d725b7fc428090254f986493887f7380961b3 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 5 Sep 2023 20:01:13 +0530 Subject: [PATCH 119/201] Construct BluetoothClassicMedium correctly. --- internal/platform/implementation/linux/platform.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 9e22395b..56648a1c 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -190,9 +190,9 @@ ImplementationPlatform::CreateBluetoothAdapter() { std::unique_ptr ImplementationPlatform::CreateBluetoothClassicMedium( BluetoothAdapter &adapter) { - auto path = static_cast(&adapter)->GetObjectPath(); return std::make_unique( - linux::getSystemBusConnection(), path); + linux::getSystemBusConnection(), + dynamic_cast(adapter)); } std::unique_ptr ImplementationPlatform::CreateBleMedium( @@ -205,6 +205,7 @@ ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { return std::make_unique(); } +namespace { static std::unique_ptr createWifiMedium( std::shared_ptr nm) { std::vector device_paths; @@ -246,6 +247,7 @@ static std::unique_ptr createWifiMedium( << ": couldn't find a wireless device on this system"; return nullptr; } +} // namespace std::unique_ptr ImplementationPlatform::CreateWifiMedium() { auto nm = From 1837e7cd3887dbbd7722f650e52fdc6e8d65d1f6 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 5 Sep 2023 20:16:40 +0530 Subject: [PATCH 120/201] BluetoothDevice: Inherit from ble_v2::BlePeripheral as well. --- .../linux/bluetooth_classic_device.cc | 2 ++ .../implementation/linux/bluetooth_classic_device.h | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index b940d62d..aa0c5373 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -17,6 +17,7 @@ #include #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/dbus.h" @@ -36,6 +37,7 @@ BluetoothDevice::BluetoothDevice(sdbus::IConnection &system_bus, } try { last_known_address_ = Address(); + unique_id_ = BluetoothUtils::ToNumber(last_known_address_); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(this, "Address", e); } diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 0226056f..e29920e9 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -24,6 +24,7 @@ #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.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/generated/dbus/bluez/device_client.h" @@ -32,8 +33,11 @@ namespace linux { // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. class BluetoothDevice : public api::BluetoothDevice, - public sdbus::ProxyInterfaces { + public sdbus::ProxyInterfaces, + public api::ble_v2::BlePeripheral { public: + using UniqueId = std::uint64_t; + BluetoothDevice(const BluetoothDevice &) = delete; BluetoothDevice(BluetoothDevice &&) = delete; BluetoothDevice &operator=(const BluetoothDevice &) = delete; @@ -42,12 +46,16 @@ class BluetoothDevice sdbus::ObjectPath device_object_path); ~BluetoothDevice() override { unregisterProxy(); } + // 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_; }; + bool ConnectToProfile(absl::string_view service_uuid); void set_pair_reply_callback( @@ -72,6 +80,7 @@ class BluetoothDevice absl::Mutex pair_callback_lock_; absl::AnyInvocable on_pair_reply_cb_ = DefaultCallback(); + UniqueId unique_id_; mutable absl::Mutex properties_mutex_; mutable std::string last_known_name_ ABSL_GUARDED_BY(properties_mutex_); From 40e57a07ef68beac86627fd532fa48f781102454 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 6 Sep 2023 19:53:03 +0530 Subject: [PATCH 121/201] Don't request a name for the default bus connection. --- internal/platform/implementation/linux/dbus.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index 9bc9b775..5a3d48f3 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -14,6 +14,7 @@ #include #include +#include #include @@ -36,8 +37,7 @@ static void disconnectBus() { static void initBusConnections() { global_system_bus_connection = sdbus::createSystemBusConnection(); global_system_bus_connection->enterEventLoopAsync(); - global_default_bus_connection = - sdbus::createDefaultBusConnection("com.google.nearby"); + global_default_bus_connection = sdbus::createDefaultBusConnection(); global_default_bus_connection->enterEventLoopAsync(); atexit(disconnectBus); } From 6b037b1b81325c18459a6d5edca63ea3122653ea Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 6 Sep 2023 23:08:06 +0530 Subject: [PATCH 122/201] Refactor --- .../platform/implementation/linux/avahi.h | 12 ++-- .../linux/bluetooth_bluez_profile.cc | 70 +++++++++---------- .../linux/bluetooth_bluez_profile.h | 3 +- .../linux/bluetooth_classic_medium.cc | 2 +- .../linux/bluetooth_classic_medium.h | 19 +++-- .../linux/bluetooth_classic_server_socket.cc | 7 +- .../platform/implementation/linux/bluez.cc | 18 ++++- .../platform/implementation/linux/bluez.h | 9 ++- 8 files changed, 79 insertions(+), 61 deletions(-) diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index 5ba38b4e..e7ed6e20 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -15,9 +15,10 @@ #ifndef PLATFORM_IMPL_LINUX_AVAHI_H_ #define PLATFORM_IMPL_LINUX_AVAHI_H_ +#include + #include #include -#include #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/generated/dbus/avahi/entrygroup_client.h" @@ -28,7 +29,7 @@ namespace nearby { namespace linux { namespace avahi { -class Server +class Server final : public sdbus::ProxyInterfaces { public: Server(sdbus::IConnection &system_bus) @@ -42,7 +43,7 @@ class Server } }; -class EntryGroup +class EntryGroup final : public sdbus::ProxyInterfaces { public: EntryGroup(sdbus::IConnection &system_bus, @@ -69,8 +70,9 @@ class EntryGroup } }; -class ServiceBrowser : public sdbus::ProxyInterfaces< - org::freedesktop::Avahi::ServiceBrowser_proxy> { +class ServiceBrowser final + : public sdbus::ProxyInterfaces< + org::freedesktop::Avahi::ServiceBrowser_proxy> { public: ServiceBrowser(sdbus::IConnection &system_bus, const sdbus::ObjectPath &service_browser_object_path, diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index f28128ae..2f0e1441 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -46,7 +46,7 @@ bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { void Profile::Release() { released_ = true; - NEARBY_LOGS(VERBOSE) << __func__ << "Profile object " << getObjectPath() + NEARBY_LOGS(VERBOSE) << __func__ << ": Profile object " << getObjectPath() << " has been released"; } @@ -54,7 +54,8 @@ void Profile::NewConnection( const sdbus::ObjectPath &device_object_path, const sdbus::UnixFd &fd, const std::map &fd_props) { if (released_) { - NEARBY_LOGS(ERROR) << __func__ << "NewConnection called on released object " + NEARBY_LOGS(ERROR) << __func__ + << ": NewConnection called on released object " << getObjectPath(); throw sdbus::Error("org.bluez.Error.Rejected", "NewConnection called on released object"); @@ -65,7 +66,7 @@ void Profile::NewConnection( if (device == nullptr) { NEARBY_LOGS(ERROR) << __func__ - << "NewConection called with a device object we don't know about: " + << ": NewConection called with a device object we don't know about: " << device_object_path; throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); } @@ -78,11 +79,7 @@ void Profile::NewConnection( FDProperties props(fd_props); absl::MutexLock l(&connections_lock_); - if (connections_.count(mac_addr) != 0) { - connections_[mac_addr].push_back(std::pair(fd, props)); - } else { - connections_[mac_addr] = std::vector{std::pair(fd, props)}; - } + connections_[mac_addr].push_back(std::pair(fd, props)); } void Profile::RequestDisconnection( @@ -104,7 +101,7 @@ void Profile::RequestDisconnection( if (connections_.count(mac_addr) == 0) { NEARBY_LOGS(ERROR) << __func__ - << "Disconnection requested, but we are not connected to this device"; + << ": Disconnection requested, but we are not connected to this device"; return; } @@ -113,7 +110,8 @@ void Profile::RequestDisconnection( bool ProfileManager::Register(std::optional name, absl::string_view service_uuid) { - if (ProfileRegistered(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; @@ -139,10 +137,7 @@ bool ProfileManager::Register(std::optional name, return false; } - { - absl::MutexLock l(®istered_service_uuids_mutex_); - registered_services_.emplace(service_uuid, profile); - } + registered_services_.emplace(service_uuid, profile); NEARBY_LOGS(INFO) << __func__ << ": Registered profile instancefor service uuid " @@ -152,7 +147,8 @@ bool ProfileManager::Register(std::optional name, } void ProfileManager::Unregister(absl::string_view service_uuid) { - if (!ProfileRegistered(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"; @@ -169,10 +165,7 @@ void ProfileManager::Unregister(absl::string_view service_uuid) { BLUEZ_LOG_METHOD_CALL_ERROR(&getProxy(), "UnregisterProfile", e); } - { - absl::MutexLock l(®istered_service_uuids_mutex_); - registered_services_.erase(std::string(service_uuid)); - } + registered_services_.erase(std::string(service_uuid)); } // Get a service record FD for a connected profile (identified by service_uuid) @@ -180,18 +173,18 @@ void ProfileManager::Unregister(absl::string_view service_uuid) { std::optional ProfileManager::GetServiceRecordFD( api::BluetoothDevice &remote_device, absl::string_view service_uuid, CancellationFlag *cancellation_flag) { - if (!ProfileRegistered(service_uuid)) { - NEARBY_LOGS(ERROR) << __func__ << ": Service " << service_uuid - << " is not registered"; - return std::nullopt; + std::shared_ptr 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(); - registered_service_uuids_mutex_.ReaderLock(); - auto profile = registered_services_[std::string(service_uuid)]; - registered_service_uuids_mutex_.ReaderUnlock(); - std::unique_ptr cancel_listener; if (cancellation_flag != nullptr) cancel_listener = std::make_unique( @@ -235,13 +228,16 @@ std::optional ProfileManager::GetServiceRecordFD( std::optional, sdbus::UnixFd>> ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, CancellationFlag *cancellation_flag) { - if (!ProfileRegistered(service_uuid)) { - return std::nullopt; - } + std::shared_ptr profile; - registered_service_uuids_mutex_.ReaderLock(); - auto profile = registered_services_[std::string(service_uuid)]; - registered_service_uuids_mutex_.ReaderUnlock(); + { + 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 " @@ -264,9 +260,9 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, 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(); + NEARBY_LOGS(VERBOSE) + << __func__ << ": Cancelled waiting for new connections on profile " + << profile->getObjectPath(); profile->connections_lock_.Unlock(); return std::nullopt; } diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index 5e025b11..31cc1bf3 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -47,7 +47,8 @@ namespace linux { class ProfileManager; class Profile final - : public sdbus::AdaptorInterfaces { + : public sdbus::AdaptorInterfaces { public: Profile(const Profile &) = delete; Profile(Profile &&) = delete; diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 3d3daa95..c1001391 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -38,7 +38,7 @@ BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, BluetoothAdapter &adapter) : ProxyInterfaces(system_bus, "org.bluez", "/"), adapter_(adapter), - devices_(std::make_unique( + devices_(std::make_shared( system_bus, adapter.GetObjectPath(), observers_)), profile_manager_( std::make_unique(system_bus, *devices_)) { diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 40d369a7..9a3b120a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -25,23 +25,20 @@ #include #include #include -#include -#include "absl/synchronization/mutex.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_devices.h" namespace nearby { namespace linux { // Container of operations that can be performed over the Bluetooth Classic // medium. -class BluetoothClassicMedium final +class BluetoothClassicMedium : public api::BluetoothClassicMedium, - sdbus::ProxyInterfaces { + protected sdbus::ProxyInterfaces { public: BluetoothClassicMedium(const BluetoothClassicMedium &) = delete; BluetoothClassicMedium(BluetoothClassicMedium &&) = delete; @@ -120,12 +117,14 @@ class BluetoothClassicMedium final private: BluetoothAdapter adapter_; - std::unique_ptr devices_; - - std::shared_ptr discovery_cb_; - - std::unique_ptr profile_manager_; ObserverList observers_; + + protected: + std::shared_ptr devices_; + + private: + std::shared_ptr discovery_cb_; + std::unique_ptr profile_manager_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc index 489423cc..f70162c8 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc @@ -33,9 +33,10 @@ std::unique_ptr BluetoothServerSocket::Accept() { auto pair = profile_manager_.GetServiceRecordFD(service_uuid_, &stopped_); if (!pair.has_value()) { - NEARBY_LOGS(ERROR) << __func__ - << "Failed to get a new connection for profile " - << service_uuid_; + if (!stopped_.Cancelled()) + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to get a new connection for profile " + << service_uuid_; return nullptr; } diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index 61bf0a02..ddd0eb55 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -28,14 +28,28 @@ std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, } sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) { - return absl::Substitute("/com/google/nearby/profiles/$0", - absl::StrReplaceAll(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(absl::string_view uuid) { + return absl::Substitute("/com/google/nearby/medium/ble/advertisement/$0", uuid); +} + } // namespace bluez } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 049503ae..12dbcb33 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -45,12 +45,17 @@ 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(absl::string_view uuid); class BluezObjectManager : public sdbus::ProxyInterfaces { From d0c6f5fc2638a3db794ef261d12f359a8760ca06 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 6 Sep 2023 23:12:21 +0530 Subject: [PATCH 123/201] Add an ObjectManager instance at / for both system and session bus connections. --- internal/platform/implementation/linux/dbus.cc | 11 ++++++++++- internal/platform/implementation/linux/dbus.h | 13 +++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index 5a3d48f3..1bbaa7b3 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -13,8 +13,8 @@ // limitations under the License. #include -#include #include +#include #include @@ -27,9 +27,13 @@ static std::unique_ptr global_system_bus_connection = nullptr; static std::unique_ptr global_default_bus_connection = nullptr; +static std::unique_ptr system_root_object_manager = nullptr; +static std::unique_ptr default_root_object_manager = nullptr; static absl::once_flag bus_connection_init_; static void disconnectBus() { + system_root_object_manager = nullptr; + default_root_object_manager = nullptr; global_system_bus_connection = nullptr; global_default_bus_connection = nullptr; } @@ -39,6 +43,11 @@ static void initBusConnections() { global_system_bus_connection->enterEventLoopAsync(); global_default_bus_connection = sdbus::createDefaultBusConnection(); global_default_bus_connection->enterEventLoopAsync(); + system_root_object_manager = + std::make_unique(*global_system_bus_connection); + default_root_object_manager = + std::make_unique(*global_default_bus_connection); + atexit(disconnectBus); } diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h index 7df2770c..a16b1fb6 100644 --- a/internal/platform/implementation/linux/dbus.h +++ b/internal/platform/implementation/linux/dbus.h @@ -15,7 +15,9 @@ #ifndef PLATFORM_IMPL_LINUX_DBUS_H_ #define PLATFORM_IMPL_LINUX_DBUS_H_ +#include #include +#include #include "internal/platform/logging.h" #define DBUS_LOG_METHOD_CALL_ERROR(p, m, e) \ @@ -46,6 +48,17 @@ namespace nearby { namespace linux { extern sdbus::IConnection &getSystemBusConnection(); extern sdbus::IConnection &getDefaultBusConnection(); +class RootObjectManager final + : public sdbus::AdaptorInterfaces { + public: + explicit RootObjectManager(sdbus::IConnection &system_bus) + : AdaptorInterfaces(system_bus, "/") { + registerAdaptor(); + } + ~RootObjectManager() { unregisterAdaptor(); } +}; + } // namespace linux } // namespace nearby #endif From e295e2eca28a1998dcd4eb3fc0471968d04487f7 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 8 Sep 2023 16:48:00 +0530 Subject: [PATCH 124/201] Allow marking/unmarking devices as lost. --- .../linux/bluetooth_classic_device.cc | 3 +- .../linux/bluetooth_classic_device.h | 7 ++++ .../implementation/linux/bluetooth_devices.cc | 37 +++++++++++++++++-- .../implementation/linux/bluetooth_devices.h | 26 ++++++++++--- 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index aa0c5373..2afa8db7 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -28,7 +28,8 @@ namespace linux { BluetoothDevice::BluetoothDevice(sdbus::IConnection &system_bus, sdbus::ObjectPath device_object_path) : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, - std::move(device_object_path)) { + std::move(device_object_path)), + lost_(false) { registerProxy(); try { last_known_name_ = Alias(); diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index e29920e9..6d5d934d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -15,6 +15,8 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ +#include + #include #include #include @@ -69,6 +71,10 @@ class BluetoothDevice on_pair_reply_cb_ = DefaultCallback(); } + void MarkLost() { lost_ = true; } + void UnmarkLost() { lost_ = false; } + bool Lost() const { return lost_; } + protected: void onConnectProfileReply(const sdbus::Error *error) override; void onPairReply(const sdbus::Error *error) override { @@ -81,6 +87,7 @@ class BluetoothDevice absl::AnyInvocable on_pair_reply_cb_ = DefaultCallback(); UniqueId unique_id_; + std::atomic_bool lost_; mutable absl::Mutex properties_mutex_; mutable std::string last_known_name_ ABSL_GUARDED_BY(properties_mutex_); diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index c50b7b93..43a0d1e7 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -12,18 +12,23 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include +#include #include #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/logging.h" namespace nearby { namespace linux { +static constexpr std::chrono::minutes kLostPeripheralsCleanupMinFreq(5); + std::shared_ptr BluetoothDevices::get_device_by_path( const sdbus::ObjectPath &device_object_path) { absl::ReaderMutexLock l(&devices_by_path_lock_); @@ -49,14 +54,40 @@ void BluetoothDevices::remove_device_by_path( 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"; + } + 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 BluetoothDevices::add_new_device( sdbus::ObjectPath device_object_path) { absl::MutexLock l(&devices_by_path_lock_); - auto pair = devices_by_path_.emplace( + auto [device_it, inserted] = devices_by_path_.emplace( std::string(device_object_path), - std::make_unique( + std::make_shared( system_bus_, std::move(device_object_path), observers_)); - return pair.first->second; + if (!inserted) device_it->second->UnmarkLost(); + return device_it->second; } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 078dc0b2..448c289c 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -15,6 +15,7 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_DEVICES_H_ +#include #include #include @@ -24,6 +25,7 @@ #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" @@ -41,19 +43,31 @@ class BluetoothDevices final { std::shared_ptr get_device_by_path(const sdbus::ObjectPath &) ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); std::shared_ptr get_device_by_address(const std::string &); - void remove_device_by_path(const sdbus::ObjectPath &) - ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); + std::shared_ptr 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 add_new_device(sdbus::ObjectPath) ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); - private: - absl::Mutex devices_by_path_lock_; - absl::flat_hash_map> - devices_by_path_ ABSL_GUARDED_BY(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: sdbus::IConnection &system_bus_; ObserverList &observers_; sdbus::ObjectPath adapter_object_path_; + + absl::Mutex devices_by_path_lock_; + absl::flat_hash_map> + devices_by_path_ ABSL_GUARDED_BY(devices_by_path_lock_); + std::chrono::time_point last_cleanup_ + ABSL_GUARDED_BY(devices_by_path_lock_); }; } // namespace linux } // namespace nearby From c62837a54660d716bb408a1739ad1a8d79f5a4c8 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 8 Sep 2023 16:48:28 +0530 Subject: [PATCH 125/201] Set discovery filter to "bredr" before starting discovery. --- .../linux/bluetooth_classic_medium.cc | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index c1001391..6a9ec652 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -117,13 +117,29 @@ bool BluetoothClassicMedium::StartDiscovery( discovery_cb_ = std::make_shared(std::move(discovery_callback)); + std::map filter; + filter["Transport"] = "bredr"; + auto &adapter = adapter_.GetBluezAdapterObject(); + try { - NEARBY_LOGS(INFO) << __func__ << ": Starting discovery on " - << adapter_.GetObjectPath(); - adapter_.GetBluezAdapterObject().StartDiscovery(); + adapter.SetDiscoveryFilter(filter); } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter_.GetBluezAdapterObject(), - "StartDiscovery", e); + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e); + return false; + } + try { + adapter.StartDiscovery(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); + return false; + } + + try { + NEARBY_LOGS(INFO) << __func__ << ": Starting BR/EDR discovery on " + << adapter_.GetObjectPath(); + adapter.StartDiscovery(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); discovery_cb_.reset(); return false; } From 2930c9319a2450a7b53fd6c1742f0994ca778ab0 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 8 Sep 2023 16:48:58 +0530 Subject: [PATCH 126/201] Add additional functions. --- .../platform/implementation/linux/bluez.cc | 34 ++++++++++++++++--- .../platform/implementation/linux/bluez.h | 5 ++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index ddd0eb55..dd4755c1 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -12,19 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/bluez.h" #include + #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(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) { @@ -46,8 +48,30 @@ sdbus::ObjectPath gatt_characteristic_path( return absl::Substitute("$0/char$1", service_path, num); } -sdbus::ObjectPath ble_advertisement_path(absl::string_view uuid) { - return absl::Substitute("/com/google/nearby/medium/ble/advertisement/$0", uuid); +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 diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 12dbcb33..4a10cbfe 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -20,6 +20,7 @@ #include #include "absl/strings/string_view.h" +#include "internal/platform/implementation/ble_v2.h" #include @@ -55,7 +56,9 @@ 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(absl::string_view uuid); +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 { From 324146d075aa913a1bdd92ae960131f5334b87de Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 8 Sep 2023 16:49:08 +0530 Subject: [PATCH 127/201] Remove unneeded functions, add UuidFromString. --- .../platform/implementation/linux/utils.cc | 358 ++---------------- .../platform/implementation/linux/utils.h | 55 +-- .../implementation/linux/utils_test.cc | 69 +--- 3 files changed, 40 insertions(+), 442 deletions(-) diff --git a/internal/platform/implementation/linux/utils.cc b/internal/platform/implementation/linux/utils.cc index 58c95ba5..c3c196cc 100644 --- a/internal/platform/implementation/linux/utils.cc +++ b/internal/platform/implementation/linux/utils.cc @@ -12,342 +12,40 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include "internal/platform/implementation/linux/utils.h" -// Standard C/C++ headers -#include -#include -#include -#include -#include -#include -#include - -// Third party headers -#include "absl/strings/ascii.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" - -// Nearby connections headers -#include "absl/strings/string_view.h" -#include "internal/platform/bluetooth_utils.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/implementation/crypto.h" -#include "internal/platform/logging.h" -#include "internal/platform/uuid.h" - -// Linux headers -#include -#include -#include -#include - namespace nearby { namespace linux { -namespace { +std::optional UuidFromString(const std::string &uuid_str) { + sd_id128_t uuid; + if (auto ret = sd_id128_from_string(uuid_str.c_str(), &uuid); ret < 0) + return std::nullopt; -std::string uint64_to_mac_address_string(uint64_t bluetoothAddress) { - std::string buffer = absl::StrFormat( - "%02llx:%02llx:%02llx:%02llx:%02llx:%02llx", bluetoothAddress >> 40, - (bluetoothAddress >> 32) & 0xff, (bluetoothAddress >> 24) & 0xff, - (bluetoothAddress >> 16) & 0xff, (bluetoothAddress >> 8) & 0xff, - bluetoothAddress & 0xff); + const int ONE = 1; + if (*(reinterpret_cast(&ONE)) == + 1) { // On a little endian platform + uint64_t msb = static_cast(uuid.bytes[7]) + + (static_cast(uuid.bytes[6]) << 8) + + (static_cast(uuid.bytes[5]) << 16) + + (static_cast(uuid.bytes[4]) << 24) + + (static_cast(uuid.bytes[3]) << 32) + + (static_cast(uuid.bytes[2]) << 40) + + (static_cast(uuid.bytes[1]) << 48) + + (static_cast(uuid.bytes[0]) << 56); + uint64_t lsb = static_cast(uuid.bytes[15]) + + (static_cast(uuid.bytes[14]) << 8) + + (static_cast(uuid.bytes[13]) << 16) + + (static_cast(uuid.bytes[12]) << 24) + + (static_cast(uuid.bytes[11]) << 32) + + (static_cast(uuid.bytes[10]) << 40) + + (static_cast(uuid.bytes[9]) << 48) + + (static_cast(uuid.bytes[8]) << 56); + return Uuid(msb, lsb); + } - return absl::AsciiStrToUpper(buffer); + return Uuid(uuid.qwords[0], uuid.qwords[1]); } - -uint64_t mac_address_string_to_uint64(absl::string_view mac_address) { - ByteArray mac_address_array = BluetoothUtils::FromString(mac_address); - uint64_t mac_address_uint64 = 0; - for (int i = 0; i < mac_address_array.size(); i++) { - mac_address_uint64 <<= 8; - mac_address_uint64 |= static_cast( - static_cast(*(mac_address_array.data() + i))); - } - return mac_address_uint64; -} - -std::string ipaddr_4bytes_to_dotdecimal_string( - absl::string_view ipaddr_4bytes) { - union addrs { - in_addr_t addr; - uint8_t bits[4]; - } address; - - address.bits[0] = ipaddr_4bytes[0]; - address.bits[1] = ipaddr_4bytes[1]; - address.bits[2] = ipaddr_4bytes[2]; - address.bits[3] = ipaddr_4bytes[3]; - - struct in_addr addr; - - addr.s_addr = address.addr; - char* ipv4_address = inet_ntoa(addr); - if (ipv4_address == nullptr) { - return {}; - } - - return std::string(ipv4_address); -} - -std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s) { - if (ipv4_s.empty()) { - return {}; - } - - struct in_addr addr; - - if (inet_aton(ipv4_s.c_str(), &addr) != 0) { - return {}; - } - - std::string ipv4_b = std::to_string(addr.s_addr); - - return std::string(); -} - -std::wstring string_to_wstring(std::string str) { - std::wstring_convert> converter; - return converter.from_bytes(str); -} - -std::string wstring_to_string(std::wstring wstr) { - std::wstring_convert> converter; - return converter.to_bytes(wstr); -} - -std::vector GetIpv4Addresses() { - std::vector result; - - struct ifaddrs* interface = nullptr; - char host[NI_MAXHOST]; - - if (getifaddrs(&interface) != 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Failed to get interfaces. Error: " - << strerror(errno); - freeifaddrs(interface); - return {}; - } - int status = 0; - for (struct ifaddrs* ifa = interface; ifa != nullptr; ifa = ifa->ifa_next) { - if (ifa->ifa_addr->sa_family == AF_INET) { - status = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, - NI_MAXHOST, nullptr, 0, NI_NUMERICHOST); - } - switch (status) { - case EAI_AGAIN: - NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " - << ifa->ifa_name - << " : The name could not be resolved at this time. " - << "Try again later."; - break; - case EAI_BADFLAGS: - NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " - << ifa->ifa_name - << " : The flags argument has an invalid value."; - break; - case EAI_FAIL: - NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " - << ifa->ifa_name - << " : A nonrecoverable error occured."; - break; - case EAI_FAMILY: - NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " - << ifa->ifa_name - << " : The address family was not recognized, " - << "or the address length was invalid for the " - << "specified family."; - break; - case EAI_MEMORY: - NEARBY_LOGS(ERROR) << __func__ << "Failed to get IP for interface: " - << ifa->ifa_name << " : Out of memory."; - break; - case EAI_NONAME: - NEARBY_LOGS(ERROR) - << __func__ << "Failed to get IP for interface: " << ifa->ifa_name - << " : The name does not resolve for the suplied arguments." - << " NI_NAMEREQD is set and the host's name cannot be located, " - << "or neither hostname nor service name were requsted."; - break; - case EAI_OVERFLOW: - NEARBY_LOGS(ERROR) - << __func__ << "Failed to get IP for interface: " << ifa->ifa_name - << " : The bugger pointed to by `host` or `serv` was too small."; - break; - case EAI_SYSTEM: - NEARBY_LOGS(ERROR) << __func__ - << "A system error occured. Error code: " << errno - << ": " << strerror(errno); - break; - } - } - freeifaddrs(interface); - return result; -} - -std::vector Get4BytesIpv4Addresses() { - std::vector result; - std::vector ipv4_addresses = GetIpv4Addresses(); - for (const auto& ipv4_address : ipv4_addresses) { - // Converts IP address from x.x.x.x to 4 bytes format using utils function - result.push_back(ipaddr_dotdecimal_to_4bytes_string(ipv4_address)); - } - - return result; -} - -/* -Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid) { - int64_t data1 = guid.Data1; - int64_t data2 = guid.Data2; - int64_t data3 = guid.Data3; - - int64_t msb = ((data1 >> 24) & 0xff) << 56 | ((data1 >> 16) & 0xff) << 48 | - ((data1 >> 8) & 0xff) << 40 | ((data1)&0xff) << 32 | - ((data2 >> 8) & 0xff) << 24 | ((data2)&0xff) << 16 | - ((data3 >> 8) & 0xff) << 8 | (data3 & 0xff); - - int64_t lsb = - ((int64_t)guid.Data4[0]) << 56 | ((int64_t)guid.Data4[1]) << 48 | - ((int64_t)guid.Data4[2]) << 40 | ((int64_t)guid.Data4[3]) << 32 | - ((int64_t)guid.Data4[4]) << 24 | ((int64_t)guid.Data4[5]) << 16 | - ((int64_t)guid.Data4[6]) << 8 | (int64_t)guid.Data4[7]; - - return Uuid(msb, lsb); -} -*/ - -/* -winrt::guid nearby_uuid_to_winrt_guid(Uuid uuid) { - winrt::guid guid; - uint64_t msb = uuid.GetMostSigBits(); - guid.Data1 = ((msb >> 56) & 0xff) << 24 | ((msb >> 48) & 0xff) << 16 | - ((msb >> 40) & 0xff) << 8 | ((msb >> 32) & 0xff); - guid.Data2 = ((msb >> 24) & 0xff) << 8 | ((msb >> 16) & 0xff); - guid.Data3 = ((msb >> 8) & 0xff) << 8 | (msb & 0xff); - uint64_t lsb = uuid.GetLeastSigBits(); - guid.Data4[0] = (lsb >> 56) & 0xff; - guid.Data4[1] = (lsb >> 48) & 0xff; - guid.Data4[2] = (lsb >> 40) & 0xff; - guid.Data4[3] = (lsb >> 32) & 0xff; - guid.Data4[4] = (lsb >> 24) & 0xff; - guid.Data4[5] = (lsb >> 16) & 0xff; - guid.Data4[6] = (lsb >> 8) & 0xff; - guid.Data4[7] = lsb & 0xff; - return guid; -} -*/ - -/* -bool is_nearby_uuid_equal_to_winrt_guid(const Uuid& uuid, - const ::winrt::guid& guid) { - return uuid == winrt_guid_to_nearby_uuid(guid); -} -*/ - -ByteArray Sha256(absl::string_view input, size_t size) { - ByteArray hash = nearby::Crypto::Sha256(input); - return ByteArray{hash.data(), size}; -} -/* -bool InspectableReader::ReadBoolean(IInspectable inspectable) { - if (inspectable == nullptr) { - return false; - } - - auto property_value = - inspectable.try_as(); - if (property_value == nullptr) { - throw std::invalid_argument("no property value interface."); - } - if (property_value.Type() != - winrt::Windows::Foundation::PropertyType::Boolean) { - throw std::invalid_argument("not uin16 data type."); - } - - return property_value.GetBoolean(); -} - -uint16 InspectableReader::ReadUint16(IInspectable inspectable) { - if (inspectable == nullptr) { - return 0; - } - - auto property_value = - inspectable.try_as(); - if (property_value == nullptr) { - throw std::invalid_argument("no property value interface."); - } - if (property_value.Type() != - winrt::Windows::Foundation::PropertyType::UInt16) { - throw std::invalid_argument("not uin16 data type."); - } - - return property_value.GetUInt16(); -} - -uint32 InspectableReader::ReadUint32(IInspectable inspectable) { - if (inspectable == nullptr) { - return 0; - } - - auto property_value = - inspectable.try_as(); - if (property_value == nullptr) { - throw std::invalid_argument("no property value interface."); - } - if (property_value.Type() != - winrt::Windows::Foundation::PropertyType::UInt32) { - throw std::invalid_argument("not uin32 data type."); - } - - return property_value.GetUInt32(); -} - -std::string InspectableReader::ReadString(IInspectable inspectable) { - if (inspectable == nullptr) { - return ""; - } - - auto property_value = - inspectable.try_as(); - if (property_value == nullptr) { - throw std::invalid_argument("no property value interface."); - } - if (property_value.Type() != - winrt::Windows::Foundation::PropertyType::String) { - throw std::invalid_argument("not string data type."); - } - - return wstring_to_string(property_value.GetString().c_str()); -} - -std::vector InspectableReader::ReadStringArray( - IInspectable inspectable) { - std::vector result; - if (inspectable == nullptr) { - return result; - } - - auto property_value = - inspectable.try_as(); - if (property_value == nullptr) { - throw std::invalid_argument("no property value interface."); - } - if (property_value.Type() != - winrt::Windows::Foundation::PropertyType::StringArray) { - throw std::invalid_argument("not string array data type."); - } - - winrt::com_array strings; - property_value.GetStringArray(strings); - - for (winrt::hstring str : strings) { - result.push_back(winrt::to_string(str)); - } - return result; -} -*/ -} // namespace } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/utils.h b/internal/platform/implementation/linux/utils.h index ef43e77e..bf9b1b7e 100644 --- a/internal/platform/implementation/linux/utils.h +++ b/internal/platform/implementation/linux/utils.h @@ -16,68 +16,17 @@ #define PLATFORM_IMPL_LINUX_UTILS_H_ #include +#include #include #include #include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" #include "internal/platform/uuid.h" namespace nearby { namespace linux { -std::string uint64_to_mac_address_string(uint64_t bluetoothAddress); -uint64_t mac_address_string_to_uint64(absl::string_view mac_address); - -std::string ipaddr_4bytes_to_dotdecimal_string(absl::string_view ipaddr_4bytes); -std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s); - -// Helpers to linux platform -std::wstring string_to_wstring(std::string str); -std::string wstring_to_string(std::wstring wstr); -ByteArray Sha256(absl::string_view input, size_t size); - -// Reads the IPv4 addresses -std::vector GetIpv4Addresses(); -std::vector Get4BytesIpv4Addresses(); - -/* -// Help methods to convert between Uuid and winrt::guid -Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid); -winrt::guid nearby_uuid_to_winrt_guid(Uuid uuid); - -// Check whether Uuid and guid is the same value. -bool is_nearby_uuid_equal_to_winrt_guid(const Uuid& uuid, - const ::winrt::guid& guid); -*/ - -namespace Constants { -// The Id of the Service Name SDP attribute -const uint16_t SdpServiceNameAttributeId = 0x100; - -// The SDP Type of the Service Name SDP attribute. -// The first byte in the SDP Attribute encodes the SDP Attribute Type as -// follows: -// - the Attribute Type size in the least significant 3 bits, -// - the SDP Attribute Type value in the most significant 5 bits. -const char SdpServiceNameAttributeType = (4 << 3) | 5; - -// Possible values for the adapter type. Refer to: -// https://learn.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_info -const uint16_t kInterfaceTypeEthernet = 6; -const uint16_t kInterfaceTypeWifi = 71; -} // namespace Constants - -/* -class InspectableReader { - public: - static bool ReadBoolean(IInspectable inspectable); - static uint16_t ReadUint16(IInspectable inspectable); - static uint32_t ReadUint32(IInspectable inspectable); - static std::string ReadString(IInspectable inspectable); - static std::vector ReadStringArray(IInspectable inspectable); -}; -*/ +std::optional UuidFromString(const std::string &uuid_str); } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/utils_test.cc b/internal/platform/implementation/linux/utils_test.cc index 228252f9..a298b843 100644 --- a/internal/platform/implementation/linux/utils_test.cc +++ b/internal/platform/implementation/linux/utils_test.cc @@ -12,74 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/utils.h" - #include +#include "absl/strings/ascii.h" +#include "internal/platform/implementation/linux/utils.h" + #include "gtest/gtest.h" namespace nearby { namespace linux { -TEST(UtilsTests, MacAddressToString) { - // Arrange - const uint64_t input = 0x000034363bc70c71; - std::string expected = "34:36:3B:C7:0C:71"; +TEST(UtilsTests, UuidFromStringRoundTrip) { + std::string input = "b5209043-f493-4b38-8c34-810aa3cd1407"; - // Act - std::string result = uint64_to_mac_address_string(input); + auto nearby_uuid = UuidFromString(input); + EXPECT_TRUE(nearby_uuid.has_value()); - // Assert - EXPECT_EQ(result, expected); + + EXPECT_EQ(absl::AsciiStrToLower(std::string{*nearby_uuid}), + "b5209043-f493-4b38-8c34-810aa3cd1407"); } - -TEST(UtilsTests, StringToMacAddress) { - // Arrange - std::string input = "34:36:3B:C7:8C:71"; - const uint64_t expected = 0x000034363bc78c71; - - // Act - uint64_t result = mac_address_string_to_uint64(input); - - // Assert - EXPECT_EQ(result, expected); -} - -constexpr absl::string_view kIpDotdecimal{"192.168.1.37"}; - -constexpr char kIp4Bytes[] = {(char)192, (char)168, (char)1, (char)37}; - -TEST(UtilsTests, Ip4BytesToDotdecimal) { - std::string result = - ipaddr_4bytes_to_dotdecimal_string(absl::string_view(kIp4Bytes)); - - EXPECT_EQ(result, kIpDotdecimal); -} - -TEST(UtilsTests, IpDotdecimalTo4Bytes) { - std::string result = - ipaddr_dotdecimal_to_4bytes_string(std::string(kIpDotdecimal)); - - EXPECT_EQ(result, std::string(kIp4Bytes, 4)); -} - -/* -TEST(UtilsTests, ConvertBetweenWinrtGuidAndNearbyUuidSuccessfully) { - Uuid uuid(0x123e4567e89b12d3, 0xa456426614174000); - winrt::guid guid("{123e4567-e89b-12d3-a456-426614174000}"); - - EXPECT_EQ(uuid, winrt_guid_to_nearby_uuid(guid)); - EXPECT_EQ(nearby_uuid_to_winrt_guid(uuid), guid); - EXPECT_TRUE(is_nearby_uuid_equal_to_winrt_guid(uuid, guid)); -} - -TEST(UtilsTests, CompareWinrtGuidAndNearbyUuidSuccessfully) { - Uuid uuid(0x123e4567e89b12d3, 0xa456426614174000); - winrt::guid guid("123e4567-e89b-12d3-a456-426614074000"); - - EXPECT_NE(uuid, winrt_guid_to_nearby_uuid(guid)); -} -*/ - } // namespace linux } // namespace nearby From 242547398136b17157b9ab68702202f1d2756ae5 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 8 Sep 2023 16:49:35 +0530 Subject: [PATCH 128/201] Shutdown: return after shutting down executor. --- internal/platform/implementation/linux/submittable_executor.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/platform/implementation/linux/submittable_executor.cc b/internal/platform/implementation/linux/submittable_executor.cc index d9eb5ca2..ecf6e634 100644 --- a/internal/platform/implementation/linux/submittable_executor.cc +++ b/internal/platform/implementation/linux/submittable_executor.cc @@ -51,6 +51,7 @@ void SubmittableExecutor::Shutdown() { if (!shut_down_) { executor_->Shutdown(); shut_down_ = true; + return; } NEARBY_LOGS(ERROR) << "Error: " << __func__ From 54d31abedf388d257f2e06b723990be217871143 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Fri, 8 Sep 2023 16:53:49 +0530 Subject: [PATCH 129/201] Add an initial BLE v2 implementation. --- internal/platform/implementation/linux/BUILD | 16 +- .../implementation/linux/ble_gatt_server.cc | 147 ++++++ .../implementation/linux/ble_gatt_server.h | 96 ++++ .../implementation/linux/ble_v2_medium.cc | 436 ++++++++++++++++++ .../implementation/linux/ble_v2_medium.h | 104 ++++- .../linux/ble_v2_server_socket.h | 42 ++ .../linux/bluez_advertisement_monitor.cc | 73 +++ .../linux/bluez_advertisement_monitor.h | 95 ++++ .../bluez_advertisement_monitor_manager.h | 87 ++++ .../linux/bluez_gatt_characteristic.cc | 231 ++++++++++ .../linux/bluez_gatt_characteristic.h | 125 +++++ .../implementation/linux/bluez_gatt_manager.h | 44 ++ .../linux/bluez_gatt_service.cc | 63 +++ .../implementation/linux/bluez_gatt_service.h | 110 +++++ .../linux/bluez_le_advertisement.cc | 54 +++ .../linux/bluez_le_advertisement.h | 112 +++++ .../advertisement_monitor_manager_client.h | 57 +++ .../dbus/bluez/advertisement_monitor_server.h | 57 +++ .../dbus/bluez/gatt_characteristic_client.h | 89 ++++ .../dbus/bluez/gatt_characteristic_server.h | 59 +++ .../dbus/bluez/gatt_manager_client.h | 46 ++ .../dbus/bluez/gatt_service_server.h | 45 ++ .../bluez/le_advertisement_manager_client.h | 77 ++++ .../dbus/bluez/le_advertisement_server.h | 65 +++ .../bluez/org.bluez.AdvertisementMonitor1.xml | 27 ++ ...org.bluez.AdvertisementMonitorManager1.xml | 14 + .../bluez/org.bluez.GattCharacteristic1.xml | 28 ++ .../dbus/bluez/org.bluez.GattManager1.xml | 13 + .../dbus/bluez/org.bluez.GattService1.xml | 10 + .../dbus/bluez/org.bluez.LEAdvertisement1.xml | 21 + .../org.bluez.LEAdvertisementManager1.xml | 19 + .../platform/implementation/linux/platform.cc | 8 +- 32 files changed, 2442 insertions(+), 28 deletions(-) create mode 100644 internal/platform/implementation/linux/ble_gatt_server.cc create mode 100644 internal/platform/implementation/linux/ble_gatt_server.h create mode 100644 internal/platform/implementation/linux/ble_v2_medium.cc create mode 100644 internal/platform/implementation/linux/ble_v2_server_socket.h create mode 100644 internal/platform/implementation/linux/bluez_advertisement_monitor.cc create mode 100644 internal/platform/implementation/linux/bluez_advertisement_monitor.h create mode 100644 internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h create mode 100644 internal/platform/implementation/linux/bluez_gatt_characteristic.cc create mode 100644 internal/platform/implementation/linux/bluez_gatt_characteristic.h create mode 100644 internal/platform/implementation/linux/bluez_gatt_manager.h create mode 100644 internal/platform/implementation/linux/bluez_gatt_service.cc create mode 100644 internal/platform/implementation/linux/bluez_gatt_service.h create mode 100644 internal/platform/implementation/linux/bluez_le_advertisement.cc create mode 100644 internal/platform/implementation/linux/bluez_le_advertisement.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitor1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitorManager1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattManager1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattService1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisement1.xml create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisementManager1.xml diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 60e094a7..2658d196 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -55,8 +55,10 @@ cc_library( name = "comm", hdrs = [ "avahi.h", + "ble_gatt_server.h", "ble_medium.h", "ble_v2_medium.h", + "ble_v2_server_socket.h", "bluetooth_adapter.h", "bluetooth_bluez_profile.h", "bluetooth_classic_device.h", @@ -66,6 +68,12 @@ cc_library( "bluetooth_devices.h", "bluetooth_pairing.h", "bluez.h", + "bluez_advertisement_monitor.h", + "bluez_advertisement_monitor_manager.h", + "bluez_gatt_characteristic.h", + "bluez_gatt_manager.h", + "bluez_gatt_service.h", + "bluez_le_advertisement.h", "dbus.h", "network_manager.h", "network_manager_active_connection.h", @@ -125,6 +133,8 @@ cc_library( name = "linux", srcs = [ "avahi.cc", + "ble_gatt_server.cc", + "ble_v2_medium.cc", "bluetooth_adapter.cc", "bluetooth_bluez_profile.cc", "bluetooth_classic_socket.cc", @@ -134,6 +144,10 @@ cc_library( "bluetooth_devices.cc", "bluetooth_pairing.cc", "bluez.cc", + "bluez_advertisement_monitor.cc", + "bluez_gatt_characteristic.cc", + "bluez_gatt_service.cc", + "bluez_le_advertisement.cc", "dbus.cc", "executor.cc", "network_manager.cc", @@ -224,6 +238,7 @@ cc_test( "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", @@ -236,7 +251,6 @@ cc_test( # "submittable_executor_test.cc", # "thread_pool_test.cc", # "timer_test.cc", - # "utils_test.cc", ], tags = ["notap"], deps = [ diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc new file mode 100644 index 00000000..f943016a --- /dev/null +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -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.h" +#include "internal/platform/implementation/linux/bluez_gatt_manager.h" +#include "internal/platform/implementation/linux/bluez_gatt_service.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 +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( + 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 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 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 diff --git a/internal/platform/implementation/linux/ble_gatt_server.h b/internal/platform/implementation/linux/ble_gatt_server.h new file mode 100644 index 00000000..1ac26939 --- /dev/null +++ b/internal/platform/implementation/linux/ble_gatt_server.h @@ -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 + +#include + +#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.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 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( + std::move(server_cb))) {} + ~GattServer() override = default; + + api::ble_v2::BlePeripheral& GetBlePeripheral() override { + return local_peripheral_; + } + absl::optional 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 devices_; + BluetoothAdapter adapter_; + LocalBlePeripheral local_peripheral_; + + std::shared_ptr server_cb_; + absl::Mutex services_mutex_; + absl::flat_hash_map> services_ + ABSL_GUARDED_BY(services_mutex_); +}; + +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc new file mode 100644 index 00000000..56289bcc --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -0,0 +1,436 @@ +// 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 +#include + +#include +#include + +#include +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_gatt_server.h" +#include "internal/platform/implementation/linux/ble_v2_medium.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(sdbus::IConnection &system_bus, + BluetoothAdapter &adapter) + : system_bus_(system_bus), + adapter_(adapter), + devices_(std::make_unique( + system_bus_, adapter_.GetObjectPath(), observers_)), + adv_monitor_manager_( + bluez::AdvertisementMonitorManager:: + DiscoverAdvertisementMonitorManager(system_bus, adapter_)), + adv_manager_( + std::make_unique(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); + } + } +} + +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 +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 proxy = + sdbus::createProxy(system_bus_, "org.bluez", adapter_.GetObjectPath()); + proxy->finishRegistration(); + + std::shared_ptr shared_cb = + std::make_shared(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{}) + .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 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{std::move(stop_adv)}); +} + +std::unique_ptr BleV2Medium::StartGattServer( + api::ble_v2::ServerGattConnectionCallback callback) { + return std::make_unique(system_bus_, adapter_, devices_, + std::move(callback)); +} + +bool BleV2Medium::StartLEDiscovery() { + std::map filter; + filter["Transport"] = "le"; + 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) { + 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( + 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; + } + + 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 false; + } + + active_adv_monitors_[service_uuid] = std::move(monitor); + 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, adv_monitor] = *monitor_it; + 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 +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( + 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; + } + + 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::move(monitor); + return std::make_unique( + 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 = 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() << "'"; + } + + active_adv_monitors_.erase(service_uuid); + + auto &adapter = adapter_.GetBluezAdapterObject(); + try { + adapter.StopDiscovery(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); + return absl::InternalError(e.getMessage()); + } + return absl::OkStatus(); + }}); +} + +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 diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index ee0d1d7d..4c627b5b 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -15,41 +15,57 @@ #ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_ #define PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_ +#include + +#include + +#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_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/uuid.h" namespace nearby { namespace linux { -class BleV2Medium : public api::ble_v2::BleMedium { +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; + + BleV2Medium(sdbus::IConnection &system_bus ABSL_ATTRIBUTE_LIFETIME_BOUND, + BluetoothAdapter &adapter); + ~BleV2Medium() override = default; + bool StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, - api::ble_v2::AdvertiseParameters advertise_set_parameters) override { - return false; - } + api::ble_v2::AdvertiseParameters advertise_set_parameters) override + ABSL_LOCKS_EXCLUDED(cur_adv_mutex_); std::unique_ptr StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, api::ble_v2::AdvertiseParameters advertise_set_parameters, - AdvertisingCallback callback) override { - return nullptr; - } - bool StopAdvertising() override { return false; } + 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 { - return false; - } - bool StopScanning() override { return false; } + ScanCallback callback) override + ABSL_LOCKS_EXCLUDED(active_adv_monitors_mutex_); + bool StopScanning() override ABSL_LOCKS_EXCLUDED(active_adv_monitors_mutex_); std::unique_ptr StartScanning( const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, - ScanningCallback callback) override { - return nullptr; - }; + ScanningCallback callback) override; std::unique_ptr StartGattServer( - api::ble_v2::ServerGattConnectionCallback callback) override { - return nullptr; - } + api::ble_v2::ServerGattConnectionCallback callback) override; std::unique_ptr ConnectToGattServer( api::ble_v2::BlePeripheral &peripheral, @@ -60,7 +76,7 @@ class BleV2Medium : public api::ble_v2::BleMedium { std::unique_ptr OpenServerSocket( const std::string &service_id) override { - return nullptr; + return std::make_unique(); } std::unique_ptr Connect( @@ -71,13 +87,53 @@ class BleV2Medium : public api::ble_v2::BleMedium { } bool IsExtendedAdvertisementsAvailable() override { return false; } bool GetRemotePeripheral(const std::string &mac_address, - GetRemotePeripheralCallback callback) override { - return false; - } + GetRemotePeripheralCallback callback) override; bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, - GetRemotePeripheralCallback callback) override { - return false; + GetRemotePeripheralCallback callback) override; + + private: + bool StartLEDiscovery(); + + bool MonitorManagerSupportsOr() { + std::vector 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; } + + sdbus::IConnection &system_bus_; + BluetoothAdapter adapter_; + ObserverList observers_ = {}; + std::shared_ptr devices_; + + std::unique_ptr adv_monitor_manager_; + absl::Mutex active_adv_monitors_mutex_; + absl::flat_hash_map> + active_adv_monitors_ ABSL_GUARDED_BY(active_adv_monitors_mutex_); + // Used by the synchronous variant of StartScanning + std::optional cur_monitored_service_uuid_; + + std::unique_ptr adv_manager_; + + absl::Mutex cur_adv_mutex_; + std::unique_ptr cur_adv_ + ABSL_GUARDED_BY(cur_adv_mutex_); + + absl::Mutex advs_mutex_; + std::list> advs_ + ABSL_GUARDED_BY(advs_mutex_); }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/ble_v2_server_socket.h b/internal/platform/implementation/linux/ble_v2_server_socket.h new file mode 100644 index 00000000..ea6734c7 --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_server_socket.h @@ -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 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 diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc new file mode 100644 index 00000000..a695807a --- /dev/null +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc @@ -0,0 +1,73 @@ +#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 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 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); + std::map service_data; + try { + service_data = peripheral->ServiceData(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(peripheral, "ServiceData", e); + 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 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 diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.h b/internal/platform/implementation/linux/bluez_advertisement_monitor.h new file mode 100644 index 00000000..24e57696 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.h @@ -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 +#include +#include + +#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 { + 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 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 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>> Patterns() + override { + std::array service_id_data = service_uuid_.data(); + return {{0, + 0x16, + {static_cast(service_id_data[3] & 0xFF), + static_cast(service_id_data[2] & 0xFF)}}}; + }; + + std::shared_ptr devices_; + api::ble_v2::BleMedium::ScanCallback scan_callback_; + absl::AnyInvocable start_scanning_result_callback_; + + std::string type_; + Uuid service_uuid_; + api::ble_v2::TxPowerLevel tx_power_level_; +}; +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h b/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h new file mode 100644 index 00000000..e8ed5d57 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h @@ -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 +#include + +#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 + std::make_unique(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 + DiscoverAdvertisementMonitorManager(sdbus::IConnection &system_bus, + const BluetoothAdapter &adapter) { + bluez::BluezObjectManager manager(system_bus); + std::map>> + 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(system_bus, adapter); + } +}; +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic.cc new file mode 100644 index 00000000..e29b2b40 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic.cc @@ -0,0 +1,231 @@ +// 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 +#include +#include + +#include "internal/platform/byte_array.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluez_gatt_characteristic.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +namespace bluez { +void GattCharacteristic::Update(const nearby::ByteArray &value) { + std::vector 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 GattCharacteristic::NotifyChanged(bool confirm, + const ByteArray &new_value) { + std::vector 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 GattCharacteristic::ReadValue( + sdbus::Result> &&result, + std::map 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(offset), + [result = std::move(result), + this](absl::StatusOr data) { + const auto &status = data.status(); + if (status.ok()) { + auto str = data.value(); + std::vector 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 GattCharacteristic::WriteValue( + sdbus::Result<> &&result, std::vector value, + std::map 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_; + + if (type != "command") { + server_cb_->on_characteristic_write_cb( + *device, characteristic, static_cast(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()))); + } + }); + } else { + result.returnResults(); + } +} + +void GattCharacteristic::StartNotify() { + if ((characteristic_.property | + api::ble_v2::GattCharacteristic::Property::kNotify) == + api::ble_v2::GattCharacteristic::Property::kNotify) { + server_cb_->characteristic_subscription_cb(characteristic_); + notifying_ = true; + } else { + throw(sdbus::Error("org.bluez.Error.NotSupported")); + } +} + +void GattCharacteristic::StopNotify() { + if ((characteristic_.property | + api::ble_v2::GattCharacteristic::Property::kNotify) == + api::ble_v2::GattCharacteristic::Property::kNotify) { + server_cb_->characteristic_unsubscription_cb(characteristic_); + notifying_ = false; + } else { + throw(sdbus::Error("org.bluez.Error.Failed")); + } +} + +std::vector GattCharacteristic::Flags() { + auto characteristic = characteristic_; + std::vector 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"); + + 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 diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic.h b/internal/platform/implementation/linux/bluez_gatt_characteristic.h new file mode 100644 index 00000000..59aa231c --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic.h @@ -0,0 +1,125 @@ +// 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_H_ +#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 GattCharacteristic final + : public sdbus::AdaptorInterfaces { + public: + GattCharacteristic(const GattCharacteristic &) = delete; + GattCharacteristic(GattCharacteristic &&) = delete; + GattCharacteristic &operator=(const GattCharacteristic &) = delete; + GattCharacteristic &operator=(GattCharacteristic &&) = delete; + + GattCharacteristic( + sdbus::IConnection &system_bus, + const sdbus::ObjectPath &service_object_path, size_t num, + const api::ble_v2::GattCharacteristic &characteristic, + std::shared_ptr server_cb, + std::shared_ptr 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) { + registerAdaptor(); + NEARBY_LOGS(VERBOSE) + << __func__ << "Creating a " + << org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME + << " object at " << getObjectPath(); + } + ~GattCharacteristic() { 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> &&result, + std::map options) override + ABSL_LOCKS_EXCLUDED(cached_value_mutex_, static_value_mutex_); + void WriteValue(sdbus::Result<> &&result, std::vector value, + std::map 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 Flags() override; + std::vector Value() override + ABSL_LOCKS_EXCLUDED(cached_value_mutex_) { + absl::ReaderMutexLock lock(&cached_value_mutex_); + return cached_value_; + } + + std::shared_ptr devices_; + std::shared_ptr server_cb_; + api::ble_v2::GattCharacteristic characteristic_; + + // Set by `GattServer::UpdateCharacteristic()` + absl::Mutex static_value_mutex_; + std::optional> static_value_ + ABSL_GUARDED_BY(static_value_mutex_); + + sdbus::ObjectPath service_object_path_; + std::atomic_bool notifying_; + absl::Mutex cached_value_mutex_; + std::vector cached_value_ ABSL_GUARDED_BY(cached_value_mutex_); + + absl::Mutex confirmed_mutex_; + bool confirmed_; +}; + +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_gatt_manager.h b/internal/platform/implementation/linux/bluez_gatt_manager.h new file mode 100644 index 00000000..0c6830ca --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_manager.h @@ -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 +#include +#include + +#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h" +namespace nearby { +namespace linux { +namespace bluez { +class GattManager + : public sdbus::ProxyInterfaces { + 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 diff --git a/internal/platform/implementation/linux/bluez_gatt_service.cc b/internal/platform/implementation/linux/bluez_gatt_service.cc new file mode 100644 index 00000000..4ff2ef2d --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_service.cc @@ -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.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/bluez_gatt_characteristic.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 GattService::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 chr = + std::make_shared( + 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 GattService::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 diff --git a/internal/platform/implementation/linux/bluez_gatt_service.h b/internal/platform/implementation/linux/bluez_gatt_service.h new file mode 100644 index 00000000..5d3edff2 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_service.h @@ -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 +#include +#include +#include +#include + +#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.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 GattService final + : public sdbus::AdaptorInterfaces { + public: + GattService(const GattService &) = delete; + GattService(GattService &&) = delete; + GattService &operator=(const GattService &) = delete; + GattService &operator=(GattService &&) = delete; + + GattService( + sdbus::IConnection &system_bus, size_t num, const Uuid &service_uuid, + std::shared_ptr server_cb, + std::shared_ptr 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(); + } + + ~GattService() { + 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 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 Includes() override { return {}; } + + absl::Mutex characterstics_mutex_; + absl::flat_hash_map> + characteristics_ ABSL_GUARDED_BY(characterstics_mutex_); + + std::shared_ptr devices_; + std::shared_ptr server_cb_; + + const std::string uuid_; + const bool primary_; +}; +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.cc b/internal/platform/implementation/linux/bluez_le_advertisement.cc new file mode 100644 index 00000000..a64244c0 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_le_advertisement.cc @@ -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 + +#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 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 diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.h b/internal/platform/implementation/linux/bluez_le_advertisement.h new file mode 100644 index 00000000..c17cbc79 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_le_advertisement.h @@ -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 +#include +#include +#include +#include + +#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 { + 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 CreateLEAdvertisement( + sdbus::IConnection& system_bus, + const api::ble_v2::BleAdvertisementData& advertising_data, + api::ble_v2::AdvertiseParameters advertising_parameters) { + static std::atomic adv_count = 0; + auto object_path = bluez::ble_advertisement_path(adv_count++); + return std::make_unique( + 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 "broadcast"; } + std::vector ServiceUUIDs() override { return {}; } + std::map ManufacturerData() override { + return {}; + } + std::vector SolicitUUIDs() override { return {}; } + std::map ServiceData() override { + return service_data_; + } + std::vector 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 service_uuids_; + std::map service_data_; + api::ble_v2::AdvertiseParameters advertise_set_parameters_; +}; + +class LEAdvertisementManager final + : public sdbus::ProxyInterfaces { + 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 diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h new file mode 100644 index 00000000..6e8a86fa --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_manager_client.h @@ -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 +#include +#include + +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 SupportedMonitorTypes() + { + return proxy_.getProperty("SupportedMonitorTypes").onInterface(INTERFACE_NAME); + } + + std::vector SupportedFeatures() + { + return proxy_.getProperty("SupportedFeatures").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h new file mode 100644 index 00000000..1991ed31 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/advertisement_monitor_server.h @@ -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 +#include +#include + +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>> Patterns() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h new file mode 100644 index 00000000..a07c3802 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h @@ -0,0 +1,89 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__generated_dbus_bluez_gatt_characteristic_client_h__proxy__H__ +#define __sdbuscpp__generated_dbus_bluez_gatt_characteristic_client_h__proxy__H__ + +#include +#include +#include + +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 ReadValue(const std::map& options) + { + std::vector result; + proxy_.callMethod("ReadValue").onInterface(INTERFACE_NAME).withArguments(options).storeResultsTo(result); + return result; + } + + void WriteValue(const std::vector& value, const std::map& options) + { + proxy_.callMethod("WriteValue").onInterface(INTERFACE_NAME).withArguments(value, options); + } + + void StartNotify() + { + proxy_.callMethod("StartNotify").onInterface(INTERFACE_NAME); + } + + void StopNotify() + { + proxy_.callMethod("StopNotify").onInterface(INTERFACE_NAME); + } + + void Confirm() + { + proxy_.callMethod("Confirm").onInterface(INTERFACE_NAME); + } + +public: + std::string UUID() + { + return proxy_.getProperty("UUID").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Service() + { + return proxy_.getProperty("Service").onInterface(INTERFACE_NAME); + } + + std::vector Value() + { + return proxy_.getProperty("Value").onInterface(INTERFACE_NAME); + } + + bool Notifying() + { + return proxy_.getProperty("Notifying").onInterface(INTERFACE_NAME); + } + + std::vector Flags() + { + return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h new file mode 100644 index 00000000..451ac678 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_server.h @@ -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 +#include +#include + +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>&& result, std::map 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 value, std::map 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>&& result, std::map options) = 0; + virtual void WriteValue(sdbus::Result<>&& result, std::vector value, std::map 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 Value() = 0; + virtual bool Notifying() = 0; + virtual std::vector Flags() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h new file mode 100644 index 00000000..340ee0af --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_manager_client.h @@ -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 +#include +#include + +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& 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 diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h new file mode 100644 index 00000000..e37253a0 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_server.h @@ -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 +#include +#include + +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 Includes() = 0; + +private: + sdbus::IObject& object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h new file mode 100644 index 00000000..eb3125df --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h @@ -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 +#include +#include + +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& 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 SupportedIncludes() + { + return proxy_.getProperty("SupportedIncludes").onInterface(INTERFACE_NAME); + } + + std::vector SupportedSecondaryChannels() + { + return proxy_.getProperty("SupportedSecondaryChannels").onInterface(INTERFACE_NAME); + } + + std::vector SupportedFeatures() + { + return proxy_.getProperty("SupportedFeatures").onInterface(INTERFACE_NAME); + } + + std::map SupportedCapabilities() + { + return proxy_.getProperty("SupportedCapabilities").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h new file mode 100644 index 00000000..89f6c0ef --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h @@ -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 +#include +#include + +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 ServiceUUIDs() = 0; + virtual std::map ManufacturerData() = 0; + virtual std::vector SolicitUUIDs() = 0; + virtual std::map ServiceData() = 0; + virtual std::vector 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 diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitor1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitor1.xml new file mode 100644 index 00000000..c92058ef --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitor1.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitorManager1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitorManager1.xml new file mode 100644 index 00000000..5b9f2e4c --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.AdvertisementMonitorManager1.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1.xml new file mode 100644 index 00000000..f99de722 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattManager1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattManager1.xml new file mode 100644 index 00000000..e353715b --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattManager1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattService1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattService1.xml new file mode 100644 index 00000000..da4f8e70 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattService1.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisement1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisement1.xml new file mode 100644 index 00000000..6fc4dcb0 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisement1.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisementManager1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisementManager1.xml new file mode 100644 index 00000000..36bb0196 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.LEAdvertisementManager1.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 56648a1c..5895a0a3 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -196,13 +196,15 @@ ImplementationPlatform::CreateBluetoothClassicMedium( } std::unique_ptr ImplementationPlatform::CreateBleMedium( - BluetoothAdapter &) { - return std::make_unique(); + BluetoothAdapter &adapter) { + return nullptr; } std::unique_ptr ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { - return std::make_unique(); + return std::make_unique( + linux::getSystemBusConnection(), + dynamic_cast(adapter)); } namespace { From 498e77e0265e71b4a73ebdfbdb9eec21656925a6 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 12:55:05 +0530 Subject: [PATCH 130/201] Make ConnectProfile a sync method. --- .../linux/generated/dbus/bluez/device_client.h | 9 ++++----- .../linux/generated/dbus/bluez/org.bluez.Device1.xml | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/device_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/device_client.h index 54102d1e..7082f3a7 100644 --- a/internal/platform/implementation/linux/generated/dbus/bluez/device_client.h +++ b/internal/platform/implementation/linux/generated/dbus/bluez/device_client.h @@ -3,8 +3,8 @@ * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! */ -#ifndef __sdbuscpp__bluez_device_client_glue_h__proxy__H__ -#define __sdbuscpp__bluez_device_client_glue_h__proxy__H__ +#ifndef __sdbuscpp__device_client_h__proxy__H__ +#define __sdbuscpp__device_client_h__proxy__H__ #include #include @@ -26,7 +26,6 @@ protected: ~Device1_proxy() = default; - virtual void onConnectProfileReply(const sdbus::Error* error) = 0; virtual void onPairReply(const sdbus::Error* error) = 0; public: @@ -40,9 +39,9 @@ public: proxy_.callMethod("Connect").onInterface(INTERFACE_NAME); } - sdbus::PendingAsyncCall ConnectProfile(const std::string& UUID) + void ConnectProfile(const std::string& UUID) { - return proxy_.callMethodAsync("ConnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID).uponReplyInvoke([this](const sdbus::Error* error){ this->onConnectProfileReply(error); }); + proxy_.callMethod("ConnectProfile").onInterface(INTERFACE_NAME).withArguments(UUID); } void DisconnectProfile(const std::string& UUID) diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Device1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Device1.xml index afc55406..09bb7a6b 100644 --- a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Device1.xml +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.Device1.xml @@ -5,7 +5,6 @@ - From 0aee88a9ca0b6d0ff8cb1fa88756d8abfdff93d0 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 12:55:27 +0530 Subject: [PATCH 131/201] Call ConnectToProfile synchronously. --- .../implementation/linux/bluetooth_classic_device.cc | 10 +--------- .../implementation/linux/bluetooth_classic_device.h | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 2afa8db7..83135672 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -103,14 +103,6 @@ std::string BluetoothDevice::GetMacAddress() const { } } -void BluetoothDevice::onConnectProfileReply(const sdbus::Error *error) { - if (error != nullptr && error->getName() != "org.bluez.Error.InProgress") { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << error->getName() - << "' with message '" << error->getMessage() - << " while connecting to profile."; - } -} - bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() << ": Attempting to connect to profile " << service_uuid; @@ -120,7 +112,7 @@ bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { } catch (const sdbus::Error &e) { NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() - << "' while trying to asynchronously connect to profile " + << "' while trying to connect to profile " << service_uuid << " on device " << getObjectPath(); return false; } diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 6d5d934d..0f5c67fc 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -76,7 +76,6 @@ class BluetoothDevice bool Lost() const { return lost_; } protected: - void onConnectProfileReply(const sdbus::Error *error) override; void onPairReply(const sdbus::Error *error) override { absl::ReaderMutexLock l(&pair_callback_lock_); on_pair_reply_cb_(error); From d47788392e9388042e24336d3f28794504dd8d79 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 13:00:28 +0530 Subject: [PATCH 132/201] Add DeviceWatcher for adding/removing devices. --- .../implementation/linux/ble_v2_medium.cc | 35 +- .../implementation/linux/ble_v2_medium.h | 4 +- .../linux/bluetooth_bluez_profile.cc | 6 +- .../linux/bluetooth_classic_medium.cc | 397 ++++++++---------- .../linux/bluetooth_classic_medium.h | 30 +- .../implementation/linux/bluetooth_devices.cc | 98 +++++ .../implementation/linux/bluetooth_devices.h | 51 +++ 7 files changed, 349 insertions(+), 272 deletions(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 56289bcc..7b990bed 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -23,6 +23,7 @@ #include "internal/platform/implementation/ble_v2.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_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" @@ -215,13 +216,16 @@ bool BleV2Medium::StartLEDiscovery() { 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) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); - return false; + if (e.getName() != "org.bluez.Error.InProgress") { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); + return false; + } } return true; @@ -274,10 +278,13 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, return false; } + auto device_watcher = std::make_unique( + 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}); @@ -291,7 +298,8 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, return false; } - active_adv_monitors_[service_uuid] = std::move(monitor); + active_adv_monitors_[service_uuid] = + std::make_pair(std::move(monitor), std::move(device_watcher)); cur_monitored_service_uuid_ = service_uuid; return true; } @@ -320,12 +328,15 @@ bool BleV2Medium::StopScanning() { 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; - auto &[_uuid, adv_monitor] = *monitor_it; - NEARBY_LOGS(VERBOSE) << __func__ << ": Removing advertising monitor " - << adv_monitor->getObjectPath(); - adv_monitor->emitInterfacesRemovedSignal( - {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + 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; @@ -363,6 +374,8 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, return nullptr; } + auto device_watcher = std::make_unique( + system_bus_, adapter_.GetObjectPath(), devices_); if (!StartLEDiscovery()) { NEARBY_LOGS(ERROR) << __func__ << ": Could not start LE discovery on adapter " @@ -380,7 +393,9 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, return nullptr; } - active_adv_monitors_[service_uuid] = std::move(monitor); + active_adv_monitors_[service_uuid] = + std::make_pair(std::move(monitor), std::move(device_watcher)); + return std::make_unique( ScanningSession{.stop_scanning = [this, service_uuid]() { absl::MutexLock lock(&active_adv_monitors_mutex_); @@ -392,7 +407,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, "Advertising monitor for this service does not exist"); } - auto &monitor = active_adv_monitors_[service_uuid]; + auto &[monitor, watcher] = active_adv_monitors_[service_uuid]; try { monitor->emitInterfacesRemovedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index 4c627b5b..145f3106 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -120,7 +120,9 @@ class BleV2Medium final : public api::ble_v2::BleMedium { std::unique_ptr adv_monitor_manager_; absl::Mutex active_adv_monitors_mutex_; - absl::flat_hash_map> + absl::flat_hash_map< + Uuid, + std::pair, std::unique_ptr>> active_adv_monitors_ ABSL_GUARDED_BY(active_adv_monitors_mutex_); // Used by the synchronous variant of StartScanning std::optional cur_monitored_service_uuid_; diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 2f0e1441..5aa359eb 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -64,11 +64,7 @@ void Profile::NewConnection( auto device = devices_.get_device_by_path(device_object_path); if (device == nullptr) { - NEARBY_LOGS(ERROR) - << __func__ - << ": NewConection called with a device object we don't know about: " - << device_object_path; - throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); + device = devices_.add_new_device(device_object_path); } auto alias = device->Alias(); diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 6a9ec652..8a795f28 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -1,233 +1,164 @@ -// 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 -#include - -#include -#include - -#include "absl/strings/string_view.h" -#include "absl/strings/substitute.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/implementation/linux/bluez.h" -#include "internal/platform/implementation/linux/generated/dbus/bluez/device_client.h" -#include "internal/platform/logging.h" - -namespace nearby { -namespace linux { -BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, - BluetoothAdapter &adapter) - : ProxyInterfaces(system_bus, "org.bluez", "/"), - adapter_(adapter), - devices_(std::make_shared( - system_bus, adapter.GetObjectPath(), observers_)), - profile_manager_( - std::make_unique(system_bus, *devices_)) { - registerProxy(); -} - -void BluetoothClassicMedium::onInterfacesAdded( - const sdbus::ObjectPath &object, - const std::map> - &interfaces) { - auto path_prefix = absl::Substitute( - "$0/dev_", adapter_.GetBluezAdapterObject().getObjectPath()); - if (object.find(path_prefix) != 0) { - return; - } - - if (devices_->get_device_by_path(object) != nullptr) { - // Device already exists. - return; - } - - if (interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1) { - NEARBY_LOGS(INFO) << __func__ << ": Encountered new device at " << object; - - auto device = devices_->add_new_device(object); - if (discovery_cb_ != nullptr && - discovery_cb_->device_discovered_cb != nullptr) { - device->SetDiscoveryCallback(discovery_cb_); - discovery_cb_->device_discovered_cb(*device); - } - - for (const auto &observer : observers_.GetObservers()) { - observer->DeviceAdded(*device); - } - } -} - -void BluetoothClassicMedium::onInterfacesRemoved( - const sdbus::ObjectPath &object, - const std::vector &interfaces) { - auto path_prefix = absl::Substitute("$0/dev_", adapter_.GetObjectPath()); - if (object.find(path_prefix) != 0) { - return; - } - - for (const auto &interface : interfaces) { - if (interface == org::bluez::Device1_proxy::INTERFACE_NAME) { - { - 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); - } - - for (const auto &observer : observers_.GetObservers()) { - observer->DeviceRemoved(*device); - } - } - devices_->remove_device_by_path(object); - } - } -} - -bool BluetoothClassicMedium::StartDiscovery( - DiscoveryCallback discovery_callback) { - discovery_cb_ = - std::make_shared(std::move(discovery_callback)); - - std::map filter; - filter["Transport"] = "bredr"; - auto &adapter = adapter_.GetBluezAdapterObject(); - - try { - adapter.SetDiscoveryFilter(filter); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e); - return false; - } - try { - adapter.StartDiscovery(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); - return false; - } - - try { - NEARBY_LOGS(INFO) << __func__ << ": Starting BR/EDR discovery on " - << adapter_.GetObjectPath(); - adapter.StartDiscovery(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); - discovery_cb_.reset(); - return false; - } - - return true; -} - -bool BluetoothClassicMedium::StopDiscovery() { - auto &adapter = adapter_.GetBluezAdapterObject(); - - try { - NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " - << adapter.getObjectPath(); - - adapter.StopDiscovery(); - this->discovery_cb_.reset(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); - return false; - } - - return true; -} - -std::unique_ptr BluetoothClassicMedium::ConnectToService( - api::BluetoothDevice &remote_device, const std::string &service_uuid, - CancellationFlag *cancellation_flag) { - auto device_object_path = bluez::device_object_path( - adapter_.GetObjectPath(), remote_device.GetMacAddress()); - if (!profile_manager_->ProfileRegistered(service_uuid)) { - if (!profile_manager_->Register("", service_uuid)) { - NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " - << service_uuid << " with Bluez"; - return nullptr; - } - } - - auto device = devices_->get_device_by_path(device_object_path); - if (device == nullptr) return nullptr; - - device->ConnectToProfile(service_uuid); - - 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 " - << device_object_path; - return nullptr; - } - - return std::unique_ptr( - new BluetoothSocket(device, fd.value())); -} - -std::unique_ptr -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( - 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 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( - new BluetoothPairing(adapter_, device)); -} - -} // namespace linux -} // namespace nearby +// 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 +#include + +#include +#include + +#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/implementation/linux/bluez.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, + BluetoothAdapter &adapter) + : system_bus_(system_bus), + adapter_(adapter), + observers_(std::make_shared>()), + devices_(std::make_shared( + system_bus, adapter.GetObjectPath(), *observers_)), + device_watcher_(nullptr), + profile_manager_( + std::make_unique(system_bus, *devices_)) {} + +bool BluetoothClassicMedium::StartDiscovery( + DiscoveryCallback discovery_callback) { + device_watcher_ = std::make_unique( + system_bus_, adapter_.GetObjectPath(), devices_, + std::make_unique(std::move(discovery_callback)), + observers_); + + std::map 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(); + device_watcher_ = nullptr; + try { + adapter.StopDiscovery(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); + return false; + } + + return true; +} + +std::unique_ptr BluetoothClassicMedium::ConnectToService( + api::BluetoothDevice &remote_device, const std::string &service_uuid, + CancellationFlag *cancellation_flag) { + auto device_object_path = bluez::device_object_path( + adapter_.GetObjectPath(), remote_device.GetMacAddress()); + if (!profile_manager_->ProfileRegistered(service_uuid)) { + if (!profile_manager_->Register("", service_uuid)) { + NEARBY_LOGS(ERROR) << __func__ << ": Could not register profile " + << service_uuid << " with Bluez"; + return nullptr; + } + } + + auto device = devices_->get_device_by_path(device_object_path); + if (device == nullptr) 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 " + << device_object_path; + return nullptr; + } + + return std::unique_ptr( + new BluetoothSocket(device, fd.value())); +} + +std::unique_ptr +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( + 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 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( + new BluetoothPairing(adapter_, device)); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 9a3b120a..18104108 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -36,17 +36,10 @@ namespace nearby { namespace linux { // Container of operations that can be performed over the Bluetooth Classic // medium. -class BluetoothClassicMedium - : public api::BluetoothClassicMedium, - protected sdbus::ProxyInterfaces { +class BluetoothClassicMedium : public api::BluetoothClassicMedium { public: - BluetoothClassicMedium(const BluetoothClassicMedium &) = delete; - BluetoothClassicMedium(BluetoothClassicMedium &&) = delete; - BluetoothClassicMedium &operator=(const BluetoothClassicMedium &) = delete; - BluetoothClassicMedium &operator=(BluetoothClassicMedium &&) = delete; BluetoothClassicMedium(sdbus::IConnection &system_bus, BluetoothAdapter &adapter); - ~BluetoothClassicMedium() override { unregisterProxy(); }; // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() // @@ -101,29 +94,20 @@ class BluetoothClassicMedium const std::string &mac_address) override; void AddObserver(Observer *observer) override { - observers_.AddObserver(observer); + observers_->AddObserver(observer); }; void RemoveObserver(Observer *observer) override { - observers_.RemoveObserver(observer); + observers_->RemoveObserver(observer); }; - protected: - void onInterfacesAdded( - const sdbus::ObjectPath &objectPath, - const std::map> - &interfacesAndProperties) override; - void onInterfacesRemoved(const sdbus::ObjectPath &objectPath, - const std::vector &interfaces) override; - private: + sdbus::IConnection &system_bus_; + BluetoothAdapter adapter_; - ObserverList observers_; - - protected: + std::shared_ptr> observers_; std::shared_ptr devices_; + std::unique_ptr device_watcher_; - private: - std::shared_ptr discovery_cb_; std::unique_ptr profile_manager_; }; diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 43a0d1e7..7eef3a80 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include @@ -19,10 +20,13 @@ #include #include +#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 { @@ -89,5 +93,99 @@ std::shared_ptr BluetoothDevices::add_new_device( if (!inserted) device_it->second->UnmarkLost(); return device_it->second; } + +void DeviceWatcher::onInterfacesAdded( + const sdbus::ObjectPath &object, + const std::map> + &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); + if (discovery_cb_ != nullptr && + discovery_cb_->device_discovered_cb != nullptr) { + device->SetDiscoveryCallback(discovery_cb_); + 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 &interfaces) { + auto path_prefix = absl::Substitute("$0/dev_", adapter_object_path_); + if (object.find(path_prefix) != 0) { + return; + } + + for (const auto &interface : interfaces) { + if (interface == org::bluez::Device1_proxy::INTERFACE_NAME) { + 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>> + 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(), + [&](std::pair< + sdbus::ObjectPath, + std::map>> + 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; + devices_->add_new_device(device_it->first); + } +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 448c289c..bebf6c87 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -18,8 +18,11 @@ #include #include +#include #include #include +#include +#include #include #include "absl/container/flat_hash_map.h" @@ -69,6 +72,54 @@ class BluetoothDevices final { std::chrono::time_point last_cleanup_ ABSL_GUARDED_BY(devices_by_path_lock_); }; + +class DeviceWatcher final : sdbus::ProxyInterfaces { + 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 devices, + std::unique_ptr + discovery_callback, + std::shared_ptr> + 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 devices) + : DeviceWatcher(system_bus, adapter_object_path, std::move(devices), + nullptr, nullptr) {} + ~DeviceWatcher() { unregisterProxy(); } + + void onInterfacesAdded( + const sdbus::ObjectPath &object, + const std::map> + &interfaces) override; + void onInterfacesRemoved(const sdbus::ObjectPath &object, + const std::vector &interfaces) override; + + private: + void notifyExistingDevices(); + + sdbus::ObjectPath adapter_object_path_; + std::shared_ptr devices_; + std::shared_ptr discovery_cb_; + std::shared_ptr> + observers_; +}; + } // namespace linux } // namespace nearby From a97244ad0235359fc4b45e78a29ea2f1fd830b22 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 13:00:51 +0530 Subject: [PATCH 133/201] Advertise as a peripheral, return the correct value for ServiceUUIDs --- .../platform/implementation/linux/bluez_le_advertisement.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.h b/internal/platform/implementation/linux/bluez_le_advertisement.h index c17cbc79..df391474 100644 --- a/internal/platform/implementation/linux/bluez_le_advertisement.h +++ b/internal/platform/implementation/linux/bluez_le_advertisement.h @@ -63,8 +63,8 @@ class LEAdvertisement final } // Properties - std::string Type() override { return "broadcast"; } - std::vector ServiceUUIDs() override { return {}; } + std::string Type() override { return "peripheral"; } + std::vector ServiceUUIDs() override { return service_uuids_; } std::map ManufacturerData() override { return {}; } From a8a2964edd6eafa7f8d06bb5581970c05cb7eeda Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 13:01:22 +0530 Subject: [PATCH 134/201] StartLEDiscovery: Use "auto" as the discovery filter transport. --- internal/platform/implementation/linux/ble_v2_medium.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 7b990bed..8eaa6974 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -207,7 +207,7 @@ std::unique_ptr BleV2Medium::StartGattServer( bool BleV2Medium::StartLEDiscovery() { std::map filter; - filter["Transport"] = "le"; + filter["Transport"] = "auto"; auto &adapter = adapter_.GetBluezAdapterObject(); try { From 386d27d6469d3bf8ea82932ba0a636b0d59fb210 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 13:02:15 +0530 Subject: [PATCH 135/201] ShutDown: Remove extraneous logs --- internal/platform/implementation/linux/thread_pool.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/platform/implementation/linux/thread_pool.cc b/internal/platform/implementation/linux/thread_pool.cc index fe2d3164..8c37dcd9 100644 --- a/internal/platform/implementation/linux/thread_pool.cc +++ b/internal/platform/implementation/linux/thread_pool.cc @@ -89,9 +89,6 @@ void ThreadPool::ShutDown() { absl::MutexLock l(&tasks_mutex_); shut_down_.store(true, std::memory_order_acquire); } - NEARBY_LOGS(INFO) - << __func__ << ": asked to shut down, waiting for active threads to stop"; - { absl::ReaderMutexLock l(&threads_mutex_); for (auto &thread : threads_) { @@ -101,7 +98,6 @@ void ThreadPool::ShutDown() { absl::MutexLock l(&threads_mutex_); threads_.clear(); - NEARBY_LOGS(INFO) << __func__ << ": shut down thread pool"; } Runnable ThreadPool::NextTask() { From d1659d2231b1dcaf4725de85e2bb0876c5532330 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 13:44:27 +0530 Subject: [PATCH 136/201] Guard discovery callbacks with a lock. --- .../linux/bluetooth_classic_device.cc | 2 +- .../linux/bluetooth_classic_device.h | 38 +++++++++++++------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 83135672..9491061f 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -159,7 +159,7 @@ void MonitoredBluetoothDevice::onPropertiesChanged( observer->DeviceConnectedStateChanged(*this, it->second); } } else if (it->first == bluez::DEVICE_NAME) { - auto callback = discovery_cb_.lock(); + auto callback = GetDiscoveryCallback(); if (callback != nullptr && callback->device_name_changed_cb != nullptr) callback->device_name_changed_cb(*this); } diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 0f5c67fc..b60a0a67 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -25,6 +25,7 @@ #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" @@ -58,33 +59,34 @@ class BluetoothDevice std::string GetAddress() const override { return GetMacAddress(); } UniqueId GetUniqueId() const override { return unique_id_; }; - bool ConnectToProfile(absl::string_view service_uuid); - void set_pair_reply_callback( - absl::AnyInvocable cb) { + absl::AnyInvocable cb) + ABSL_LOCKS_EXCLUDED(pair_callback_lock_) { absl::MutexLock l(&pair_callback_lock_); on_pair_reply_cb_ = std::move(cb); } - void reset_pair_reply_callback() { + void reset_pair_reply_callback() ABSL_LOCKS_EXCLUDED(pair_callback_lock_) { absl::MutexLock l(&pair_callback_lock_); - on_pair_reply_cb_ = DefaultCallback(); + on_pair_reply_cb_ = nullptr; } + bool ConnectToProfile(absl::string_view service_uuid); void MarkLost() { lost_ = true; } void UnmarkLost() { lost_ = false; } bool Lost() const { return lost_; } protected: - void onPairReply(const sdbus::Error *error) override { + void onPairReply(const sdbus::Error *error) override + ABSL_LOCKS_EXCLUDED(pair_callback_lock_) { absl::ReaderMutexLock l(&pair_callback_lock_); - on_pair_reply_cb_(error); + if (on_pair_reply_cb_ != nullptr) on_pair_reply_cb_(error); }; private: absl::Mutex pair_callback_lock_; - absl::AnyInvocable on_pair_reply_cb_ = - DefaultCallback(); + absl::AnyInvocable on_pair_reply_cb_ + ABSL_GUARDED_BY(pair_callback_lock_) = nullptr; UniqueId unique_id_; std::atomic_bool lost_; @@ -112,8 +114,9 @@ class MonitoredBluetoothDevice final ~MonitoredBluetoothDevice() override { unregisterProxy(); } void SetDiscoveryCallback( - std::shared_ptr - &callback) { + std::shared_ptr &callback) + ABSL_LOCKS_EXCLUDED(discovery_cb_mutex_) { + absl::MutexLock lock(&discovery_cb_mutex_); discovery_cb_ = callback; }; @@ -124,8 +127,19 @@ class MonitoredBluetoothDevice final const std::vector &invalidatedProperties) override; private: + std::shared_ptr + GetDiscoveryCallback() ABSL_LOCKS_EXCLUDED(discovery_cb_mutex_) { + discovery_cb_mutex_.ReaderLock(); + auto callback = discovery_cb_.lock(); + discovery_cb_mutex_.ReaderUnlock(); + + return callback; + } + ObserverList &observers_; - std::weak_ptr discovery_cb_; + absl::Mutex discovery_cb_mutex_; + std::weak_ptr discovery_cb_ + ABSL_GUARDED_BY(discovery_cb_mutex_); }; } // namespace linux From 567ee6741b3c01e37348fe1359aa902de6b0ca11 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 13:44:45 +0530 Subject: [PATCH 137/201] Minor refactor --- .../implementation/linux/bluetooth_devices.cc | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 7eef3a80..97484df6 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -64,6 +64,7 @@ void BluetoothDevices::mark_peripheral_lost( 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(); } @@ -106,9 +107,9 @@ void DeviceWatcher::onInterfacesAdded( 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) { - device->SetDiscoveryCallback(discovery_cb_); discovery_cb_->device_discovered_cb(*device); } @@ -127,32 +128,31 @@ void DeviceWatcher::onInterfacesRemoved( return; } - for (const auto &interface : interfaces) { - if (interface == org::bluez::Device1_proxy::INTERFACE_NAME) { - 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; - } + 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); - } + 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); + if (observers_ != nullptr) { + for (const auto &observer : observers_->GetObservers()) { + observer->DeviceRemoved(*device); } + devices_->remove_device_by_path(object); + } else { + devices_->mark_peripheral_lost(object); } } } @@ -167,12 +167,8 @@ void DeviceWatcher::notifyExistingDevices() { DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); return; } - auto device_it = std::find_if( - objects.begin(), objects.end(), - [&](std::pair< - sdbus::ObjectPath, - std::map>> - entry) { + auto device_it = + std::find_if(objects.begin(), objects.end(), [&](auto entry) { auto &[device_path, interfaces] = entry; return device_path.find( @@ -183,7 +179,10 @@ void DeviceWatcher::notifyExistingDevices() { for (; device_it != objects.end(); device_it++) { NEARBY_LOGS(VERBOSE) << __func__ << ": Adding existing device " << device_it->first; - devices_->add_new_device(device_it->first); + auto device = devices_->add_new_device(device_it->first); + if (discovery_cb_ != nullptr) { + device->SetDiscoveryCallback(discovery_cb_); + } } } From bc4c1e76c9b4dbbb9655a09ac17eb131cf87a629 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 21:41:37 +0530 Subject: [PATCH 138/201] Use shared_ptrs for dbus connections for top-level classes. --- .../implementation/linux/ble_v2_medium.cc | 30 +++++------ .../implementation/linux/ble_v2_medium.h | 7 +-- .../implementation/linux/bluetooth_adapter.h | 14 +++--- .../linux/bluetooth_classic_medium.cc | 11 ++-- .../linux/bluetooth_classic_medium.h | 5 +- .../platform/implementation/linux/dbus.cc | 50 ++++++------------- internal/platform/implementation/linux/dbus.h | 3 +- .../implementation/linux/device_info.cc | 12 ++--- .../implementation/linux/device_info.h | 4 +- .../implementation/linux/network_manager.cc | 6 +-- .../implementation/linux/network_manager.h | 28 ++++++++--- .../network_manager_active_connection.cc | 2 +- .../linux/network_manager_active_connection.h | 8 ++- .../platform/implementation/linux/platform.cc | 28 +++++------ .../implementation/linux/wifi_direct.cc | 14 +++--- .../implementation/linux/wifi_direct.h | 5 +- .../linux/wifi_direct_server_socket.cc | 6 +-- .../linux/wifi_direct_server_socket.h | 10 ++-- .../implementation/linux/wifi_hotspot.cc | 2 +- .../implementation/linux/wifi_hotspot.h | 13 ++--- .../linux/wifi_hotspot_server_socket.cc | 6 +-- .../linux/wifi_hotspot_server_socket.h | 10 ++-- .../platform/implementation/linux/wifi_lan.cc | 17 +++---- .../platform/implementation/linux/wifi_lan.h | 6 +-- .../linux/wifi_lan_server_socket.cc | 2 +- .../linux/wifi_lan_server_socket.h | 11 ++-- .../implementation/linux/wifi_medium.cc | 14 +++--- .../implementation/linux/wifi_medium.h | 6 ++- 28 files changed, 154 insertions(+), 176 deletions(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 8eaa6974..bbc31d8d 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -33,17 +33,17 @@ namespace nearby { namespace linux { -BleV2Medium::BleV2Medium(sdbus::IConnection &system_bus, - BluetoothAdapter &adapter) - : system_bus_(system_bus), +BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) + : system_bus_(adapter.GetConnection()), adapter_(adapter), devices_(std::make_unique( - system_bus_, adapter_.GetObjectPath(), observers_)), + *system_bus_, adapter_.GetObjectPath(), observers_)), + root_object_manager_(std::make_unique(*system_bus_)), adv_monitor_manager_( bluez::AdvertisementMonitorManager:: - DiscoverAdvertisementMonitorManager(system_bus, adapter_)), - adv_manager_( - std::make_unique(system_bus, adapter)), + DiscoverAdvertisementMonitorManager(*system_bus_, adapter_)), + adv_manager_(std::make_unique(*system_bus_, + adapter)), cur_adv_(nullptr) { if (adv_monitor_manager_) { NEARBY_LOGS(VERBOSE) @@ -81,7 +81,7 @@ bool BleV2Medium::StartAdvertising( } cur_adv_ = bluez::LEAdvertisement::CreateLEAdvertisement( - system_bus_, advertising_data, advertise_set_parameters); + *system_bus_, advertising_data, advertise_set_parameters); NEARBY_LOGS(INFO) << __func__ << ": Registering advertisement " << cur_adv_->getObjectPath() << " on bluetooth adapter " @@ -136,7 +136,7 @@ BleV2Medium::StartAdvertising( } std::shared_ptr proxy = - sdbus::createProxy(system_bus_, "org.bluez", adapter_.GetObjectPath()); + sdbus::createProxy(*system_bus_, "org.bluez", adapter_.GetObjectPath()); proxy->finishRegistration(); std::shared_ptr shared_cb = @@ -144,7 +144,7 @@ BleV2Medium::StartAdvertising( absl::MutexLock lock(&advs_mutex_); advs_.push_front(bluez::LEAdvertisement::CreateLEAdvertisement( - system_bus_, advertising_data, advertise_set_parameters)); + *system_bus_, advertising_data, advertise_set_parameters)); auto adv_it = advs_.begin(); auto pending_call = @@ -201,7 +201,7 @@ BleV2Medium::StartAdvertising( std::unique_ptr BleV2Medium::StartGattServer( api::ble_v2::ServerGattConnectionCallback callback) { - return std::make_unique(system_bus_, adapter_, devices_, + return std::make_unique(*system_bus_, adapter_, devices_, std::move(callback)); } @@ -264,7 +264,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, } auto monitor = std::make_unique( - system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, + *system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, std::move(callback)); try { monitor->emitInterfacesAddedSignal( @@ -279,7 +279,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, } auto device_watcher = std::make_unique( - system_bus_, adapter_.GetObjectPath(), devices_); + *system_bus_, adapter_.GetObjectPath(), devices_); if (!StartLEDiscovery()) { NEARBY_LOGS(ERROR) << __func__ << ": Could not start LE discovery on adapter " @@ -360,7 +360,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, } auto monitor = std::make_unique( - system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, + *system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, std::move(callback)); try { monitor->emitInterfacesAddedSignal( @@ -375,7 +375,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, } auto device_watcher = std::make_unique( - system_bus_, adapter_.GetObjectPath(), devices_); + *system_bus_, adapter_.GetObjectPath(), devices_); if (!StartLEDiscovery()) { NEARBY_LOGS(ERROR) << __func__ << ": Could not start LE discovery on adapter " diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index 145f3106..8b59c0da 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -29,6 +29,7 @@ #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 { @@ -40,8 +41,7 @@ class BleV2Medium final : public api::ble_v2::BleMedium { BleV2Medium &operator=(const BleV2Medium &) = delete; BleV2Medium &operator=(BleV2Medium &&) = delete; - BleV2Medium(sdbus::IConnection &system_bus ABSL_ATTRIBUTE_LIFETIME_BOUND, - BluetoothAdapter &adapter); + explicit BleV2Medium(BluetoothAdapter &adapter); ~BleV2Medium() override = default; bool StartAdvertising( @@ -113,11 +113,12 @@ class BleV2Medium final : public api::ble_v2::BleMedium { end; } - sdbus::IConnection &system_bus_; + std::shared_ptr system_bus_; BluetoothAdapter adapter_; ObserverList observers_ = {}; std::shared_ptr devices_; + std::unique_ptr root_object_manager_; std::unique_ptr adv_monitor_manager_; absl::Mutex active_adv_monitors_mutex_; absl::flat_hash_map< diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h index 3d2bc900..810cae8f 100644 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ b/internal/platform/implementation/linux/bluetooth_adapter.h @@ -37,15 +37,11 @@ class BluezAdapter : public sdbus::ProxyInterfaces { class BluetoothAdapter : public api::BluetoothAdapter { public: - BluetoothAdapter(const BluetoothAdapter &) = default; - BluetoothAdapter(BluetoothAdapter &&) = delete; - BluetoothAdapter &operator=(const BluetoothAdapter &) = default; - BluetoothAdapter &operator=(BluetoothAdapter &&) = delete; - - BluetoothAdapter(sdbus::IConnection &system_bus, + BluetoothAdapter(std::shared_ptr system_bus, const sdbus::ObjectPath &adapter_object_path) - : bluez_adapter_( - std::make_shared(system_bus, adapter_object_path)) {} + : system_bus_(std::move(system_bus)), + bluez_adapter_(std::make_shared(*system_bus_, + adapter_object_path)) {} ~BluetoothAdapter() override = default; @@ -76,8 +72,10 @@ class BluetoothAdapter : public api::BluetoothAdapter { } BluezAdapter &GetBluezAdapterObject() { return *bluez_adapter_; } + std::shared_ptr GetConnection() { return system_bus_; } private: + std::shared_ptr system_bus_; std::shared_ptr bluez_adapter_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 8a795f28..036315d6 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -33,21 +33,20 @@ namespace nearby { namespace linux { -BluetoothClassicMedium::BluetoothClassicMedium(sdbus::IConnection &system_bus, - BluetoothAdapter &adapter) - : system_bus_(system_bus), +BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter) + : system_bus_(adapter.GetConnection()), adapter_(adapter), observers_(std::make_shared>()), devices_(std::make_shared( - system_bus, adapter.GetObjectPath(), *observers_)), + *system_bus_, adapter.GetObjectPath(), *observers_)), device_watcher_(nullptr), profile_manager_( - std::make_unique(system_bus, *devices_)) {} + std::make_unique(*system_bus_, *devices_)) {} bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { device_watcher_ = std::make_unique( - system_bus_, adapter_.GetObjectPath(), devices_, + *system_bus_, adapter_.GetObjectPath(), devices_, std::make_unique(std::move(discovery_callback)), observers_); diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 18104108..7192206c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -38,8 +38,7 @@ namespace linux { // medium. class BluetoothClassicMedium : public api::BluetoothClassicMedium { public: - BluetoothClassicMedium(sdbus::IConnection &system_bus, - BluetoothAdapter &adapter); + explicit BluetoothClassicMedium(BluetoothAdapter &adapter); // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() // @@ -101,7 +100,7 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium { }; private: - sdbus::IConnection &system_bus_; + std::shared_ptr system_bus_; BluetoothAdapter adapter_; std::shared_ptr> observers_; diff --git a/internal/platform/implementation/linux/dbus.cc b/internal/platform/implementation/linux/dbus.cc index 1bbaa7b3..6a45b1f6 100644 --- a/internal/platform/implementation/linux/dbus.cc +++ b/internal/platform/implementation/linux/dbus.cc @@ -19,47 +19,29 @@ #include #include "absl/base/call_once.h" +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/dbus.h" namespace nearby { namespace linux { -static std::unique_ptr global_system_bus_connection = - nullptr; -static std::unique_ptr global_default_bus_connection = - nullptr; -static std::unique_ptr system_root_object_manager = nullptr; -static std::unique_ptr default_root_object_manager = nullptr; -static absl::once_flag bus_connection_init_; -static void disconnectBus() { - system_root_object_manager = nullptr; - default_root_object_manager = nullptr; - global_system_bus_connection = nullptr; - global_default_bus_connection = nullptr; -} +namespace { +static absl::Mutex global_system_bus_mutex; +static std::weak_ptr global_system_bus_connection + ABSL_GUARDED_BY(global_system_bus_mutex); +} // namespace -static void initBusConnections() { - global_system_bus_connection = sdbus::createSystemBusConnection(); - global_system_bus_connection->enterEventLoopAsync(); - global_default_bus_connection = sdbus::createDefaultBusConnection(); - global_default_bus_connection->enterEventLoopAsync(); - system_root_object_manager = - std::make_unique(*global_system_bus_connection); - default_root_object_manager = - std::make_unique(*global_default_bus_connection); +std::shared_ptr getSystemBusConnection() { + absl::MutexLock lock(&global_system_bus_mutex); + auto bus = global_system_bus_connection.lock(); + if (bus == nullptr) { + bus = + std::shared_ptr(sdbus::createSystemBusConnection()); + bus->enterEventLoopAsync(); + global_system_bus_connection = bus; + } - atexit(disconnectBus); -} - -sdbus::IConnection &getSystemBusConnection() { - absl::call_once(bus_connection_init_, initBusConnections); - assert(global_system_bus_connection != nullptr); - return *global_system_bus_connection; -} -sdbus::IConnection &getDefaultBusConnection() { - absl::call_once(bus_connection_init_, initBusConnections); - assert(global_default_bus_connection != nullptr); - return *global_default_bus_connection; + return bus; } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h index a16b1fb6..d9908495 100644 --- a/internal/platform/implementation/linux/dbus.h +++ b/internal/platform/implementation/linux/dbus.h @@ -46,8 +46,7 @@ namespace nearby { namespace linux { -extern sdbus::IConnection &getSystemBusConnection(); -extern sdbus::IConnection &getDefaultBusConnection(); +extern std::shared_ptr getSystemBusConnection(); class RootObjectManager final : public sdbus::AdaptorInterfaces { diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 8a97814e..02eb564c 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -58,13 +58,13 @@ void CurrentUserSession::onUnlock() { } } -DeviceInfo::DeviceInfo(sdbus::IConnection &system_bus) - : system_bus_(system_bus), - current_user_session_(std::make_unique(system_bus_)), - login_manager_(std::make_unique(system_bus_)) {} +DeviceInfo::DeviceInfo(std::shared_ptr system_bus) + : system_bus_(std::move(system_bus)), + current_user_session_(std::make_unique(*system_bus_)), + login_manager_(std::make_unique(*system_bus_)) {} std::optional DeviceInfo::GetOsDeviceName() const { - avahi::Server avahi(system_bus_); + avahi::Server avahi(*system_bus_); try { std::string hostname = avahi.GetHostNameFqdn(); std::wstring_convert, char16_t> convert; @@ -76,7 +76,7 @@ std::optional DeviceInfo::GetOsDeviceName() const { } api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { - Hostnamed hostnamed(system_bus_); + Hostnamed hostnamed(*system_bus_); try { std::string chasis = hostnamed.Chassis(); api::DeviceInfo::DeviceType device = api::DeviceInfo::DeviceType::kUnknown; diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index 67b54b30..f864117d 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -119,7 +119,7 @@ class LoginManager final class DeviceInfo final : public api::DeviceInfo { public: - explicit DeviceInfo(sdbus::IConnection &system_bus); + explicit DeviceInfo(std::shared_ptr system_bus); std::optional GetOsDeviceName() const override; api::DeviceInfo::DeviceType GetDeviceType() const override; @@ -160,7 +160,7 @@ class DeviceInfo final : public api::DeviceInfo { bool AllowSleep() override; private: - sdbus::IConnection &system_bus_; + std::shared_ptr system_bus_; std::unique_ptr current_user_session_; std::unique_ptr login_manager_; std::optional inhibit_fd_; diff --git a/internal/platform/implementation/linux/network_manager.cc b/internal/platform/implementation/linux/network_manager.cc index 4c10a96f..6089980e 100644 --- a/internal/platform/implementation/linux/network_manager.cc +++ b/internal/platform/implementation/linux/network_manager.cc @@ -47,7 +47,7 @@ NetworkManagerObjectManager::GetActiveConnectionForAccessPoint( for (auto &path : devices) { if (path == device_path) { return std::make_unique( - getProxy().getConnection(), object_path); + system_bus_, object_path); } } } @@ -80,8 +80,8 @@ NetworkManagerObjectManager::GetIp4Config( sdbus::ObjectPath specific_object = props["SpecificObject"]; if (specific_object == active_connection) { sdbus::ObjectPath ip4config = props["Ip4Config"]; - return std::make_unique( - getProxy().getConnection(), ip4config); + return std::make_unique(system_bus_, + ip4config); } } } diff --git a/internal/platform/implementation/linux/network_manager.h b/internal/platform/implementation/linux/network_manager.h index 1c7c51af..7f6d889d 100644 --- a/internal/platform/implementation/linux/network_manager.h +++ b/internal/platform/implementation/linux/network_manager.h @@ -34,9 +34,10 @@ class NetworkManager final NetworkManager(NetworkManager &&) = delete; NetworkManager &operator=(const NetworkManager &) = delete; NetworkManager &operator=(NetworkManager &&) = delete; - explicit NetworkManager(sdbus::IConnection &system_bus) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + explicit NetworkManager(std::shared_ptr system_bus) + : ProxyInterfaces(*system_bus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager"), + system_bus_(std::move(system_bus)), state_(kNMStateUnknown) { registerProxy(); try { @@ -60,6 +61,7 @@ class NetworkManager final }; NMState getState() const { return state_; } + std::shared_ptr GetConnection() { return system_bus_; } protected: void onCheckPermissions() override {} @@ -90,6 +92,7 @@ class NetworkManager final #undef NM_STATE_CASE_SET }; + std::shared_ptr system_bus_; std::atomic state_; }; @@ -101,13 +104,17 @@ class NetworkManagerIP4Config NetworkManagerIP4Config(NetworkManagerIP4Config &&) = delete; NetworkManagerIP4Config &operator=(const NetworkManagerIP4Config &) = delete; NetworkManagerIP4Config &operator=(NetworkManagerIP4Config &&) = delete; - NetworkManagerIP4Config(sdbus::IConnection &system_bus, + NetworkManagerIP4Config(std::shared_ptr system_bus, const sdbus::ObjectPath &config_object_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - config_object_path) { + : ProxyInterfaces(*system_bus, "org.freedesktop.NetworkManager", + config_object_path), + system_bus_(std::move(system_bus)) { registerProxy(); } ~NetworkManagerIP4Config() { unregisterProxy(); } + + private: + std::shared_ptr system_bus_; }; class NetworkManagerObjectManager final @@ -119,9 +126,11 @@ class NetworkManagerObjectManager final delete; NetworkManagerObjectManager &operator=(NetworkManagerObjectManager &&) = delete; - explicit NetworkManagerObjectManager(sdbus::IConnection &system_bus) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", - "/org/freedesktop") { + explicit NetworkManagerObjectManager( + std::shared_ptr system_bus) + : ProxyInterfaces(*system_bus, "org.freedesktop.NetworkManager", + "/org/freedesktop"), + system_bus_(std::move(system_bus)) { registerProxy(); } ~NetworkManagerObjectManager() { unregisterProxy(); } @@ -140,6 +149,9 @@ class NetworkManagerObjectManager final void onInterfacesRemoved( const sdbus::ObjectPath &objectPath, const std::vector &interfaces) override {} + + private: + std::shared_ptr system_bus_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/network_manager_active_connection.cc b/internal/platform/implementation/linux/network_manager_active_connection.cc index b97c2f2d..8bb6a44b 100644 --- a/internal/platform/implementation/linux/network_manager_active_connection.cc +++ b/internal/platform/implementation/linux/network_manager_active_connection.cc @@ -79,7 +79,7 @@ std::vector NetworkManagerActiveConnection::GetIP4Addresses() { return {}; } - NetworkManagerIP4Config ip4config(getProxy().getConnection(), ip4config_path); + NetworkManagerIP4Config ip4config(system_bus_, ip4config_path); std::vector> address_data; try { address_data = ip4config.AddressData(); diff --git a/internal/platform/implementation/linux/network_manager_active_connection.h b/internal/platform/implementation/linux/network_manager_active_connection.h index 1d4aeb91..5ff19379 100644 --- a/internal/platform/implementation/linux/network_manager_active_connection.h +++ b/internal/platform/implementation/linux/network_manager_active_connection.h @@ -63,9 +63,11 @@ class NetworkManagerActiveConnection NetworkManagerActiveConnection &operator=(NetworkManagerActiveConnection &&) = delete; explicit NetworkManagerActiveConnection( - sdbus::IConnection &system_bus, sdbus::ObjectPath active_connection_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + std::shared_ptr system_bus, + sdbus::ObjectPath active_connection_path) + : ProxyInterfaces(*system_bus, "org.freedesktop.NetworkManager", std::move(active_connection_path)), + system_bus_(std::move(system_bus)), state_(kStateUnknown), reason_(kStateReasonUnknown) { registerProxy(); @@ -99,6 +101,8 @@ class NetworkManagerActiveConnection std::vector GetIP4Addresses(); private: + std::shared_ptr system_bus_; + absl::Mutex state_mutex_; ActiveConnectionState state_ ABSL_GUARDED_BY(state_mutex_); ActiveConnectionStateReason reason_ ABSL_GUARDED_BY(state_mutex_); diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 5895a0a3..632d3732 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -29,7 +29,6 @@ #include "internal/platform/implementation/input_file.h" #include "internal/platform/implementation/linux/atomic_boolean.h" #include "internal/platform/implementation/linux/atomic_uint32.h" -#include "internal/platform/implementation/linux/ble_medium.h" #include "internal/platform/implementation/linux/ble_v2_medium.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_classic_medium.h" @@ -166,15 +165,14 @@ ImplementationPlatform::CreateScheduledExecutor() { std::unique_ptr ImplementationPlatform::CreateBluetoothAdapter() { - auto manager = - linux::bluez::BluezObjectManager(linux::getSystemBusConnection()); + auto system_bus = linux::getSystemBusConnection(); + auto manager = linux::bluez::BluezObjectManager(*system_bus); try { auto interfaces = manager.GetManagedObjects(); for (auto &[object, properties] : interfaces) { if (properties.count(org::bluez::Adapter1_proxy::INTERFACE_NAME) == 1) { NEARBY_LOGS(INFO) << __func__ << ": found bluetooth adapter " << object; - return std::make_unique( - linux::getSystemBusConnection(), object); + return std::make_unique(system_bus, object); } } } catch (const sdbus::Error &e) { @@ -191,19 +189,17 @@ std::unique_ptr ImplementationPlatform::CreateBluetoothClassicMedium( BluetoothAdapter &adapter) { return std::make_unique( - linux::getSystemBusConnection(), dynamic_cast(adapter)); } std::unique_ptr ImplementationPlatform::CreateBleMedium( BluetoothAdapter &adapter) { - return nullptr; + return nullptr; } std::unique_ptr ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { return std::make_unique( - linux::getSystemBusConnection(), dynamic_cast(adapter)); } @@ -219,8 +215,7 @@ static std::unique_ptr createWifiMedium( return nullptr; } - auto manager = - linux::NetworkManagerObjectManager(linux::getSystemBusConnection()); + auto manager = linux::NetworkManagerObjectManager(nm->GetConnection()); std::map>> @@ -239,8 +234,8 @@ static std::unique_ptr createWifiMedium( Wireless_proxy::INTERFACE_NAME) == 1) { NEARBY_LOGS(INFO) << __func__ << ": Found a wireless device at :" << device_path; - return std::make_unique( - nm, linux::getSystemBusConnection(), device_path); + return std::make_unique(nm, + device_path); } } } @@ -259,8 +254,9 @@ std::unique_ptr ImplementationPlatform::CreateWifiMedium() { std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { - return std::make_unique( - linux::getSystemBusConnection()); + auto nm = + std::make_shared(linux::getSystemBusConnection()); + return std::make_unique(nm); } std::unique_ptr @@ -275,7 +271,7 @@ ImplementationPlatform::CreateWifiHotspotMedium() { } return std::make_unique( - linux::getSystemBusConnection(), nm, std::move(wifiMedium)); + nm, std::move(wifiMedium)); } std::unique_ptr @@ -290,7 +286,7 @@ ImplementationPlatform::CreateWifiDirectMedium() { } return std::make_unique( - linux::getSystemBusConnection(), nm, std::move(wifiMedium)); + nm, std::move(wifiMedium)); } std::unique_ptr ImplementationPlatform::CreateTimer() { diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index 8aa605e2..b0e43ea4 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -104,7 +104,7 @@ NetworkManagerWifiDirectMedium::ListenForService(int port) { } return std::make_unique( - sock, system_bus_, active_connection->getObjectPath(), network_manager_); + sock, std::move(active_connection), network_manager_); } bool NetworkManagerWifiDirectMedium::ConnectWifiDirect( @@ -159,7 +159,8 @@ bool NetworkManagerWifiDirectMedium::StartWifiDirect( // medium is currently just a regular wifi hotspot. // auto wireless_device = std::make_unique( // network_manager_, system_bus_, wireless_device_->getObjectPath()); - // auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, + // auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, + // network_manager_, // std::move(wireless_device)); // HotspotCredentials hotspot_creds; @@ -168,17 +169,18 @@ bool NetworkManagerWifiDirectMedium::StartWifiDirect( // wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID()); // wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword()); // return true; - return false; + return false; } bool NetworkManagerWifiDirectMedium::StopWifiDirect() { // auto wireless_device = std::make_unique( // network_manager_, system_bus_, wireless_device_->getObjectPath()); - // auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, network_manager_, + // auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, + // network_manager_, // std::move(wireless_device)); - // return hotspot.DisconnectWifiHotspot(); - return false; + // return hotspot.DisconnectWifiHotspot(); + return false; } } // namespace linux diff --git a/internal/platform/implementation/linux/wifi_direct.h b/internal/platform/implementation/linux/wifi_direct.h index 3d376080..05711aaf 100644 --- a/internal/platform/implementation/linux/wifi_direct.h +++ b/internal/platform/implementation/linux/wifi_direct.h @@ -28,10 +28,9 @@ namespace linux { class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium { public: NetworkManagerWifiDirectMedium( - sdbus::IConnection &system_bus, std::shared_ptr network_manager, std::unique_ptr wireless_device) - : system_bus_(system_bus), + : system_bus_(network_manager->GetConnection()), network_manager_(std::move(network_manager)), wireless_device_(std::move(wireless_device)) {} @@ -56,7 +55,7 @@ class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium { private: bool ConnectedToWifi(); - sdbus::IConnection &system_bus_; + std::shared_ptr system_bus_; std::shared_ptr network_manager_; std::unique_ptr wireless_device_; }; diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.cc b/internal/platform/implementation/linux/wifi_direct_server_socket.cc index b2c9495f..099e6d3a 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.cc @@ -22,14 +22,12 @@ namespace nearby { namespace linux { std::string NetworkManagerWifiDirectServerSocket::GetIPAddress() const { - NetworkManagerActiveConnection active_conn(system_bus_, - active_connection_path_); - auto ip4addresses = active_conn.GetIP4Addresses(); + auto ip4addresses = active_conn_->GetIP4Addresses(); if (ip4addresses.empty()) { NEARBY_LOGS(ERROR) << __func__ << ": Could not find any IPv4 addresses for active connection " - << active_connection_path_; + << active_conn_->getObjectPath(); return std::string(); } return ip4addresses[0]; diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.h b/internal/platform/implementation/linux/wifi_direct_server_socket.h index 1f5fe879..34a88e9a 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.h @@ -16,6 +16,7 @@ #define PLATFORM_IMPL_LINUX_WIFI_DIRECT_SERVER_SOCKET_H_ #include +#include "internal/platform/implementation/linux/network_manager_active_connection.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_direct.h" namespace nearby { @@ -24,12 +25,10 @@ class NetworkManagerWifiDirectServerSocket : public api::WifiDirectServerSocket { public: NetworkManagerWifiDirectServerSocket( - int socket, sdbus::IConnection &system_bus, - sdbus::ObjectPath active_connection_path, + int socket, std::unique_ptr active_conn, std::shared_ptr network_manager) : fd_(socket), - system_bus_(system_bus), - active_connection_path_(std::move(active_connection_path)), + active_conn_(std::move(active_conn)), network_manager_(std::move(network_manager)) {} std::string GetIPAddress() const override; @@ -39,8 +38,7 @@ class NetworkManagerWifiDirectServerSocket private: sdbus::UnixFd fd_; - sdbus::IConnection &system_bus_; - sdbus::ObjectPath active_connection_path_; + std::unique_ptr active_conn_; std::shared_ptr network_manager_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index d1b1715f..151d4748 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -122,7 +122,7 @@ NetworkManagerWifiHotspotMedium::ListenForService(int port) { } return std::make_unique( - sock, system_bus_, active_connection->getObjectPath(), network_manager_); + sock, std::move(active_connection), network_manager_); } bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( diff --git a/internal/platform/implementation/linux/wifi_hotspot.h b/internal/platform/implementation/linux/wifi_hotspot.h index f00c9b7a..d1b143db 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.h +++ b/internal/platform/implementation/linux/wifi_hotspot.h @@ -26,22 +26,19 @@ namespace linux { class NetworkManagerWifiHotspotMedium : public api::WifiHotspotMedium { public: NetworkManagerWifiHotspotMedium( - sdbus::IConnection &system_bus, std::shared_ptr network_manager, sdbus::ObjectPath wireless_device_object_path) - : system_bus_(system_bus), + : system_bus_(network_manager->GetConnection()), wireless_device_(std::make_unique( - network_manager, system_bus, - std::move(wireless_device_object_path))), + network_manager, std::move(wireless_device_object_path))), network_manager_(std::move(network_manager)) {} NetworkManagerWifiHotspotMedium( - sdbus::IConnection &system_bus, std::shared_ptr network_manager, std::unique_ptr wireless_device) - : system_bus_(system_bus), + : system_bus_(network_manager->GetConnection()), wireless_device_(std::move(wireless_device)), network_manager_(std::move(network_manager)) {} - + bool IsInterfaceValid() const override { return true; } std::unique_ptr ConnectToService( absl::string_view ip_address, int port, @@ -64,7 +61,7 @@ class NetworkManagerWifiHotspotMedium : public api::WifiHotspotMedium { bool WifiHotspotActive(); bool ConnectedToWifi(); - sdbus::IConnection &system_bus_; + std::shared_ptr system_bus_; std::unique_ptr wireless_device_; std::shared_ptr network_manager_; }; diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc index e4e880bb..d74f8f91 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc @@ -22,14 +22,12 @@ namespace nearby { namespace linux { std::string NetworkManagerWifiHotspotServerSocket::GetIPAddress() const { - NetworkManagerActiveConnection active_conn(system_bus_, - active_connection_path_); - auto ip4addresses = active_conn.GetIP4Addresses(); + auto ip4addresses = active_conn_->GetIP4Addresses(); if (ip4addresses.empty()) { NEARBY_LOGS(ERROR) << __func__ << ": Could not find any IPv4 addresses for active connection " - << active_connection_path_; + << active_conn_->getObjectPath(); return {}; } return ip4addresses[0]; diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h index db4ff7f9..587ef20a 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h @@ -17,6 +17,7 @@ #include +#include "internal/platform/implementation/linux/network_manager_active_connection.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_hotspot.h" @@ -26,12 +27,10 @@ class NetworkManagerWifiHotspotServerSocket : public api::WifiHotspotServerSocket { public: NetworkManagerWifiHotspotServerSocket( - int socket, sdbus::IConnection &system_bus, - sdbus::ObjectPath active_connection_path, + int socket, std::unique_ptr active_conn, std::shared_ptr network_manager) : fd_(socket), - system_bus_(system_bus), - active_connection_path_(std::move(active_connection_path)), + active_conn_(std::move(active_conn)), network_manager_(std::move(network_manager)) {} std::string GetIPAddress() const override; @@ -41,8 +40,7 @@ class NetworkManagerWifiHotspotServerSocket private: sdbus::UnixFd fd_; - sdbus::IConnection &system_bus_; - sdbus::ObjectPath active_connection_path_; + std::unique_ptr active_conn_; std::shared_ptr network_manager_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 53413a3c..f1af9510 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -31,16 +31,16 @@ #include "internal/platform/implementation/linux/wifi_lan.h" #include "internal/platform/implementation/linux/wifi_lan_server_socket.h" #include "internal/platform/implementation/linux/wifi_lan_socket.h" -#include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { -WifiLanMedium::WifiLanMedium(sdbus::IConnection &system_bus) - : system_bus_(system_bus), - network_manager_(std::make_shared(system_bus)), - avahi_(std::make_shared(system_bus)) {} +WifiLanMedium::WifiLanMedium( + std::shared_ptr network_manager) + : system_bus_(network_manager->GetConnection()), + network_manager_(std::move(network_manager)), + avahi_(std::make_shared(*system_bus_)) {} bool WifiLanMedium::IsNetworkConnected() const { auto state = network_manager_->getState(); @@ -99,7 +99,7 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { } auto entry_group = - std::make_unique(system_bus_, entry_group_path); + std::make_unique(*system_bus_, entry_group_path); try { entry_group->AddService( @@ -166,7 +166,7 @@ bool WifiLanMedium::StartDiscovery( service_browsers_.emplace( service_type, std::make_unique( - system_bus_, browser_object_path, std::move(callback), avahi_)); + *system_bus_, browser_object_path, std::move(callback), avahi_)); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(avahi_, "ServiceBrowserPrepare", e); return false; @@ -261,8 +261,7 @@ std::unique_ptr WifiLanMedium::ListenForService( NEARBY_LOGS(VERBOSE) << __func__ << "Listening for services on port " << port; - return std::make_unique(sock, network_manager_, - system_bus_); + return std::make_unique(sock, network_manager_); } absl::optional> GetDynamicPortRange() { diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 60c56fae..11abe585 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -14,6 +14,7 @@ #ifndef PLATFORM_IMPL_LINUX_WIFI_LAN_H_ #define PLATFORM_IMPL_LINUX_WIFI_LAN_H_ +#include #include #include "absl/container/flat_hash_map.h" @@ -27,7 +28,7 @@ namespace nearby { namespace linux { class WifiLanMedium : public api::WifiLanMedium { public: - explicit WifiLanMedium(sdbus::IConnection &system_bus); + explicit WifiLanMedium(std::shared_ptr network_manager); bool IsNetworkConnected() const override; @@ -59,8 +60,7 @@ class WifiLanMedium : public api::WifiLanMedium { } private: - sdbus::IConnection &system_bus_; - + std::shared_ptr system_bus_; std::shared_ptr network_manager_; std::shared_ptr avahi_; diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index 52f54334..d4bbd1b9 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -42,7 +42,7 @@ std::string WifiLanServerSocket::GetIPAddress() const { } for (auto &path : connection_paths) { - auto active_connection = + auto active_connection = std::make_unique(system_bus_, path); std::string conn_type; try { diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.h b/internal/platform/implementation/linux/wifi_lan_server_socket.h index 3b5a75fe..44aec805 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.h @@ -21,19 +21,18 @@ #include #include "internal/platform/exception.h" -#include "internal/platform/implementation/linux/wifi_medium.h" +#include "internal/platform/implementation/linux/network_manager.h" #include "internal/platform/implementation/wifi_lan.h" namespace nearby { namespace linux { class WifiLanServerSocket : public api::WifiLanServerSocket { public: - explicit WifiLanServerSocket(int socket, - std::shared_ptr network_manager, - sdbus::IConnection &system_bus) + explicit WifiLanServerSocket(int socket, + std::shared_ptr network_manager) : fd_(sdbus::UnixFd(socket)), network_manager_(std::move(network_manager)), - system_bus_(system_bus) {} + system_bus_(network_manager_->GetConnection()) {} std::string GetIPAddress() const override; int GetPort() const override; @@ -44,7 +43,7 @@ class WifiLanServerSocket : public api::WifiLanServerSocket { private: sdbus::UnixFd fd_; std::shared_ptr network_manager_; - sdbus::IConnection &system_bus_; + std::shared_ptr system_bus_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index da49c599..cc7d734c 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -64,8 +64,8 @@ api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { information_ = api::WifiInformation{false}; return information_; } - active_access_point = std::make_unique( - getProxy().getConnection(), ap_path); + active_access_point = + std::make_unique(*system_bus_, ap_path); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(this, "ActiveAccessPoint", e); } @@ -77,7 +77,7 @@ api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { information_ = api::WifiInformation{true, ssid, active_access_point->HwAddress(), to_signed(active_access_point->Frequency())}; - NetworkManagerObjectManager manager(getProxy().getConnection()); + NetworkManagerObjectManager manager(system_bus_); auto ip4config = manager.GetIp4Config(active_access_point->getObjectPath()); if (ip4config != nullptr) { @@ -211,7 +211,6 @@ static inline std::pair AuthAlgAndKeyMgmt( api::WifiAuthType auth_type) { switch (auth_type) { case api::WifiAuthType::kUnknown: - return {"open", "none"}; case api::WifiAuthType::kOpen: return {"open", "none"}; case api::WifiAuthType::kWpaPsk: @@ -289,8 +288,8 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath() << ": Added a new connection at " << connection_path; - auto active_connection = NetworkManagerActiveConnection( - getProxy().getConnection(), active_conn_path); + auto active_connection = + NetworkManagerActiveConnection(system_bus_, active_conn_path); auto [reason, timeout] = active_connection.WaitForConnection(); if (timeout) { NEARBY_LOGS(ERROR) @@ -345,7 +344,7 @@ NetworkManagerWifiMedium::GetActiveConnection() { return nullptr; } - auto object_manager = NetworkManagerObjectManager(getProxy().getConnection()); + auto object_manager = NetworkManagerObjectManager(system_bus_); auto conn = object_manager.GetActiveConnectionForAccessPoint(active_ap_path, getObjectPath()); @@ -357,6 +356,5 @@ NetworkManagerWifiMedium::GetActiveConnection() { } return conn; } - } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index b4ef095b..13dce06c 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -48,10 +48,11 @@ class NetworkManagerWifiMedium delete; NetworkManagerWifiMedium &operator=(NetworkManagerWifiMedium &&) = delete; NetworkManagerWifiMedium(std::shared_ptr network_manager, - sdbus::IConnection &system_bus, const sdbus::ObjectPath &wireless_device_object_path) - : ProxyInterfaces(system_bus, "org.freedesktop.NetworkManager", + : ProxyInterfaces(*network_manager->GetConnection(), + "org.freedesktop.NetworkManager", wireless_device_object_path), + system_bus_(network_manager->GetConnection()), network_manager_(std::move(network_manager)), last_scan_(-1) { registerProxy(); @@ -111,6 +112,7 @@ class NetworkManagerWifiMedium std::vector &ssid) ABSL_LOCKS_EXCLUDED(known_access_points_lock_); + std::shared_ptr system_bus_; std::shared_ptr network_manager_; api::WifiCapability capability_; From f489a179a6d2cc8984eb5956768d4bcfb1e2f0bf Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 21:42:30 +0530 Subject: [PATCH 139/201] Remove org.freedesktop.LogControl implementation. The final application is in charge of logging, not the library. --- .../implementation/linux/log_message.cc | 90 ++++--------------- .../implementation/linux/log_message.h | 87 +----------------- 2 files changed, 18 insertions(+), 159 deletions(-) diff --git a/internal/platform/implementation/linux/log_message.cc b/internal/platform/implementation/linux/log_message.cc index 0f2bc3b5..bb29d634 100644 --- a/internal/platform/implementation/linux/log_message.cc +++ b/internal/platform/implementation/linux/log_message.cc @@ -30,36 +30,12 @@ #include "internal/platform/implementation/linux/log_message.h" namespace nearby { -static std::unique_ptr global_log_control_; -static absl::once_flag log_control_init_; - -static void cleanup_log_control() { - global_log_control_ = nullptr; -} - -static void init_log_control(std::nullptr_t) { - global_log_control_ = - std::make_unique(linux::getDefaultBusConnection()); - atexit(cleanup_log_control); -} - -namespace api { -void LogMessage::SetMinLogSeverity(Severity severity) { - absl::call_once(log_control_init_, init_log_control, nullptr); - assert(global_log_control_ != nullptr); - global_log_control_->LogLevel(severity); -} - -bool LogMessage::ShouldCreateLogMessage(Severity severity) { - absl::call_once(log_control_init_, init_log_control, nullptr); - assert(global_log_control_ != nullptr); - return severity >= global_log_control_->GetLogLevel(); -} - -} // namespace api namespace linux { -static inline google::LogSeverity ConvertSeverity( - api::LogMessage::Severity severity) { + +std::atomic min_log_severity_ = + api::LogMessage::Severity::kInfo; + +inline google::LogSeverity ConvertSeverity(api::LogMessage::Severity severity) { switch (severity) { case api::LogMessage::Severity::kWarning: return google::GLOG_WARNING; @@ -73,52 +49,9 @@ static inline google::LogSeverity ConvertSeverity( return google::GLOG_INFO; } } -static inline int ConvertSeverityToSyslog(google::LogSeverity severity) { - switch (severity) { - case google::GLOG_WARNING: - return LOG_WARNING; - case google::GLOG_ERROR: - return LOG_ERR; - case google::GLOG_FATAL: - return LOG_EMERG; - case google::GLOG_INFO: - default: - return LOG_INFO; - } -} -// TODO: Set a LogSink depending on the target set by LogControl LogMessage::LogMessage(const char *file, int line, Severity severity) - : log_streamer_(file, line, ConvertSeverity(severity), - global_log_control_.get(), false) {} - -static absl::Mutex cout_mutex; - -void LogControl::send(google::LogSeverity severity, const char *full_filename, - const char *base_filename, int line, - const struct ::tm *tm_time, const char *message, - size_t message_len) { - switch (log_target_) { - case kJournal: - sd_journal_send("MESSAGE=%s", message, "PRIORITY=%d", - ConvertSeverityToSyslog(severity), "CODE_FILE=%s", - base_filename, "CODE_LINE=%d", line, NULL); - break; - case kSyslog: { - auto str = LogSink::ToString(severity, base_filename, line, tm_time, - message, message_len); - syslog(ConvertSeverityToSyslog(severity), "%s", str.c_str()); - break; - } - case kConsole: - default: - absl::MutexLock l(&cout_mutex); - std::cout << LogSink::ToString(severity, base_filename, line, tm_time, - message, message_len) - << "\n"; - break; - } -} + : log_streamer_(file, line, ConvertSeverity(severity)) {} void LogMessage::Print(const char *format, ...) { char *buf = nullptr; @@ -136,4 +69,15 @@ void LogMessage::Print(const char *format, ...) { std::ostream &LogMessage::Stream() { return log_streamer_.stream(); } } // namespace linux + +namespace api { + +void LogMessage::SetMinLogSeverity(Severity severity) { + linux::min_log_severity_ = severity; +} + +bool LogMessage::ShouldCreateLogMessage(Severity severity) { + return severity >= linux::min_log_severity_; +} +} // namespace api } // namespace nearby diff --git a/internal/platform/implementation/linux/log_message.h b/internal/platform/implementation/linux/log_message.h index 07ef773c..c11b5d60 100644 --- a/internal/platform/implementation/linux/log_message.h +++ b/internal/platform/implementation/linux/log_message.h @@ -17,9 +17,9 @@ #include #include +#include #include "glog/logging.h" -#include "internal/platform/implementation/linux/generated/dbus/logcontrol/logcontrol_server.h" #include "internal/platform/implementation/log_message.h" namespace nearby { @@ -38,91 +38,6 @@ class LogMessage : public api::LogMessage { private: google::LogMessage log_streamer_; - static api::LogMessage::Severity min_log_severity_; -}; - -class LogControl - : public sdbus::AdaptorInterfaces, - public google::LogSink { - public: - LogControl(sdbus::IConnection &system_bus) - : AdaptorInterfaces(system_bus, "/org/freedesktop/LogControl1"), - severity_(api::LogMessage::LogMessage::Severity::kVerbose), - log_target_(kConsole) { - registerAdaptor(); - } - ~LogControl() { unregisterAdaptor(); } - - void LogLevel(const LogMessage::Severity &severity) { severity_ = severity; } - - LogMessage::Severity GetLogLevel() { return severity_; } - - protected: - std::string LogLevel() override { - switch (severity_) { - case api::LogMessage::Severity::kInfo: - return "info"; - case api::LogMessage::Severity::kWarning: - return "warning"; - case api::LogMessage::Severity::kError: - return "err"; - case api::LogMessage::Severity::kFatal: - return "emerg"; - case api::LogMessage::Severity::kVerbose: - default: - return "debug"; - } - } - - void LogLevel(const std::string &value) override { - if (value == "debug") - severity_ = api::LogMessage::Severity::kVerbose; - else if (value == "info") - severity_ = api::LogMessage::Severity::kInfo; - else if (value == "warning") - severity_ = api::LogMessage::Severity::kWarning; - else if (value == "err") - severity_ = api::LogMessage::Severity::kError; - else if (value == "crit" || value == "alert" || value == "emerg") - severity_ = api::LogMessage::Severity::kFatal; - } - - enum LogTarget { kConsole, kKernel, kJournal, kSyslog }; - - std::string LogTarget() override { - switch (log_target_) { - case kKernel: - return "kmsg"; - case kJournal: - return "journal"; - case kSyslog: - return "syslog"; - case kConsole: - default: - return "console"; - } - } - - void LogTarget(const std::string &value) override { - if (value == "console") - log_target_ = kConsole; - else if (value == "kmsg") - log_target_ = kKernel; - else if (value == "journal") - log_target_ = kJournal; - else if (value == "syslog") - log_target_ = kSyslog; - } - - std::string SyslogIdentifier() override { return "com.google.nearby"; } - - void send(google::LogSeverity severity, const char *full_filename, - const char *base_filename, int line, const struct ::tm *tm_time, - const char *message, size_t message_len) override; - - private: - std::atomic severity_; - std::atomic log_target_; }; } // namespace linux } // namespace nearby From c7a5bdcebb8c40f66c633210dd6c9a9014329213 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 21:58:18 +0530 Subject: [PATCH 140/201] Destroy DeviceWatcher _after_ stopping discovery. This lets DeviceWatcher receive InterfacesRemoved signals so that we can potentially get rid of lost devices. --- internal/platform/implementation/linux/ble_v2_medium.cc | 9 +++++---- .../implementation/linux/bluetooth_classic_medium.cc | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index bbc31d8d..d51bc4cb 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -419,16 +419,17 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, << "' and message '" << e.getMessage() << "'"; } - active_adv_monitors_.erase(service_uuid); - 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); - return absl::InternalError(e.getMessage()); + status = absl::InternalError(e.getMessage()); } - return absl::OkStatus(); + active_adv_monitors_.erase(service_uuid); + return status; }}); } diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 036315d6..676ce017 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -81,15 +81,16 @@ bool BluetoothClassicMedium::StopDiscovery() { auto &adapter = adapter_.GetBluezAdapterObject(); NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " << adapter.getObjectPath(); - device_watcher_ = nullptr; + auto ret = true; try { adapter.StopDiscovery(); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); - return false; + ret = false; } + device_watcher_ = nullptr; - return true; + return ret; } std::unique_ptr BluetoothClassicMedium::ConnectToService( From 799a8e94044e9f4a6751c9363cfca5f65a1c9eb4 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 23:11:38 +0530 Subject: [PATCH 141/201] Register: Fix bug with profile options not getting correctly set --- .../implementation/linux/bluetooth_bluez_profile.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 5aa359eb..f9702d1e 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -121,11 +121,12 @@ bool ProfileManager::Register(std::optional name, std::map options; if (name.has_value()) { options["Name"] = std::string(*name); - options["RequireAuthorization"] = false; - options["RequireAuthentication"] = false; - options["Channel"] = static_cast(0); - options["PSM"] = static_cast(0); } + options["RequireAuthorization"] = false; + options["RequireAuthentication"] = false; + options["Channel"] = static_cast(0); + options["PSM"] = static_cast(0); + RegisterProfile(profile->getObjectPath(), std::string(service_uuid), options); } catch (const sdbus::Error &e) { @@ -136,7 +137,7 @@ bool ProfileManager::Register(std::optional name, registered_services_.emplace(service_uuid, profile); NEARBY_LOGS(INFO) << __func__ - << ": Registered profile instancefor service uuid " + << ": Registered profile instance for service uuid " << service_uuid; return true; From 936b332aba067497a641431233ec6218ff88fc19 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 23:12:30 +0530 Subject: [PATCH 142/201] Minor refactor --- .../linux/bluetooth_classic_medium.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 676ce017..dd7179bc 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -28,7 +28,6 @@ #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/implementation/linux/bluez.h" #include "internal/platform/logging.h" namespace nearby { @@ -96,18 +95,21 @@ bool BluetoothClassicMedium::StopDiscovery() { std::unique_ptr BluetoothClassicMedium::ConnectToService( api::BluetoothDevice &remote_device, const std::string &service_uuid, CancellationFlag *cancellation_flag) { - auto device_object_path = bluez::device_object_path( - adapter_.GetObjectPath(), remote_device.GetMacAddress()); if (!profile_manager_->ProfileRegistered(service_uuid)) { - if (!profile_manager_->Register("", 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 device = devices_->get_device_by_path(device_object_path); - if (device == nullptr) 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; @@ -118,8 +120,7 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( if (!fd.has_value()) { NEARBY_LOGS(WARNING) << __func__ << ": Failed to get a new connection for profile " - << service_uuid << " for device " - << device_object_path; + << service_uuid << " for device " << address; return nullptr; } From 4267ec43f3c9464ce83f43f97f6db93952e64023 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sat, 9 Sep 2023 23:46:10 +0530 Subject: [PATCH 143/201] Don't provide auth-alg for WPA connections. --- .../platform/implementation/linux/wifi_medium.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index cc7d734c..4309404f 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -207,14 +207,14 @@ NetworkManagerWifiMedium::SearchBySSID(absl::string_view ssid, return ap; } -static inline std::pair AuthAlgAndKeyMgmt( - api::WifiAuthType auth_type) { +static inline std::pair, std::string> +AuthAlgAndKeyMgmt(api::WifiAuthType auth_type) { switch (auth_type) { case api::WifiAuthType::kUnknown: case api::WifiAuthType::kOpen: return {"open", "none"}; case api::WifiAuthType::kWpaPsk: - return {"shared", "wpa-psk"}; + return {std::nullopt, "wpa-psk"}; case api::WifiAuthType::kWep: return {"none", "wep"}; } @@ -267,12 +267,14 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( {"assigned-mac-address", "random"}, }}, {"802-11-wireless-security", - std::map{{"auth-alg", auth_alg}, - {"key-mgmt", key_mgmt}}}}; + std::map{{"key-mgmt", key_mgmt}}}}; if (!password.empty()) { connection_settings["802-11-wireless-security"]["psk"] = std::string(password); } + if (auth_alg.has_value()) { + connection_settings["802-11-wireless-security"]["auth-alg"] = *auth_alg; + } sdbus::ObjectPath connection_path, active_conn_path; try { @@ -310,6 +312,7 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( return api::WifiConnectionStatus::kAuthFailure; } + NEARBY_LOGS(INFO) << __func__ << ": Activated connection " << connection_path; return api::WifiConnectionStatus::kConnected; } From 358d01f3504915bdf1a1894fc7a337c9cdcb2c4f Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 10 Sep 2023 00:10:34 +0530 Subject: [PATCH 144/201] ConntectToService: Use ConnectedToWifi instead of WifiHotspotActive --- internal/platform/implementation/linux/wifi_hotspot.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 151d4748..f12c4c69 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -35,7 +35,7 @@ std::unique_ptr NetworkManagerWifiHotspotMedium::ConnectToService( absl::string_view ip_address, int port, CancellationFlag *cancellation_flag) { - if (!WifiHotspotActive()) { + if (!ConnectedToWifi()) { NEARBY_LOGS(ERROR) << __func__ << ": Cannot connect to service without an active WiFi hotspot"; From 71ba41c14db23669de962bc6e15beb95d05a9b98 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 10 Sep 2023 00:11:10 +0530 Subject: [PATCH 145/201] StartWifiHotspot: Disable PMF explicitly for the hotspot. --- internal/platform/implementation/linux/wifi_hotspot.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index f12c4c69..ca8fa918 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -186,13 +186,9 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( {"security", "802-11-wireless-security"}}}, {"802-11-wireless-security", std::map{ - {"group", std::vector{"ccmp"}}, + {"pmf", static_cast( + 1)}, // NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE {"key-mgmt", "wpa-psk"}, - { - "pairwise", - std::vector{"ccmp"}, - }, - {"proto", std::vector{"rsn"}}, {"psk", password}}}, {"ipv4", std::map{{"method", "shared"}}}, {"ipv6", std::map{ From 70f732239e9aea5a3d12efa6f43b3a9fdf2a528d Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 10 Sep 2023 00:14:18 +0530 Subject: [PATCH 146/201] Shutdown wifi server sockets before closing them. --- .../implementation/linux/wifi_direct_server_socket.cc | 1 + .../implementation/linux/wifi_hotspot_server_socket.cc | 10 ++++++---- .../implementation/linux/wifi_lan_server_socket.cc | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.cc b/internal/platform/implementation/linux/wifi_direct_server_socket.cc index 099e6d3a..b4e46cc5 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.cc @@ -66,6 +66,7 @@ NetworkManagerWifiDirectServerSocket::Accept() { Exception NetworkManagerWifiDirectServerSocket::Close() { int fd = fd_.release(); + shutdown(fd, SHUT_RDWR); auto ret = close(fd); if (ret < 0) { NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc index d74f8f91..88d7e5d0 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc @@ -34,7 +34,7 @@ std::string NetworkManagerWifiHotspotServerSocket::GetIPAddress() const { } int NetworkManagerWifiHotspotServerSocket::GetPort() const { - struct sockaddr_in sin{}; + struct sockaddr_in sin {}; socklen_t len = sizeof(sin); auto ret = getsockname(fd_.get(), reinterpret_cast(&sin), &len); @@ -49,7 +49,7 @@ int NetworkManagerWifiHotspotServerSocket::GetPort() const { std::unique_ptr NetworkManagerWifiHotspotServerSocket::Accept() { - struct sockaddr_in addr{}; + struct sockaddr_in addr {}; socklen_t len = sizeof(addr); auto conn = @@ -65,10 +65,12 @@ NetworkManagerWifiHotspotServerSocket::Accept() { } Exception NetworkManagerWifiHotspotServerSocket::Close() { + int fd = fd_.release(); + shutdown(fd, SHUT_RDWR); auto ret = close(fd_.release()); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket: " - << std::strerror(errno); + NEARBY_LOGS(ERROR) << __func__ + << ": Error closing socket: " << std::strerror(errno); return {Exception::kFailed}; } diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index d4bbd1b9..7669c08a 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -106,6 +106,7 @@ std::unique_ptr WifiLanServerSocket::Accept() { Exception WifiLanServerSocket::Close() { int fd = fd_.release(); + shutdown(fd, SHUT_RDWR); auto ret = close(fd); if (ret < 0) { NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " From 8c762ea9ab55ef4b52633429125ff4ecb3a61ce5 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Sun, 10 Sep 2023 00:14:52 +0530 Subject: [PATCH 147/201] Reenable Start/StopWifiDirect --- .../implementation/linux/wifi_direct.cc | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index b0e43ea4..189c82bd 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -157,30 +157,27 @@ bool NetworkManagerWifiDirectMedium::StartWifiDirect( WifiDirectCredentials *wifi_direct_credentials) { // According to the comments in the windows implementation, the wifi direct // medium is currently just a regular wifi hotspot. - // auto wireless_device = std::make_unique( - // network_manager_, system_bus_, wireless_device_->getObjectPath()); - // auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, - // network_manager_, - // std::move(wireless_device)); + auto wireless_device = std::make_unique( + network_manager_, wireless_device_->getObjectPath()); + auto hotspot = NetworkManagerWifiHotspotMedium(network_manager_, + std::move(wireless_device)); - // HotspotCredentials hotspot_creds; - // if (!hotspot.StartWifiHotspot(&hotspot_creds)) return false; + HotspotCredentials hotspot_creds; + if (!hotspot.StartWifiHotspot(&hotspot_creds)) return false; - // wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID()); - // wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword()); - // return true; + wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID()); + wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword()); + return true; return false; } bool NetworkManagerWifiDirectMedium::StopWifiDirect() { - // auto wireless_device = std::make_unique( - // network_manager_, system_bus_, wireless_device_->getObjectPath()); - // auto hotspot = NetworkManagerWifiHotspotMedium(system_bus_, - // network_manager_, - // std::move(wireless_device)); + auto wireless_device = std::make_unique( + network_manager_, wireless_device_->getObjectPath()); + auto hotspot = NetworkManagerWifiHotspotMedium(network_manager_, + std::move(wireless_device)); - // return hotspot.DisconnectWifiHotspot(); - return false; + return hotspot.DisconnectWifiHotspot(); } } // namespace linux From 0d32fb37fbb51dee7a7f4c89be3362201c23db85 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 13:13:28 +0530 Subject: [PATCH 148/201] Move all NetworkManager D-Bus code to its own namespace. --- .../implementation/linux/network_manager.cc | 14 ++--- .../implementation/linux/network_manager.h | 42 +++++++-------- .../network_manager_active_connection.cc | 52 ++++++++++--------- .../linux/network_manager_active_connection.h | 24 ++++----- .../platform/implementation/linux/platform.cc | 12 ++--- .../implementation/linux/wifi_direct.cc | 1 - .../implementation/linux/wifi_direct.h | 5 +- .../linux/wifi_direct_server_socket.h | 8 +-- .../implementation/linux/wifi_hotspot.cc | 8 +-- .../implementation/linux/wifi_hotspot.h | 6 +-- .../linux/wifi_hotspot_server_socket.h | 10 ++-- .../platform/implementation/linux/wifi_lan.cc | 10 ++-- .../platform/implementation/linux/wifi_lan.h | 4 +- .../linux/wifi_lan_server_socket.cc | 4 +- .../linux/wifi_lan_server_socket.h | 4 +- .../implementation/linux/wifi_medium.cc | 13 +++-- .../implementation/linux/wifi_medium.h | 9 ++-- 17 files changed, 112 insertions(+), 114 deletions(-) diff --git a/internal/platform/implementation/linux/network_manager.cc b/internal/platform/implementation/linux/network_manager.cc index 6089980e..5c046fa5 100644 --- a/internal/platform/implementation/linux/network_manager.cc +++ b/internal/platform/implementation/linux/network_manager.cc @@ -20,8 +20,9 @@ namespace nearby { namespace linux { -std::unique_ptr -NetworkManagerObjectManager::GetActiveConnectionForAccessPoint( +namespace networkmanager { +std::unique_ptr +ObjectManager::GetActiveConnectionForAccessPoint( const sdbus::ObjectPath &access_point, const sdbus::ObjectPath &device_path) { std::map devices = props["Devices"]; for (auto &path : devices) { if (path == device_path) { - return std::make_unique( + return std::make_unique( system_bus_, object_path); } } @@ -57,8 +58,7 @@ NetworkManagerObjectManager::GetActiveConnectionForAccessPoint( return nullptr; } -std::unique_ptr -NetworkManagerObjectManager::GetIp4Config( +std::unique_ptr ObjectManager::GetIp4Config( const sdbus::ObjectPath &active_connection) { std::map>> @@ -80,8 +80,7 @@ NetworkManagerObjectManager::GetIp4Config( sdbus::ObjectPath specific_object = props["SpecificObject"]; if (specific_object == active_connection) { sdbus::ObjectPath ip4config = props["Ip4Config"]; - return std::make_unique(system_bus_, - ip4config); + return std::make_unique(system_bus_, ip4config); } } } @@ -89,5 +88,6 @@ NetworkManagerObjectManager::GetIp4Config( return nullptr; } +} // namespace networkmanager } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/network_manager.h b/internal/platform/implementation/linux/network_manager.h index 7f6d889d..7226f769 100644 --- a/internal/platform/implementation/linux/network_manager.h +++ b/internal/platform/implementation/linux/network_manager.h @@ -27,6 +27,7 @@ namespace nearby { namespace linux { +namespace networkmanager { class NetworkManager final : public sdbus::ProxyInterfaces { public: @@ -96,48 +97,44 @@ class NetworkManager final std::atomic state_; }; -class NetworkManagerIP4Config - : public sdbus::ProxyInterfaces< - org::freedesktop::NetworkManager::IP4Config_proxy> { +class IP4Config : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::IP4Config_proxy> { public: - NetworkManagerIP4Config(const NetworkManagerIP4Config &) = delete; - NetworkManagerIP4Config(NetworkManagerIP4Config &&) = delete; - NetworkManagerIP4Config &operator=(const NetworkManagerIP4Config &) = delete; - NetworkManagerIP4Config &operator=(NetworkManagerIP4Config &&) = delete; - NetworkManagerIP4Config(std::shared_ptr system_bus, - const sdbus::ObjectPath &config_object_path) + IP4Config(const IP4Config &) = delete; + IP4Config(IP4Config &&) = delete; + IP4Config &operator=(const IP4Config &) = delete; + IP4Config &operator=(IP4Config &&) = delete; + IP4Config(std::shared_ptr system_bus, + const sdbus::ObjectPath &config_object_path) : ProxyInterfaces(*system_bus, "org.freedesktop.NetworkManager", config_object_path), system_bus_(std::move(system_bus)) { registerProxy(); } - ~NetworkManagerIP4Config() { unregisterProxy(); } + ~IP4Config() { unregisterProxy(); } private: std::shared_ptr system_bus_; }; -class NetworkManagerObjectManager final +class ObjectManager final : public sdbus::ProxyInterfaces { public: - NetworkManagerObjectManager(const NetworkManagerObjectManager &) = delete; - NetworkManagerObjectManager(NetworkManagerObjectManager &&) = delete; - NetworkManagerObjectManager &operator=(const NetworkManagerObjectManager &) = - delete; - NetworkManagerObjectManager &operator=(NetworkManagerObjectManager &&) = - delete; - explicit NetworkManagerObjectManager( - std::shared_ptr system_bus) + ObjectManager(const ObjectManager &) = delete; + ObjectManager(ObjectManager &&) = delete; + ObjectManager &operator=(const ObjectManager &) = delete; + ObjectManager &operator=(ObjectManager &&) = delete; + explicit ObjectManager(std::shared_ptr system_bus) : ProxyInterfaces(*system_bus, "org.freedesktop.NetworkManager", "/org/freedesktop"), system_bus_(std::move(system_bus)) { registerProxy(); } - ~NetworkManagerObjectManager() { unregisterProxy(); } + ~ObjectManager() { unregisterProxy(); } - std::unique_ptr GetIp4Config( + std::unique_ptr GetIp4Config( const sdbus::ObjectPath &access_point); - std::unique_ptr + std::unique_ptr GetActiveConnectionForAccessPoint(const sdbus::ObjectPath &access_point_path, const sdbus::ObjectPath &device_path); @@ -154,6 +151,7 @@ class NetworkManagerObjectManager final std::shared_ptr system_bus_; }; +} // namespace networkmanager } // namespace linux } // namespace nearby #endif diff --git a/internal/platform/implementation/linux/network_manager_active_connection.cc b/internal/platform/implementation/linux/network_manager_active_connection.cc index 8bb6a44b..6202abac 100644 --- a/internal/platform/implementation/linux/network_manager_active_connection.cc +++ b/internal/platform/implementation/linux/network_manager_active_connection.cc @@ -23,54 +23,55 @@ namespace nearby { namespace linux { +namespace networkmanager { std::ostream &operator<<( std::ostream &stream, - const NetworkManagerActiveConnection::ActiveConnectionStateReason &reason) { + const ActiveConnection::ActiveConnectionStateReason &reason) { switch (reason) { - case NetworkManagerActiveConnection::kStateReasonUnknown: - return stream - << "The reason for the active connection state change is unknown."; - case NetworkManagerActiveConnection::kStateReasonNone: + case ActiveConnection::kStateReasonUnknown: + return stream << "The reason for the active connection state change is " + "unknown."; + case ActiveConnection::kStateReasonNone: return stream << "No reason was given for the active connection state change."; - case NetworkManagerActiveConnection::kStateReasonUserDisconnected: + case ActiveConnection::kStateReasonUserDisconnected: return stream << "The active connection changed state because the user " "disconnected it."; - case NetworkManagerActiveConnection::kStateReasonDeviceDisconnected: - return stream - << "The active connection changed state because the device it was " - "using was disconnected."; - case NetworkManagerActiveConnection::kStateReasonServiceStopped: + case ActiveConnection::kStateReasonDeviceDisconnected: + return stream << "The active connection changed state because the " + "device it was " + "using was disconnected."; + case ActiveConnection::kStateReasonServiceStopped: return stream << "The service providing the VPN connection was stopped."; - case NetworkManagerActiveConnection::kStateReasonIPConfigInvalid: + case ActiveConnection::kStateReasonIPConfigInvalid: return stream << "The IP config of the active connection was invalid."; - case NetworkManagerActiveConnection::kStateReasonConnectTimeout: + case ActiveConnection::kStateReasonConnectTimeout: return stream << "The connection attempt to the VPN service timed out."; - case NetworkManagerActiveConnection::kStateReasonServiceStartTimeout: + case ActiveConnection::kStateReasonServiceStartTimeout: return stream << "A timeout occurred while starting the service providing the " "VPN connection."; - case NetworkManagerActiveConnection::kStateReasonServiceStartFailed: + case ActiveConnection::kStateReasonServiceStartFailed: return stream << "Starting the service providing the VPN connection failed."; - case NetworkManagerActiveConnection::kStateReasonNoSecrets: + case ActiveConnection::kStateReasonNoSecrets: return stream << "Necessary secrets for the connection were not provided."; - case NetworkManagerActiveConnection::kStateReasonLoginFailed: + case ActiveConnection::kStateReasonLoginFailed: return stream << "Authentication to the server failed."; - case NetworkManagerActiveConnection::kStateReasonConnectionRemoved: + case ActiveConnection::kStateReasonConnectionRemoved: return stream << "The connection was deleted from settings."; - case NetworkManagerActiveConnection::kStateReasonDependencyFailed: + case ActiveConnection::kStateReasonDependencyFailed: return stream << "Master connection of this connection failed to activate."; - case NetworkManagerActiveConnection::kStateReasonDeviceRealizeFailed: + case ActiveConnection::kStateReasonDeviceRealizeFailed: return stream << "Could not create the software device link."; - case NetworkManagerActiveConnection::kStateReasonDeviceRemoved: + case ActiveConnection::kStateReasonDeviceRemoved: return stream << "The device this connection depended on disappeared."; } } -std::vector NetworkManagerActiveConnection::GetIP4Addresses() { +std::vector ActiveConnection::GetIP4Addresses() { sdbus::ObjectPath ip4config_path; try { ip4config_path = Ip4Config(); @@ -79,7 +80,7 @@ std::vector NetworkManagerActiveConnection::GetIP4Addresses() { return {}; } - NetworkManagerIP4Config ip4config(system_bus_, ip4config_path); + IP4Config ip4config(system_bus_, ip4config_path); std::vector> address_data; try { address_data = ip4config.AddressData(); @@ -97,8 +98,8 @@ std::vector NetworkManagerActiveConnection::GetIP4Addresses() { return ip4addresses; } -std::pair, bool> -NetworkManagerActiveConnection::WaitForConnection(absl::Duration timeout) { +std::pair, bool> +ActiveConnection::WaitForConnection(absl::Duration timeout) { NEARBY_LOGS(VERBOSE) << __func__ << ": Waiting for an update to " << getObjectPath() << "'s state"; @@ -120,5 +121,6 @@ NetworkManagerActiveConnection::WaitForConnection(absl::Duration timeout) { return state == kStateActivated ? std::pair{std::nullopt, false} : std::pair{std::optional(reason), false}; } +} // namespace networkmanager } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/network_manager_active_connection.h b/internal/platform/implementation/linux/network_manager_active_connection.h index 5ff19379..0e06fe6a 100644 --- a/internal/platform/implementation/linux/network_manager_active_connection.h +++ b/internal/platform/implementation/linux/network_manager_active_connection.h @@ -26,7 +26,8 @@ namespace nearby { namespace linux { -class NetworkManagerActiveConnection +namespace networkmanager { +class ActiveConnection : public sdbus::ProxyInterfaces< org::freedesktop::NetworkManager::Connection::Active_proxy> { public: @@ -55,16 +56,12 @@ class NetworkManagerActiveConnection kStateReasonDeviceRemoved = 14, }; - NetworkManagerActiveConnection(const NetworkManagerActiveConnection &) = - delete; - NetworkManagerActiveConnection(NetworkManagerActiveConnection &&) = delete; - NetworkManagerActiveConnection &operator=( - const NetworkManagerActiveConnection &) = delete; - NetworkManagerActiveConnection &operator=(NetworkManagerActiveConnection &&) = - delete; - explicit NetworkManagerActiveConnection( - std::shared_ptr system_bus, - sdbus::ObjectPath active_connection_path) + ActiveConnection(const ActiveConnection &) = delete; + ActiveConnection(ActiveConnection &&) = delete; + ActiveConnection &operator=(const ActiveConnection &) = delete; + ActiveConnection &operator=(ActiveConnection &&) = delete; + explicit ActiveConnection(std::shared_ptr system_bus, + sdbus::ObjectPath active_connection_path) : ProxyInterfaces(*system_bus, "org.freedesktop.NetworkManager", std::move(active_connection_path)), system_bus_(std::move(system_bus)), @@ -80,7 +77,7 @@ class NetworkManagerActiveConnection DBUS_LOG_PROPERTY_GET_ERROR(this, "State", e); } } - virtual ~NetworkManagerActiveConnection() { unregisterProxy(); } + virtual ~ActiveConnection() { unregisterProxy(); } protected: void onStateChanged(const uint32_t &state, const uint32_t &reason) override @@ -110,8 +107,9 @@ class NetworkManagerActiveConnection extern std::ostream &operator<<( std::ostream &stream, - const NetworkManagerActiveConnection::ActiveConnectionStateReason &reason); + const ActiveConnection::ActiveConnectionStateReason &reason); +} // namespace networkmanager } // namespace linux } // namespace nearby #endif diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 632d3732..1829a717 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -205,7 +205,7 @@ ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { namespace { static std::unique_ptr createWifiMedium( - std::shared_ptr nm) { + std::shared_ptr nm) { std::vector device_paths; try { @@ -215,7 +215,7 @@ static std::unique_ptr createWifiMedium( return nullptr; } - auto manager = linux::NetworkManagerObjectManager(nm->GetConnection()); + auto manager = linux::networkmanager::ObjectManager(nm->GetConnection()); std::map>> @@ -248,21 +248,21 @@ static std::unique_ptr createWifiMedium( std::unique_ptr ImplementationPlatform::CreateWifiMedium() { auto nm = - std::make_shared(linux::getSystemBusConnection()); + std::make_shared(linux::getSystemBusConnection()); return createWifiMedium(nm); } std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { auto nm = - std::make_shared(linux::getSystemBusConnection()); + std::make_shared(linux::getSystemBusConnection()); return std::make_unique(nm); } std::unique_ptr ImplementationPlatform::CreateWifiHotspotMedium() { auto nm = - std::make_shared(linux::getSystemBusConnection()); + std::make_shared(linux::getSystemBusConnection()); auto wifiMedium = createWifiMedium(nm); if (wifiMedium == nullptr) { @@ -277,7 +277,7 @@ ImplementationPlatform::CreateWifiHotspotMedium() { std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { auto nm = - std::make_shared(linux::getSystemBusConnection()); + std::make_shared(linux::getSystemBusConnection()); auto wifiMedium = createWifiMedium(nm); if (wifiMedium == nullptr) { diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index 189c82bd..5830b16d 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -168,7 +168,6 @@ bool NetworkManagerWifiDirectMedium::StartWifiDirect( wifi_direct_credentials->SetSSID(hotspot_creds.GetSSID()); wifi_direct_credentials->SetPassword(hotspot_creds.GetPassword()); return true; - return false; } bool NetworkManagerWifiDirectMedium::StopWifiDirect() { diff --git a/internal/platform/implementation/linux/wifi_direct.h b/internal/platform/implementation/linux/wifi_direct.h index 05711aaf..42d773e8 100644 --- a/internal/platform/implementation/linux/wifi_direct.h +++ b/internal/platform/implementation/linux/wifi_direct.h @@ -20,6 +20,7 @@ #include +#include "internal/platform/implementation/linux/network_manager.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_direct.h" @@ -28,7 +29,7 @@ namespace linux { class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium { public: NetworkManagerWifiDirectMedium( - std::shared_ptr network_manager, + std::shared_ptr network_manager, std::unique_ptr wireless_device) : system_bus_(network_manager->GetConnection()), network_manager_(std::move(network_manager)), @@ -56,7 +57,7 @@ class NetworkManagerWifiDirectMedium : public api::WifiDirectMedium { bool ConnectedToWifi(); std::shared_ptr system_bus_; - std::shared_ptr network_manager_; + std::shared_ptr network_manager_; std::unique_ptr wireless_device_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.h b/internal/platform/implementation/linux/wifi_direct_server_socket.h index 34a88e9a..727ab490 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.h @@ -25,8 +25,8 @@ class NetworkManagerWifiDirectServerSocket : public api::WifiDirectServerSocket { public: NetworkManagerWifiDirectServerSocket( - int socket, std::unique_ptr active_conn, - std::shared_ptr network_manager) + int socket, std::unique_ptr active_conn, + std::shared_ptr network_manager) : fd_(socket), active_conn_(std::move(active_conn)), network_manager_(std::move(network_manager)) {} @@ -38,8 +38,8 @@ class NetworkManagerWifiDirectServerSocket private: sdbus::UnixFd fd_; - std::unique_ptr active_conn_; - std::shared_ptr network_manager_; + std::unique_ptr active_conn_; + std::shared_ptr network_manager_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index ca8fa918..3e673721 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -195,14 +195,14 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( {"addr-gen-mode", static_cast(1)}, {"method", "shared"}, }}}; - std::unique_ptr active_conn; + std::unique_ptr active_conn; try { auto [path, active_path, result] = network_manager_->AddAndActivateConnection2( connection_settings, wireless_device_->getObjectPath(), "/", {{"persist", "volatile"}, {"bind-activation", "dbus-client"}}); - active_conn = std::make_unique(system_bus_, - active_path); + active_conn = std::make_unique( + system_bus_, active_path); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "AddAndActivateConnection2", e); @@ -248,7 +248,7 @@ bool NetworkManagerWifiHotspotMedium::StopWifiHotspot() { DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "ActiveAccessPoint", e); } - auto object_manager = NetworkManagerObjectManager(system_bus_); + auto object_manager = networkmanager::ObjectManager(system_bus_); auto active_connection = wireless_device_->GetActiveConnection(); if (active_connection == nullptr) { NEARBY_LOGS(ERROR) diff --git a/internal/platform/implementation/linux/wifi_hotspot.h b/internal/platform/implementation/linux/wifi_hotspot.h index d1b143db..2eed28cb 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.h +++ b/internal/platform/implementation/linux/wifi_hotspot.h @@ -26,14 +26,14 @@ namespace linux { class NetworkManagerWifiHotspotMedium : public api::WifiHotspotMedium { public: NetworkManagerWifiHotspotMedium( - std::shared_ptr network_manager, + std::shared_ptr network_manager, sdbus::ObjectPath wireless_device_object_path) : system_bus_(network_manager->GetConnection()), wireless_device_(std::make_unique( network_manager, std::move(wireless_device_object_path))), network_manager_(std::move(network_manager)) {} NetworkManagerWifiHotspotMedium( - std::shared_ptr network_manager, + std::shared_ptr network_manager, std::unique_ptr wireless_device) : system_bus_(network_manager->GetConnection()), wireless_device_(std::move(wireless_device)), @@ -63,7 +63,7 @@ class NetworkManagerWifiHotspotMedium : public api::WifiHotspotMedium { std::shared_ptr system_bus_; std::unique_ptr wireless_device_; - std::shared_ptr network_manager_; + std::shared_ptr network_manager_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h index 587ef20a..d6130aeb 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h @@ -17,8 +17,8 @@ #include +#include "internal/platform/implementation/linux/network_manager.h" #include "internal/platform/implementation/linux/network_manager_active_connection.h" -#include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_hotspot.h" namespace nearby { @@ -27,8 +27,8 @@ class NetworkManagerWifiHotspotServerSocket : public api::WifiHotspotServerSocket { public: NetworkManagerWifiHotspotServerSocket( - int socket, std::unique_ptr active_conn, - std::shared_ptr network_manager) + int socket, std::unique_ptr active_conn, + std::shared_ptr network_manager) : fd_(socket), active_conn_(std::move(active_conn)), network_manager_(std::move(network_manager)) {} @@ -40,8 +40,8 @@ class NetworkManagerWifiHotspotServerSocket private: sdbus::UnixFd fd_; - std::unique_ptr active_conn_; - std::shared_ptr network_manager_; + std::unique_ptr active_conn_; + std::shared_ptr network_manager_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index f1af9510..99d52c31 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -37,16 +37,16 @@ namespace nearby { namespace linux { WifiLanMedium::WifiLanMedium( - std::shared_ptr network_manager) + std::shared_ptr network_manager) : system_bus_(network_manager->GetConnection()), - network_manager_(std::move(network_manager)), + network_manager_(std::move(network_manager)), avahi_(std::make_shared(*system_bus_)) {} bool WifiLanMedium::IsNetworkConnected() const { auto state = network_manager_->getState(); - return state == NetworkManager::kNMStateConnectedLocal || - state == NetworkManager::kNMStateConnectedSite || - state == NetworkManager::kNMStateConnectedGlobal; + return state == networkmanager::NetworkManager::kNMStateConnectedLocal || + state == networkmanager::NetworkManager::kNMStateConnectedSite || + state == networkmanager::NetworkManager::kNMStateConnectedGlobal; } std::optional> entry_group_key( diff --git a/internal/platform/implementation/linux/wifi_lan.h b/internal/platform/implementation/linux/wifi_lan.h index 11abe585..5b4b278c 100644 --- a/internal/platform/implementation/linux/wifi_lan.h +++ b/internal/platform/implementation/linux/wifi_lan.h @@ -28,7 +28,7 @@ namespace nearby { namespace linux { class WifiLanMedium : public api::WifiLanMedium { public: - explicit WifiLanMedium(std::shared_ptr network_manager); + explicit WifiLanMedium(std::shared_ptr network_manager); bool IsNetworkConnected() const override; @@ -61,7 +61,7 @@ class WifiLanMedium : public api::WifiLanMedium { private: std::shared_ptr system_bus_; - std::shared_ptr network_manager_; + std::shared_ptr network_manager_; std::shared_ptr avahi_; diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index 7669c08a..b82ff2a4 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -43,7 +43,7 @@ std::string WifiLanServerSocket::GetIPAddress() const { for (auto &path : connection_paths) { auto active_connection = - std::make_unique(system_bus_, path); + std::make_unique(system_bus_, path); std::string conn_type; try { conn_type = active_connection->Type(); @@ -53,7 +53,7 @@ std::string WifiLanServerSocket::GetIPAddress() const { } if (conn_type == "802-11-wireless" || conn_type == "802-3-ethernet") { auto ip4config_path = active_connection->Ip4Config(); - NetworkManagerIP4Config ip4config(system_bus_, ip4config_path); + networkmanager::IP4Config ip4config(system_bus_, ip4config_path); std::vector> address_data; try { diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.h b/internal/platform/implementation/linux/wifi_lan_server_socket.h index 44aec805..d81bd7a3 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.h @@ -29,7 +29,7 @@ namespace linux { class WifiLanServerSocket : public api::WifiLanServerSocket { public: explicit WifiLanServerSocket(int socket, - std::shared_ptr network_manager) + std::shared_ptr network_manager) : fd_(sdbus::UnixFd(socket)), network_manager_(std::move(network_manager)), system_bus_(network_manager_->GetConnection()) {} @@ -42,7 +42,7 @@ class WifiLanServerSocket : public api::WifiLanServerSocket { private: sdbus::UnixFd fd_; - std::shared_ptr network_manager_; + std::shared_ptr network_manager_; std::shared_ptr system_bus_; }; } // namespace linux diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 4309404f..8e4624ef 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -26,7 +26,6 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/dbus.h" -#include "internal/platform/implementation/linux/generated/dbus/networkmanager/connection_active_client.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" #include "internal/platform/implementation/linux/network_manager_active_connection.h" #include "internal/platform/implementation/linux/wifi_medium.h" @@ -77,7 +76,7 @@ api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { information_ = api::WifiInformation{true, ssid, active_access_point->HwAddress(), to_signed(active_access_point->Frequency())}; - NetworkManagerObjectManager manager(system_bus_); + networkmanager::ObjectManager manager(system_bus_); auto ip4config = manager.GetIp4Config(active_access_point->getObjectPath()); if (ip4config != nullptr) { @@ -291,7 +290,7 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath() << ": Added a new connection at " << connection_path; auto active_connection = - NetworkManagerActiveConnection(system_bus_, active_conn_path); + networkmanager::ActiveConnection(system_bus_, active_conn_path); auto [reason, timeout] = active_connection.WaitForConnection(); if (timeout) { NEARBY_LOGS(ERROR) @@ -307,8 +306,8 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( << active_conn_path << " failed to activate, NMActiveConnectionStateReason:" << *reason; - if (*reason == NetworkManagerActiveConnection::kStateReasonNoSecrets || - *reason == NetworkManagerActiveConnection::kStateReasonLoginFailed) + if (*reason == networkmanager::ActiveConnection::kStateReasonNoSecrets || + *reason == networkmanager::ActiveConnection::kStateReasonLoginFailed) return api::WifiConnectionStatus::kAuthFailure; } @@ -331,7 +330,7 @@ std::string NetworkManagerWifiMedium::GetIpAddress() { return information_.ip_address_dot_decimal; } -std::unique_ptr +std::unique_ptr NetworkManagerWifiMedium::GetActiveConnection() { sdbus::ObjectPath active_ap_path; @@ -347,7 +346,7 @@ NetworkManagerWifiMedium::GetActiveConnection() { return nullptr; } - auto object_manager = NetworkManagerObjectManager(system_bus_); + auto object_manager = networkmanager::ObjectManager(system_bus_); auto conn = object_manager.GetActiveConnectionForAccessPoint(active_ap_path, getObjectPath()); diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 13dce06c..4c393a55 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -47,8 +47,9 @@ class NetworkManagerWifiMedium NetworkManagerWifiMedium &operator=(const NetworkManagerWifiMedium &) = delete; NetworkManagerWifiMedium &operator=(NetworkManagerWifiMedium &&) = delete; - NetworkManagerWifiMedium(std::shared_ptr network_manager, - const sdbus::ObjectPath &wireless_device_object_path) + NetworkManagerWifiMedium( + std::shared_ptr network_manager, + const sdbus::ObjectPath &wireless_device_object_path) : ProxyInterfaces(*network_manager->GetConnection(), "org.freedesktop.NetworkManager", wireless_device_object_path), @@ -85,7 +86,7 @@ class NetworkManagerWifiMedium bool VerifyInternetConnectivity() override; std::string GetIpAddress() override; - std::unique_ptr GetActiveConnection(); + std::unique_ptr GetActiveConnection(); protected: void onPropertiesChanged( @@ -113,7 +114,7 @@ class NetworkManagerWifiMedium ABSL_LOCKS_EXCLUDED(known_access_points_lock_); std::shared_ptr system_bus_; - std::shared_ptr network_manager_; + std::shared_ptr network_manager_; api::WifiCapability capability_; api::WifiInformation information_{false}; From 5574c3baf0ae0a8edafc21e6c6c54228b345ecff Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 15:45:52 +0530 Subject: [PATCH 149/201] Add a constants namespace to network_manager.h --- .../implementation/linux/network_manager.h | 32 +++++++++++++++++-- .../implementation/linux/wifi_hotspot.cc | 22 +++++++------ 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/internal/platform/implementation/linux/network_manager.h b/internal/platform/implementation/linux/network_manager.h index 7226f769..b4b96cb7 100644 --- a/internal/platform/implementation/linux/network_manager.h +++ b/internal/platform/implementation/linux/network_manager.h @@ -134,9 +134,9 @@ class ObjectManager final std::unique_ptr GetIp4Config( const sdbus::ObjectPath &access_point); - std::unique_ptr - GetActiveConnectionForAccessPoint(const sdbus::ObjectPath &access_point_path, - const sdbus::ObjectPath &device_path); + std::unique_ptr GetActiveConnectionForAccessPoint( + const sdbus::ObjectPath &access_point_path, + const sdbus::ObjectPath &device_path); protected: void onInterfacesAdded( @@ -151,6 +151,32 @@ class ObjectManager final std::shared_ptr system_bus_; }; +namespace constants { +// Indicates the 802.11 mode an access point or device is currently in. +enum NM80211Mode { + kNM80211ModeUnknown = 0, + kNM80211ModeAdHoc = 1, + kNM80211ModeInfra = 2, + kNM80211ModeAP = 3, + kNM80211ModeMesh = 4, +}; + +const int32_t kNMTernaryDefault = -1; +const int32_t kNMTernaryFalse = 0; +const int32_t kNMTernaryTrue = 1; + +namespace setting { +const int32_t kWirelessSecurityPMFDefaut = 0; +const int32_t kWirelessSecurityPMFDisable = 1; +const int32_t kWirelessSecurityPMFOptional = 2; +const int32_t kWirelessSecurityPMFRequired = 3; + +const int32_t kIP6ConfigAddrGenModeEUI64 = 0; +const int32_t kIP6ConfigAddrGenModeStablePrivacy = 1; +const int32_t kIP6ConfigAddrGenModeDefaultOrEUI64 = 2; +const int32_t kIP6ConfigAddrGenModeDefault = 3; +} // namespace setting +} // namespace constants } // namespace networkmanager } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 3e673721..c7d6fc6b 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -22,6 +22,7 @@ #include #include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/network_manager.h" #include "internal/platform/implementation/linux/wifi_hotspot.h" #include "internal/platform/implementation/linux/wifi_hotspot_server_socket.h" #include "internal/platform/implementation/linux/wifi_hotspot_socket.h" @@ -179,22 +180,23 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( {"802-11-wireless", std::map{ {"assigned-mac-address", "random"}, - {"ap-isolation", - static_cast(0)}, // NM_TERNARY_FALSE + {"ap-isolation", networkmanager::constants::kNMTernaryFalse}, {"mode", "ap"}, {"ssid", ssid_bytes}, {"security", "802-11-wireless-security"}}}, {"802-11-wireless-security", std::map{ - {"pmf", static_cast( - 1)}, // NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE + {"pmf", networkmanager::constants::setting:: + kWirelessSecurityPMFDisable}, {"key-mgmt", "wpa-psk"}, {"psk", password}}}, {"ipv4", std::map{{"method", "shared"}}}, - {"ipv6", std::map{ - {"addr-gen-mode", static_cast(1)}, - {"method", "shared"}, - }}}; + {"ipv6", + std::map{ + {"addr-gen-mode", networkmanager::constants::setting:: + kIP6ConfigAddrGenModeStablePrivacy}, + {"method", "shared"}, + }}}; std::unique_ptr active_conn; try { auto [path, active_path, result] = @@ -311,7 +313,7 @@ bool NetworkManagerWifiHotspotMedium::DisconnectWifiHotspot() { bool NetworkManagerWifiHotspotMedium::WifiHotspotActive() { try { auto mode = wireless_device_->Mode(); - return mode == 3; // NM_802_11_MODE_AP + return mode == networkmanager::constants::kNM80211ModeAP; } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e); return false; @@ -321,7 +323,7 @@ bool NetworkManagerWifiHotspotMedium::WifiHotspotActive() { bool NetworkManagerWifiHotspotMedium::ConnectedToWifi() { try { auto mode = wireless_device_->Mode(); - return mode == 2; // NM_802_11_MODE_INFRA + return mode == networkmanager::constants::kNM80211ModeInfra; } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(wireless_device_, "Mode", e); return false; From 6e524684a68cc699f929d12851253c29f2cb2bdc Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 17:37:30 +0530 Subject: [PATCH 150/201] Rename bluez_gatt_characteristic.{cc,h} to bluez_gatt_characteristic_server --- internal/platform/implementation/linux/BUILD | 4 +- .../implementation/linux/ble_gatt_server.cc | 2 +- ...cc => bluez_gatt_characteristic_server.cc} | 2 +- ...c.h => bluez_gatt_characteristic_server.h} | 4 +- .../linux/bluez_gatt_service.cc | 2 +- .../implementation/linux/bluez_gatt_service.h | 2 +- .../dbus/bluez/gatt_characteristic_client.h | 39 ++++++++++++++++--- 7 files changed, 42 insertions(+), 13 deletions(-) rename internal/platform/implementation/linux/{bluez_gatt_characteristic.cc => bluez_gatt_characteristic_server.cc} (99%) rename internal/platform/implementation/linux/{bluez_gatt_characteristic.h => bluez_gatt_characteristic_server.h} (97%) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 2658d196..ebea2627 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -70,7 +70,7 @@ cc_library( "bluez.h", "bluez_advertisement_monitor.h", "bluez_advertisement_monitor_manager.h", - "bluez_gatt_characteristic.h", + "bluez_gatt_characteristic_server.h", "bluez_gatt_manager.h", "bluez_gatt_service.h", "bluez_le_advertisement.h", @@ -145,7 +145,7 @@ cc_library( "bluetooth_pairing.cc", "bluez.cc", "bluez_advertisement_monitor.cc", - "bluez_gatt_characteristic.cc", + "bluez_gatt_characteristic_server.cc", "bluez_gatt_service.cc", "bluez_le_advertisement.cc", "dbus.cc", diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc index f943016a..88362275 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.cc +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -15,7 +15,7 @@ #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.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.h" #include "internal/platform/implementation/linux/dbus.h" diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc similarity index 99% rename from internal/platform/implementation/linux/bluez_gatt_characteristic.cc rename to internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc index e29b2b40..71768c4e 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic.cc +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc @@ -18,7 +18,7 @@ #include "internal/platform/byte_array.h" #include "internal/platform/implementation/ble_v2.h" -#include "internal/platform/implementation/linux/bluez_gatt_characteristic.h" +#include "internal/platform/implementation/linux/bluez_gatt_characteristic_server.h" #include "internal/platform/logging.h" namespace nearby { diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic.h b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h similarity index 97% rename from internal/platform/implementation/linux/bluez_gatt_characteristic.h rename to internal/platform/implementation/linux/bluez_gatt_characteristic_server.h index 59aa231c..92837e0d 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic.h +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_H_ -#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_H_ +#ifndef PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_SERVER_H_ +#define PLATFORM_IMPL_LINUX_BLUEZ_GATT_CHARACTERISTIC_SERVER_H_ #include #include diff --git a/internal/platform/implementation/linux/bluez_gatt_service.cc b/internal/platform/implementation/linux/bluez_gatt_service.cc index 4ff2ef2d..d8ae5b0b 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service.cc +++ b/internal/platform/implementation/linux/bluez_gatt_service.cc @@ -15,7 +15,7 @@ #include "internal/platform/implementation/linux/bluez_gatt_service.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/ble_v2.h" -#include "internal/platform/implementation/linux/bluez_gatt_characteristic.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" diff --git a/internal/platform/implementation/linux/bluez_gatt_service.h b/internal/platform/implementation/linux/bluez_gatt_service.h index 5d3edff2..9390b151 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service.h +++ b/internal/platform/implementation/linux/bluez_gatt_service.h @@ -25,7 +25,7 @@ #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.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" diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h index a07c3802..1bdc9087 100644 --- a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_characteristic_client.h @@ -3,8 +3,8 @@ * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! */ -#ifndef __sdbuscpp__generated_dbus_bluez_gatt_characteristic_client_h__proxy__H__ -#define __sdbuscpp__generated_dbus_bluez_gatt_characteristic_client_h__proxy__H__ +#ifndef __sdbuscpp__gatt_characteristic_client_h__proxy__H__ +#define __sdbuscpp__gatt_characteristic_client_h__proxy__H__ #include #include @@ -39,6 +39,20 @@ public: proxy_.callMethod("WriteValue").onInterface(INTERFACE_NAME).withArguments(value, options); } + std::tuple AcquireWrite(const std::map& options) + { + std::tuple result; + proxy_.callMethod("AcquireWrite").onInterface(INTERFACE_NAME).withArguments(options).storeResultsTo(result); + return result; + } + + std::tuple AcquireNotify(const std::map& options) + { + std::tuple result; + proxy_.callMethod("AcquireNotify").onInterface(INTERFACE_NAME).withArguments(options).storeResultsTo(result); + return result; + } + void StartNotify() { proxy_.callMethod("StartNotify").onInterface(INTERFACE_NAME); @@ -49,12 +63,12 @@ public: proxy_.callMethod("StopNotify").onInterface(INTERFACE_NAME); } - void Confirm() +public: + uint16_t Handle() { - proxy_.callMethod("Confirm").onInterface(INTERFACE_NAME); + return proxy_.getProperty("Handle").onInterface(INTERFACE_NAME); } -public: std::string UUID() { return proxy_.getProperty("UUID").onInterface(INTERFACE_NAME); @@ -80,6 +94,21 @@ public: 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_; }; From bcbcaa54a2013be96c760e93d30da7f16bf347e4 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 17:39:03 +0530 Subject: [PATCH 151/201] Avoid raising an exception in case of an invalid text attribute --- internal/platform/implementation/linux/avahi.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/platform/implementation/linux/avahi.cc b/internal/platform/implementation/linux/avahi.cc index b9c5b068..1092a73b 100644 --- a/internal/platform/implementation/linux/avahi.cc +++ b/internal/platform/implementation/linux/avahi.cc @@ -52,6 +52,7 @@ void ServiceBrowser::onItemNew(const int32_t &interface, 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)); @@ -94,6 +95,7 @@ void ServiceBrowser::onItemRemove( 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)); From e40faf5dddbfb3ee7ef8f2761bcee81f65d72048 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 17:43:50 +0530 Subject: [PATCH 152/201] Rename GattCharacteristic to GattCharacteristicServer. --- .../implementation/linux/ble_gatt_server.cc | 4 ++-- .../linux/bluez_gatt_characteristic_server.cc | 14 +++++++------- .../linux/bluez_gatt_characteristic_server.h | 14 +++++++------- .../implementation/linux/bluez_gatt_service.cc | 6 +++--- .../implementation/linux/bluez_gatt_service.h | 4 ++-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc index 88362275..37dc51a9 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.cc +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -80,7 +80,7 @@ GattServer::CreateCharacteristic( bool GattServer::UpdateCharacteristic( const api::ble_v2::GattCharacteristic& characteristic, const nearby::ByteArray& value) { - std::shared_ptr chr = nullptr; + std::shared_ptr chr = nullptr; { absl::ReaderMutexLock lock(&services_mutex_); if (services_.count(characteristic.service_uuid) == 0) { @@ -107,7 +107,7 @@ bool GattServer::UpdateCharacteristic( absl::Status GattServer::NotifyCharacteristicChanged( const api::ble_v2::GattCharacteristic& characteristic, bool confirm, const ByteArray& new_value) { - std::shared_ptr chr = nullptr; + std::shared_ptr chr = nullptr; { absl::ReaderMutexLock lock(&services_mutex_); if (services_.count(characteristic.service_uuid) == 0) { diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc index 71768c4e..79c1b3e6 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc @@ -24,7 +24,7 @@ namespace nearby { namespace linux { namespace bluez { -void GattCharacteristic::Update(const nearby::ByteArray &value) { +void GattCharacteristicServer::Update(const nearby::ByteArray &value) { std::vector bytes(value.size()); const auto *buf = value.data(); for (auto i = 0; i < value.size(); i++) bytes[i] = buf[i]; @@ -33,7 +33,7 @@ void GattCharacteristic::Update(const nearby::ByteArray &value) { static_value_ = std::move(bytes); } -absl::Status GattCharacteristic::NotifyChanged(bool confirm, +absl::Status GattCharacteristicServer::NotifyChanged(bool confirm, const ByteArray &new_value) { std::vector bytes(new_value.size()); const auto *buf = new_value.data(); @@ -69,7 +69,7 @@ absl::Status GattCharacteristic::NotifyChanged(bool confirm, } } -void GattCharacteristic::ReadValue( +void GattCharacteristicServer::ReadValue( sdbus::Result> &&result, std::map options) { { @@ -127,7 +127,7 @@ void GattCharacteristic::ReadValue( }); } -void GattCharacteristic::WriteValue( +void GattCharacteristicServer::WriteValue( sdbus::Result<> &&result, std::vector value, std::map options) { uint16_t offset = options["offset"]; @@ -172,7 +172,7 @@ void GattCharacteristic::WriteValue( } } -void GattCharacteristic::StartNotify() { +void GattCharacteristicServer::StartNotify() { if ((characteristic_.property | api::ble_v2::GattCharacteristic::Property::kNotify) == api::ble_v2::GattCharacteristic::Property::kNotify) { @@ -183,7 +183,7 @@ void GattCharacteristic::StartNotify() { } } -void GattCharacteristic::StopNotify() { +void GattCharacteristicServer::StopNotify() { if ((characteristic_.property | api::ble_v2::GattCharacteristic::Property::kNotify) == api::ble_v2::GattCharacteristic::Property::kNotify) { @@ -194,7 +194,7 @@ void GattCharacteristic::StopNotify() { } } -std::vector GattCharacteristic::Flags() { +std::vector GattCharacteristicServer::Flags() { auto characteristic = characteristic_; std::vector flags; diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h index 92837e0d..6f7d5c16 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h @@ -38,17 +38,17 @@ namespace nearby { namespace linux { namespace bluez { -class GattCharacteristic final +class GattCharacteristicServer final : public sdbus::AdaptorInterfaces { public: - GattCharacteristic(const GattCharacteristic &) = delete; - GattCharacteristic(GattCharacteristic &&) = delete; - GattCharacteristic &operator=(const GattCharacteristic &) = delete; - GattCharacteristic &operator=(GattCharacteristic &&) = delete; + GattCharacteristicServer(const GattCharacteristicServer &) = delete; + GattCharacteristicServer(GattCharacteristicServer &&) = delete; + GattCharacteristicServer &operator=(const GattCharacteristicServer &) = delete; + GattCharacteristicServer &operator=(GattCharacteristicServer &&) = delete; - GattCharacteristic( + GattCharacteristicServer( sdbus::IConnection &system_bus, const sdbus::ObjectPath &service_object_path, size_t num, const api::ble_v2::GattCharacteristic &characteristic, @@ -68,7 +68,7 @@ class GattCharacteristic final << org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME << " object at " << getObjectPath(); } - ~GattCharacteristic() { unregisterAdaptor(); } + ~GattCharacteristicServer() { unregisterAdaptor(); } void Update(const nearby::ByteArray &value) ABSL_LOCKS_EXCLUDED(static_value_mutex_); diff --git a/internal/platform/implementation/linux/bluez_gatt_service.cc b/internal/platform/implementation/linux/bluez_gatt_service.cc index d8ae5b0b..17b94158 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service.cc +++ b/internal/platform/implementation/linux/bluez_gatt_service.cc @@ -30,8 +30,8 @@ bool GattService::AddCharacteristic( api::ble_v2::GattCharacteristic characteristic{ characteristic_uuid, service_uuid, permission, property}; auto count = characteristics_.size(); - std::shared_ptr chr = - std::make_shared( + std::shared_ptr chr = + std::make_shared( getObject().getConnection(), getObjectPath(), count, characteristic, server_cb_, devices_); try { @@ -50,7 +50,7 @@ bool GattService::AddCharacteristic( return true; } -std::shared_ptr GattService::GetCharacteristic( +std::shared_ptr GattService::GetCharacteristic( const Uuid &uuid) { absl::ReaderMutexLock lock(&characterstics_mutex_); if (characteristics_.count(uuid) == 0) { diff --git a/internal/platform/implementation/linux/bluez_gatt_service.h b/internal/platform/implementation/linux/bluez_gatt_service.h index 9390b151..eb5ba51e 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service.h +++ b/internal/platform/implementation/linux/bluez_gatt_service.h @@ -83,7 +83,7 @@ class GattService final api::ble_v2::GattCharacteristic::Permission permission, api::ble_v2::GattCharacteristic::Property property) ABSL_LOCKS_EXCLUDED(characterstics_mutex_); - std::shared_ptr GetCharacteristic(const Uuid &uuid) + std::shared_ptr GetCharacteristic(const Uuid &uuid) ABSL_LOCKS_EXCLUDED(characterstics_mutex_); private: @@ -94,7 +94,7 @@ class GattService final std::vector Includes() override { return {}; } absl::Mutex characterstics_mutex_; - absl::flat_hash_map> + absl::flat_hash_map> characteristics_ ABSL_GUARDED_BY(characterstics_mutex_); std::shared_ptr devices_; From 7f732a52e7dd220e8b019c4e74a464faab69709b Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 17:46:42 +0530 Subject: [PATCH 153/201] Rename bluez_gatt_service.{cc,h} to bluez_gatt_service_server --- internal/platform/implementation/linux/BUILD | 4 ++-- internal/platform/implementation/linux/ble_gatt_server.cc | 2 +- internal/platform/implementation/linux/ble_gatt_server.h | 2 +- .../{bluez_gatt_service.cc => bluez_gatt_service_server.cc} | 2 +- .../{bluez_gatt_service.h => bluez_gatt_service_server.h} | 0 .../platform/implementation/linux/count_down_latch_test.cc | 4 ++++ 6 files changed, 9 insertions(+), 5 deletions(-) rename internal/platform/implementation/linux/{bluez_gatt_service.cc => bluez_gatt_service_server.cc} (99%) rename internal/platform/implementation/linux/{bluez_gatt_service.h => bluez_gatt_service_server.h} (100%) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index ebea2627..6b67fd4c 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -72,7 +72,7 @@ cc_library( "bluez_advertisement_monitor_manager.h", "bluez_gatt_characteristic_server.h", "bluez_gatt_manager.h", - "bluez_gatt_service.h", + "bluez_gatt_service_server.h", "bluez_le_advertisement.h", "dbus.h", "network_manager.h", @@ -146,7 +146,7 @@ cc_library( "bluez.cc", "bluez_advertisement_monitor.cc", "bluez_gatt_characteristic_server.cc", - "bluez_gatt_service.cc", + "bluez_gatt_service_server.cc", "bluez_le_advertisement.cc", "dbus.cc", "executor.cc", diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc index 37dc51a9..eb6650b4 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.cc +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -17,7 +17,7 @@ #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.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" diff --git a/internal/platform/implementation/linux/ble_gatt_server.h b/internal/platform/implementation/linux/ble_gatt_server.h index 1ac26939..814c3f2d 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.h +++ b/internal/platform/implementation/linux/ble_gatt_server.h @@ -27,7 +27,7 @@ #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.h" +#include "internal/platform/implementation/linux/bluez_gatt_service_server.h" #include "internal/platform/uuid.h" namespace nearby { diff --git a/internal/platform/implementation/linux/bluez_gatt_service.cc b/internal/platform/implementation/linux/bluez_gatt_service_server.cc similarity index 99% rename from internal/platform/implementation/linux/bluez_gatt_service.cc rename to internal/platform/implementation/linux/bluez_gatt_service_server.cc index 17b94158..3d04b383 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service.cc +++ b/internal/platform/implementation/linux/bluez_gatt_service_server.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "internal/platform/implementation/linux/bluez_gatt_service.h" +#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" diff --git a/internal/platform/implementation/linux/bluez_gatt_service.h b/internal/platform/implementation/linux/bluez_gatt_service_server.h similarity index 100% rename from internal/platform/implementation/linux/bluez_gatt_service.h rename to internal/platform/implementation/linux/bluez_gatt_service_server.h diff --git a/internal/platform/implementation/linux/count_down_latch_test.cc b/internal/platform/implementation/linux/count_down_latch_test.cc index 08147a1f..672067ed 100644 --- a/internal/platform/implementation/linux/count_down_latch_test.cc +++ b/internal/platform/implementation/linux/count_down_latch_test.cc @@ -81,6 +81,10 @@ TEST_F(CountDownLatchTests, CountDownLatchAwaitSucceeds) { // Act nearby::Exception result = countDownLatch->Await(); + for (auto& thread : threads) { + thread.join(); + } + // Assert EXPECT_EQ(result.value, nearby::Exception::kSuccess); EXPECT_EQ(count, 3); From fa81c030adf378b0967747017bddf4035255bc19 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 17:53:44 +0530 Subject: [PATCH 154/201] Rename class GattService to GattServiceServer --- .../implementation/linux/ble_gatt_server.cc | 2 +- .../implementation/linux/ble_gatt_server.h | 2 +- .../linux/bluez_gatt_service_server.cc | 4 ++-- .../linux/bluez_gatt_service_server.h | 14 +++++++------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc index eb6650b4..7a25a47d 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.cc +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -41,7 +41,7 @@ GattServer::CreateCharacteristic( } auto count = services_.size(); - auto service = std::make_unique( + auto service = std::make_unique( system_bus_, count, service_uuid, server_cb_, devices_); try { service->emitInterfacesAddedSignal( diff --git a/internal/platform/implementation/linux/ble_gatt_server.h b/internal/platform/implementation/linux/ble_gatt_server.h index 814c3f2d..b7f38706 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.h +++ b/internal/platform/implementation/linux/ble_gatt_server.h @@ -87,7 +87,7 @@ class GattServer : public api::ble_v2::GattServer { std::shared_ptr server_cb_; absl::Mutex services_mutex_; - absl::flat_hash_map> services_ + absl::flat_hash_map> services_ ABSL_GUARDED_BY(services_mutex_); }; diff --git a/internal/platform/implementation/linux/bluez_gatt_service_server.cc b/internal/platform/implementation/linux/bluez_gatt_service_server.cc index 3d04b383..34ab4a50 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service_server.cc +++ b/internal/platform/implementation/linux/bluez_gatt_service_server.cc @@ -22,7 +22,7 @@ namespace nearby { namespace linux { namespace bluez { -bool GattService::AddCharacteristic( +bool GattServiceServer::AddCharacteristic( const Uuid &service_uuid, const Uuid &characteristic_uuid, api::ble_v2::GattCharacteristic::Permission permission, api::ble_v2::GattCharacteristic::Property property) { @@ -50,7 +50,7 @@ bool GattService::AddCharacteristic( return true; } -std::shared_ptr GattService::GetCharacteristic( +std::shared_ptr GattServiceServer::GetCharacteristic( const Uuid &uuid) { absl::ReaderMutexLock lock(&characterstics_mutex_); if (characteristics_.count(uuid) == 0) { diff --git a/internal/platform/implementation/linux/bluez_gatt_service_server.h b/internal/platform/implementation/linux/bluez_gatt_service_server.h index eb5ba51e..d0422762 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service_server.h +++ b/internal/platform/implementation/linux/bluez_gatt_service_server.h @@ -34,17 +34,17 @@ namespace nearby { namespace linux { namespace bluez { -class GattService final +class GattServiceServer final : public sdbus::AdaptorInterfaces { public: - GattService(const GattService &) = delete; - GattService(GattService &&) = delete; - GattService &operator=(const GattService &) = delete; - GattService &operator=(GattService &&) = delete; + GattServiceServer(const GattServiceServer &) = delete; + GattServiceServer(GattServiceServer &&) = delete; + GattServiceServer &operator=(const GattServiceServer &) = delete; + GattServiceServer &operator=(GattServiceServer &&) = delete; - GattService( + GattServiceServer( sdbus::IConnection &system_bus, size_t num, const Uuid &service_uuid, std::shared_ptr server_cb, std::shared_ptr devices) @@ -59,7 +59,7 @@ class GattService final << " object at " << getObjectPath(); } - ~GattService() { + ~GattServiceServer() { absl::MutexLock lock(&characterstics_mutex_); for (auto &[_uuid, characteristic] : characteristics_) { NEARBY_LOGS(VERBOSE) << __func__ << ": Removing characteristic " From c4bd3b1bcba2b403217ac1c135150ead6a0fc010 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 17:54:06 +0530 Subject: [PATCH 155/201] Add a client variant DBus description for GattCharacteristic1. This file contains additional methods that our Characteristic server interfaces don't support yet. --- .../org.bluez.GattCharacteristic1-client.xml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1-client.xml diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1-client.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1-client.xml new file mode 100644 index 00000000..94fcb206 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattCharacteristic1-client.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 18e471ac375c90780107aaf2233a05c2199a95a0 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 17:59:20 +0530 Subject: [PATCH 156/201] Add gatt_service_client.h --- .../dbus/bluez/gatt_service_client.h | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_client.h diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_client.h new file mode 100644 index 00000000..fa36acc6 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_client.h @@ -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 +#include +#include + +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 Includes() + { + return proxy_.getProperty("Includes").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif From 2abd9f4d835a7cce791de9325b5898ca869019a4 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 18:11:45 +0530 Subject: [PATCH 157/201] Flags: Support write-without-response when writing is enabled. --- .../implementation/linux/bluez_gatt_characteristic_server.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc index 79c1b3e6..cddfbbf0 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc @@ -211,8 +211,10 @@ std::vector GattCharacteristicServer::Flags() { api::ble_v2::GattCharacteristic::Permission::kWrite || (characteristic.property & api::ble_v2::GattCharacteristic::Property::kWrite) == - 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) == From d7abb1775109297033767342e02408f10deeb8ce Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 18:38:48 +0530 Subject: [PATCH 158/201] Share one notification session for all calls between Start/StopNotify --- .../linux/bluez_gatt_characteristic_server.cc | 12 ++++++++---- .../linux/bluez_gatt_characteristic_server.h | 8 ++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc index cddfbbf0..4f104a82 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc @@ -33,8 +33,8 @@ void GattCharacteristicServer::Update(const nearby::ByteArray &value) { static_value_ = std::move(bytes); } -absl::Status GattCharacteristicServer::NotifyChanged(bool confirm, - const ByteArray &new_value) { +absl::Status GattCharacteristicServer::NotifyChanged( + bool confirm, const ByteArray &new_value) { std::vector bytes(new_value.size()); const auto *buf = new_value.data(); for (auto i = 0; i < new_value.size(); i++) bytes[i] = buf[i]; @@ -187,8 +187,12 @@ void GattCharacteristicServer::StopNotify() { if ((characteristic_.property | api::ble_v2::GattCharacteristic::Property::kNotify) == api::ble_v2::GattCharacteristic::Property::kNotify) { - server_cb_->characteristic_unsubscription_cb(characteristic_); - notifying_ = false; + 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")); } diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h index 6f7d5c16..3fcd7652 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h @@ -45,7 +45,8 @@ class GattCharacteristicServer final public: GattCharacteristicServer(const GattCharacteristicServer &) = delete; GattCharacteristicServer(GattCharacteristicServer &&) = delete; - GattCharacteristicServer &operator=(const GattCharacteristicServer &) = delete; + GattCharacteristicServer &operator=(const GattCharacteristicServer &) = + delete; GattCharacteristicServer &operator=(GattCharacteristicServer &&) = delete; GattCharacteristicServer( @@ -61,7 +62,8 @@ class GattCharacteristicServer final characteristic_(characteristic), service_object_path_(service_object_path), notifying_(false), - confirmed_(false) { + confirmed_(false), + notify_sessions_(0) { registerAdaptor(); NEARBY_LOGS(VERBOSE) << __func__ << "Creating a " @@ -116,6 +118,8 @@ class GattCharacteristicServer final absl::Mutex confirmed_mutex_; bool confirmed_; + + std::atomic_size_t notify_sessions_; }; } // namespace bluez From 4bdc46e25732f82b2f1fc8eb3ef4c132c17c3e2f Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Mon, 11 Sep 2023 18:41:49 +0530 Subject: [PATCH 159/201] Make all calls to WriteValue synchronous for now. --- .../linux/bluez_gatt_characteristic_server.cc | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc index 4f104a82..f6404283 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc @@ -144,40 +144,41 @@ void GattCharacteristicServer::WriteValue( std::string data(value.begin(), value.end()); auto characteristic = characteristic_; - if (type != "command") { - server_cb_->on_characteristic_write_cb( - *device, characteristic, static_cast(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()))); - } - }); - } else { - result.returnResults(); - } + // TODO: Support writes without response. + server_cb_->on_characteristic_write_cb( + *device, characteristic, static_cast(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) { - server_cb_->characteristic_subscription_cb(characteristic_); - notifying_ = true; + 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")); } From 0231dc656a3f65fd71f8e0b5c5b77d9adefda5d5 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 13 Sep 2023 14:23:11 +0530 Subject: [PATCH 160/201] BluezObjectManager: Mark the destructor as virtual --- internal/platform/implementation/linux/bluez.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 4a10cbfe..55a3d02f 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -67,14 +67,14 @@ class BluezObjectManager : ProxyInterfaces(system_bus, "org.bluez", "/") { registerProxy(); } - ~BluezObjectManager() { unregisterProxy(); } + virtual ~BluezObjectManager() { unregisterProxy(); } protected: - void onInterfacesAdded( + void onInterfacesAdded( const sdbus::ObjectPath &objectPath, const std::map> &interfacesAndProperties) override {} - void onInterfacesRemoved( + void onInterfacesRemoved( const sdbus::ObjectPath &objectPath, const std::vector &interfaces) override {} }; From e61a3aa677038d81d0f0d92d993765683dd08396 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 13 Sep 2023 14:32:44 +0530 Subject: [PATCH 161/201] Add support for GATT clients. --- internal/platform/implementation/linux/BUILD | 5 + .../implementation/linux/ble_gatt_client.cc | 428 ++++++++++++++++++ .../implementation/linux/ble_gatt_client.h | 210 +++++++++ .../implementation/linux/ble_v2_medium.cc | 19 +- .../implementation/linux/ble_v2_medium.h | 6 +- .../platform/implementation/linux/bluez.h | 6 +- .../linux/bluez_gatt_characteristic_client.cc | 41 ++ .../linux/bluez_gatt_characteristic_client.h | 71 +++ .../linux/bluez_gatt_service_client.h | 40 ++ .../linux/gatt_service_client.h | 0 10 files changed, 819 insertions(+), 7 deletions(-) create mode 100644 internal/platform/implementation/linux/ble_gatt_client.cc create mode 100644 internal/platform/implementation/linux/ble_gatt_client.h create mode 100644 internal/platform/implementation/linux/bluez_gatt_characteristic_client.cc create mode 100644 internal/platform/implementation/linux/bluez_gatt_characteristic_client.h create mode 100644 internal/platform/implementation/linux/bluez_gatt_service_client.h create mode 100644 internal/platform/implementation/linux/gatt_service_client.h diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 6b67fd4c..fa2e32f0 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -56,6 +56,7 @@ cc_library( hdrs = [ "avahi.h", "ble_gatt_server.h", + "ble_gatt_client.h", "ble_medium.h", "ble_v2_medium.h", "ble_v2_server_socket.h", @@ -70,8 +71,10 @@ cc_library( "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", @@ -133,6 +136,7 @@ cc_library( name = "linux", srcs = [ "avahi.cc", + "ble_gatt_client.cc", "ble_gatt_server.cc", "ble_v2_medium.cc", "bluetooth_adapter.cc", @@ -145,6 +149,7 @@ cc_library( "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", diff --git a/internal/platform/implementation/linux/ble_gatt_client.cc b/internal/platform/implementation/linux/ble_gatt_client.cc new file mode 100644 index 00000000..936ec6c2 --- /dev/null +++ b/internal/platform/implementation/linux/ble_gatt_client.cc @@ -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 +#include +#include +#include + +#include + +#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 &characteristic_uuids) { + return gatt_discovery_->DiscoverServiceAndCharacteristics( + peripheral_object_path_, service_uuid, characteristic_uuids, + discovery_cancel_); +} + +absl::optional 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 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 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(value_bytes.begin(), value_bytes.end())}; + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(chr, "ReadValue", e); + return std::optional(); + } + }, + 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 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 + 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>( + 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>> + objects; + try { + objects = GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(this, "GetManagedObjects", e); + return false; + } + + absl::flat_hash_map cached_services; + absl::MutexLock lock(&mutex_); + auto chr_it = std::find_if( + objects.cbegin(), objects.cend(), + [](std::pair>> + 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 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>{}); + 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 &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 +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(system_bus_, + path_it->second); +} + +std::unique_ptr +BluezGattDiscovery::GetSubscribedCharacteristic( + const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid, + const Uuid &characteristic_uuid, + absl::AnyInvocable + 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( + system_bus_, device_object_path, std::move(on_characteristic_changed_cb)); +} + +std::optional> +BluezGattDiscovery::characteristicProperties( + const sdbus::ObjectPath &path, + const std::map &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(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> + &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 &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 diff --git a/internal/platform/implementation/linux/ble_gatt_client.h b/internal/platform/implementation/linux/ble_gatt_client.h new file mode 100644 index 00000000..f86f9970 --- /dev/null +++ b/internal/platform/implementation/linux/ble_gatt_client.h @@ -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 + +#include +#include + +#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 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>::iterator; + CallbackIter AddPeripheralConnection( + const sdbus::ObjectPath &device_object_path, + absl::AnyInvocable 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 &characteristic_uuids, CancellationFlag &cancel) + ABSL_LOCKS_EXCLUDED(mutex_); + std::unique_ptr GetCharacteristic( + const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid, + const Uuid &characteristic_uuid) ABSL_LOCKS_EXCLUDED(mutex_); + std::unique_ptr GetSubscribedCharacteristic( + const sdbus::ObjectPath &device_object_path, const Uuid &service_uuid, + const Uuid &characteristic_uuid, + absl::AnyInvocable + on_characteristic_changed_cb) ABSL_LOCKS_EXCLUDED(mutex_); + + protected: + void onInterfacesAdded( + const sdbus::ObjectPath &objectPath, + const std::map> + &interfacesAndProperties) override ABSL_LOCKS_EXCLUDED(mutex_); + void onInterfacesRemoved(const sdbus::ObjectPath &objectPath, + const std::vector &interfaces) override + ABSL_LOCKS_EXCLUDED(mutex_); + + private: + std::optional> + characteristicProperties( + const sdbus::ObjectPath &path, + const std::map &properties) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + void Shutdown() ABSL_LOCKS_EXCLUDED(mutex_); + + std::shared_ptr system_bus_; + + absl::Mutex peripheral_disconnected_callbacks_mutex_; + absl::flat_hash_map>> + peripheral_disconnected_callbacks_ + ABSL_GUARDED_BY(peripheral_disconnected_callbacks_mutex_); + + absl::Mutex mutex_; + absl::flat_hash_map> + cached_services_ ABSL_GUARDED_BY(mutex_); + // Tuple order: service uuid, characteristic uuid, device object path + absl::flat_hash_map, + sdbus::ObjectPath> + discovered_characteristics_ ABSL_GUARDED_BY(mutex_); + absl::flat_hash_map> + 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 system_bus, + const sdbus::ObjectPath &peripheral_object_path, + std::shared_ptr gatt_discovery, + absl::AnyInvocable 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 &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 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 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 + 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 system_bus_; + sdbus::ObjectPath peripheral_object_path_; + std::shared_ptr 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>; + absl::Mutex characteristics_mutex_; + absl::flat_hash_map + characteristics_ ABSL_GUARDED_BY(characteristics_mutex_); +}; + +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index d51bc4cb..677aada5 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -18,11 +18,12 @@ #include #include -#include #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_advertisement_monitor.h" #include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h" @@ -38,6 +39,7 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) adapter_(adapter), devices_(std::make_unique( *system_bus_, adapter_.GetObjectPath(), observers_)), + gatt_discovery_(std::make_shared(system_bus_)), root_object_manager_(std::make_unique(*system_bus_)), adv_monitor_manager_( bluez::AdvertisementMonitorManager:: @@ -56,6 +58,10 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) 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( @@ -205,6 +211,17 @@ std::unique_ptr BleV2Medium::StartGattServer( std::move(callback)); } +std::unique_ptr BleV2Medium::ConnectToGattServer( + api::ble_v2::BlePeripheral &peripheral, + api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::ClientGattConnectionCallback callback) { + auto &device = dynamic_cast(peripheral); + + return std::make_unique(system_bus_, device.getObjectPath(), + gatt_discovery_, + std::move(callback.disconnected_cb)); +} + bool BleV2Medium::StartLEDiscovery() { std::map filter; filter["Transport"] = "auto"; diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index 8b59c0da..ed1238a7 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -23,6 +23,7 @@ #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" @@ -70,9 +71,7 @@ class BleV2Medium final : public api::ble_v2::BleMedium { std::unique_ptr ConnectToGattServer( api::ble_v2::BlePeripheral &peripheral, api::ble_v2::TxPowerLevel tx_power_level, - api::ble_v2::ClientGattConnectionCallback callback) override { - return nullptr; - } + api::ble_v2::ClientGattConnectionCallback callback) override; std::unique_ptr OpenServerSocket( const std::string &service_id) override { @@ -117,6 +116,7 @@ class BleV2Medium final : public api::ble_v2::BleMedium { BluetoothAdapter adapter_; ObserverList observers_ = {}; std::shared_ptr devices_; + std::shared_ptr gatt_discovery_; std::unique_ptr root_object_manager_; std::unique_ptr adv_monitor_manager_; diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 55a3d02f..2d595a67 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -63,18 +63,18 @@ int16_t TxPowerLevelDbm(api::ble_v2::TxPowerLevel level); class BluezObjectManager : public sdbus::ProxyInterfaces { public: - BluezObjectManager(sdbus::IConnection &system_bus) + explicit BluezObjectManager(sdbus::IConnection &system_bus) : ProxyInterfaces(system_bus, "org.bluez", "/") { registerProxy(); } virtual ~BluezObjectManager() { unregisterProxy(); } protected: - void onInterfacesAdded( + void onInterfacesAdded( const sdbus::ObjectPath &objectPath, const std::map> &interfacesAndProperties) override {} - void onInterfacesRemoved( + void onInterfacesRemoved( const sdbus::ObjectPath &objectPath, const std::vector &interfaces) override {} }; diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_client.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic_client.cc new file mode 100644 index 00000000..19e4b7c5 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_client.cc @@ -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 +#include +#include + +#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& changedProperties, + const std::vector& invalidatedProperties) { + if (interfaceName != org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME) + return; + + if (changedProperties.count("Value") == 1) { + std::vector 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 diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_client.h b/internal/platform/implementation/linux/bluez_gatt_characteristic_client.h new file mode 100644 index 00000000..38b731cb --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_client.h @@ -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 +#include +#include + +#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 { + public: + GattCharacteristicClient(std::shared_ptr 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& changedProperties, + const std::vector& invalidatedProperties) override {} + + std::shared_ptr system_bus_; +}; + +class SubscribedGattCharacteristicClient : public GattCharacteristicClient { + public: + SubscribedGattCharacteristicClient( + std::shared_ptr system_bus, sdbus::ObjectPath path, + absl::AnyInvocable 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& changedProperties, + const std::vector& invalidatedProperties) override; + + private: + absl::AnyInvocable notify_callback_; +}; +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif diff --git a/internal/platform/implementation/linux/bluez_gatt_service_client.h b/internal/platform/implementation/linux/bluez_gatt_service_client.h new file mode 100644 index 00000000..ac1d99d4 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_service_client.h @@ -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 + +#include +#include + +#include "internal/platform/implementation/linux/generated/dbus/bluez/gatt_service_client.h" + +namespace nearby { +namespace linux { +class GattServiceClient final + : public sdbus::ProxyInterfaces { + public: + GattServiceClient(std::shared_ptr 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 diff --git a/internal/platform/implementation/linux/gatt_service_client.h b/internal/platform/implementation/linux/gatt_service_client.h new file mode 100644 index 00000000..e69de29b From 42be2b343dac8eba64fa3065600b3ebfdba4b622 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 13 Sep 2023 16:47:49 +0530 Subject: [PATCH 162/201] Move all common TCP sockets code to tcp_server_socket.h. --- internal/platform/implementation/linux/BUILD | 1 + .../implementation/linux/wifi_direct.cc | 60 +++--------------- .../linux/wifi_direct_server_socket.cc | 39 ++---------- .../linux/wifi_direct_server_socket.h | 8 ++- .../implementation/linux/wifi_direct_socket.h | 19 ++---- .../platform/implementation/linux/wifi_lan.cc | 61 +++---------------- .../linux/wifi_lan_server_socket.cc | 39 ++---------- .../linux/wifi_lan_server_socket.h | 10 +-- .../implementation/linux/wifi_lan_socket.h | 22 +++---- 9 files changed, 53 insertions(+), 206 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index fa2e32f0..0e150f61 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -82,6 +82,7 @@ cc_library( "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", diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index 5830b16d..37ef709b 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -17,6 +17,7 @@ #include #include +#include "internal/platform/implementation/linux/tcp_server_socket.h" #include "internal/platform/implementation/linux/wifi_direct.h" #include "internal/platform/implementation/linux/wifi_direct_server_socket.h" #include "internal/platform/implementation/linux/wifi_direct_socket.h" @@ -31,29 +32,10 @@ std::unique_ptr NetworkManagerWifiDirectMedium::ConnectToService( absl::string_view ip_address, int port, CancellationFlag *cancellation_flag) { - int sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error opening socket: " << std::strerror(errno); - return nullptr; - } + auto socket = TCPSocket::Connect(std::string(ip_address), port); + if (!socket.has_value()) return nullptr; - NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" - << port; - struct sockaddr_in addr; - addr.sin_addr.s_addr = inet_addr(std::string(ip_address).c_str()); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - auto ret = - connect(sock, reinterpret_cast(&addr), sizeof(addr)); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " - << std::strerror(errno); - return nullptr; - } - - return std::make_unique(sock); + return std::make_unique(std::move(*socket)); } std::unique_ptr @@ -72,39 +54,11 @@ NetworkManagerWifiDirectMedium::ListenForService(int port) { return nullptr; } - auto sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error opening socket: " << std::strerror(errno); - return nullptr; - } - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr(ip4addresses[0].c_str()); - addr.sin_port = htons(port); - - auto ret = - bind(sock, reinterpret_cast(&addr), sizeof(addr)); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error binding to socket: " << std::strerror(errno); - return nullptr; - } - - NEARBY_LOGS(VERBOSE) << __func__ << ": Listening for services on " - << ip4addresses[0] << ":" << port << " on device " - << wireless_device_->getObjectPath(); - - ret = listen(sock, 0); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " - << std::strerror(errno); - return nullptr; - } + auto socket = TCPServerSocket::Listen(std::ref(ip4addresses[0]), port); + if (!socket.has_value()) return nullptr; return std::make_unique( - sock, std::move(active_connection), network_manager_); + std::move(*socket), std::move(active_connection), network_manager_); } bool NetworkManagerWifiDirectMedium::ConnectWifiDirect( diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.cc b/internal/platform/implementation/linux/wifi_direct_server_socket.cc index b4e46cc5..395f412b 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.cc @@ -34,47 +34,18 @@ std::string NetworkManagerWifiDirectServerSocket::GetIPAddress() const { } int NetworkManagerWifiDirectServerSocket::GetPort() const { - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - auto ret = - getsockname(fd_.get(), reinterpret_cast(&sin), &len); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error getting information for socket " - << fd_.get() << ": " << std::strerror(errno); - return 0; - } - - return ntohs(sin.sin_port); + return server_socket_.GetPort(); } std::unique_ptr NetworkManagerWifiDirectServerSocket::Accept() { - struct sockaddr_in addr; - socklen_t len = sizeof(addr); - - auto conn = - accept(fd_.get(), reinterpret_cast(&addr), &len); - if (conn < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error accepting incoming connections on socket " - << fd_.get() << ": " << std::strerror(errno); - return nullptr; - } - - return std::make_unique(conn); + auto sock = server_socket_.Accept(); + if (!sock.has_value()) return nullptr; + return std::make_unique(std::move(*sock)); } Exception NetworkManagerWifiDirectServerSocket::Close() { - int fd = fd_.release(); - shutdown(fd, SHUT_RDWR); - auto ret = close(fd); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " - << std::strerror(errno); - return {Exception::kFailed}; - } - - return {Exception::kSuccess}; + return server_socket_.Close(); } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.h b/internal/platform/implementation/linux/wifi_direct_server_socket.h index 727ab490..03077626 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.h @@ -17,6 +17,7 @@ #include #include "internal/platform/implementation/linux/network_manager_active_connection.h" +#include "internal/platform/implementation/linux/tcp_server_socket.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi_direct.h" namespace nearby { @@ -25,9 +26,10 @@ class NetworkManagerWifiDirectServerSocket : public api::WifiDirectServerSocket { public: NetworkManagerWifiDirectServerSocket( - int socket, std::unique_ptr active_conn, + TCPServerSocket socket, + std::unique_ptr active_conn, std::shared_ptr network_manager) - : fd_(socket), + : server_socket_(std::move(socket)), active_conn_(std::move(active_conn)), network_manager_(std::move(network_manager)) {} @@ -37,7 +39,7 @@ class NetworkManagerWifiDirectServerSocket Exception Close() override; private: - sdbus::UnixFd fd_; + TCPServerSocket server_socket_; std::unique_ptr active_conn_; std::shared_ptr network_manager_; }; diff --git a/internal/platform/implementation/linux/wifi_direct_socket.h b/internal/platform/implementation/linux/wifi_direct_socket.h index 011b0617..293d1789 100644 --- a/internal/platform/implementation/linux/wifi_direct_socket.h +++ b/internal/platform/implementation/linux/wifi_direct_socket.h @@ -17,29 +17,22 @@ #include "internal/platform/exception.h" #include "internal/platform/implementation/linux/stream.h" +#include "internal/platform/implementation/linux/tcp_server_socket.h" #include "internal/platform/implementation/wifi_direct.h" namespace nearby { namespace linux { class WifiDirectSocket : public api::WifiDirectSocket { public: - explicit WifiDirectSocket(int socket) - : fd_(sdbus::UnixFd(socket)), output_stream_(fd_), input_stream_(fd_) {} + explicit WifiDirectSocket(TCPSocket socket) : socket_(std::move(socket)) {} - InputStream &GetInputStream() override { return input_stream_; }; - OutputStream &GetOutputStream() override { return output_stream_; }; + InputStream &GetInputStream() override { return socket_.GetInputStream(); } + OutputStream &GetOutputStream() override { return socket_.GetOutputStream(); } - Exception Close() override { - input_stream_.Close(); - output_stream_.Close(); - - return Exception{Exception::kSuccess}; - }; + Exception Close() override { return socket_.Close(); }; private: - sdbus::UnixFd fd_; - OutputStream output_stream_; - InputStream input_stream_; + TCPSocket socket_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 99d52c31..7e825497 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -28,6 +28,7 @@ #include "absl/strings/substitute.h" #include "internal/platform/implementation/linux/avahi.h" #include "internal/platform/implementation/linux/dbus.h" +#include "internal/platform/implementation/linux/tcp_server_socket.h" #include "internal/platform/implementation/linux/wifi_lan.h" #include "internal/platform/implementation/linux/wifi_lan_server_socket.h" #include "internal/platform/implementation/linux/wifi_lan_socket.h" @@ -204,64 +205,18 @@ bool WifiLanMedium::StopDiscovery(const std::string &service_type) { std::unique_ptr WifiLanMedium::ConnectToService( const std::string &ip_address, int port, CancellationFlag *cancellation_flag) { - int sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error opening socket: " << std::strerror(errno); - return nullptr; - } - - NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" - << port; - struct sockaddr_in addr; - addr.sin_addr.s_addr = inet_addr(ip_address.c_str()); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - auto ret = - connect(sock, reinterpret_cast(&addr), sizeof(addr)); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " - << std::strerror(errno); - return nullptr; - } - - sdbus::UnixFd fd(sock); - return std::make_unique(std::move(fd)); + auto socket = TCPSocket::Connect(ip_address, port); + if (!socket.has_value()) return nullptr; + return std::make_unique(*socket); } std::unique_ptr WifiLanMedium::ListenForService( int port) { - auto sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error opening socket: " << std::strerror(errno); - return nullptr; - } + auto socket = TCPServerSocket::Listen(std::nullopt, port); + if (!socket.has_value()) return nullptr; - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(port); - - auto ret = - bind(sock, reinterpret_cast(&addr), sizeof(addr)); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error binding to socket: " << std::strerror(errno); - return nullptr; - } - - ret = listen(sock, 0); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " - << std::strerror(errno); - return nullptr; - } - - NEARBY_LOGS(VERBOSE) << __func__ << "Listening for services on port " << port; - - return std::make_unique(sock, network_manager_); + return std::make_unique(std::move(*socket), + network_manager_); } absl::optional> GetDynamicPortRange() { diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index b82ff2a4..cffde75c 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -27,7 +27,6 @@ #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/wifi_lan_server_socket.h" #include "internal/platform/implementation/linux/wifi_lan_socket.h" -#include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/logging.h" namespace nearby { @@ -75,46 +74,18 @@ std::string WifiLanServerSocket::GetIPAddress() const { } int WifiLanServerSocket::GetPort() const { - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - auto ret = - getsockname(fd_.get(), reinterpret_cast(&sin), &len); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error getting information for socket " - << fd_.get() << ": " << std::strerror(errno); - return 0; - } - - return ntohs(sin.sin_port); + return server_socket_.GetPort(); } std::unique_ptr WifiLanServerSocket::Accept() { - struct sockaddr_in addr; - socklen_t len = sizeof(addr); + auto sock = server_socket_.Accept(); + if (!sock.has_value()) return nullptr; - auto conn = - accept(fd_.get(), reinterpret_cast(&addr), &len); - if (conn < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": Error accepting incoming connections on socket " - << fd_.get() << ": " << std::strerror(errno); - return nullptr; - } - - return std::make_unique(sdbus::UnixFd(conn)); + return std::make_unique(std::move(*sock)); } Exception WifiLanServerSocket::Close() { - int fd = fd_.release(); - shutdown(fd, SHUT_RDWR); - auto ret = close(fd); - if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " - << std::strerror(errno); - return {Exception::kFailed}; - } - - return {Exception::kSuccess}; + return server_socket_.Close(); } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.h b/internal/platform/implementation/linux/wifi_lan_server_socket.h index d81bd7a3..00730bac 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.h @@ -22,15 +22,17 @@ #include "internal/platform/exception.h" #include "internal/platform/implementation/linux/network_manager.h" +#include "internal/platform/implementation/linux/tcp_server_socket.h" #include "internal/platform/implementation/wifi_lan.h" namespace nearby { namespace linux { class WifiLanServerSocket : public api::WifiLanServerSocket { public: - explicit WifiLanServerSocket(int socket, - std::shared_ptr network_manager) - : fd_(sdbus::UnixFd(socket)), + explicit WifiLanServerSocket( + TCPServerSocket socket, + std::shared_ptr network_manager) + : server_socket_(std::move(socket)), network_manager_(std::move(network_manager)), system_bus_(network_manager_->GetConnection()) {} @@ -41,7 +43,7 @@ class WifiLanServerSocket : public api::WifiLanServerSocket { Exception Close() override; private: - sdbus::UnixFd fd_; + TCPServerSocket server_socket_; std::shared_ptr network_manager_; std::shared_ptr system_bus_; }; diff --git a/internal/platform/implementation/linux/wifi_lan_socket.h b/internal/platform/implementation/linux/wifi_lan_socket.h index 63c29b63..816fa065 100644 --- a/internal/platform/implementation/linux/wifi_lan_socket.h +++ b/internal/platform/implementation/linux/wifi_lan_socket.h @@ -20,6 +20,7 @@ #include #include "internal/platform/implementation/linux/stream.h" +#include "internal/platform/implementation/linux/tcp_server_socket.h" #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/input_stream.h" #include "internal/platform/output_stream.h" @@ -28,21 +29,18 @@ namespace nearby { namespace linux { class WifiLanSocket : public api::WifiLanSocket { public: - explicit WifiLanSocket(sdbus::UnixFd fd) - : output_stream_(fd), input_stream_(fd) {} + explicit WifiLanSocket(TCPSocket sock) : socket_(std::move(sock)) {} - 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}; - }; + nearby::InputStream &GetInputStream() override { + return socket_.GetInputStream(); + } + nearby::OutputStream &GetOutputStream() override { + return socket_.GetOutputStream(); + } + Exception Close() override { return socket_.Close(); } private: - OutputStream output_stream_; - InputStream input_stream_; + TCPSocket socket_; }; } // namespace linux } // namespace nearby From f4c487188a1dc1a07b7bceb3817ddd2321cbf0ec Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 13 Sep 2023 17:43:25 +0530 Subject: [PATCH 163/201] Rewrite ActiveConnectionStateReason as a struct with an enum Value --- .../network_manager_active_connection.cc | 92 ++++++++++--------- .../linux/network_manager_active_connection.h | 48 ++++++---- .../implementation/linux/wifi_hotspot.cc | 2 +- .../implementation/linux/wifi_medium.cc | 14 ++- 4 files changed, 87 insertions(+), 69 deletions(-) diff --git a/internal/platform/implementation/linux/network_manager_active_connection.cc b/internal/platform/implementation/linux/network_manager_active_connection.cc index 6202abac..10a364eb 100644 --- a/internal/platform/implementation/linux/network_manager_active_connection.cc +++ b/internal/platform/implementation/linux/network_manager_active_connection.cc @@ -24,50 +24,54 @@ namespace nearby { namespace linux { namespace networkmanager { -std::ostream &operator<<( - std::ostream &stream, - const ActiveConnection::ActiveConnectionStateReason &reason) { - switch (reason) { - case ActiveConnection::kStateReasonUnknown: - return stream << "The reason for the active connection state change is " - "unknown."; - case ActiveConnection::kStateReasonNone: - return stream - << "No reason was given for the active connection state change."; - case ActiveConnection::kStateReasonUserDisconnected: - return stream << "The active connection changed state because the user " - "disconnected it."; - case ActiveConnection::kStateReasonDeviceDisconnected: - return stream << "The active connection changed state because the " - "device it was " - "using was disconnected."; - case ActiveConnection::kStateReasonServiceStopped: - return stream << "The service providing the VPN connection was stopped."; - case ActiveConnection::kStateReasonIPConfigInvalid: - return stream << "The IP config of the active connection was invalid."; - case ActiveConnection::kStateReasonConnectTimeout: - return stream << "The connection attempt to the VPN service timed out."; - case ActiveConnection::kStateReasonServiceStartTimeout: - return stream - << "A timeout occurred while starting the service providing the " - "VPN connection."; - case ActiveConnection::kStateReasonServiceStartFailed: - return stream - << "Starting the service providing the VPN connection failed."; - case ActiveConnection::kStateReasonNoSecrets: - return stream - << "Necessary secrets for the connection were not provided."; - case ActiveConnection::kStateReasonLoginFailed: - return stream << "Authentication to the server failed."; - case ActiveConnection::kStateReasonConnectionRemoved: - return stream << "The connection was deleted from settings."; - case ActiveConnection::kStateReasonDependencyFailed: - return stream - << "Master connection of this connection failed to activate."; - case ActiveConnection::kStateReasonDeviceRealizeFailed: - return stream << "Could not create the software device link."; - case ActiveConnection::kStateReasonDeviceRemoved: - return stream << "The device this connection depended on disappeared."; +std::string ActiveConnection::ActiveConnectionStateReason::ToString() const { + switch (value) { + case ActiveConnection::ActiveConnectionStateReason::kStateReasonUnknown: + return "The reason for the active connection state change is " + "unknown."; + case ActiveConnection::ActiveConnectionStateReason::kStateReasonNone: + return "No reason was given for the active connection state change."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonUserDisconnected: + return "The active connection changed state because the user " + "disconnected it."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonDeviceDisconnected: + return "The active connection changed state because the " + "device it was " + "using was disconnected."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonServiceStopped: + return "The service providing the VPN connection was stopped."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonIPConfigInvalid: + return "The IP config of the active connection was invalid."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonConnectTimeout: + return "The connection attempt to the VPN service timed out."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonServiceStartTimeout: + return "A timeout occurred while starting the service providing the " + "VPN connection."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonServiceStartFailed: + return "Starting the service providing the VPN connection failed."; + case ActiveConnection::ActiveConnectionStateReason::kStateReasonNoSecrets: + return "Necessary secrets for the connection were not provided."; + case ActiveConnection::ActiveConnectionStateReason::kStateReasonLoginFailed: + return "Authentication to the server failed."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonConnectionRemoved: + return "The connection was deleted from settings."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonDependencyFailed: + return "Master connection of this connection failed to activate."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonDeviceRealizeFailed: + return "Could not create the software device link."; + case ActiveConnection::ActiveConnectionStateReason:: + kStateReasonDeviceRemoved: + return "The device this connection depended on disappeared."; } } diff --git a/internal/platform/implementation/linux/network_manager_active_connection.h b/internal/platform/implementation/linux/network_manager_active_connection.h index 0e06fe6a..7d1a3bc7 100644 --- a/internal/platform/implementation/linux/network_manager_active_connection.h +++ b/internal/platform/implementation/linux/network_manager_active_connection.h @@ -38,22 +38,27 @@ class ActiveConnection kStateDeactivating = 3, kStateDeactivated = 4 }; - enum ActiveConnectionStateReason { - kStateReasonUnknown = 0, - kStateReasonNone = 1, - kStateReasonUserDisconnected = 2, - kStateReasonDeviceDisconnected = 3, - kStateReasonServiceStopped = 4, - kStateReasonIPConfigInvalid = 5, - kStateReasonConnectTimeout = 6, - kStateReasonServiceStartTimeout = 7, - kStateReasonServiceStartFailed = 8, - kStateReasonNoSecrets = 9, - kStateReasonLoginFailed = 10, - kStateReasonConnectionRemoved = 11, - kStateReasonDependencyFailed = 12, - kStateReasonDeviceRealizeFailed = 13, - kStateReasonDeviceRemoved = 14, + struct ActiveConnectionStateReason { + enum Value { + kStateReasonUnknown = 0, + kStateReasonNone = 1, + kStateReasonUserDisconnected = 2, + kStateReasonDeviceDisconnected = 3, + kStateReasonServiceStopped = 4, + kStateReasonIPConfigInvalid = 5, + kStateReasonConnectTimeout = 6, + kStateReasonServiceStartTimeout = 7, + kStateReasonServiceStartFailed = 8, + kStateReasonNoSecrets = 9, + kStateReasonLoginFailed = 10, + kStateReasonConnectionRemoved = 11, + kStateReasonDependencyFailed = 12, + kStateReasonDeviceRealizeFailed = 13, + kStateReasonDeviceRemoved = 14, + }; + + Value value{kStateReasonUnknown}; + std::string ToString() const; }; ActiveConnection(const ActiveConnection &) = delete; @@ -66,7 +71,8 @@ class ActiveConnection std::move(active_connection_path)), system_bus_(std::move(system_bus)), state_(kStateUnknown), - reason_(kStateReasonUnknown) { + reason_{ActiveConnection::ActiveConnectionStateReason:: + kStateReasonUnknown} { registerProxy(); try { auto state = State(); @@ -86,8 +92,12 @@ class ActiveConnection if (state >= kStateUnknown && state <= kStateDeactivated) { state_ = static_cast(state); } - if (reason >= kStateReasonUnknown && reason <= kStateReasonDeviceRemoved) { - reason_ = static_cast(reason); + if (reason >= ActiveConnection::ActiveConnectionStateReason:: + kStateReasonUnknown && + reason <= ActiveConnection::ActiveConnectionStateReason:: + kStateReasonDeviceRemoved) { + reason_ = ActiveConnectionStateReason{ + static_cast(reason)}; } } diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index c7d6fc6b..fa1a3962 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -218,7 +218,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( << ": timed out while waiting for connection " << active_conn->getObjectPath() << " to be activated, last NMActiveConnectionStateReason: " - << reason.value(); + << reason->ToString(); DisconnectWifiHotspot(); return false; } diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index 8e4624ef..ed555559 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -238,7 +238,7 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( if (auto ret = sd_id128_randomize(&id); ret < 0) { NEARBY_LOGS(ERROR) << __func__ - << ": could not generation a connection UUID"; + << ": could not generate a connection UUID"; return api::WifiConnectionStatus::kUnknown; } @@ -297,7 +297,7 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( << __func__ << ": " << getObjectPath() << ": timed out while waiting for connection " << active_conn_path << " to be activated, last NMActiveConnectionStateReason: " - << reason.value(); + << reason->ToString(); return api::WifiConnectionStatus::kUnknown; } @@ -305,9 +305,13 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() << ": connection " << active_conn_path << " failed to activate, NMActiveConnectionStateReason:" - << *reason; - if (*reason == networkmanager::ActiveConnection::kStateReasonNoSecrets || - *reason == networkmanager::ActiveConnection::kStateReasonLoginFailed) + << reason->ToString(); + if (reason->value == + networkmanager::ActiveConnection::ActiveConnectionStateReason:: + kStateReasonNoSecrets || + reason->value == + networkmanager::ActiveConnection::ActiveConnectionStateReason:: + kStateReasonLoginFailed) return api::WifiConnectionStatus::kAuthFailure; } From e754f3bee4a2efdef36bf8e1bc9f3ec9e4b627e4 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Wed, 13 Sep 2023 18:53:36 +0530 Subject: [PATCH 164/201] Unify all code for generating random data into functions in utils --- .../platform/implementation/linux/utils.cc | 51 ++++++++++++++ .../platform/implementation/linux/utils.h | 4 ++ .../implementation/linux/utils_test.cc | 21 +++++- .../implementation/linux/wifi_hotspot.cc | 66 ++++++------------- .../implementation/linux/wifi_medium.cc | 31 +++------ 5 files changed, 106 insertions(+), 67 deletions(-) diff --git a/internal/platform/implementation/linux/utils.cc b/internal/platform/implementation/linux/utils.cc index c3c196cc..9de6ebd2 100644 --- a/internal/platform/implementation/linux/utils.cc +++ b/internal/platform/implementation/linux/utils.cc @@ -12,9 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include +#include "absl/strings/str_cat.h" #include "internal/platform/implementation/linux/utils.h" +#include "internal/platform/logging.h" namespace nearby { namespace linux { @@ -47,5 +51,52 @@ std::optional UuidFromString(const std::string &uuid_str) { return Uuid(uuid.qwords[0], uuid.qwords[1]); } + +std::optional NewUuidStr() { + sd_id128_t id; + char id_cstr[SD_ID128_UUID_STRING_MAX]; + if (auto ret = sd_id128_randomize(&id); ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": could not generate a random UUID: " + << std::strerror(ret); + return std::nullopt; + } + + return std::string(sd_id128_to_uuid_string(id, id_cstr)); +} + +std::string RandString(std::string allowed_chars, size_t length) { + thread_local static std::random_device device{}; + + std::mt19937 gen{device()}; + std::uniform_int_distribution dist(0, allowed_chars.length() - 1); + + std::string s; + s.reserve(length); + + for (auto i = 0; i < length; i++) { + s += allowed_chars[dist(gen)]; + } + + return s; +} + +std::string RandSSID() { + std::string allowed_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789"; + + return absl::StrCat("DIRECT-", RandString(allowed_chars, 25)); +} + +std::string RandWPAPassphrase() { + std::string allowed_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "!\"#$%&'()*+,-./[\\]^_`~{|}"; + + return RandString(allowed_chars, 63); +} } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/utils.h b/internal/platform/implementation/linux/utils.h index bf9b1b7e..3f251f4a 100644 --- a/internal/platform/implementation/linux/utils.h +++ b/internal/platform/implementation/linux/utils.h @@ -27,6 +27,10 @@ namespace nearby { namespace linux { std::optional UuidFromString(const std::string &uuid_str); +std::optional NewUuidStr(); + +std::string RandSSID(); +std::string RandWPAPassphrase(); } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/utils_test.cc b/internal/platform/implementation/linux/utils_test.cc index a298b843..9e8e6529 100644 --- a/internal/platform/implementation/linux/utils_test.cc +++ b/internal/platform/implementation/linux/utils_test.cc @@ -28,9 +28,28 @@ TEST(UtilsTests, UuidFromStringRoundTrip) { auto nearby_uuid = UuidFromString(input); EXPECT_TRUE(nearby_uuid.has_value()); - EXPECT_EQ(absl::AsciiStrToLower(std::string{*nearby_uuid}), "b5209043-f493-4b38-8c34-810aa3cd1407"); } + +TEST(UtilsTests, GenNewUuid) { + auto uuid_str = NewUuidStr(); + EXPECT_TRUE(uuid_str.has_value()); + auto uuid = UuidFromString(*uuid_str); + EXPECT_TRUE(uuid.has_value()); + EXPECT_EQ(absl::AsciiStrToLower(std::string{*uuid}), + *uuid_str); +} + +TEST(UtilsTests, GenRandSSID) { + std::string ssid = RandSSID(); + EXPECT_EQ(ssid.length(), 32); + EXPECT_EQ(ssid.find("DIRECT-"), 0); +} + +TEST(UtilsTests, GenRandRandWPAPassphrase) { + std::string password = RandWPAPassphrase(); + EXPECT_EQ(password.length(), 63); +} } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index fa1a3962..1ce8059d 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -19,10 +19,9 @@ #include #include -#include - #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/network_manager.h" +#include "internal/platform/implementation/linux/utils.h" #include "internal/platform/implementation/linux/wifi_hotspot.h" #include "internal/platform/implementation/linux/wifi_hotspot_server_socket.h" #include "internal/platform/implementation/linux/wifi_hotspot_socket.h" @@ -135,64 +134,41 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( return false; } - sd_id128_t id; - if (auto ret = sd_id128_randomize(&id); ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": error generating a 128-bit ID: " - << std::strerror(ret); - return false; - } - - char id_cstr[SD_ID128_UUID_STRING_MAX]; - sd_id128_to_string(id, id_cstr); - - std::string ssid = absl::StrCat("DIRECT-", id_cstr); - ssid.resize(32); + std::string ssid = RandSSID(); hotspot_credentials->SetSSID(ssid); - if (auto ret = sd_id128_randomize(&id); ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": error generating a 128-bit ID: " - << std::strerror(ret); - return false; - } - - sd_id128_to_string(id, id_cstr); - std::string password = std::string(id_cstr, 15); + std::string password = RandWPAPassphrase(); hotspot_credentials->SetPassword(password); - if (auto ret = sd_id128_randomize(&id); ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": error generating a 128-bit ID: " - << std::strerror(ret); + auto connection_id = NewUuidStr(); + if (!connection_id.has_value()) { + NEARBY_LOGS(ERROR) << __func__ << ": could not generate a connection UUID"; return false; } - sd_id128_to_uuid_string(id, id_cstr); - std::vector ssid_bytes(ssid.begin(), ssid.end()); std::map> connection_settings{ { "connection", - std::map{ - {"uuid", std::string(id_cstr)}, - {"id", "Google Nearby Hotspot"}, - {"type", "802-11-wireless"}, - {"zone", "Public"}}, + {{"uuid", *connection_id}, + {"id", "Google Nearby Hotspot"}, + {"type", "802-11-wireless"}, + {"zone", "Public"}}, }, {"802-11-wireless", - std::map{ - {"assigned-mac-address", "random"}, - {"ap-isolation", networkmanager::constants::kNMTernaryFalse}, - {"mode", "ap"}, - {"ssid", ssid_bytes}, - {"security", "802-11-wireless-security"}}}, + {{"assigned-mac-address", "random"}, + {"ap-isolation", networkmanager::constants::kNMTernaryFalse}, + {"mode", "ap"}, + {"ssid", std::vector(ssid.begin(), ssid.end())}, + {"security", "802-11-wireless-security"}}}, {"802-11-wireless-security", - std::map{ - {"pmf", networkmanager::constants::setting:: - kWirelessSecurityPMFDisable}, - {"key-mgmt", "wpa-psk"}, - {"psk", password}}}, - {"ipv4", std::map{{"method", "shared"}}}, + {{"pmf", + networkmanager::constants::setting::kWirelessSecurityPMFDisable}, + {"key-mgmt", "wpa-psk"}, + {"psk", password}}}, + {"ipv4", {{"method", "shared"}}}, {"ipv6", - std::map{ + { {"addr-gen-mode", networkmanager::constants::setting:: kIP6ConfigAddrGenModeStablePrivacy}, {"method", "shared"}, diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index ed555559..e9c33d2d 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -28,6 +28,7 @@ #include "internal/platform/implementation/linux/dbus.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" #include "internal/platform/implementation/linux/network_manager_active_connection.h" +#include "internal/platform/implementation/linux/utils.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/wifi.h" @@ -229,21 +230,10 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( return api::WifiConnectionStatus::kConnectionFailure; } - std::vector ssid_bytes(ssid.begin(), ssid.end()); - std::string connection_id; - - { - sd_id128_t id; - char id_cstr[SD_ID128_UUID_STRING_MAX]; - - if (auto ret = sd_id128_randomize(&id); ret < 0) { - NEARBY_LOGS(ERROR) << __func__ - << ": could not generate a connection UUID"; - return api::WifiConnectionStatus::kUnknown; - } - - sd_id128_to_uuid_string(id, id_cstr); - connection_id = std::string(id_cstr); + auto connection_id = NewUuidStr(); + if (!connection_id.has_value()) { + NEARBY_LOGS(ERROR) << __func__ << ": could not generate a connection UUID"; + return api::WifiConnectionStatus::kUnknown; } auto [auth_alg, key_mgmt] = AuthAlgAndKeyMgmt(auth_type); @@ -251,22 +241,21 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( std::map> connection_settings{ {"connection", - std::map{ - {"uuid", connection_id}, + { + {"uuid", *connection_id}, {"autoconnect", true}, {"id", std::string(ssid)}, {"type", "802-11-wireless"}, {"zone", "Public"}, }}, {"802-11-wireless", - std::map{ - {"ssid", ssid_bytes}, + { + {"ssid", std::vector(ssid.begin(), ssid.end())}, {"mode", "infrastructure"}, {"security", "802-11-wireless-security"}, {"assigned-mac-address", "random"}, }}, - {"802-11-wireless-security", - std::map{{"key-mgmt", key_mgmt}}}}; + {"802-11-wireless-security", {{"key-mgmt", key_mgmt}}}}; if (!password.empty()) { connection_settings["802-11-wireless-security"]["psk"] = std::string(password); From 300155257f542be28b8cdadf3c7ddc1baf09c915 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 26 Sep 2023 17:25:00 +0530 Subject: [PATCH 165/201] Use Adapter's SupportedSecondaryChannels to check if EA is supported --- .../platform/implementation/linux/ble_v2_medium.cc | 10 ++++++++++ internal/platform/implementation/linux/ble_v2_medium.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 677aada5..296cee5a 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -222,6 +222,16 @@ std::unique_ptr BleV2Medium::ConnectToGattServer( 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 filter; filter["Transport"] = "auto"; diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index ed1238a7..c3a9f638 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -84,7 +84,7 @@ class BleV2Medium final : public api::ble_v2::BleMedium { CancellationFlag *cancellation_flag) override { return nullptr; } - bool IsExtendedAdvertisementsAvailable() override { return false; } + bool IsExtendedAdvertisementsAvailable() override; bool GetRemotePeripheral(const std::string &mac_address, GetRemotePeripheralCallback callback) override; bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, From 36c1bb4c8fe13cbf358edb5d84b2cf33e6a50725 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 26 Sep 2023 17:42:49 +0530 Subject: [PATCH 166/201] Remove unneeded header. --- internal/platform/implementation/linux/bluetooth_pairing.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 9cc0b2f5..1b7c464a 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -17,7 +17,6 @@ #include #include #include -#include #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" From b4bd7ddbb8d047d0a6587bf952f286f3208e25c8 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 26 Sep 2023 17:43:01 +0530 Subject: [PATCH 167/201] Delete gatt_service_client.h. --- internal/platform/implementation/linux/gatt_service_client.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 internal/platform/implementation/linux/gatt_service_client.h diff --git a/internal/platform/implementation/linux/gatt_service_client.h b/internal/platform/implementation/linux/gatt_service_client.h deleted file mode 100644 index e69de29b..00000000 From 97af86a414789e2db5ee0b9b0a9dfa63bb2765dc Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 26 Sep 2023 18:34:56 +0530 Subject: [PATCH 168/201] Fix race conditions with bluetooth devices being erased while being used. --- .../implementation/linux/ble_v2_medium.cc | 9 +- .../linux/bluetooth_bluez_profile.cc | 8 +- .../linux/bluetooth_classic_device.cc | 96 +++++++------------ .../linux/bluetooth_classic_device.h | 86 ++++++++++++----- .../linux/bluetooth_classic_medium.cc | 2 +- .../implementation/linux/bluetooth_devices.cc | 4 +- .../implementation/linux/bluetooth_devices.h | 7 +- .../implementation/linux/bluetooth_pairing.cc | 63 +++--------- .../implementation/linux/bluetooth_pairing.h | 6 +- .../linux/bluez_advertisement_monitor.cc | 11 +-- 10 files changed, 135 insertions(+), 157 deletions(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 296cee5a..aafe2d68 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -25,6 +25,7 @@ #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" @@ -38,7 +39,7 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) : system_bus_(adapter.GetConnection()), adapter_(adapter), devices_(std::make_unique( - *system_bus_, adapter_.GetObjectPath(), observers_)), + system_bus_, adapter_.GetObjectPath(), observers_)), gatt_discovery_(std::make_shared(system_bus_)), root_object_manager_(std::make_unique(*system_bus_)), adv_monitor_manager_( @@ -215,10 +216,10 @@ std::unique_ptr BleV2Medium::ConnectToGattServer( api::ble_v2::BlePeripheral &peripheral, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::ClientGattConnectionCallback callback) { - auto &device = dynamic_cast(peripheral); + auto path = bluez::device_object_path(adapter_.GetObjectPath(), + peripheral.GetAddress()); - return std::make_unique(system_bus_, device.getObjectPath(), - gatt_discovery_, + return std::make_unique(system_bus_, path, gatt_discovery_, std::move(callback.disconnected_cb)); } diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index f9702d1e..d371a315 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -67,10 +67,10 @@ void Profile::NewConnection( device = devices_.add_new_device(device_object_path); } - auto alias = device->Alias(); - auto mac_addr = device->Address(); + auto alias = device->GetName(); + auto mac_addr = device->GetAddress(); NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() - << ": Connected to " << device->getObjectPath(); + << ": Connected to " << mac_addr; FDProperties props(fd_props); @@ -89,7 +89,7 @@ void Profile::RequestDisconnection( throw sdbus::Error("org.bluez.Error.Rejected", "Unknown object"); } - auto mac_addr = device->Address(); + auto mac_addr = device->GetMacAddress(); NEARBY_LOGS(VERBOSE) << __func__ << ": Disconnection requested for device " << device_object_path; diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 9491061f..035c887d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -12,118 +12,96 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include #include -#include #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(sdbus::IConnection &system_bus, - sdbus::ObjectPath device_object_path) - : ProxyInterfaces(system_bus, bluez::SERVICE_DEST, - std::move(device_object_path)), - lost_(false) { - registerProxy(); +BluetoothDevice::BluetoothDevice(std::shared_ptr device) + : lost_(false), device_(device) { try { - last_known_name_ = Alias(); + last_known_name_ = device->Alias(); } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(this, "Alias", e); + DBUS_LOG_PROPERTY_GET_ERROR(device, "Alias", e); } try { - last_known_address_ = Address(); + last_known_address_ = device->Address(); unique_id_ = BluetoothUtils::ToNumber(last_known_address_); } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(this, "Address", e); + DBUS_LOG_PROPERTY_GET_ERROR(device, "Address", e); } } std::string BluetoothDevice::GetName() const { - auto bluez_device = - sdbus::createProxy(getProxy().getConnection(), bluez::SERVICE_DEST, - getProxy().getObjectPath()); + auto device = device_.lock(); + if (device == nullptr) { + absl::ReaderMutexLock l(&properties_mutex_); + return last_known_name_; + } try { - std::string alias = - bluez_device->getProperty("Alias").onInterface(bluez::DEVICE_INTERFACE); + std::string alias = device->Alias(); { absl::MutexLock l(&properties_mutex_); last_known_name_ = alias; } return alias; } catch (const sdbus::Error &e) { - if (e.getName() == "org.freedesktop.DBus.Error.UnknownObject") { - NEARBY_LOGS(VERBOSE) - << __func__ << ": " << getObjectPath() - << ": device is no longer known, returning last known name"; - absl::ReaderMutexLock l(&properties_mutex_); - return last_known_name_; - } - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get Alias for device " - << bluez_device->getObjectPath(); - return std::string(); + DBUS_LOG_PROPERTY_GET_ERROR(device, "Alias", e); + return {}; } } std::string BluetoothDevice::GetMacAddress() const { - auto bluez_device = - sdbus::createProxy(getProxy().getConnection(), bluez::SERVICE_DEST, - getProxy().getObjectPath()); + auto device = device_.lock(); + if (device == nullptr) { + absl::ReaderMutexLock l(&properties_mutex_); + return last_known_name_; + } try { - std::string addr = bluez_device->getProperty("Address").onInterface( - bluez::DEVICE_INTERFACE); + std::string addr = device->Address(); { absl::MutexLock l(&properties_mutex_); last_known_address_ = addr; } return addr; } catch (const sdbus::Error &e) { - if (e.getName() == "org.freedesktop.DBus.Error.UnknownObject") { - NEARBY_LOGS(VERBOSE) - << __func__ << ": " << getObjectPath() - << ": device is no longer known, returning last known address"; - absl::ReaderMutexLock l(&properties_mutex_); - return last_known_address_; - } - - NEARBY_LOGS(ERROR) << __func__ << "Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get Address for device " - << bluez_device->getObjectPath(); + DBUS_LOG_PROPERTY_GET_ERROR(device, "Address", e); return std::string(); } } bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { - NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() - << ": Attempting to connect to profile " << service_uuid; + auto device = device_.lock(); + if (device == nullptr) return false; try { - ConnectProfile(std::string(service_uuid)); + device->ConnectProfile(std::string(service_uuid)); return true; } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to connect to profile " - << service_uuid << " on device " << getObjectPath(); + DBUS_LOG_METHOD_CALL_ERROR(device, "ConnectProfile", e); return false; } } MonitoredBluetoothDevice::MonitoredBluetoothDevice( - sdbus::IConnection &system_bus, const sdbus::ObjectPath &device_object_path, + std::shared_ptr system_bus, + std::shared_ptr device, ObserverList &observers) - : BluetoothDevice(system_bus, device_object_path), - ProxyInterfaces(system_bus, bluez::SERVICE_DEST, - std::string(device_object_path)), + : BluetoothDevice(std::move(device)), + ProxyInterfaces(*system_bus, bluez::SERVICE_DEST, + device->getObjectPath()), + system_bus_(std::move(system_bus)), observers_(observers) { registerProxy(); } @@ -142,20 +120,20 @@ void MonitoredBluetoothDevice::onPropertiesChanged( NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() << ": Notifying observers about address change"; std::string address = it->second; - for (auto &observer : observers_.GetObservers()) { + 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 (auto &observer : observers_.GetObservers()) { + 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 (auto &observer : observers_.GetObservers()) { + for (const auto &observer : observers_.GetObservers()) { observer->DeviceConnectedStateChanged(*this, it->second); } } else if (it->first == bluez::DEVICE_NAME) { diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index b60a0a67..57c6a2c2 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -16,7 +16,9 @@ #define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_DEVICE_H_ #include +#include +#include #include #include #include @@ -29,15 +31,15 @@ #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 sdbus::ProxyInterfaces, - public api::ble_v2::BlePeripheral { +class BluetoothDevice : public api::BluetoothDevice, + public api::ble_v2::BlePeripheral { public: using UniqueId = std::uint64_t; @@ -45,9 +47,7 @@ class BluetoothDevice BluetoothDevice(BluetoothDevice &&) = delete; BluetoothDevice &operator=(const BluetoothDevice &) = delete; BluetoothDevice &operator=(BluetoothDevice &&) = delete; - BluetoothDevice(sdbus::IConnection &system_bus, - sdbus::ObjectPath device_object_path); - ~BluetoothDevice() override { unregisterProxy(); } + explicit BluetoothDevice(std::shared_ptr device); // BluetoothDevice methods // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() @@ -59,16 +59,57 @@ class BluetoothDevice std::string GetAddress() const override { return GetMacAddress(); } UniqueId GetUniqueId() const override { return unique_id_; }; - void set_pair_reply_callback( - absl::AnyInvocable cb) - ABSL_LOCKS_EXCLUDED(pair_callback_lock_) { - absl::MutexLock l(&pair_callback_lock_); - on_pair_reply_cb_ = std::move(cb); + std::optional> 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; + } } - void reset_pair_reply_callback() ABSL_LOCKS_EXCLUDED(pair_callback_lock_) { - absl::MutexLock l(&pair_callback_lock_); - on_pair_reply_cb_ = nullptr; + std::optional 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 cb) { + auto device = device_.lock(); + if (device != nullptr) device->SetPairReplyCallback(std::move(cb)); } bool ConnectToProfile(absl::string_view service_uuid); @@ -76,23 +117,14 @@ class BluetoothDevice void UnmarkLost() { lost_ = false; } bool Lost() const { return lost_; } - 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: - absl::Mutex pair_callback_lock_; - absl::AnyInvocable on_pair_reply_cb_ - ABSL_GUARDED_BY(pair_callback_lock_) = nullptr; 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 device_; }; class MonitoredBluetoothDevice final @@ -109,7 +141,8 @@ class MonitoredBluetoothDevice final delete; MonitoredBluetoothDevice &operator=(MonitoredBluetoothDevice &&) = delete; MonitoredBluetoothDevice( - sdbus::IConnection &system_bus, const sdbus::ObjectPath &, + std::shared_ptr system_bus, + std::shared_ptr device, ObserverList &observers); ~MonitoredBluetoothDevice() override { unregisterProxy(); } @@ -127,6 +160,7 @@ class MonitoredBluetoothDevice final const std::vector &invalidatedProperties) override; private: + std::shared_ptr system_bus_; std::shared_ptr GetDiscoveryCallback() ABSL_LOCKS_EXCLUDED(discovery_cb_mutex_) { discovery_cb_mutex_.ReaderLock(); diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index dd7179bc..e179340f 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -37,7 +37,7 @@ BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter) adapter_(adapter), observers_(std::make_shared>()), devices_(std::make_shared( - *system_bus_, adapter.GetObjectPath(), *observers_)), + system_bus_, adapter.GetObjectPath(), *observers_)), device_watcher_(nullptr), profile_manager_( std::make_unique(*system_bus_, *devices_)) {} diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 97484df6..05058c97 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -90,7 +90,9 @@ std::shared_ptr BluetoothDevices::add_new_device( auto [device_it, inserted] = devices_by_path_.emplace( std::string(device_object_path), std::make_shared( - system_bus_, std::move(device_object_path), observers_)); + system_bus_, + std::make_shared(system_bus_, device_object_path), + observers_)); if (!inserted) device_it->second->UnmarkLost(); return device_it->second; } diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index bebf6c87..08c4d24a 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -37,9 +37,10 @@ namespace linux { class BluetoothDevices final { public: BluetoothDevices( - sdbus::IConnection &system_bus, sdbus::ObjectPath adapter_object_path, + std::shared_ptr system_bus, + sdbus::ObjectPath adapter_object_path, ObserverList &observers) - : system_bus_(system_bus), + : system_bus_(std::move(system_bus)), observers_(observers), adapter_object_path_(std::move(adapter_object_path)) {} @@ -62,7 +63,7 @@ class BluetoothDevices final { void cleanup_lost_peripherals() ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); private: - sdbus::IConnection &system_bus_; + std::shared_ptr system_bus_; ObserverList &observers_; sdbus::ObjectPath adapter_object_path_; diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 1b7c464a..0e51961c 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -36,7 +36,7 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { << "Got error '" << error->getName() << "' with message '" << error->getMessage() << "' while pairing with device " - << device_->getObjectPath(); + << device_->GetMacAddress(); if (name == "org.bluez.Error.AuthenticationCanceled") { err = api::BluetoothPairingCallback::PairingError::kAuthCanceled; @@ -61,7 +61,10 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { BluetoothPairing::BluetoothPairing( BluetoothAdapter &adapter, std::shared_ptr remote_device) - : device_(std::move(remote_device)), adapter_(adapter) {} + : 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) { @@ -75,66 +78,28 @@ bool BluetoothPairing::InitiatePairing( bool BluetoothPairing::FinishPairing( std::optional pin_code) { - device_->set_pair_reply_callback([this](const sdbus::Error *error) { + device_->SetPairReplyCallback([this](const sdbus::Error *error) { this->pairing_reply_handler(error); }); - try { - pair_async_call_ = device_->Pair(); - } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to initiate pairing for device " - << device_->getObjectPath(); - return false; - } - + auto call = device_->Pair(); + if (!call.has_value()) return false; + pair_async_call_ = *call; return true; } bool BluetoothPairing::CancelPairing() { - try { - if (pair_async_call_.isPending()) { - pair_async_call_.cancel(); - } - - device_->CancelPairing(); - } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to cancel pairing for device " - << device_->getObjectPath(); - return false; + if (pair_async_call_.isPending()) { + pair_async_call_.cancel(); } - return true; + return device_->CancelPairing(); } bool BluetoothPairing::Unpair() { - try { - adapter_.RemoveDeviceByObjectPath(device_->getObjectPath()); - return true; - } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to unpair device " - << device_->getObjectPath() << " on adapter " - << adapter_.GetObjectPath(); - return false; - } + return adapter_.RemoveDeviceByObjectPath(device_object_path_); } -bool BluetoothPairing::IsPaired() { - try { - bool bonded = device_->Bonded(); - return bonded; - } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() - << "' with message '" << e.getMessage() - << "' while trying to get Bonded state for device " - << device_->getObjectPath(); - return false; - } -} +bool BluetoothPairing::IsPaired() { return device_->Bonded(); } } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_pairing.h b/internal/platform/implementation/linux/bluetooth_pairing.h index 768a43e0..0f7cc51d 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.h +++ b/internal/platform/implementation/linux/bluetooth_pairing.h @@ -31,7 +31,8 @@ namespace nearby { namespace linux { class BluetoothPairing final : public api::BluetoothPairing { public: - BluetoothPairing(BluetoothAdapter &adapter, std::shared_ptr remote_device); + BluetoothPairing(BluetoothAdapter &adapter, + std::shared_ptr remote_device); bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; bool FinishPairing(std::optional pin_code) override; @@ -45,7 +46,8 @@ class BluetoothPairing final : public api::BluetoothPairing { sdbus::PendingAsyncCall pair_async_call_; std::shared_ptr device_; - linux::BluetoothAdapter &adapter_; + sdbus::ObjectPath device_object_path_; + linux::BluetoothAdapter adapter_; api::BluetoothPairingCallback pairing_cb_; }; diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc index a695807a..cdb7d04a 100644 --- a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc @@ -39,16 +39,11 @@ AdvertisementMonitor::AdvertisementMonitor( void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) { devices_->cleanup_lost_peripherals(); auto peripheral = devices_->add_new_device(device); - std::map service_data; - try { - service_data = peripheral->ServiceData(); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(peripheral, "ServiceData", e); - return; - } + 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) { + for (const auto &[uuid_str, data] : *service_data) { auto uuid = UuidFromString(uuid_str); if (!uuid.has_value()) { NEARBY_LOGS(ERROR) From 71f54ac820eb6ffe65d18e35eaacced38c591b12 Mon Sep 17 00:00:00 2001 From: Vibhav Pant Date: Tue, 26 Sep 2023 18:35:48 +0530 Subject: [PATCH 169/201] Add headers. --- .../implementation/linux/bluez_device.h | 65 +++++++ .../implementation/linux/tcp_server_socket.h | 173 ++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 internal/platform/implementation/linux/bluez_device.h create mode 100644 internal/platform/implementation/linux/tcp_server_socket.h diff --git a/internal/platform/implementation/linux/bluez_device.h b/internal/platform/implementation/linux/bluez_device.h new file mode 100644 index 00000000..f419cbf0 --- /dev/null +++ b/internal/platform/implementation/linux/bluez_device.h @@ -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 +#include +#include + +#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 { + public: + Device(std::shared_ptr 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 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 system_bus; + absl::Mutex pair_callback_lock_; + absl::AnyInvocable on_pair_reply_cb_ + ABSL_GUARDED_BY(pair_callback_lock_) = nullptr; +}; +} // namespace bluez +} // namespace linux +} // namespace nearby +#endif diff --git a/internal/platform/implementation/linux/tcp_server_socket.h b/internal/platform/implementation/linux/tcp_server_socket.h new file mode 100644 index 00000000..764360c9 --- /dev/null +++ b/internal/platform/implementation/linux/tcp_server_socket.h @@ -0,0 +1,173 @@ +// 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_TCP_SERVER_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_TCP_SERVER_SOCKET_H_ + +#include +#include +#include +#include + +#include + +#include "internal/platform/exception.h" +#include "internal/platform/implementation/linux/stream.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { +class TCPSocket { + public: + explicit TCPSocket(const sdbus::UnixFd& fd) + : closed_(false), output_stream_(fd), input_stream_(fd) {} + + static std::optional Connect(const std::string& ip_address, + int port) { + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return std::nullopt; + } + + NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" + << port; + struct sockaddr_in addr; + addr.sin_addr.s_addr = inet_addr(ip_address.c_str()); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + auto ret = + connect(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " + << std::strerror(errno); + return std::nullopt; + } + + return TCPSocket(sdbus::UnixFd(sock)); + } + + InputStream& GetInputStream() { return input_stream_; } + OutputStream& GetOutputStream() { return output_stream_; } + + Exception Close() { + if (closed_) return {Exception::kFailed}; + + closed_ = true; + input_stream_.Close(); + output_stream_.Close(); + + return {Exception::kSuccess}; + }; + + private: + bool closed_; + + OutputStream output_stream_; + InputStream input_stream_; +}; + +class TCPServerSocket { + public: + explicit TCPServerSocket(int fd) : fd_(fd) {} + + static std::optional Listen( + std::optional> ip_address, + int port) { + auto sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error opening socket: " << std::strerror(errno); + return std::nullopt; + } + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + if (ip_address.has_value()) + addr.sin_addr.s_addr = inet_addr(ip_address->get().c_str()); + else + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + auto ret = + bind(sock, reinterpret_cast(&addr), sizeof(addr)); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error binding to socket: " + << std::strerror(errno); + return std::nullopt; + } + + ret = listen(sock, 0); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " + << std::strerror(errno); + return std::nullopt; + } + + return TCPServerSocket(sock); + } + std::optional Accept() { + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + + auto conn = + accept(fd_.get(), reinterpret_cast(&addr), &len); + if (conn < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error accepting incoming connections on socket " + << fd_.get() << ": " << std::strerror(errno); + return std::nullopt; + } + + return TCPSocket(sdbus::UnixFd(conn)); + }; + + Exception Close() { + int fd = fd_.release(); + shutdown(fd, SHUT_RDWR); + auto ret = close(fd); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " + << std::strerror(errno); + return {Exception::kFailed}; + } + + return {Exception::kSuccess}; + }; + + int GetPort() const { + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + auto ret = + getsockname(fd_.get(), reinterpret_cast(&sin), &len); + if (ret < 0) { + NEARBY_LOGS(ERROR) << __func__ + << ": Error getting information for socket " + << fd_.get() << ": " << std::strerror(errno); + return 0; + } + + return ntohs(sin.sin_port); + } + + private: + sdbus::UnixFd fd_; +}; +} // namespace linux +} // namespace nearby + +#endif From 578f253121e9d70b7a27f2ba6a00e609e244f0f9 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sun, 28 Dec 2025 16:52:21 +0000 Subject: [PATCH 170/201] Remove existing linux implementation folder before importing subtree --- internal/platform/implementation/linux/BUILD | 143 --------- .../platform/implementation/linux/atomics.h | 49 ---- .../implementation/linux/bluetooth_adapter.cc | 91 ------ .../implementation/linux/bluetooth_adapter.h | 125 -------- .../linux/bluetooth_adapter_test.cc | 94 ------ .../implementation/linux/bluetooth_classic.cc | 277 ------------------ .../implementation/linux/bluetooth_classic.h | 222 -------------- .../platform/implementation/linux/crypto.cc | 57 ---- .../implementation/linux/device_info.cc | 60 ---- .../implementation/linux/device_info.h | 69 ----- .../linux/generated/avahi-proxy.h | 95 ------ .../implementation/linux/generated/avahi.xml | 56 ---- .../generated/bluez_adapter_client_glue.h | 184 ------------ .../linux/generated/bluez_client_glue.h | 46 --- .../generated/bluez_device_client_glue.h | 225 -------------- .../linux/generated/org.bluez.Adapter1.xml | 36 --- .../linux/generated/org.bluez.Device1.xml | 46 --- .../linux/generated/org.bluez.xml | 20 -- .../linux/multi_thread_executor.h | 90 ------ .../linux/multi_thread_executor_test.cc | 114 ------- .../platform/implementation/linux/platform.cc | 150 ---------- .../platform/implementation/linux/platform.h | 17 -- .../linux/scheduled_executor.cc | 0 .../implementation/linux/scheduled_executor.h | 97 ------ .../implementation/linux/system_clock.cc | 49 ---- 25 files changed, 2412 deletions(-) delete mode 100644 internal/platform/implementation/linux/BUILD delete mode 100644 internal/platform/implementation/linux/atomics.h delete mode 100644 internal/platform/implementation/linux/bluetooth_adapter.cc delete mode 100644 internal/platform/implementation/linux/bluetooth_adapter.h delete mode 100644 internal/platform/implementation/linux/bluetooth_adapter_test.cc delete mode 100644 internal/platform/implementation/linux/bluetooth_classic.cc delete mode 100644 internal/platform/implementation/linux/bluetooth_classic.h delete mode 100644 internal/platform/implementation/linux/crypto.cc delete mode 100644 internal/platform/implementation/linux/device_info.cc delete mode 100644 internal/platform/implementation/linux/device_info.h delete mode 100644 internal/platform/implementation/linux/generated/avahi-proxy.h delete mode 100644 internal/platform/implementation/linux/generated/avahi.xml delete mode 100644 internal/platform/implementation/linux/generated/bluez_adapter_client_glue.h delete mode 100644 internal/platform/implementation/linux/generated/bluez_client_glue.h delete mode 100644 internal/platform/implementation/linux/generated/bluez_device_client_glue.h delete mode 100644 internal/platform/implementation/linux/generated/org.bluez.Adapter1.xml delete mode 100644 internal/platform/implementation/linux/generated/org.bluez.Device1.xml delete mode 100644 internal/platform/implementation/linux/generated/org.bluez.xml delete mode 100644 internal/platform/implementation/linux/multi_thread_executor.h delete mode 100644 internal/platform/implementation/linux/multi_thread_executor_test.cc delete mode 100644 internal/platform/implementation/linux/platform.cc delete mode 100644 internal/platform/implementation/linux/platform.h delete mode 100644 internal/platform/implementation/linux/scheduled_executor.cc delete mode 100644 internal/platform/implementation/linux/scheduled_executor.h delete mode 100644 internal/platform/implementation/linux/system_clock.cc diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD deleted file mode 100644 index 3b20885a..00000000 --- a/internal/platform/implementation/linux/BUILD +++ /dev/null @@ -1,143 +0,0 @@ -cc_library( - name = "types", - srcs = [ - "device_info.cc", - ], - hdrs = [ - "atomics.h", - "bluetooth_adapter.h", - "device_info.h", - "generated/bluez_adapter_client_glue.h", - "multi_thread_executor.h", - "platform.h", - "scheduled_executor.h", - ], - visibility = ["//visibility:private"], - deps = [ - "//internal/base:file_path", - "//internal/platform:base", - "//internal/platform:logging", - "//internal/platform/implementation:types", - "@com_google_absl//absl/strings", - "@sdbus_cpp", - "@sdbus_cpp//:libsystemd", - ], -) - -cc_library( - name = "linux", - srcs = [ - "bluetooth_adapter.cc", - "platform.cc", - "scheduled_executor.cc", - "system_clock.cc", - ], - hdrs = [ - "bluetooth_adapter.h", - "device_info.h", - ], - visibility = ["//visibility:public"], - deps = [ - ":crypto_impl", - ":types", - "//connections/implementation/flags:connections_flags", - "//internal/base:file_path", - "//internal/base:files", - "//internal/flags:nearby_flags", - "//internal/platform:base", - "//internal/platform:cancellation_flag", - "//internal/platform:logging", - "//internal/platform:mac_address", - "//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:wifi_utils", - "//internal/platform/implementation/shared:count_down_latch", - "//internal/platform/implementation/shared:posix_condition_variable", - "//internal/platform/implementation/shared:posix_mutex", - "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/base:nullability", - "@com_google_absl//absl/container:flat_hash_map", - "@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", - "@com_google_absl//absl/types:span", - "@nlohmann_json//:json", - "@sdbus_cpp", - "@sdbus_cpp//:libsystemd", - ], -) - -# The existing target that other BUILD files select on; keep for compatibility. -cc_library( - name = "linux_platform_impl", - srcs = [], - hdrs = [], - visibility = ["//visibility:public"], - deps = [ - ":linux", - ":types", - ], -) - -cc_library( - name = "multi_thread_executor_hdrs", - hdrs = ["multi_thread_executor.h"], - visibility = ["//visibility:public"], - deps = [ - "//internal/platform/implementation:types", - ], -) - -cc_test( - name = "bluetooth_adapter_test", - srcs = [ - "bluetooth_adapter_test.cc", - ], - deps = [ - ":linux", - ":types", - "//internal/platform:base", - "//internal/platform/implementation:platform", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/synchronization", - "@com_google_absl//absl/time", - "@com_google_googletest//:gtest_main", - "@sdbus_cpp", - "@sdbus_cpp//:libsystemd", - ], -) - -cc_library( - name = "crypto_impl", - srcs = ["crypto.cc"], - linkopts = ["-lcrypto"], # usually enough; -lssl not needed for hashing - deps = [ - "//internal/platform/implementation:types", - "@com_google_absl//absl/strings", - ], -) - -cc_test( - name = "multi_thread_executor_test", - srcs = [ - "multi_thread_executor_test.cc", - ], - deps = [ - # Depend on the header-only target to pick up the linux header without - # pulling system libraries. - ":multi_thread_executor_hdrs", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/synchronization", - "@com_google_absl//absl/time", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/internal/platform/implementation/linux/atomics.h b/internal/platform/implementation/linux/atomics.h deleted file mode 100644 index 2c6f1f1d..00000000 --- a/internal/platform/implementation/linux/atomics.h +++ /dev/null @@ -1,49 +0,0 @@ -// filepath: /workspace/internal/platform/implementation/linux/atomics.h -// -// Created by root on 10/2/25. -// -#ifndef LINUX_ATOMIC_BOOLEAN_H -#define LINUX_ATOMIC_BOOLEAN_H -#include -#include "internal/platform/implementation/atomic_boolean.h" -#include "internal/platform/implementation/atomic_reference.h" -namespace nearby -{ - namespace linux - { - // A boolean value that may be updated atomically. - class AtomicBoolean : public api::AtomicBoolean - { - public: - explicit AtomicBoolean(bool value = false) : atomic_boolean_(value) - { - } - ~AtomicBoolean() override = default; - // Atomically read and return current value. - [[nodiscard]] 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; - }; - - class AtomicUint32 : public api::AtomicUint32 - { - public: - explicit AtomicUint32(std::uint32_t value = 0) : atomic_uint32_(value) {} - ~AtomicUint32() override = default; - - // Atomically reads and returns stored value. - [[nodiscard]] std::uint32_t Get() const override { return atomic_uint32_.load(); } - - // Atomically stores value. - void Set(std::uint32_t value) override { atomic_uint32_.store(value); } - - private: - std::atomic atomic_uint32_{0}; - }; - } // namespace api -} // namespace nearby -#endif //LINUX_ATOMIC_BOOLEAN_H diff --git a/internal/platform/implementation/linux/bluetooth_adapter.cc b/internal/platform/implementation/linux/bluetooth_adapter.cc deleted file mode 100644 index 9c0c95f7..00000000 --- a/internal/platform/implementation/linux/bluetooth_adapter.cc +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - - -#include "absl/base/attributes.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/linux/bluetooth_adapter.h" - -namespace nearby { -namespace linux { - bool BluetoothAdapter::SetStatus(Status status) - { - if (status == Status::kEnabled) - { - Powered(true); - } - else - { - Powered(false); - } - return true; - } - bool BluetoothAdapter::IsEnabled() const - { - return Powered(); - } - api::BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const - { - if (!IsEnabled()) - { - return ScanMode::kNone; - } - if (Discoverable()) - { - return ScanMode::kConnectableDiscoverable; - } - return ScanMode::kConnectable; - } - bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) - { - if (!IsEnabled()) return false; - switch (scan_mode) - { - case ScanMode::kConnectable: - Discoverable(false); - return true; - case ScanMode::kConnectableDiscoverable: - Discoverable(true); - return true; - default: - return false; - } - } - std::string BluetoothAdapter::GetMacAddress() const - { - return Address(); - } - std::string BluetoothAdapter::GetName() const - { - return Alias(); - } - bool BluetoothAdapter::SetName(absl::string_view name) - { - try { - Alias(std::string(name)); - return true; - } catch (const sdbus::Error&) {return false;} - } - - bool BluetoothAdapter::SetName(absl::string_view name,bool persist) - { - return BluetoothAdapter::SetName(name); - } - - - -} // namespace linux -} // namespace nearby - diff --git a/internal/platform/implementation/linux/bluetooth_adapter.h b/internal/platform/implementation/linux/bluetooth_adapter.h deleted file mode 100644 index 28f5048d..00000000 --- a/internal/platform/implementation/linux/bluetooth_adapter.h +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PLATFORM_LINUX_IMPL_BLUETOOTH_ADAPTER_H_ -#define PLATFORM_LINUX_IMPL_BLUETOOTH_ADAPTER_H_ - -#include -#include -#include - -#include "absl/base/attributes.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/bluetooth_adapter.h" -#include "internal/platform/implementation/linux/generated/bluez_adapter_client_glue.h" - -#include "internal/platform/mac_address.h" -#include "internal/platform/implementation/bluetooth_classic.h" -constexpr uint8_t kAndroidDiscoverableBluetoothNameMaxLength = 37; // bytes - -namespace nearby { -namespace linux { - -// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html -class BluetoothAdapter : public api::BluetoothAdapter, public sdbus::ProxyInterfaces { - public: - BluetoothAdapter(sdbus::IConnection& system_bus, - const sdbus::ObjectPath& object_path): ProxyInterfaces( - system_bus, - "org.bluez", object_path ) - { - registerProxy(); - }; - ~BluetoothAdapter() override - { - unregisterProxy(); - }; - - //// Eligible statuses of the BluetoothAdapter. - //enum class Status { - // kDisabled, - // kEnabled, - //}; - - // Synchronously sets the status of the BluetoothAdapter to 'status', and - // returns true if the operation was a success. - bool SetStatus(Status status) override; - // Returns true if the BluetoothAdapter's current status is - // Status::Value::kEnabled. - bool IsEnabled() const override; - - // Scan modes of a BluetoothAdapter, as described at - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode(). - //enum class ScanMode { - // kUnknown, - // kNone, - // kConnectable, - // kConnectableDiscoverable, - //}; - - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode() - // - // Returns ScanMode::kUnknown on error. - ScanMode GetScanMode() const override; - // Synchronously sets the scan mode of the adapter, and returns true if the - // operation was a success. - bool SetScanMode(ScanMode scan_mode) override; - - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName() - // Returns an empty string on error - std::string GetName() const override; - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String) - bool SetName(absl::string_view name) override; - bool SetName(absl::string_view name, bool persist) override; - - // Returns BT MAC address assigned to this adapter. - ABSL_DEPRECATED("Use GetAddress() instead.") - std::string GetMacAddress() const override; - - // Implementation for migration only. Once subclasses implement this, the - // above GetMacAddress() can be removed. - MacAddress GetAddress() const override { - std::string mac_address = GetMacAddress(); - if (mac_address.empty()) { - return {}; - } - MacAddress address; - MacAddress::FromString(mac_address, address); - return address; - } -}; - - // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. - class BluetoothDevice : public api::BluetoothDevice { - public: - ~BluetoothDevice() override = default; - - // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName() - std::string GetName() const override; - std::string GetMacAddress() const override; - MacAddress GetAddress() const override; - BluetoothAdapter& GetAdapter() { return adapter_; } - - private: - // Only BluetoothAdapter may instantiate BluetoothDevice. - friend class BluetoothAdapter; - - explicit BluetoothDevice(BluetoothAdapter* adapter); - - BluetoothAdapter& adapter_; - }; -} // namespace linux -} // namespace nearby - -#endif // PLATFORM_LINUX_IMPL_BLUETOOTH_ADAPTER_H_ diff --git a/internal/platform/implementation/linux/bluetooth_adapter_test.cc b/internal/platform/implementation/linux/bluetooth_adapter_test.cc deleted file mode 100644 index 7550aa77..00000000 --- a/internal/platform/implementation/linux/bluetooth_adapter_test.cc +++ /dev/null @@ -1,94 +0,0 @@ -// filepath: /workspace/internal/platform/implementation/linux/bluetooth_adapter_test.cc -// Copyright 2024 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "internal/platform/implementation/linux/bluetooth_adapter.h" - -#include -#include - -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/notification.h" -#include "internal/platform/implementation/bluetooth_adapter.h" -#include - -namespace nearby { -namespace linux { -namespace { - -constexpr absl::string_view kName = "Test Radio Name"; - -// Tests are disabled because they may interact with the system DBus and -// modify adapter state; they are intended as compile-time and manual-run -// validations to mirror the Windows test suite. - -TEST(BluetoothAdapter, DISABLED_SetStatusReturnsTrue) { - auto connection = sdbus::createSystemBusConnection(); - connection -> enterEventLoopAsync(); - sdbus::ObjectPath object_path{"/org/bluez/hci0"}; - BluetoothAdapter adapter(*connection, object_path); - - // Our implementation returns bool; assert it returns true on attempted - // enable. This test is disabled by default to avoid changing system state. - EXPECT_TRUE(adapter.SetStatus(api::BluetoothAdapter::Status::kEnabled)); -} - -TEST(BluetoothAdapter, DISABLED_SetAndGetName) { - auto connection = sdbus::createSystemBusConnection(); - connection -> enterEventLoopAsync(); - sdbus::ObjectPath object_path{"/org/bluez/hci0"}; - BluetoothAdapter adapter(*connection, object_path); - - const std::string new_name = "nearby-linux-test-name"; - bool ok = adapter.SetName(new_name); - EXPECT_TRUE(ok); - if (ok) { - // If SetName succeeded, GetName should reflect the set value. - EXPECT_EQ(adapter.GetName(), new_name); - } -} - -TEST(BluetoothAdapter, DISABLED_GetMacAddressNotEmpty) { - auto connection = sdbus::createSystemBusConnection(); - connection -> enterEventLoopAsync(); - sdbus::ObjectPath object_path{"/org/bluez/hci0"}; - BluetoothAdapter adapter(*connection, object_path); - - EXPECT_FALSE(adapter.GetMacAddress().empty()); -} - -TEST(BluetoothAdapter, DISABLED_SetScanModeWhenEnabled) { - auto connection = sdbus::createSystemBusConnection(); - connection -> enterEventLoopAsync(); - sdbus::ObjectPath object_path{"/org/bluez/hci0"}; - BluetoothAdapter adapter(*connection, object_path); - - if (!adapter.IsEnabled()) { - GTEST_SKIP() << "Adapter not enabled on this machine; skipping scan-mode test."; - } - - // Try to set discoverable connectable; may be disallowed by system policy. - bool set_ok = adapter.SetScanMode(api::BluetoothAdapter::ScanMode::kConnectableDiscoverable); - if (!set_ok) { - GTEST_SKIP() << "SetScanMode returned false; skipping further scan-mode checks."; - } - - auto scan_mode = adapter.GetScanMode(); - EXPECT_EQ(scan_mode, api::BluetoothAdapter::ScanMode::kConnectableDiscoverable); -} - -} // namespace -} // namespace linux -} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic.cc b/internal/platform/implementation/linux/bluetooth_classic.cc deleted file mode 100644 index e97266ed..00000000 --- a/internal/platform/implementation/linux/bluetooth_classic.cc +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "internal/platform/implementation/linux/bluetooth_classic.h" - -#include -#include -#include -#include - -#include "absl/functional/any_invocable.h" -#include "absl/log/check.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/mutex.h" -#include "internal/platform/cancellation_flag.h" -#include "internal/platform/cancellation_flag_listener.h" -#include "internal/platform/exception.h" -#include "internal/platform/implementation/bluetooth_adapter.h" -#include "internal/platform/implementation/bluetooth_classic.h" -#include "internal/platform/implementation/g3/bluetooth_adapter.h" -#include "internal/platform/logging.h" -#include "internal/platform/mac_address.h" -#include "internal/platform/medium_environment.h" -#include "internal/platform/types.h" - -namespace nearby { -namespace linux { - -BluetoothDevice* BluetoothSocket::GetRemoteDevice() { - BluetoothSocket* remote_socket = - static_cast(GetRemoteSocket()); - if (remote_socket == nullptr || remote_socket->adapter_ == nullptr) { - return nullptr; - } - return &remote_socket->adapter_->GetDevice(); -} - -std::unique_ptr BluetoothServerSocket::Accept() { - absl::MutexLock lock(mutex_); - while (!closed_ && pending_sockets_.empty()) { - cond_.Wait(&mutex_); - } - // whether or not we were running in the wait loop, return early if closed. - if (closed_) return {}; - auto* remote_socket = - pending_sockets_.extract(pending_sockets_.begin()).value(); - CHECK(remote_socket); - auto local_socket = std::make_unique(adapter_); - local_socket->Connect(*remote_socket); - remote_socket->Connect(*local_socket); - cond_.SignalAll(); - return local_socket; -} - -bool BluetoothServerSocket::Connect(BluetoothSocket& socket) { - absl::MutexLock lock(mutex_); - if (closed_) return false; - if (socket.IsConnected()) { - LOG(ERROR) << "Failed to connect to BT server socket: already connected"; - return true; // already connected. - } - // add client socket to the pending list - pending_sockets_.emplace(&socket); - cond_.SignalAll(); - while (!socket.IsConnected()) { - cond_.Wait(&mutex_); - if (closed_) return false; - } - return true; -} - -void BluetoothServerSocket::SetCloseNotifier( - absl::AnyInvocable notifier) { - absl::MutexLock lock(mutex_); - close_notifier_ = std::move(notifier); -} - -BluetoothServerSocket::~BluetoothServerSocket() { - absl::MutexLock lock(mutex_); - DoClose(); -} - -Exception BluetoothServerSocket::Close() { - absl::MutexLock lock(mutex_); - return DoClose(); -} - -Exception BluetoothServerSocket::DoClose() { - bool should_notify = !closed_; - closed_ = true; - if (should_notify) { - cond_.SignalAll(); - if (close_notifier_) { - auto notifier = std::move(close_notifier_); - mutex_.unlock(); - // Notifier may contain calls to public API, and may cause deadlock, if - // mutex_ is held during the call. - notifier(); - mutex_.lock(); - } - } - return {Exception::kSuccess}; -} - -BluetoothPairing::BluetoothPairing(api::BluetoothDevice& remote_device) - : remote_device_(remote_device) {} - -BluetoothPairing::~BluetoothPairing() { - MediumEnvironment::Instance().ClearBluetoothDevicesForPairing(); -} - -bool BluetoothPairing::InitiatePairing( - api::BluetoothPairingCallback pairing_cb) { - return MediumEnvironment::Instance().InitiatePairing(&remote_device_, - std::move(pairing_cb)); -} - -bool BluetoothPairing::FinishPairing( - std::optional pin_code) { - return MediumEnvironment::Instance().FinishPairing(&remote_device_); -} - -bool BluetoothPairing::CancelPairing() { - return MediumEnvironment::Instance().CancelPairing(&remote_device_); -} - -bool BluetoothPairing::Unpair() { - return MediumEnvironment::Instance().SetPairingState(&remote_device_, false); -} - -bool BluetoothPairing::IsPaired() { - return MediumEnvironment::Instance().IsPaired(&remote_device_); -} - -BluetoothClassicMedium::BluetoothClassicMedium(api::BluetoothAdapter& adapter) - : adapter_(static_cast(&adapter)) { - adapter_->SetBluetoothClassicMedium(this); - auto& env = MediumEnvironment::Instance(); - env.RegisterBluetoothMedium(*this, GetAdapter()); -} - -BluetoothClassicMedium::~BluetoothClassicMedium() { - adapter_->SetBluetoothClassicMedium(nullptr); - auto& env = MediumEnvironment::Instance(); - env.UnregisterBluetoothMedium(*this); -} - -bool BluetoothClassicMedium::StartDiscovery(DiscoveryCallback callback) { - auto& env = MediumEnvironment::Instance(); - env.UpdateBluetoothMedium(*this, std::move(callback)); - return true; -} - -bool BluetoothClassicMedium::StopDiscovery() { - auto& env = MediumEnvironment::Instance(); - env.UpdateBluetoothMedium(*this, {}); - return true; -} - -std::unique_ptr BluetoothClassicMedium::ConnectToService( - api::BluetoothDevice& remote_device, const std::string& service_uuid, - CancellationFlag* cancellation_flag) { - LOG(INFO) << "G3 ConnectToService [self]: medium=" << this - << ", adapter=" << &GetAdapter() - << ", device=" << &GetAdapter().GetDevice(); - - // Find the device in the MediumEnvironment, so that injected devices are - // supported in tests. - api::BluetoothDevice* device = - MediumEnvironment::Instance().FindBluetoothDevice( - remote_device.GetAddress()); - if (device == nullptr) { - LOG(ERROR) << "G3 ConnectToService [peer]: device=" << &remote_device - << " not found"; - return {}; - } - - auto& adapter = down_cast(device)->GetAdapter(); - auto* medium = - down_cast(adapter.GetBluetoothClassicMedium()); - - if (!medium) return {}; // Adapter is not bound to medium. Bail out. - - BluetoothServerSocket* server_socket = nullptr; - LOG(INFO) << "G3 ConnectToService [peer]: medium=" << medium - << ", adapter=" << &adapter << ", device=" << &remote_device - << ", uuid=" << service_uuid; - // Then, find our server socket context in this medium. - { - absl::MutexLock medium_lock(medium->mutex_); - auto item = medium->sockets_.find(service_uuid); - server_socket = item != medium->sockets_.end() ? item->second : nullptr; - if (server_socket == nullptr) { - LOG(ERROR) << "Failed to find BT Server socket: uuid=" << service_uuid; - return {}; - } - } - - if (cancellation_flag->Cancelled()) { - LOG(ERROR) << "G3 Bluetooth Connect: Has been cancelled: " - "service_uuid=" - << service_uuid; - return {}; - } - - CancellationFlagListener listener(cancellation_flag, [&server_socket]() { - LOG(INFO) << "G3 Bluetooth Cancel Connect."; - if (server_socket != nullptr) server_socket->Close(); - }); - - auto socket = std::make_unique(&GetAdapter()); - // Finally, Request to connect to this socket. - if (!server_socket->Connect(*socket)) { - LOG(ERROR) << "Failed to connect to existing BT Server socket: uuid=" - << service_uuid; - return {}; - } - - if (cancellation_flag->Cancelled()) { - LOG(ERROR) << "G3 Bluetooth Connect: Has been cancelled after connected: " - "service_uuid=" - << service_uuid; - socket->Close(); - return {}; - } - - LOG(INFO) << "G3 ConnectToService: connected: socket=" << socket.get(); - return socket; -} - -std::unique_ptr -BluetoothClassicMedium::ListenForService(const std::string& service_name, - const std::string& service_uuid) { - auto socket = std::make_unique(GetAdapter()); - socket->SetCloseNotifier([this, uuid = service_uuid]() { - absl::MutexLock lock(mutex_); - sockets_.erase(uuid); - }); - LOG(INFO) << "Adding service: medium=" << this << ", uuid=" << service_uuid; - absl::MutexLock lock(mutex_); - sockets_.emplace(service_uuid, socket.get()); - return socket; -} - -std::unique_ptr BluetoothClassicMedium::CreatePairing( - api::BluetoothDevice& remote_device) { - return std::make_unique(remote_device); -} - -api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice( - MacAddress mac_address) { - return MediumEnvironment::Instance().FindBluetoothDevice(mac_address); -} - -void BluetoothClassicMedium::AddObserver( - api::BluetoothClassicMedium::Observer* observer) { - MediumEnvironment::Instance().AddObserver(observer); -} - -void BluetoothClassicMedium::RemoveObserver( - api::BluetoothClassicMedium::Observer* observer) { - MediumEnvironment::Instance().RemoveObserver(observer); -} - -} // namespace linux -} // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic.h b/internal/platform/implementation/linux/bluetooth_classic.h deleted file mode 100644 index fef9dc3e..00000000 --- a/internal/platform/implementation/linux/bluetooth_classic.h +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_H_ -#define PLATFORM_IMPL_LINUX_BLUETOOTH_CLASSIC_H_ - -#include -#include -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" -#include "absl/synchronization/mutex.h" -#include "internal/platform/exception.h" -#include "internal/platform/implementation/bluetooth_classic.h" -#include "internal/platform/implementation/g3/bluetooth_adapter.h" -#include "internal/platform/implementation/g3/socket_base.h" -#include "internal/platform/input_stream.h" -#include "internal/platform/mac_address.h" -#include "internal/platform/output_stream.h" - -namespace nearby { -namespace linux { - -// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html. -class BluetoothSocket : public api::BluetoothSocket, public SocketBase { - public: - BluetoothSocket() = default; - explicit BluetoothSocket(BluetoothAdapter* adapter) : adapter_(adapter) {} - - // Returns the InputStream of this connected BluetoothSocket. - InputStream& GetInputStream() override { - return SocketBase::GetInputStream(); - } - - // Returns the OutputStream of this connected BluetoothSocket. - // This stream is for local side to write. - OutputStream& GetOutputStream() override { - return SocketBase::GetOutputStream(); - } - - // Closes both input and output streams, marks Socket as closed. - // After this call object should be treated as not connected. - // Returns Exception::kIo on error, Exception::kSuccess otherwise. - Exception Close() override { return SocketBase::Close(); } - - // https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html#getRemoteDevice() - // Returns valid BluetoothDevice pointer if there is a connection, and - // nullptr otherwise. - BluetoothDevice* GetRemoteDevice() override; - - private: - BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only. -}; - -// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html. -class BluetoothServerSocket : public api::BluetoothServerSocket { - public: - explicit BluetoothServerSocket(BluetoothAdapter& adapter) - : adapter_(&adapter) {} - ~BluetoothServerSocket() override; - - // 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. - // - // Called by the server side of a connection. - // Returns BluetoothSocket to the server side. - // If not null, returned socket is connected to its remote (client-side) peer. - std::unique_ptr Accept() override - ABSL_LOCKS_EXCLUDED(mutex_); - - // Blocks until either: - // - connection is available, or - // - server socket is closed, or - // - error happens. - // - // Called by the client side of a connection. - // socket is an initialized BluetoothSocket, associated with a client - // BluetoothAdapter. - // Returns true, if socket is successfully connected. - bool Connect(BluetoothSocket& socket) ABSL_LOCKS_EXCLUDED(mutex_); - - // Called by the server side of a connection before passing ownership of - // BluetoothServerSocker to user, to track validity of a pointer to this - // server socket, - void SetCloseNotifier(absl::AnyInvocable notifier) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns Exception::kIo on error, Exception::kSuccess otherwise. - // Calls close_notifier if it was previously set, and marks socket as closed. - Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); - - private: - Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - absl::Mutex mutex_; - absl::CondVar cond_; - BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only. - absl::flat_hash_set pending_sockets_ - ABSL_GUARDED_BY(mutex_); - absl::AnyInvocable close_notifier_ ABSL_GUARDED_BY(mutex_); - bool closed_ ABSL_GUARDED_BY(mutex_) = false; -}; - -// A concrete implementation for BluetoothPairing. -class BluetoothPairing : public api::BluetoothPairing { - public: - explicit BluetoothPairing(api::BluetoothDevice& remote_device); - BluetoothPairing(const BluetoothPairing&) = default; - BluetoothPairing& operator=(const BluetoothPairing&) = default; - ~BluetoothPairing() override; - - bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; - bool FinishPairing(std::optional pin_code) override; - bool CancelPairing() override; - bool Unpair() override; - bool IsPaired() override; - - private: - api::BluetoothDevice& remote_device_; -}; - -// Container of operations that can be performed over the Bluetooth Classic -// medium. -class BluetoothClassicMedium : public api::BluetoothClassicMedium { - public: - explicit BluetoothClassicMedium(api::BluetoothAdapter& adapter); - ~BluetoothClassicMedium() override; - - // NOTE(DiscoveryCallback): - // BluetoothDevice is a proxy object created as a result of BT discovery. - // Its lifetime spans between calls to device_discovered_cb and - // device_lost_cb. - // It is safe to use BluetoothDevice in device_discovered_cb() callback - // and at any time afterwards, until device_lost_cb() is called. - // It is not safe to use BluetoothDevice after returning from - // device_lost_cb() callback. - // https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery() - // - // Returns true once the process of discovery has been initiated. - bool StartDiscovery(DiscoveryCallback callback) override - ABSL_LOCKS_EXCLUDED(mutex_); - - // 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 ABSL_LOCKS_EXCLUDED(mutex_); - - // Connects to existing remote BT service. - // - // 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 ConnectToService( - api::BluetoothDevice& remote_device, const std::string& service_uuid, - CancellationFlag* cancellation_flag) override ABSL_LOCKS_EXCLUDED(mutex_); - - BluetoothAdapter& GetAdapter() { return *adapter_; } - - // Creates BT service, and begins listening for remote attempts to connect. - // - // 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 on error. - std::unique_ptr ListenForService( - const std::string& service_name, const std::string& service_uuid) override - ABSL_LOCKS_EXCLUDED(mutex_); - - // Return a Bluetooth pairing instance to handle the pairing process with the - // remote device. - std::unique_ptr CreatePairing( - api::BluetoothDevice& remote_device) override; - - api::BluetoothDevice* GetRemoteDevice(MacAddress mac_address) override; - - void AddObserver(Observer* observer) override; - void RemoveObserver(Observer* observer) override; - - private: - absl::Mutex mutex_; - BluetoothAdapter* adapter_; // Our device adapter; read-only. - absl::flat_hash_map sockets_ - ABSL_GUARDED_BY(mutex_); -}; - -} // namespace linux -} // namespace nearby - -#endif // PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_ diff --git a/internal/platform/implementation/linux/crypto.cc b/internal/platform/implementation/linux/crypto.cc deleted file mode 100644 index 334aeceb..00000000 --- a/internal/platform/implementation/linux/crypto.cc +++ /dev/null @@ -1,57 +0,0 @@ -// ...existing code... -// filepath: /workspace/internal/platform/implementation/linux/crypto.cc -// 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 -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include - -// Function implementations for platform/api/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(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 - -// ...existing code... diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc deleted file mode 100644 index bf2ab9a5..00000000 --- a/internal/platform/implementation/linux/device_info.cc +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include "internal/platform/implementation/linux/device_info.h" -#include "internal/base/file_path.h" - -namespace nearby -{ - namespace linux - { - // TODO: Add proper implementations to grab device names and types from D-bus - - std::optional DeviceInfo::GetOsDeviceName() const - { - return "TestLinux" ; - }; - api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const - { - return api::DeviceInfo::DeviceType::kLaptop; - }; - std::optional DeviceInfo::GetDownloadPath() const - { - char* download_path = getenv("XDG_DOWNLOAD_DIR"); - if (download_path == nullptr) - { - download_path = getenv("HOME"); - if (download_path != nullptr) - { - std::string path = std::string(download_path) + "/Downloads"; - return FilePath(path); - } - } - return FilePath(std::string(download_path)); - }; - std::optional DeviceInfo::GetLocalAppDataPath() const - { - char* dir = getenv("XDG_STATE_HOME"); - if (dir == nullptr) - { - return FilePath("/tmp"); - } - return FilePath(std::string(dir)).append(FilePath("com.google.nearby")) ; - } - std::optional DeviceInfo::GetCommonAppDataPath() const - { - return GetLocalAppDataPath(); - }; - std::optional DeviceInfo::GetTemporaryPath() const - { - return FilePath("/tmp"); - } - std::optional DeviceInfo::GetLogPath() const - { - return FilePath("/tmp/nearby/logs"); - }; - std::optional DeviceInfo::GetCrashDumpPath() const - { - return FilePath("/tmp/nearby/crashdump"); - } - } -} diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h deleted file mode 100644 index d1982788..00000000 --- a/internal/platform/implementation/linux/device_info.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef PLATFORM_IMPL_LINUX_INFO_H_ -#define PLATFORM_IMPL_LINUX_INFO_H_ - -#include -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/base/file_path.h" -#include "internal/platform/implementation/device_info.h" - -namespace nearby { -namespace linux { - -class DeviceInfo: public api::DeviceInfo { - public: - ~DeviceInfo() = default; - - // Gets device name. - std::optional GetOsDeviceName() const override; - api::DeviceInfo::DeviceType GetDeviceType() const override; - api::DeviceInfo::OsType GetOsType() const override - { - return api::DeviceInfo::OsType::kWindows; //TODO: should probably change to linux - }; - - // Gets known paths of current user. - std::optional GetDownloadPath() const override; - std::optional GetLocalAppDataPath() const override; - std::optional GetCommonAppDataPath() const override; - std::optional GetTemporaryPath() const override; - std::optional GetLogPath() const override; - std::optional GetCrashDumpPath() const override; - - // Monitor screen status - bool IsScreenLocked() const override - { - return false; - }; - void RegisterScreenLockedListener( - absl::string_view listener_name, - std::function callback) override {return;}; - void UnregisterScreenLockedListener( - absl::string_view listener_name) override { return;}; - - // Control device sleep - bool PreventSleep() override {return true;}; - bool AllowSleep() override { return true;}; -}; - -} // namespace linux -} // namespace nearby - -#endif // PLATFORM_IMPL_LINUX_INFO_H_ diff --git a/internal/platform/implementation/linux/generated/avahi-proxy.h b/internal/platform/implementation/linux/generated/avahi-proxy.h deleted file mode 100644 index b59d99f1..00000000 --- a/internal/platform/implementation/linux/generated/avahi-proxy.h +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! - */ - -#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_avahi_proxy_h__proxy__H__ -#define __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_avahi_proxy_h__proxy__H__ - -#include -#include -#include - -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) - { - } - - Server_proxy(const Server_proxy&) = delete; - Server_proxy& operator=(const Server_proxy&) = delete; - Server_proxy(Server_proxy&&) = default; - Server_proxy& operator=(Server_proxy&&) = default; - - ~Server_proxy() = default; - -public: - sdbus::ObjectPath ServiceBrowserNew(const int32_t& interface, const int32_t& protocol, const std::string& type, const std::string& domain) - { - sdbus::ObjectPath result; - proxy_->callMethod("ServiceBrowserNew").onInterface(INTERFACE_NAME).withArguments(interface, protocol, type, domain).storeResultsTo(result); - return result; - } - - std::tuple>> 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) - { - std::tuple>> result; - proxy_->callMethod("ResolveService").onInterface(INTERFACE_NAME).withArguments(interface, protocol, name, type, domain, aprotocol).storeResultsTo(result); - return result; - } - -private: - sdbus::IProxy* proxy_; -}; - -}}} // namespaces - -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){ this->onItemNew(interface, protocol, name, type, domain); }); - 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){ this->onItemRemove(interface, protocol, name, type, domain); }); - } - - ServiceBrowser_proxy(const ServiceBrowser_proxy&) = delete; - ServiceBrowser_proxy& operator=(const ServiceBrowser_proxy&) = delete; - ServiceBrowser_proxy(ServiceBrowser_proxy&&) = default; - ServiceBrowser_proxy& operator=(ServiceBrowser_proxy&&) = default; - - ~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) = 0; - virtual void onItemRemove(const int32_t& interface, const int32_t& protocol, const std::string& name, const std::string& type, const std::string& domain) = 0; - -public: - void Free() - { - proxy_->callMethod("Free").onInterface(INTERFACE_NAME); - } - -private: - sdbus::IProxy* proxy_; -}; - -}}} // namespaces - -#endif diff --git a/internal/platform/implementation/linux/generated/avahi.xml b/internal/platform/implementation/linux/generated/avahi.xml deleted file mode 100644 index 9d5a3d81..00000000 --- a/internal/platform/implementation/linux/generated/avahi.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/internal/platform/implementation/linux/generated/bluez_adapter_client_glue.h b/internal/platform/implementation/linux/generated/bluez_adapter_client_glue.h deleted file mode 100644 index b2198797..00000000 --- a/internal/platform/implementation/linux/generated/bluez_adapter_client_glue.h +++ /dev/null @@ -1,184 +0,0 @@ - -/* - * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! - */ - -#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_bluez_adapter_client_glue_h__proxy__H__ -#define __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_bluez_adapter_client_glue_h__proxy__H__ - -#include -#include -#include - -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(const Adapter1_proxy&) = delete; - Adapter1_proxy& operator=(const Adapter1_proxy&) = delete; - Adapter1_proxy(Adapter1_proxy&&) = default; - Adapter1_proxy& operator=(Adapter1_proxy&&) = default; - - ~Adapter1_proxy() = default; - -public: - void StartDiscovery() - { - proxy_->callMethod("StartDiscovery").onInterface(INTERFACE_NAME); - } - - void SetDiscoveryFilter(const std::map& 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 GetDiscoveryFilters() - { - std::vector result; - proxy_->callMethod("GetDiscoveryFilters").onInterface(INTERFACE_NAME).storeResultsTo(result); - return result; - } - - void ConnectDevice(const std::map& properties) - { - proxy_->callMethod("ConnectDevice").onInterface(INTERFACE_NAME).withArguments(properties); - } - -public: - std::string Address() const - { - 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() const - { - 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() const - { - 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() const - { - 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 UUIDs() - { - return proxy_->getProperty("UUIDs").onInterface(INTERFACE_NAME); - } - - std::string Modalias() - { - return proxy_->getProperty("Modalias").onInterface(INTERFACE_NAME); - } - - std::vector Roles() - { - return proxy_->getProperty("Roles").onInterface(INTERFACE_NAME); - } - - std::vector ExperimentalFeatures() - { - return proxy_->getProperty("ExperimentalFeatures").onInterface(INTERFACE_NAME); - } - -private: - sdbus::IProxy* proxy_; -}; - -}} // namespaces - -#endif diff --git a/internal/platform/implementation/linux/generated/bluez_client_glue.h b/internal/platform/implementation/linux/generated/bluez_client_glue.h deleted file mode 100644 index 44e253b3..00000000 --- a/internal/platform/implementation/linux/generated/bluez_client_glue.h +++ /dev/null @@ -1,46 +0,0 @@ - -/* - * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! - */ - -#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_bluez_client_glue_h__proxy__H__ -#define __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_bluez_client_glue_h__proxy__H__ - -#include -#include -#include - -namespace org { -namespace freedesktop { -namespace DBus { - -class ObjectManager_proxy -{ -public: - static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.ObjectManager"; - -protected: - ObjectManager_proxy(sdbus::IProxy& proxy) - : proxy_(&proxy) - { - proxy_->uponSignal("InterfacesAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& object_path, const std::map>& interfaces_and_properties){ this->onInterfacesAdded(object_path, interfaces_and_properties); }); - proxy_->uponSignal("InterfacesRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& object_path, const std::vector& interfaces){ this->onInterfacesRemoved(object_path, interfaces); }); - } - - ObjectManager_proxy(const ObjectManager_proxy&) = delete; - ObjectManager_proxy& operator=(const ObjectManager_proxy&) = delete; - ObjectManager_proxy(ObjectManager_proxy&&) = default; - ObjectManager_proxy& operator=(ObjectManager_proxy&&) = default; - - ~ObjectManager_proxy() = default; - - virtual void onInterfacesAdded(const sdbus::ObjectPath& object_path, const std::map>& interfaces_and_properties) = 0; - virtual void onInterfacesRemoved(const sdbus::ObjectPath& object_path, const std::vector& interfaces) = 0; - -private: - sdbus::IProxy* proxy_; -}; - -}}} // namespaces - -#endif diff --git a/internal/platform/implementation/linux/generated/bluez_device_client_glue.h b/internal/platform/implementation/linux/generated/bluez_device_client_glue.h deleted file mode 100644 index 76c69bb1..00000000 --- a/internal/platform/implementation/linux/generated/bluez_device_client_glue.h +++ /dev/null @@ -1,225 +0,0 @@ - -/* - * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! - */ - -#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_bluez_device_client_glue_h__proxy__H__ -#define __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_bluez_device_client_glue_h__proxy__H__ - -#include -#include -#include - -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) - { - proxy_->uponSignal("Disconnected").onInterface(INTERFACE_NAME).call([this](const std::string& name, const std::string& message){ this->onDisconnected(name, message); }); - } - - Device1_proxy(const Device1_proxy&) = delete; - Device1_proxy& operator=(const Device1_proxy&) = delete; - Device1_proxy(Device1_proxy&&) = default; - Device1_proxy& operator=(Device1_proxy&&) = default; - - ~Device1_proxy() = default; - - virtual void onDisconnected(const std::string& name, const std::string& message) = 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); - } - - void Pair() - { - proxy_->callMethod("Pair").onInterface(INTERFACE_NAME); - } - - 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); - } - - bool CablePairing() - { - return proxy_->getProperty("CablePairing").onInterface(INTERFACE_NAME); - } - - int16_t RSSI() - { - return proxy_->getProperty("RSSI").onInterface(INTERFACE_NAME); - } - - bool Connected() - { - return proxy_->getProperty("Connected").onInterface(INTERFACE_NAME); - } - - std::vector 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 ManufacturerData() - { - return proxy_->getProperty("ManufacturerData").onInterface(INTERFACE_NAME); - } - - std::map 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 AdvertisingFlags() - { - return proxy_->getProperty("AdvertisingFlags").onInterface(INTERFACE_NAME); - } - - std::map 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> Sets() - { - return proxy_->getProperty("Sets").onInterface(INTERFACE_NAME); - } - -private: - sdbus::IProxy* proxy_; -}; - -}} // namespaces - -#endif diff --git a/internal/platform/implementation/linux/generated/org.bluez.Adapter1.xml b/internal/platform/implementation/linux/generated/org.bluez.Adapter1.xml deleted file mode 100644 index 1984689b..00000000 --- a/internal/platform/implementation/linux/generated/org.bluez.Adapter1.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/internal/platform/implementation/linux/generated/org.bluez.Device1.xml b/internal/platform/implementation/linux/generated/org.bluez.Device1.xml deleted file mode 100644 index a56ec7dc..00000000 --- a/internal/platform/implementation/linux/generated/org.bluez.Device1.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/internal/platform/implementation/linux/generated/org.bluez.xml b/internal/platform/implementation/linux/generated/org.bluez.xml deleted file mode 100644 index 4071a17c..00000000 --- a/internal/platform/implementation/linux/generated/org.bluez.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/internal/platform/implementation/linux/multi_thread_executor.h b/internal/platform/implementation/linux/multi_thread_executor.h deleted file mode 100644 index 606f4ca8..00000000 --- a/internal/platform/implementation/linux/multi_thread_executor.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef PLATFORM_IMPL_LINUX_MULTI_THREAD_EXECUTOR_H_ -#define PLATFORM_IMPL_LINUX_MULTI_THREAD_EXECUTOR_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal/platform/implementation/submittable_executor.h" -#include "internal/platform/runnable.h" - -namespace nearby { -namespace linux { - -class MultiThreadExecutor : public api::SubmittableExecutor { - public: - explicit MultiThreadExecutor(int max_parallelism) - : shutdown_(false) { - for (int i = 0; i < max_parallelism; ++i) { - workers_.emplace_back([this]() { WorkerLoop(); }); - } - } - - ~MultiThreadExecutor() override { - Shutdown(); - for (auto& worker : workers_) { - if (worker.joinable()) worker.join(); - } - } - void Schedule(Runnable&& runnable, absl::Duration delay) { - if (shutdown_) return; - std::thread([this, runnable = std::move(runnable), delay]() mutable { - std::this_thread::sleep_for(std::chrono::nanoseconds( - absl::ToInt64Nanoseconds(delay))); // delaying execution - DoSubmit(std::move(runnable)); - }).detach(); - } - - void Execute(Runnable&& runnable) override { - DoSubmit(std::move(runnable)); - } - - bool DoSubmit(Runnable&& runnable) override { - { - std::lock_guard lock(mutex_); - if (shutdown_) return false; - tasks_.emplace(std::move(runnable)); - } - cv_.notify_one(); - return true; - } - - void Shutdown() override { - { - std::lock_guard lock(mutex_); - shutdown_ = true; - } - cv_.notify_all(); - } - - private: - void WorkerLoop() { - while (true) { - Runnable task; - { - std::unique_lock lock(mutex_); - cv_.wait(lock, [this] { return shutdown_ || !tasks_.empty(); }); - if (shutdown_ && tasks_.empty()) return; - task = std::move(tasks_.front()); - tasks_.pop(); - } - if (task) task(); - } - } - - std::vector workers_; - std::queue tasks_; - std::mutex mutex_; - std::condition_variable cv_; - std::atomic shutdown_; -}; - -} // namespace linux -} // namespace nearby - -#endif // PLATFORM_IMPL_LINUX_MULTI_THREAD_EXECUTOR_H_ diff --git a/internal/platform/implementation/linux/multi_thread_executor_test.cc b/internal/platform/implementation/linux/multi_thread_executor_test.cc deleted file mode 100644 index 5ce20ed4..00000000 --- a/internal/platform/implementation/linux/multi_thread_executor_test.cc +++ /dev/null @@ -1,114 +0,0 @@ -// filepath: /workspace/internal/platform/implementation/linux/multi_thread_executor_test.cc -// Copyright 2025 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "internal/platform/implementation/linux/multi_thread_executor.h" - -#include - -#include "gtest/gtest.h" -#include "absl/synchronization/mutex.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" - -namespace nearby { -namespace linux { - -namespace { -const int kMaxThreads = 4; -} - -TEST(LinuxMultiThreadExecutorTest, ConstructorDestructorWorks) { - MultiThreadExecutor executor(kMaxThreads); -} - -TEST(LinuxMultiThreadExecutorTest, CanExecute) { - absl::CondVar cond; - std::atomic_bool done = false; - MultiThreadExecutor executor(kMaxThreads); - executor.Execute([&done, &cond]() { - done = true; - cond.SignalAll(); - }); - absl::Mutex mutex; - { - absl::MutexLock lock(&mutex); - if (!done) { - cond.WaitWithTimeout(&mutex, absl::Seconds(1)); - } - } - EXPECT_TRUE(done); -} - -TEST(LinuxMultiThreadExecutorTest, JobsExecuteInParallel) { - absl::Mutex mutex; - absl::CondVar thread_cond; - absl::CondVar test_cond; - MultiThreadExecutor executor(kMaxThreads); - int count = 0; - - for (int i = 0; i < kMaxThreads; ++i) { - executor.Execute([&]() { - absl::MutexLock lock(&mutex); - count++; - test_cond.Signal(); - thread_cond.Wait(&mutex); - count--; - test_cond.Signal(); - }); - } - - { - absl::MutexLock lock(&mutex); - while (count < kMaxThreads) { - if (test_cond.WaitWithTimeout(&mutex, absl::Seconds(30))) break; - } - } - - EXPECT_EQ(count, kMaxThreads); - thread_cond.SignalAll(); - - { - absl::MutexLock lock(&mutex); - while (count > 0) { - if (test_cond.WaitWithTimeout(&mutex, absl::Seconds(30))) break; - } - } - EXPECT_EQ(count, 0); -} - -TEST(LinuxMultiThreadExecutorTest, CanScheduleDelayedTask) { - MultiThreadExecutor executor(kMaxThreads); - std::atomic_bool ran = false; - auto start = absl::Now(); - executor.Schedule([&ran]() { ran = true; }, absl::Milliseconds(100)); - // Busy-wait using absl sleep to allow scheduled task to run - for (int i = 0; i < 20 && !ran; ++i) { - absl::SleepFor(absl::Milliseconds(20)); - } - EXPECT_TRUE(ran); - auto elapsed = absl::Now() - start; - EXPECT_GE(absl::ToInt64Milliseconds(elapsed), 80); -} - -TEST(LinuxMultiThreadExecutorTest, ShutdownPreventsSubmit) { - MultiThreadExecutor executor(kMaxThreads); - executor.Shutdown(); - // After Shutdown, DoSubmit should return false when trying to submit work. - bool submitted = executor.DoSubmit([]() {}); - EXPECT_FALSE(submitted); -} - -} // namespace linux -} // namespace nearby diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc deleted file mode 100644 index 522641fd..00000000 --- a/internal/platform/implementation/linux/platform.cc +++ /dev/null @@ -1,150 +0,0 @@ -// filepath: /workspace/internal/platform/implementation/linux/platform.cc -// Minimal Linux implementation of ImplementationPlatform. - -#include "internal/platform/implementation/platform.h" - -#include -#include - -#include "bluetooth_adapter.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" -#include "internal/platform/implementation/atomic_boolean.h" -#include "internal/platform/implementation/atomic_reference.h" -#include "internal/platform/implementation/count_down_latch.h" -#include "internal/platform/implementation/http_loader.h" -#include "internal/platform/implementation/shared/count_down_latch.h" -#include "internal/platform/implementation/linux/atomics.h" -#include "internal/platform/implementation/linux/multi_thread_executor.h" -#include "internal/platform/implementation/linux/scheduled_executor.h" -#include "internal/platform/implementation/linux/device_info.h" -#include "internal/platform/implementation/shared/posix_mutex.h" -#include "internal/platform/implementation/shared/posix_condition_variable.h" - - -#include -namespace nearby { -namespace api { - -std::string ImplementationPlatform::GetCustomSavePath(const std::string& parent_folder, - const std::string& file_name) { - return absl::StrCat(parent_folder, "/", file_name); -} - -std::string ImplementationPlatform::GetDownloadPath(const std::string& parent_folder, - const std::string& file_name) { - return absl::StrCat("/tmp/", file_name); -} - -std::string ImplementationPlatform::GetDownloadPath(const std::string& file_name) { - return absl::StrCat("/tmp/", file_name); -} - -std::string ImplementationPlatform::GetAppDataPath(const std::string& file_name) { - return absl::StrCat("/tmp/", file_name); -} - -OSName ImplementationPlatform::GetCurrentOS() { return OSName::kLinux; } - -std::unique_ptr ImplementationPlatform::CreateAtomicBoolean(bool initial_value) { - return std::make_unique(initial_value); -} - -std::unique_ptr ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) { - return std::make_unique(value); -} - -std::unique_ptr ImplementationPlatform::CreateCountDownLatch(std::int32_t count) { - return std::make_unique(count); -} - -#pragma push_macro("CreateMutex") -#undef CreateMutex -std::unique_ptr ImplementationPlatform::CreateMutex(Mutex::Mode mode) { - // Use the shared POSIX mutex implementation. The posix::Mutex is recursive by - // design (uses PTHREAD_MUTEX_RECURSIVE), so return it for both regular and - // recursive modes to use a consistent POSIX implementation across Linux. - return std::make_unique(); -} -#pragma pop_macro("CreateMutex") - -std::unique_ptr ImplementationPlatform::CreateConditionVariable(Mutex* mutex) { - if (mutex == nullptr) return nullptr; - // Expect a posix::Mutex instance here; if it's not, return nullptr. - auto* derived = dynamic_cast(mutex); - if (!derived) return nullptr; - return std::make_unique(derived); -} - -std::unique_ptr ImplementationPlatform::CreateInputFile(PayloadId, std::int64_t) { - return nullptr; -} - -std::unique_ptr ImplementationPlatform::CreateInputFile(const std::string&, size_t) { - return nullptr; -} - -std::unique_ptr ImplementationPlatform::CreateOutputFile(PayloadId) { - return nullptr; -} - -std::unique_ptr ImplementationPlatform::CreateOutputFile(const std::string&) { - return nullptr; -} - -std::unique_ptr ImplementationPlatform::CreateLogMessage(const char* file, int line, LogMessage::Severity severity) { - return nullptr; -} - -std::unique_ptr ImplementationPlatform::CreateSingleThreadExecutor() { - return std::make_unique(1); -} - -std::unique_ptr ImplementationPlatform::CreateMultiThreadExecutor(std::int32_t max_concurrency) { - return std::make_unique(static_cast(max_concurrency)); -} - -std::unique_ptr ImplementationPlatform::CreateScheduledExecutor() { - return std::unique_ptr(new linux::ScheduledExecutor()); -} - -std::unique_ptr ImplementationPlatform::CreateAwdlMedium() { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateBluetoothAdapter() -{ - static auto connection = sdbus::createConnection(); - connection -> enterEventLoopAsync(); - return std::make_unique(*connection, "/org/bluez/hci0"); -} -std::unique_ptr ImplementationPlatform::CreateBluetoothClassicMedium(BluetoothAdapter&) { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateBleMedium(BluetoothAdapter&) { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter&) { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateCredentialStorage() { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateServerSyncMedium() { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateWifiMedium() { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateWifiHotspotMedium() { return nullptr; } -std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { return nullptr; } - -std::unique_ptr ImplementationPlatform::CreateTimer() { return nullptr; } - -std::unique_ptr ImplementationPlatform::CreateDeviceInfo() { - return std::make_unique(); -} - -#ifndef NO_WEBRTC -std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { return nullptr; } -#endif - -absl::StatusOr ImplementationPlatform::SendRequest(const WebRequest& request) { - return absl::UnimplementedError("HTTP loader not implemented on this minimal linux platform"); -} - -#ifndef NEARBY_CHROMIUM -std::unique_ptr ImplementationPlatform::CreatePreferencesManager(absl::string_view path) { - return nullptr; -} -#endif - -} // namespace api -} // namespace nearby diff --git a/internal/platform/implementation/linux/platform.h b/internal/platform/implementation/linux/platform.h deleted file mode 100644 index 35868ea7..00000000 --- a/internal/platform/implementation/linux/platform.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef WORKSPACE_PLATFORM_H -#define WORKSPACE_PLATFORM_H -#include "internal/platform/implementation/platform.h" - -namespace nearby -{ - namespace linux - { - class Platform: public api::ImplementationPlatform - { - }; - - } - - -} -#endif //WORKSPACE_PLATFORM_H \ No newline at end of file diff --git a/internal/platform/implementation/linux/scheduled_executor.cc b/internal/platform/implementation/linux/scheduled_executor.cc deleted file mode 100644 index e69de29b..00000000 diff --git a/internal/platform/implementation/linux/scheduled_executor.h b/internal/platform/implementation/linux/scheduled_executor.h deleted file mode 100644 index 6012d0da..00000000 --- a/internal/platform/implementation/linux/scheduled_executor.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// Created by root on 10/8/25. -// - -#ifndef WORKSPACE_SCHEDULED_EXECUTOR_H -#define WORKSPACE_SCHEDULED_EXECUTOR_H - -#include "internal/platform/implementation/scheduled_executor.h" -#include "internal/platform/runnable.h" -#include "internal/platform/implementation/cancelable.h" -#include "internal/platform/implementation/linux/multi_thread_executor.h" -#include -#include -#include -#include "absl/time/time.h" - -namespace nearby -{ - namespace linux - { - // Minimal ScheduledExecutor implementation for linux. - class ScheduledExecutor : public api::ScheduledExecutor - { - public: - ~ScheduledExecutor() override = default; - ScheduledExecutor() : shutdown_(false), executor_(1) {} - - // Schedule a runnable to run after `duration`. Returns a Cancelable which - // can be used to cancel the scheduled task before it runs. - std::shared_ptr Schedule(Runnable&& runnable, - absl::Duration duration) override - { - class ScheduledCancelable : public api::Cancelable { - public: - enum Status { kNotRun, kExecuted, kCanceled }; - ScheduledCancelable() : status_(kNotRun) {} - bool Cancel() override { - Status expected = kNotRun; - return status_.compare_exchange_strong(expected, kCanceled); - } - [[nodiscard]] bool IsCanceled() const { return status_.load() == kCanceled; } - [[nodiscard]] bool MarkExecuted() { - Status expected = kNotRun; - return status_.compare_exchange_strong(expected, kExecuted); - } - - private: - std::atomic status_; - }; - - auto cancelable = std::make_shared(); - if (shutdown_.load()) return cancelable; - - // Move runnable into the thread task. - Runnable task = [this, cancelable, runnable = std::move(runnable)]() mutable { - if (shutdown_.load()) return; - if (cancelable->IsCanceled()) return; - if (!cancelable->MarkExecuted()) return; - // Use executor_ to run the actual runnable. - executor_.Execute(std::move(runnable)); - }; - - // Spawn a detached thread that sleeps for the duration then runs the task - // through executor_. Using a detached thread is simple and sufficient for - // a minimal implementation. - std::thread([d = duration, t = std::move(task), cancelable, this]() mutable { - if (absl::ToInt64Nanoseconds(d) > 0) { - std::this_thread::sleep_for(std::chrono::nanoseconds( - absl::ToInt64Nanoseconds(d))); - } - if (shutdown_.load()) return; - if (cancelable->IsCanceled()) return; - if (t) t(); - }).detach(); - - return cancelable; - }; - - void Execute(Runnable&& runnable) override { - if (shutdown_.load()) return; - executor_.Execute(std::move(runnable)); - } - - void Shutdown() override { - if (!shutdown_.exchange(true)) { - executor_.Shutdown(); - } - } - - private: - std::atomic shutdown_; - // Reuse the multi-thread executor implementation for running tasks. - linux::MultiThreadExecutor executor_; - }; - } -} -#endif //WORKSPACE_SCHEDULED_EXECUTOR_H diff --git a/internal/platform/implementation/linux/system_clock.cc b/internal/platform/implementation/linux/system_clock.cc deleted file mode 100644 index c6a07f98..00000000 --- a/internal/platform/implementation/linux/system_clock.cc +++ /dev/null @@ -1,49 +0,0 @@ -// ...existing code... -// filepath: /workspace/internal/platform/implementation/linux/system_clock.cc -// 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/system_clock.h" - -#include - -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "internal/platform/exception.h" - -namespace nearby { - -// Initialize global system state. -void SystemClock::Init() {} - -// Returns current elapsed (monotonic) time. -absl::Time SystemClock::ElapsedRealtime() { - const auto now = std::chrono::steady_clock::now().time_since_epoch(); - const auto nanos = - std::chrono::duration_cast(now).count(); - - // Represent monotonic time as an absl::Time value. - // (Anchor is arbitrary; only differences matter for elapsed time.) - return absl::FromUnixNanos(static_cast(nanos)); -} - -// Pauses current thread for the specified duration. -Exception SystemClock::Sleep(absl::Duration duration) { - absl::SleepFor(duration); - return {Exception::kSuccess}; -} - -} // namespace nearby - - From 1f3da1490687a5b68eb72c21e7a928f57082ddcc Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Mon, 29 Dec 2025 04:39:40 +0000 Subject: [PATCH 171/201] fixed logging bugs --- internal/platform/implementation/linux/dbus.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h index d9908495..c0dfae9f 100644 --- a/internal/platform/implementation/linux/dbus.h +++ b/internal/platform/implementation/linux/dbus.h @@ -22,7 +22,7 @@ #define DBUS_LOG_METHOD_CALL_ERROR(p, m, e) \ do { \ - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (e).getName() \ + LOG(ERROR) << __func__ << ": Got error '" << (e).getName() \ << "' with message '" << (e).getMessage() \ << "' while calling " << (m) << " on object " \ << (p)->getObjectPath(); \ @@ -30,7 +30,7 @@ #define DBUS_LOG_PROPERTY_GET_ERROR(p, prop, e) \ do { \ - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (e).getName() \ + LOG(ERROR) << __func__ << ": Got error '" << (e).getName() \ << "' with message '" << (e).getMessage() \ << "' while getting property " << (prop) \ << " on object " << (p)->getObjectPath(); \ @@ -38,7 +38,7 @@ #define DBUS_LOG_PROPERTY_SET_ERROR(p, prop, e) \ do { \ - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (e).getName() \ + LOG(ERROR) << __func__ << ": Got error '" << (e).getName() \ << "' with message '" << (e).getMessage() \ << "' while setting property " << (prop) \ << " on object " << (p)->getObjectPath(); \ From 5f93c4695488856a426f22a999200014c538da92 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Mon, 29 Dec 2025 04:41:32 +0000 Subject: [PATCH 172/201] ported over BUILD file --- internal/platform/implementation/linux/BUILD | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 0e150f61..daf6c43e 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -46,8 +46,8 @@ cc_library( ":comm", "//internal/platform/implementation:types", "@com_google_absl//absl/strings", - "@libsystemd//:lib", - "@sdbus_cpp//:lib", + "@sdbus_cpp//:libsystemd", + "@sdbus_cpp//:sdbus_cpp", ], ) @@ -114,8 +114,8 @@ cc_library( "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", - "@libsystemd//:lib", - "@sdbus_cpp//:lib", + "@sdbus_cpp//:libsystemd", + "@sdbus_cpp//:sdbus_cpp", ], visibility = ["//visibility:private"], ) @@ -212,8 +212,8 @@ cc_library( "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", "@nlohmann_json//:json", - "@libsystemd//:lib", - "@sdbus_cpp//:lib", + "@sdbus_cpp//:libsystemd", + "@sdbus_cpp//:sdbus_cpp", "@libcurl//:lib" ], ) From 6c41d26a861f2bc4134e446636f4e2efefa05cc6 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Mon, 29 Dec 2025 13:35:08 +0000 Subject: [PATCH 173/201] Doesn't build yet. But did more work to align the older fork with newer APIs. --- .gitignore | 1 + internal/platform/implementation/linux/BUILD | 44 +++++++-------- .../platform/implementation/linux/avahi.cc | 18 +++--- .../platform/implementation/linux/avahi.h | 4 +- .../implementation/linux/ble_gatt_client.cc | 14 ++--- .../implementation/linux/ble_gatt_server.cc | 10 ++-- .../implementation/linux/ble_v2_medium.cc | 56 +++++++++---------- .../linux/bluetooth_bluez_profile.cc | 32 +++++------ .../linux/bluetooth_bluez_profile.h | 2 +- .../linux/bluetooth_classic_device.cc | 12 ++-- .../linux/bluetooth_classic_device.h | 14 +++-- .../linux/bluetooth_classic_medium.cc | 16 +++--- .../linux/bluetooth_classic_medium.h | 3 +- .../linux/bluetooth_classic_server_socket.cc | 8 +-- .../linux/bluetooth_classic_socket.cc | 10 ++-- .../implementation/linux/bluetooth_devices.cc | 9 ++- .../implementation/linux/bluetooth_devices.h | 7 ++- .../implementation/linux/bluetooth_pairing.cc | 4 +- .../platform/implementation/linux/bluez.h | 2 +- .../linux/bluez_advertisement_monitor.cc | 2 +- .../bluez_advertisement_monitor_manager.h | 4 +- .../linux/bluez_gatt_characteristic_server.cc | 2 +- .../linux/bluez_gatt_characteristic_server.h | 2 +- .../linux/bluez_gatt_service_server.cc | 2 +- .../linux/bluez_gatt_service_server.h | 6 +- .../linux/bluez_le_advertisement.cc | 2 +- .../linux/bluez_le_advertisement.h | 2 +- .../implementation/linux/device_info.cc | 2 +- .../platform/implementation/linux/executor.cc | 4 +- .../implementation/linux/file_path.cc | 6 +- .../implementation/linux/http_loader.cc | 8 +-- .../implementation/linux/network_manager.h | 2 +- .../network_manager_active_connection.cc | 2 +- .../platform/implementation/linux/platform.cc | 32 ++++++----- .../linux/preferences_manager.cc | 10 ++-- .../linux/preferences_manager_test.cc | 4 +- .../linux/preferences_repository.cc | 26 ++++----- .../linux/scheduled_executor.cc | 6 +- .../platform/implementation/linux/stream.cc | 4 +- .../linux/submittable_executor.cc | 6 +- .../implementation/linux/tcp_server_socket.h | 18 +++--- .../implementation/linux/thread_pool.cc | 10 ++-- .../platform/implementation/linux/timer.cc | 35 +++--------- .../platform/implementation/linux/timer.h | 1 - .../platform/implementation/linux/utils.cc | 2 +- .../implementation/linux/wifi_direct.cc | 6 +- .../linux/wifi_direct_server_socket.cc | 2 +- .../implementation/linux/wifi_hotspot.cc | 40 ++++++------- .../linux/wifi_hotspot_server_socket.cc | 8 +-- .../platform/implementation/linux/wifi_lan.cc | 18 +++--- .../linux/wifi_lan_server_socket.cc | 2 +- .../implementation/linux/wifi_medium.cc | 26 ++++----- 52 files changed, 279 insertions(+), 289 deletions(-) diff --git a/.gitignore b/.gitignore index c0299bed..f00588f4 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,4 @@ bazel-* # Devcontainers /.devcontainer/ /connections/walkietalkie/ +/third_party/ diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index daf6c43e..189d7715 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -32,12 +32,12 @@ cc_library( "submittable_executor.h", "timer.h", "thread_pool.h", - "log_message.h", + #"log_message.h", "utils.h", ], srcs = [ "device_info.cc", - "log_message.cc", + #"log_message.cc", "timer.cc", ], copts = ["-lrt"], @@ -57,9 +57,9 @@ cc_library( "avahi.h", "ble_gatt_server.h", "ble_gatt_client.h", - "ble_medium.h", - "ble_v2_medium.h", - "ble_v2_server_socket.h", +# "ble_medium.h", +# "ble_v2_medium.h", +# "ble_v2_server_socket.h", "bluetooth_adapter.h", "bluetooth_bluez_profile.h", "bluetooth_classic_device.h", @@ -69,14 +69,15 @@ cc_library( "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", + "bluez_device.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", @@ -137,9 +138,9 @@ cc_library( name = "linux", srcs = [ "avahi.cc", - "ble_gatt_client.cc", - "ble_gatt_server.cc", - "ble_v2_medium.cc", +# "ble_gatt_client.cc", +# "ble_gatt_server.cc", +# "ble_v2_medium.cc", "bluetooth_adapter.cc", "bluetooth_bluez_profile.cc", "bluetooth_classic_socket.cc", @@ -149,11 +150,11 @@ cc_library( "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", +# "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", @@ -214,7 +215,6 @@ cc_library( "@nlohmann_json//:json", "@sdbus_cpp//:libsystemd", "@sdbus_cpp//:sdbus_cpp", - "@libcurl//:lib" ], ) diff --git a/internal/platform/implementation/linux/avahi.cc b/internal/platform/implementation/linux/avahi.cc index 1092a73b..3d601898 100644 --- a/internal/platform/implementation/linux/avahi.cc +++ b/internal/platform/implementation/linux/avahi.cc @@ -25,14 +25,14 @@ void ServiceBrowser::onItemNew(const int32_t &interface, const std::string &type, const std::string &domain, const uint32_t &flags) { - NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + LOG(INFO) << __func__ << ": " << getObjectPath() << ": Found new item through the ServiceBrowser: " << "interface: " << interface << ", protocol: " << protocol << ", name: '" << name << "', type: '" << type << "', domain: '" << domain << "', flags: " << flags; if (flags & kAvahiLookupResultLocal) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Ignoring local service."; + LOG(INFO) << __func__ << ": Ignoring local service."; return; } @@ -51,7 +51,7 @@ void ServiceBrowser::onItemNew(const int32_t &interface, 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; + LOG(WARNING) << " found invalid text attribute: " << attr_str; continue; } @@ -68,14 +68,14 @@ 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() + LOG(INFO) << __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."; + LOG(INFO) << __func__ << ": Ignoring local service."; return; } @@ -94,7 +94,7 @@ void ServiceBrowser::onItemRemove( 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; + LOG(WARNING) << " found invalid text attribute: " << attr_str; continue; } @@ -108,18 +108,18 @@ void ServiceBrowser::onItemRemove( } void ServiceBrowser::onFailure(const std::string &error) { - NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() + LOG(ERROR) << __func__ << ": " << getObjectPath() << ": ServiceBrowser reported a failure: " << error; } void ServiceBrowser::onAllForNow() { - NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + LOG(INFO) << __func__ << ": " << getObjectPath() << ": notified via ServiceBrowser that all records have " "been added for now"; } void ServiceBrowser::onCacheExhausted() { - NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + LOG(INFO) << __func__ << ": " << getObjectPath() << ": notified via ServiceBrowser of cache exhaustion"; } diff --git a/internal/platform/implementation/linux/avahi.h b/internal/platform/implementation/linux/avahi.h index e7ed6e20..4dc61db9 100644 --- a/internal/platform/implementation/linux/avahi.h +++ b/internal/platform/implementation/linux/avahi.h @@ -53,7 +53,7 @@ class EntryGroup final registerProxy(); } ~EntryGroup() { - NEARBY_LOGS(VERBOSE) << __func__ << ": Freeing entry group " + LOG(INFO) << __func__ << ": Freeing entry group " << getObjectPath(); try { @@ -85,7 +85,7 @@ class ServiceBrowser final registerProxy(); } ~ServiceBrowser() { - NEARBY_LOGS(VERBOSE) << __func__ << ": Freeing service browser " + LOG(INFO) << __func__ << ": Freeing service browser " << getObjectPath(); try { diff --git a/internal/platform/implementation/linux/ble_gatt_client.cc b/internal/platform/implementation/linux/ble_gatt_client.cc index 936ec6c2..d3fd0451 100644 --- a/internal/platform/implementation/linux/ble_gatt_client.cc +++ b/internal/platform/implementation/linux/ble_gatt_client.cc @@ -85,7 +85,7 @@ absl::optional GattClient::ReadCharacteristic( const api::ble_v2::GattCharacteristic &characteristic) { absl::ReaderMutexLock lock(&characteristics_mutex_); if (characteristics_.count(characteristic) == 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Unknown characteristic '" + LOG(ERROR) << __func__ << ": Unknown characteristic '" << absl::Substitute("$0", characteristic) << "'"; return std::nullopt; } @@ -109,7 +109,7 @@ bool GattClient::WriteCharacteristic( absl::string_view value, WriteType type) { absl::ReaderMutexLock lock(&characteristics_mutex_); if (characteristics_.count(characteristic) == 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Unknown characteristic '" + LOG(ERROR) << __func__ << ": Unknown characteristic '" << absl::Substitute("$0", characteristic) << "'"; return false; } @@ -139,7 +139,7 @@ bool GattClient::SetCharacteristicSubscription( on_characteristic_changed_cb) { absl::MutexLock lock(&characteristics_mutex_); if (characteristics_.count(characteristic) == 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Unknown characteristic '" + LOG(ERROR) << __func__ << ": Unknown characteristic '" << absl::Substitute("$0", characteristic) << "'"; return false; } @@ -295,7 +295,7 @@ BluezGattDiscovery::GetCharacteristic( 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 " + LOG(ERROR) << __func__ << ": No characteristic known for device " << device_object_path << " with service " << std::string{service_uuid} << " and UUID " << std::string{characteristic_uuid}; @@ -318,7 +318,7 @@ BluezGattDiscovery::GetSubscribedCharacteristic( 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 " + LOG(ERROR) << __func__ << ": No characteristic known for device " << device_object_path << " with service " << std::string{service_uuid} << " and UUID " << std::string{characteristic_uuid}; @@ -338,7 +338,7 @@ BluezGattDiscovery::characteristicProperties( 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 + LOG(ERROR) << ": Couldn't parse UUID '" << chr_uuid_str << "' in characteristic " << path; return std::nullopt; } @@ -355,7 +355,7 @@ BluezGattDiscovery::characteristicProperties( 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 + LOG(ERROR) << ": Couldn't parse UUID '" << service_uuid_str << "' in service " << service_path; return std::nullopt; } diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc index 7a25a47d..927c6d62 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.cc +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -47,7 +47,7 @@ GattServer::CreateCharacteristic( service->emitInterfacesAddedSignal( {org::bluez::GattService1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error& e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": error emitting InterfacesAdded signal for object path " << service->getObjectPath() << " with name '" << e.getName() @@ -59,7 +59,7 @@ GattServer::CreateCharacteristic( property)) { bluez::GattManager manager(system_bus_, adapter_.GetObjectPath()); try { - NEARBY_LOGS(VERBOSE) << __func__ << ": registering service " + LOG(INFO) << __func__ << ": registering service " << service->getObjectPath(); manager.RegisterApplication("/", {}); } catch (const sdbus::Error& e) { @@ -84,7 +84,7 @@ bool GattServer::UpdateCharacteristic( { absl::ReaderMutexLock lock(&services_mutex_); if (services_.count(characteristic.service_uuid) == 0) { - NEARBY_LOGS(ERROR) << __func__ << ": GATT Service " + LOG(ERROR) << __func__ << ": GATT Service " << std::string{characteristic.service_uuid} << " doesn't exist"; return false; @@ -93,7 +93,7 @@ bool GattServer::UpdateCharacteristic( characteristic.uuid); } if (chr == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": Characteristic " + LOG(ERROR) << __func__ << ": Characteristic " << std::string{characteristic.uuid} << " does not exist under service " << std::string{characteristic.service_uuid}; @@ -132,7 +132,7 @@ 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 " + LOG(INFO) << __func__ << ": Unregistering service " << service->getObjectPath(); try { manager.UnregisterApplication("/"); diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index aafe2d68..ee791021 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -49,7 +49,7 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) adapter)), cur_adv_(nullptr) { if (adv_monitor_manager_) { - NEARBY_LOGS(VERBOSE) + LOG(INFO) << __func__ << ": Registering path / with AdvertisementMonitorManager at " << adv_monitor_manager_->getObjectPath(); @@ -60,7 +60,7 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) } } if (gatt_discovery_->InitializeKnownServices()) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Could not initialize known GATT services"; } } @@ -69,20 +69,20 @@ 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 " + LOG(WARNING) << "BLE cannot start advertising because the " "bluetooth adapter is not enabled."; return false; } if (advertising_data.service_data.empty()) { - NEARBY_LOGS(WARNING) + LOG(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__ + LOG(ERROR) << __func__ << "Advertising is already enabled for this medium."; return false; } @@ -90,7 +90,7 @@ bool BleV2Medium::StartAdvertising( cur_adv_ = bluez::LEAdvertisement::CreateLEAdvertisement( *system_bus_, advertising_data, advertise_set_parameters); - NEARBY_LOGS(INFO) << __func__ << ": Registering advertisement " + LOG(INFO) << __func__ << ": Registering advertisement " << cur_adv_->getObjectPath() << " on bluetooth adapter " << adapter_.GetObjectPath(); @@ -108,10 +108,10 @@ bool BleV2Medium::StartAdvertising( bool BleV2Medium::StopAdvertising() { absl::MutexLock lock(&cur_adv_mutex_); if (cur_adv_ == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": Advertising is not enabled."; + LOG(ERROR) << __func__ << ": Advertising is not enabled."; return false; } - NEARBY_LOGS(VERBOSE) << __func__ << "Unregistering advertisement object " + LOG(INFO) << __func__ << "Unregistering advertisement object " << cur_adv_->getObjectPath(); try { @@ -131,13 +131,13 @@ BleV2Medium::StartAdvertising( api::ble_v2::AdvertiseParameters advertise_set_parameters, AdvertisingCallback callback) { if (!adapter_.IsEnabled()) { - NEARBY_LOGS(WARNING) << ": BLE cannot start advertising because the " + LOG(WARNING) << ": BLE cannot start advertising because the " "bluetooth adapter is not enabled."; return nullptr; } if (advertising_data.service_data.empty()) { - NEARBY_LOGS(WARNING) + LOG(WARNING) << ": BLE cannot start to advertise due to invalid service data."; return nullptr; } @@ -189,7 +189,7 @@ BleV2Medium::StartAdvertising( }); absl::AnyInvocable stop_adv = [&, adv_it]() { - NEARBY_LOGS(VERBOSE) << __func__ << ": Unregistering advertisement object " + LOG(INFO) << __func__ << ": Unregistering advertisement object " << (*adv_it)->getObjectPath(); absl::MutexLock lock(&advs_mutex_); try { @@ -246,7 +246,7 @@ bool BleV2Medium::StartLEDiscovery() { } try { - NEARBY_LOGS(INFO) << __func__ << ": Starting LE discovery on " + LOG(INFO) << __func__ << ": Starting LE discovery on " << adapter.getObjectPath(); adapter.StartDiscovery(); } catch (const sdbus::Error &e) { @@ -263,21 +263,21 @@ 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__ + LOG(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__ + LOG(WARNING) << __func__ << ": Advertising monitor not supported by BlueZ"; // TODO: Implement manual monitoring. return false; } if (!MonitorManagerSupportsOr()) { - NEARBY_LOGS(WARNING) + LOG(WARNING) << __func__ << ": \"or_patterns\" not supported by AdvertisementMonitorManager"; // TODO: Implement manual monitoring. @@ -286,7 +286,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, absl::MutexLock lock(&active_adv_monitors_mutex_); if (active_adv_monitors_.count(service_uuid) == 1) { - NEARBY_LOGS(ERROR) << __func__ << ": an advertising session for service " + LOG(ERROR) << __func__ << ": an advertising session for service " << std::string{service_uuid} << " already exists"; return false; } @@ -298,7 +298,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, monitor->emitInterfacesAddedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": error emitting InterfacesAdded signal for object path " << monitor->getObjectPath() << " with name '" << e.getName() @@ -309,7 +309,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, auto device_watcher = std::make_unique( *system_bus_, adapter_.GetObjectPath(), devices_); if (!StartLEDiscovery()) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Could not start LE discovery on adapter " << adapter_.GetObjectPath(); device_watcher = nullptr; @@ -317,7 +317,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, monitor->emitInterfacesRemovedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": error emitting InterfacesRemoved signal for object path " << monitor->getObjectPath() << " with name '" << e.getName() @@ -334,7 +334,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, bool BleV2Medium::StopScanning() { if (!cur_monitored_service_uuid_.has_value()) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": No sync scanning session is currently active."; return false; } @@ -345,7 +345,7 @@ bool BleV2Medium::StopScanning() { } auto &adapter = adapter_.GetBluezAdapterObject(); - NEARBY_LOGS(VERBOSE) << __func__ << ": Stopping discovery for adapter " + LOG(INFO) << __func__ << ": Stopping discovery for adapter " << adapter.getObjectPath(); try { adapter.StopDiscovery(); @@ -360,7 +360,7 @@ bool BleV2Medium::StopScanning() { auto &[_uuid, session] = *monitor_it; auto &[adv_monitor, _watcher] = session; - NEARBY_LOGS(VERBOSE) << __func__ << ": Removing advertising monitor " + LOG(INFO) << __func__ << ": Removing advertising monitor " << adv_monitor->getObjectPath(); adv_monitor->emitInterfacesRemovedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); @@ -382,7 +382,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, absl::MutexLock lock(&active_adv_monitors_mutex_); if (active_adv_monitors_.count(service_uuid) == 1) { - NEARBY_LOGS(ERROR) << __func__ << ": Service " << std::string{service_uuid} + LOG(ERROR) << __func__ << ": Service " << std::string{service_uuid} << " is already being advertised"; return nullptr; } @@ -394,7 +394,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, monitor->emitInterfacesAddedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": error emitting InterfacesAdded signal for object path " << monitor->getObjectPath() << " with name '" << e.getName() @@ -405,14 +405,14 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, auto device_watcher = std::make_unique( *system_bus_, adapter_.GetObjectPath(), devices_); if (!StartLEDiscovery()) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Could not start LE discovery on adapter " << adapter_.GetObjectPath(); try { monitor->emitInterfacesRemovedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": error emitting InterfacesRemoved signal for object path " << monitor->getObjectPath() << " with name '" << e.getName() @@ -428,7 +428,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, ScanningSession{.stop_scanning = [this, service_uuid]() { absl::MutexLock lock(&active_adv_monitors_mutex_); if (active_adv_monitors_.count(service_uuid) == 0) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Advertising monitor for service " << std::string{service_uuid} << " does not exist anymore"; return absl::NotFoundError( @@ -440,7 +440,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, monitor->emitInterfacesRemovedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": error emitting InterfacesRemoved signal for object path " << monitor->getObjectPath() << " with name '" << e.getName() diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index d371a315..25e0f3f9 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -46,7 +46,7 @@ bool ProfileManager::ProfileRegistered(absl::string_view service_uuid) { void Profile::Release() { released_ = true; - NEARBY_LOGS(VERBOSE) << __func__ << ": Profile object " << getObjectPath() + LOG(INFO) << __func__ << ": Profile object " << getObjectPath() << " has been released"; } @@ -54,7 +54,7 @@ void Profile::NewConnection( const sdbus::ObjectPath &device_object_path, const sdbus::UnixFd &fd, const std::map &fd_props) { if (released_) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": NewConnection called on released object " << getObjectPath(); throw sdbus::Error("org.bluez.Error.Rejected", @@ -69,7 +69,7 @@ void Profile::NewConnection( auto alias = device->GetName(); auto mac_addr = device->GetAddress(); - NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + LOG(INFO) << __func__ << ": " << getObjectPath() << ": Connected to " << mac_addr; FDProperties props(fd_props); @@ -82,7 +82,7 @@ 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() + LOG(ERROR) << __func__ << ": " << getObjectPath() << ": RequestDisconnection called with a device object " "we don't know about: " << device_object_path; @@ -90,12 +90,12 @@ void Profile::RequestDisconnection( } auto mac_addr = device->GetMacAddress(); - NEARBY_LOGS(VERBOSE) << __func__ << ": Disconnection requested for device " + LOG(INFO) << __func__ << ": Disconnection requested for device " << device_object_path; absl::MutexLock l(&connections_lock_); if (connections_.count(mac_addr) == 0) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Disconnection requested, but we are not connected to this device"; return; @@ -108,7 +108,7 @@ bool ProfileManager::Register(std::optional 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 " + LOG(WARNING) << __func__ << ": Trying to register profile " << service_uuid << " which was already registered."; return true; } @@ -136,7 +136,7 @@ bool ProfileManager::Register(std::optional name, registered_services_.emplace(service_uuid, profile); - NEARBY_LOGS(INFO) << __func__ + LOG(INFO) << __func__ << ": Registered profile instance for service uuid " << service_uuid; @@ -146,14 +146,14 @@ bool ProfileManager::Register(std::optional name, 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) + LOG(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 " + LOG(INFO) << __func__ << ": Unregistering profile " << profile_object_path; try { @@ -174,7 +174,7 @@ std::optional ProfileManager::GetServiceRecordFD( { absl::ReaderMutexLock lock(®istered_service_uuids_mutex_); if (registered_services_.count(std::string(service_uuid)) == 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Service " << service_uuid + LOG(ERROR) << __func__ << ": Service " << service_uuid << " is not registered"; return std::nullopt; } @@ -190,7 +190,7 @@ std::optional ProfileManager::GetServiceRecordFD( profile->connections_lock_.Unlock(); }); - NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() + LOG(INFO) << __func__ << ": " << profile->getObjectPath() << ": Attempting to get a FD for service " << service_uuid << " on device " << mac_addr; @@ -204,7 +204,7 @@ std::optional ProfileManager::GetServiceRecordFD( absl::Condition(&cond)); if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) { - NEARBY_LOGS(VERBOSE) + LOG(INFO) << __func__ << ": " << profile->getObjectPath() << ": " << remote_device.GetMacAddress() << ": Cancelled waiting for a new connection on profile " @@ -236,7 +236,7 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, profile = registered_services_[std::string(service_uuid)]; } - NEARBY_LOGS(VERBOSE) << __func__ << ": " << profile->getObjectPath() + LOG(INFO) << __func__ << ": " << profile->getObjectPath() << ": Attempting to get a FD for service " << service_uuid; @@ -257,7 +257,7 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, profile->connections_lock_.Await(absl::Condition(&cond)); if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) { - NEARBY_LOGS(VERBOSE) + LOG(INFO) << __func__ << ": Cancelled waiting for new connections on profile " << profile->getObjectPath(); profile->connections_lock_.Unlock(); @@ -273,7 +273,7 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, auto device = devices_.get_device_by_address(mac_addr); if (device == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": Device " << mac_addr + LOG(ERROR) << __func__ << ": Device " << mac_addr << " is no longer available"; return std::nullopt; } diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index 31cc1bf3..85ec7717 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -60,7 +60,7 @@ class Profile final released_(false), devices_(devices) { registerAdaptor(); - NEARBY_LOGS(VERBOSE) << __func__ << ": Created a new BlueZ profile at :" + LOG(INFO) << __func__ << ": Created a new BlueZ profile at :" << getObjectPath(); } ~Profile() { unregisterAdaptor(); } diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 035c887d..b094df62 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -35,8 +35,8 @@ BluetoothDevice::BluetoothDevice(std::shared_ptr device) DBUS_LOG_PROPERTY_GET_ERROR(device, "Alias", e); } try { - last_known_address_ = device->Address(); - unique_id_ = BluetoothUtils::ToNumber(last_known_address_); + MacAddress::FromString(device -> Address(), last_known_address_); + unique_id_ = last_known_address_.address(); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(device, "Address", e); } @@ -73,7 +73,7 @@ std::string BluetoothDevice::GetMacAddress() const { std::string addr = device->Address(); { absl::MutexLock l(&properties_mutex_); - last_known_address_ = addr; + MacAddress::FromString(addr, last_known_address_); } return addr; } catch (const sdbus::Error &e) { @@ -117,20 +117,20 @@ void MonitoredBluetoothDevice::onPropertiesChanged( for (auto it = changedProperties.begin(); it != changedProperties.end(); it++) { if (it->first == bluez::DEVICE_PROP_ADDRESS) { - NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + LOG(INFO) << __func__ << ": " << getObjectPath() << ": Notifying observers about address change"; std::string address = it->second; for (const auto &observer : observers_.GetObservers()) { observer->DeviceAddressChanged(*this, address); } } else if (it->first == bluez::DEVICE_PROP_PAIRED) { - NEARBY_LOGS(VERBOSE) << __func__ << ": " << getObjectPath() + LOG(INFO) << __func__ << ": " << getObjectPath() << "Notifying observers about paired status change."; for (const auto &observer : observers_.GetObservers()) { observer->DevicePairedChanged(*this, it->second); } } else if (it->first == bluez::DEVICE_PROP_CONNECTED) { - NEARBY_LOGS(VERBOSE) + LOG(INFO) << __func__ << ": " << getObjectPath() << "Notifying observers about connected status change"; for (const auto &observer : observers_.GetObservers()) { diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 57c6a2c2..d87d4239 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -29,7 +29,7 @@ #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/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" @@ -38,8 +38,10 @@ namespace nearby { namespace linux { // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. -class BluetoothDevice : public api::BluetoothDevice, - public api::ble_v2::BlePeripheral { + + // TODO: This used to inherit from ble_v2::BlePeripheral. Removed that since APIs have now changed +class BluetoothDevice : public api::BluetoothDevice + { public: using UniqueId = std::uint64_t; @@ -55,9 +57,9 @@ class BluetoothDevice : public api::BluetoothDevice, // Returns BT MAC address assigned to this device. std::string GetMacAddress() const override; + MacAddress GetAddress() const override { return last_known_address_; } // BlePeripheral methods - std::string GetAddress() const override { return GetMacAddress(); } - UniqueId GetUniqueId() const override { return unique_id_; }; + //UniqueId GetUniqueId() const override { return unique_id_; }; std::optional> ServiceData() { auto device = device_.lock(); @@ -123,7 +125,7 @@ class BluetoothDevice : public api::BluetoothDevice, 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 MacAddress last_known_address_ ABSL_GUARDED_BY(properties_mutex_); mutable std::weak_ptr device_; }; diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index e179340f..6ef9c7ab 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -62,7 +62,7 @@ bool BluetoothClassicMedium::StartDiscovery( } try { - NEARBY_LOGS(INFO) << __func__ << ": Starting BR/EDR discovery on " + LOG(INFO) << __func__ << ": Starting BR/EDR discovery on " << adapter_.GetObjectPath(); adapter.StartDiscovery(); } catch (const sdbus::Error &e) { @@ -78,7 +78,7 @@ bool BluetoothClassicMedium::StartDiscovery( bool BluetoothClassicMedium::StopDiscovery() { auto &adapter = adapter_.GetBluezAdapterObject(); - NEARBY_LOGS(INFO) << __func__ << "Stopping discovery on " + LOG(INFO) << __func__ << "Stopping discovery on " << adapter.getObjectPath(); auto ret = true; try { @@ -97,7 +97,7 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( 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 " + LOG(ERROR) << __func__ << ": Could not register profile " << service_uuid << " with Bluez"; return nullptr; } @@ -106,7 +106,7 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( auto address = remote_device.GetMacAddress(); auto device = devices_->get_device_by_address(address); if (device == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": Device " << address + LOG(ERROR) << __func__ << ": Device " << address << " is no longer known"; return nullptr; } @@ -118,7 +118,7 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( auto fd = profile_manager_->GetServiceRecordFD(remote_device, service_uuid, cancellation_flag); if (!fd.has_value()) { - NEARBY_LOGS(WARNING) << __func__ + LOG(WARNING) << __func__ << ": Failed to get a new connection for profile " << service_uuid << " for device " << address; return nullptr; @@ -133,7 +133,7 @@ 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 " + LOG(ERROR) << __func__ << ": Could not register profile " << service_name << " " << service_uuid << " with Bluez"; return nullptr; @@ -145,8 +145,8 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, } api::BluetoothDevice *BluetoothClassicMedium::GetRemoteDevice( - const std::string &mac_address) { - auto device = devices_->get_device_by_address(mac_address); +MacAddress mac_address) { + auto device = devices_->get_device_by_address(mac_address.ToString()); if (device == nullptr) return nullptr; return device.get(); diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 7192206c..b8fd3b93 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -89,8 +89,7 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium { std::unique_ptr CreatePairing( api::BluetoothDevice &remote_device) override; - api::BluetoothDevice *GetRemoteDevice( - const std::string &mac_address) override; + api::BluetoothDevice *GetRemoteDevice(MacAddress mac_address) override; void AddObserver(Observer *observer) override { observers_->AddObserver(observer); diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc index f70162c8..8657997d 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc @@ -23,18 +23,18 @@ namespace nearby { namespace linux { std::unique_ptr BluetoothServerSocket::Accept() { if (stopped_.Cancelled()) { - NEARBY_LOGS(ERROR) << __func__ << ": server socket has been stopped"; + LOG(ERROR) << __func__ << ": server socket has been stopped"; return nullptr; } - NEARBY_LOGS(VERBOSE) << __func__ + LOG(INFO) << __func__ << ": accepting new connections for service uuid " << service_uuid_; auto pair = profile_manager_.GetServiceRecordFD(service_uuid_, &stopped_); if (!pair.has_value()) { if (!stopped_.Cancelled()) - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Failed to get a new connection for profile " << service_uuid_; return nullptr; @@ -45,7 +45,7 @@ std::unique_ptr BluetoothServerSocket::Accept() { } Exception BluetoothServerSocket::Close() { - NEARBY_LOGS(ERROR) << __func__ << ": closing bluetooth server socket"; + LOG(ERROR) << __func__ << ": closing bluetooth server socket"; stopped_.Cancel(); profile_manager_.Unregister(service_uuid_); diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 325cce9f..d8e7d3bd 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -32,7 +32,7 @@ Exception Poller::Ready() { auto ret = poll(fds_, 1, -1); if (ret < 0) { if (errno == EAGAIN) continue; - NEARBY_LOGS(ERROR) << __func__ << ": error polling socket for I/O: " + LOG(ERROR) << __func__ << ": error polling socket for I/O: " << std::strerror(errno); return {Exception::kIo}; } @@ -40,11 +40,11 @@ Exception Poller::Ready() { return {Exception::kSuccess}; } if ((fds_[0].revents & POLLHUP) != 0) { - NEARBY_LOGS(ERROR) << __func__ << ": socket disconnected"; + LOG(ERROR) << __func__ << ": socket disconnected"; return {Exception::kIo}; } if ((fds_[0].revents & (POLLERR | POLLNVAL)) != 0) { - NEARBY_LOGS(ERROR) << __func__ << ": an error occured on the socket"; + LOG(ERROR) << __func__ << ": an error occured on the socket"; return {Exception::kIo}; } } @@ -68,7 +68,7 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { 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__ + LOG(ERROR) << __func__ << ": error reading data on bluetooth socket: " << std::strerror(errno); return {Exception::kIo}; @@ -101,7 +101,7 @@ Exception BluetoothOutputStream::Write(const ByteArray &data) { write(fd_.get(), &buf[total_wrote], (data.size() - total_wrote)); if (wrote < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": error writing data on bluetooth socket: " << std::strerror(errno); return {Exception::kIo}; diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 05058c97..f311491b 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -17,7 +17,6 @@ #include #include -#include #include #include "absl/strings/substitute.h" @@ -62,7 +61,7 @@ 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 + LOG(ERROR) << __func__ << ": Device " << device_object_path << " doesn't exist"; return; } @@ -135,14 +134,14 @@ void DeviceWatcher::onInterfacesRemoved( if (removed_device_it != interfaces.end()) { auto device = devices_->get_device_by_path(object); if (device == nullptr) { - NEARBY_LOGS(WARNING) << __func__ + LOG(WARNING) << __func__ << ": received InterfacesRemoved for a device " "we don't know about: " << object; return; } - NEARBY_LOGS(INFO) << __func__ << ": Device " << object + LOG(INFO) << __func__ << ": Device " << object << " has been removed"; if (discovery_cb_ != nullptr && discovery_cb_->device_lost_cb != nullptr) { discovery_cb_->device_lost_cb(*device); @@ -179,7 +178,7 @@ void DeviceWatcher::notifyExistingDevices() { }); for (; device_it != objects.end(); device_it++) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Adding existing device " + LOG(INFO) << __func__ << ": Adding existing device " << device_it->first; auto device = devices_->add_new_device(device_it->first); if (discovery_cb_ != nullptr) { diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 08c4d24a..d5b3f241 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -49,8 +49,11 @@ class BluetoothDevices final { std::shared_ptr get_device_by_address(const std::string &); std::shared_ptr get_device_by_unique_id( api::ble_v2::BlePeripheral::UniqueId id) { - auto addr = BluetoothUtils::FromNumber(id); - return get_device_by_address(addr); + // TODO: Should probably remove BlePeripheral stuff from here but we can keep it since we can convert to/from + // uint64_t + MacAddress tmp; + MacAddress::FromUint64(id, tmp); + return get_device_by_address(tmp.ToString()); } std::shared_ptr add_new_device(sdbus::ObjectPath) diff --git a/internal/platform/implementation/linux/bluetooth_pairing.cc b/internal/platform/implementation/linux/bluetooth_pairing.cc index 0e51961c..607798c0 100644 --- a/internal/platform/implementation/linux/bluetooth_pairing.cc +++ b/internal/platform/implementation/linux/bluetooth_pairing.cc @@ -32,7 +32,7 @@ void BluetoothPairing::pairing_reply_handler(const sdbus::Error *error) { api::BluetoothPairingCallback::PairingError err = api::BluetoothPairingCallback::PairingError::kAuthFailed; - NEARBY_LOGS(ERROR) << __func__ << ": " + LOG(ERROR) << __func__ << ": " << "Got error '" << error->getName() << "' with message '" << error->getMessage() << "' while pairing with device " @@ -63,7 +63,7 @@ BluetoothPairing::BluetoothPairing( BluetoothAdapter &adapter, std::shared_ptr remote_device) : device_(std::move(remote_device)), device_object_path_(bluez::device_object_path(adapter.GetObjectPath(), - device_->GetAddress())), + device_->GetAddress().ToString())), adapter_(adapter) {} bool BluetoothPairing::InitiatePairing( diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 2d595a67..29ce772c 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -26,7 +26,7 @@ #define BLUEZ_LOG_METHOD_CALL_ERROR(proxy, method, err) \ do { \ - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << (err).getName() \ + LOG(ERROR) << __func__ << ": Got error '" << (err).getName() \ << "' with message '" << (err).getMessage() \ << "' while calling " << method << " on object " \ << (proxy)->getObjectPath(); \ diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc index cdb7d04a..335e9ca7 100644 --- a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc @@ -46,7 +46,7 @@ void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) { for (const auto &[uuid_str, data] : *service_data) { auto uuid = UuidFromString(uuid_str); if (!uuid.has_value()) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Could not parse UUID string in ServiceData for peripheral " << peripheral->getObjectPath(); diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h b/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h index e8ed5d57..8a05e976 100644 --- a/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h @@ -62,7 +62,7 @@ class AdvertisementMonitorManager final return nullptr; } if (objects.count(adapter.GetObjectPath()) == 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Adapter object no longer exists " + LOG(ERROR) << __func__ << ": Adapter object no longer exists " << adapter.GetObjectPath(); return nullptr; } @@ -70,7 +70,7 @@ class AdvertisementMonitorManager final if (objects[adapter.GetObjectPath()].count( org::bluez::AdvertisementMonitorManager1_proxy::INTERFACE_NAME) == 0) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Adapter " << adapter.GetObjectPath() << " doesn't provide " << org::bluez::AdvertisementMonitorManager1_proxy::INTERFACE_NAME; diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc index f6404283..428c7071 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc @@ -61,7 +61,7 @@ absl::Status GattCharacteristicServer::NotifyChanged( {"Value"}); return absl::OkStatus(); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error emitting PropertiesChanged signal on " << getObjectPath() << " with name '" << e.getName() << "' and message '" << e.getMessage() << "'"; diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h index 3fcd7652..b6613755 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.h @@ -65,7 +65,7 @@ class GattCharacteristicServer final confirmed_(false), notify_sessions_(0) { registerAdaptor(); - NEARBY_LOGS(VERBOSE) + LOG(INFO) << __func__ << "Creating a " << org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME << " object at " << getObjectPath(); diff --git a/internal/platform/implementation/linux/bluez_gatt_service_server.cc b/internal/platform/implementation/linux/bluez_gatt_service_server.cc index 34ab4a50..28700bca 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service_server.cc +++ b/internal/platform/implementation/linux/bluez_gatt_service_server.cc @@ -38,7 +38,7 @@ bool GattServiceServer::AddCharacteristic( chr->emitInterfacesAddedSignal( {org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": error emitting InterfacesAdded signal for object path " << chr->getObjectPath() << " with name '" << e.getName() diff --git a/internal/platform/implementation/linux/bluez_gatt_service_server.h b/internal/platform/implementation/linux/bluez_gatt_service_server.h index d0422762..582d6abb 100644 --- a/internal/platform/implementation/linux/bluez_gatt_service_server.h +++ b/internal/platform/implementation/linux/bluez_gatt_service_server.h @@ -54,7 +54,7 @@ class GattServiceServer final uuid_(service_uuid), primary_(true) { registerAdaptor(); - NEARBY_LOGS(VERBOSE) << __func__ << ": Created a " + LOG(INFO) << __func__ << ": Created a " << org::bluez::GattService1_adaptor::INTERFACE_NAME << " object at " << getObjectPath(); } @@ -62,13 +62,13 @@ class GattServiceServer final ~GattServiceServer() { absl::MutexLock lock(&characterstics_mutex_); for (auto &[_uuid, characteristic] : characteristics_) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Removing characteristic " + LOG(INFO) << __func__ << ": Removing characteristic " << characteristic->getObjectPath(); try { characteristic->emitInterfacesRemovedSignal( {org::bluez::GattCharacteristic1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": error emitting InterfacesRemoved signal for object path " << characteristic->getObjectPath() << " with name '" << e.getName() diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.cc b/internal/platform/implementation/linux/bluez_le_advertisement.cc index a64244c0..1607ade0 100644 --- a/internal/platform/implementation/linux/bluez_le_advertisement.cc +++ b/internal/platform/implementation/linux/bluez_le_advertisement.cc @@ -45,7 +45,7 @@ LEAdvertisement::LEAdvertisement( registerAdaptor(); - NEARBY_LOGS(VERBOSE) << __func__ + LOG(INFO) << __func__ << ": Created a org.bluez.LEAdvertisement1 instance at " << getObjectPath(); } diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.h b/internal/platform/implementation/linux/bluez_le_advertisement.h index df391474..d4e8cc11 100644 --- a/internal/platform/implementation/linux/bluez_le_advertisement.h +++ b/internal/platform/implementation/linux/bluez_le_advertisement.h @@ -58,7 +58,7 @@ class LEAdvertisement final private: // Methods void Release() override { - NEARBY_LOGS(INFO) << __func__ + LOG(INFO) << __func__ << ": LE Advertisement released: " << getObjectPath(); } diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 02eb564c..7462f1c5 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -170,7 +170,7 @@ bool DeviceInfo::PreventSleep() { bool DeviceInfo::AllowSleep() { if (!inhibit_fd_.has_value()) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << "No inhibit lock is acquired at the moment"; return false; } diff --git a/internal/platform/implementation/linux/executor.cc b/internal/platform/implementation/linux/executor.cc index c4b22d37..e8962239 100644 --- a/internal/platform/implementation/linux/executor.cc +++ b/internal/platform/implementation/linux/executor.cc @@ -29,13 +29,13 @@ Executor::Executor(size_t max_concurrency) void Executor::Execute(Runnable &&runnable) { if (shut_down_) { - NEARBY_LOGS(VERBOSE) << "Warning: " << __func__ + LOG(INFO) << "Warning: " << __func__ << ": Attempt to execute on a shut down pool."; return; } if (runnable == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": Runnable was null."; + LOG(ERROR) << __func__ << ": Runnable was null."; return; } diff --git a/internal/platform/implementation/linux/file_path.cc b/internal/platform/implementation/linux/file_path.cc index 57a49860..1cc1d1cd 100644 --- a/internal/platform/implementation/linux/file_path.cc +++ b/internal/platform/implementation/linux/file_path.cc @@ -156,7 +156,7 @@ std::wstring FilePath::CreateOutputFileWithRename(std::wstring path) { } if (count > 0) { - NEARBY_LOGS(INFO) << "Renamed " << wstring_to_string(path) << " to " + LOG(INFO) << "Renamed " << wstring_to_string(path) << " to " << wstring_to_string(target); } @@ -189,14 +189,14 @@ 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) + LOG(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) + LOG(INFO) << "In path " << wstring_to_string(path) << " replaced \'" << std::string(1, character) << "\' with \'" << std::string(1, kReplacementChar); character = kReplacementChar; diff --git a/internal/platform/implementation/linux/http_loader.cc b/internal/platform/implementation/linux/http_loader.cc index 2d6a7262..06d03c96 100644 --- a/internal/platform/implementation/linux/http_loader.cc +++ b/internal/platform/implementation/linux/http_loader.cc @@ -438,7 +438,7 @@ absl::Status HttpLoader::ConnectWebServer() { request_.body.size())); } else { - NEARBY_LOGS(ERROR) << "Failed to open internet with error " + LOG(ERROR) << "Failed to open internet with error " << "Invalid request method: " << request_.method << "."; return absl::FailedPreconditionError( "Failed to open internet: Invalid request method."); @@ -446,7 +446,7 @@ absl::Status HttpLoader::ConnectWebServer() { for (const auto &ret : option_return_codes) { if (ret) { - NEARBY_LOGS(ERROR) << "Failed to open internet with error " + LOG(ERROR) << "Failed to open internet with error " << curl_easy_strerror(ret) << "."; return absl::FailedPreconditionError( absl::StrCat(curl_easy_strerror(ret))); @@ -460,7 +460,7 @@ absl::Status HttpLoader::SendRequest() { CURLcode ret = curl_easy_perform(curl_); if (ret != CURLE_OK) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << "Failed to send request to remote web server with error " << curl_easy_strerror(ret) << "."; return absl::FailedPreconditionError(absl::StrCat(curl_easy_strerror(ret))); @@ -500,7 +500,7 @@ absl::StatusOr HttpLoader::ProcessResponse() { // Append data to response web_response.body.assign(response_strings_, download_size); } else { - NEARBY_LOGS(ERROR) + LOG(ERROR) << "Failed to read response from remote web server with error " << curl_easy_strerror(ret) << "."; return absl::FailedPreconditionError( diff --git a/internal/platform/implementation/linux/network_manager.h b/internal/platform/implementation/linux/network_manager.h index b4b96cb7..bad70919 100644 --- a/internal/platform/implementation/linux/network_manager.h +++ b/internal/platform/implementation/linux/network_manager.h @@ -86,7 +86,7 @@ class NetworkManager final NM_STATE_CASE_SET(kNMStateConnectedSite); NM_STATE_CASE_SET(kNMStateConnectedGlobal); default: - NEARBY_LOGS(ERROR) << __func__ << "invalid NMState value: " << val + LOG(ERROR) << __func__ << "invalid NMState value: " << val << ", setting state to unknown"; NM_STATE_CASE_SET(kNMStateUnknown); } diff --git a/internal/platform/implementation/linux/network_manager_active_connection.cc b/internal/platform/implementation/linux/network_manager_active_connection.cc index 10a364eb..d8ee63d0 100644 --- a/internal/platform/implementation/linux/network_manager_active_connection.cc +++ b/internal/platform/implementation/linux/network_manager_active_connection.cc @@ -104,7 +104,7 @@ std::vector ActiveConnection::GetIP4Addresses() { std::pair, bool> ActiveConnection::WaitForConnection(absl::Duration timeout) { - NEARBY_LOGS(VERBOSE) << __func__ << ": Waiting for an update to " + LOG(INFO) << __func__ << ": Waiting for an update to " << getObjectPath() << "'s state"; auto state_changed = [this]() { diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 1829a717..1b90f7ee 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -29,7 +29,7 @@ #include "internal/platform/implementation/input_file.h" #include "internal/platform/implementation/linux/atomic_boolean.h" #include "internal/platform/implementation/linux/atomic_uint32.h" -#include "internal/platform/implementation/linux/ble_v2_medium.h" +//#include "internal/platform/implementation/linux/ble_v2_medium.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_classic_medium.h" #include "internal/platform/implementation/linux/bluez.h" @@ -45,13 +45,15 @@ #include "internal/platform/implementation/linux/wifi_lan.h" #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/platform.h" + +#include "absl/strings/str_cat.h" + #include "internal/platform/implementation/shared/count_down_latch.h" #include "internal/platform/implementation/shared/file.h" #include "internal/platform/implementation/submittable_executor.h" #include "internal/platform/implementation/wifi_hotspot.h" #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/payload_id.h" -#include "log_message.h" #include "scheduled_executor.h" namespace nearby { @@ -135,7 +137,7 @@ std::unique_ptr ImplementationPlatform::CreateOutputFile( try { std::filesystem::create_directories(path.parent_path()); } catch (std::filesystem::filesystem_error const &err) { - NEARBY_LOGS(ERROR) << __func__ << ": error creating directory tree " + LOG(ERROR) << __func__ << ": error creating directory tree " << path.parent_path() << ": " << err.what(); } @@ -144,7 +146,9 @@ std::unique_ptr ImplementationPlatform::CreateOutputFile( std::unique_ptr ImplementationPlatform::CreateLogMessage( const char *file, int line, LogMessage::Severity severity) { - return std::make_unique(file, line, severity); + return nullptr; + // Disabled LogMessage + // return std::make_unique(file, line, severity); } std::unique_ptr @@ -171,7 +175,7 @@ ImplementationPlatform::CreateBluetoothAdapter() { auto interfaces = manager.GetManagedObjects(); for (auto &[object, properties] : interfaces) { if (properties.count(org::bluez::Adapter1_proxy::INTERFACE_NAME) == 1) { - NEARBY_LOGS(INFO) << __func__ << ": found bluetooth adapter " << object; + LOG(INFO) << __func__ << ": found bluetooth adapter " << object; return std::make_unique(system_bus, object); } } @@ -180,7 +184,7 @@ ImplementationPlatform::CreateBluetoothAdapter() { return nullptr; } - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": couldn't find a bluetooth adapter on this system"; return nullptr; } @@ -199,8 +203,10 @@ std::unique_ptr ImplementationPlatform::CreateBleMedium( std::unique_ptr ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { - return std::make_unique( - dynamic_cast(adapter)); + return nullptr; + // TODO: Enable BLEv2 once BlueZ support is added. + // return std::make_unique( + // dynamic_cast(adapter)); } namespace { @@ -232,7 +238,7 @@ static std::unique_ptr createWifiMedium( auto device = objects[device_path]; if (device.count(org::freedesktop::NetworkManager::Device:: Wireless_proxy::INTERFACE_NAME) == 1) { - NEARBY_LOGS(INFO) << __func__ + LOG(INFO) << __func__ << ": Found a wireless device at :" << device_path; return std::make_unique(nm, device_path); @@ -240,7 +246,7 @@ static std::unique_ptr createWifiMedium( } } - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": couldn't find a wireless device on this system"; return nullptr; } @@ -266,7 +272,7 @@ ImplementationPlatform::CreateWifiHotspotMedium() { auto wifiMedium = createWifiMedium(nm); if (wifiMedium == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": Could not create a WiFi medium"; + LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; return nullptr; } @@ -281,7 +287,7 @@ ImplementationPlatform::CreateWifiDirectMedium() { auto wifiMedium = createWifiMedium(nm); if (wifiMedium == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": Could not create a WiFi medium"; + LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; return nullptr; } @@ -339,7 +345,7 @@ absl::StatusOr ImplementationPlatform::SendRequest( api::WebResponse response; if (curl_easy_perform(handle) != CURLE_OK) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error performing HTTP request: " << errbuf; return absl::Status(absl::StatusCode::kUnknown, errbuf); } diff --git a/internal/platform/implementation/linux/preferences_manager.cc b/internal/platform/implementation/linux/preferences_manager.cc index f0a8d8ee..0c598a2b 100644 --- a/internal/platform/implementation/linux/preferences_manager.cc +++ b/internal/platform/implementation/linux/preferences_manager.cc @@ -186,7 +186,7 @@ void PreferencesManager::Remove(absl::string_view key) { // Writes data to storage. bool PreferencesManager::Commit() { if (!preferences_repository_->SavePreferences(value_)) { - NEARBY_LOGS(ERROR) << "Failed to save preference." << std::endl; + LOG(ERROR) << "Failed to save preference." << std::endl; return false; } return true; @@ -194,7 +194,7 @@ bool PreferencesManager::Commit() { bool PreferencesManager::SetValue(absl::string_view key, const json& value) { if (!value_.is_object()) { - NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_=" + LOG(ERROR) << "Preferences is no longer an object! value_=" << value_.dump(4); value_ = json::object(); } @@ -211,7 +211,7 @@ template T PreferencesManager::GetValue(absl::string_view key, const T& default_value) const { if (!value_.is_object()) { - NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_=" + LOG(ERROR) << "Preferences is no longer an object! value_=" << value_.dump(4); return default_value; } @@ -227,7 +227,7 @@ template bool PreferencesManager::SetArrayValue(absl::string_view key, absl::Span value) { if (!value_.is_object()) { - NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_=" + LOG(ERROR) << "Preferences is no longer an object! value_=" << value_.dump(4); value_ = json::object(); } @@ -251,7 +251,7 @@ std::vector PreferencesManager::GetArrayValue( std::vector result; if (!value_.is_object()) { - NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_=" + LOG(ERROR) << "Preferences is no longer an object! value_=" << value_.dump(4); for (const T& value : default_value) { diff --git a/internal/platform/implementation/linux/preferences_manager_test.cc b/internal/platform/implementation/linux/preferences_manager_test.cc index d1aa5393..e549eb02 100644 --- a/internal/platform/implementation/linux/preferences_manager_test.cc +++ b/internal/platform/implementation/linux/preferences_manager_test.cc @@ -45,7 +45,7 @@ TEST(PreferencesManager, CorruptedConfigFile) { std::ofstream output_stream{settingsPath / "preferences.json"}; output_stream << "CORRUPTED" << std::endl; - NEARBY_LOGS(INFO) << "Loading preferences from: " << settingsPath.string(); + LOG(INFO) << "Loading preferences from: " << settingsPath.string(); EXPECT_EQ(PreferencesManager(settingsPath.string()).GetInteger("data", 100), 100); } @@ -56,7 +56,7 @@ TEST(PreferencesManager, ValidConfigFile) { output_stream << "{\"data\":8, \"name\": \"Valid\"}" << std::endl; output_stream.close(); - NEARBY_LOGS(INFO) << "Loading preferences from: " << settingsPath.string(); + LOG(INFO) << "Loading preferences from: " << settingsPath.string(); EXPECT_EQ(PreferencesManager(settingsPath.string()).GetInteger("data", 100), 8); } diff --git a/internal/platform/implementation/linux/preferences_repository.cc b/internal/platform/implementation/linux/preferences_repository.cc index 5732414c..e92a6a58 100644 --- a/internal/platform/implementation/linux/preferences_repository.cc +++ b/internal/platform/implementation/linux/preferences_repository.cc @@ -38,7 +38,7 @@ json PreferencesRepository::LoadPreferences() { // The top level root should be an object, if it's not then something went // wrong or the file was corrupted. if (!preferences.value().is_object()) { - NEARBY_LOGS(ERROR) << "Preferences loaded was not a valid object: " + LOG(ERROR) << "Preferences loaded was not a valid object: " << preferences.value().dump(4); return json::object(); @@ -47,17 +47,17 @@ json PreferencesRepository::LoadPreferences() { return preferences.value(); } - NEARBY_LOGS(ERROR) << "Could not load preferences file, trying backup."; + LOG(ERROR) << "Could not load preferences file, trying backup."; // In the future we should switch to using a transaction log or another // stable method which doesn't pose a risk of losing settings preferences = RestoreFromBackup(); if (preferences.has_value()) { - NEARBY_LOGS(ERROR) << "Successfully recovered from backup."; + LOG(ERROR) << "Successfully recovered from backup."; return preferences.value(); } - NEARBY_LOGS(ERROR) << "Failed to load preferences file from back up."; + LOG(ERROR) << "Failed to load preferences file from back up."; return json::object(); } @@ -68,7 +68,7 @@ bool PreferencesRepository::SavePreferences(json preferences) { std::filesystem::path path = path_; if (!std::filesystem::exists(path) && !std::filesystem::create_directories(path)) { - NEARBY_LOGS(ERROR) << "Failed to create preferences path."; + LOG(ERROR) << "Failed to create preferences path."; return false; } @@ -77,7 +77,7 @@ bool PreferencesRepository::SavePreferences(json preferences) { // Create a backup without moving the bytes on disk if (std::filesystem::exists(full_name)) { - NEARBY_LOGS(INFO) << "Making backup of preferences file."; + LOG(INFO) << "Making backup of preferences file."; std::filesystem::rename(full_name, full_name_backup); } @@ -87,16 +87,16 @@ bool PreferencesRepository::SavePreferences(json preferences) { // Make sure the file wasn't saved in a corrupted state if (!AttemptLoad().has_value()) { - NEARBY_LOGS(ERROR) << "Preferences saved to disk in corrupted state. " + LOG(ERROR) << "Preferences saved to disk in corrupted state. " "Restoring from backup."; if (!RestoreFromBackup().has_value()) { - NEARBY_LOGS(ERROR) << "Failed to restore preferences file."; + LOG(ERROR) << "Failed to restore preferences file."; return false; } } } catch (const std::exception& e) { - NEARBY_LOGS(ERROR) << "Failed to save preferences file: " << e.what(); + LOG(ERROR) << "Failed to save preferences file: " << e.what(); return false; } @@ -120,13 +120,13 @@ std::optional PreferencesRepository::AttemptLoad() { preferences_file.close(); if (preferences.is_discarded()) { - NEARBY_LOGS(ERROR) << "Preferences file corrupted."; + LOG(ERROR) << "Preferences file corrupted."; return std::nullopt; } return preferences; } catch (const std::exception& e) { - NEARBY_LOGS(ERROR) << "Exception while loading preferences: " << e.what(); + LOG(ERROR) << "Exception while loading preferences: " << e.what(); return std::nullopt; } } @@ -137,14 +137,14 @@ std::optional PreferencesRepository::RestoreFromBackup() { std::filesystem::path full_name_backup = path / kPreferencesBackupFileName; if (!std::filesystem::exists(full_name_backup)) { - NEARBY_LOGS(WARNING) + LOG(WARNING) << "Backup requested but no backup preferences file found."; return std::nullopt; } std::filesystem::rename(full_name_backup, full_name); - NEARBY_LOGS(INFO) << "Attempting load from backup preferences."; + LOG(INFO) << "Attempting load from backup preferences."; return AttemptLoad(); } diff --git a/internal/platform/implementation/linux/scheduled_executor.cc b/internal/platform/implementation/linux/scheduled_executor.cc index 57d153a3..c044d780 100644 --- a/internal/platform/implementation/linux/scheduled_executor.cc +++ b/internal/platform/implementation/linux/scheduled_executor.cc @@ -35,7 +35,7 @@ ScheduledExecutor::ScheduledExecutor() std::shared_ptr ScheduledExecutor::Schedule( Runnable &&runnable, absl::Duration duration) { if (shut_down_) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Attempt to Schedule on a shut down executor."; return nullptr; @@ -58,7 +58,7 @@ std::shared_ptr ScheduledExecutor::Schedule( void ScheduledExecutor::Execute(Runnable &&runnable) { if (shut_down_) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Attempt to Execute on a shut down executor."; return; } @@ -77,7 +77,7 @@ void ScheduledExecutor::Shutdown() { executor_->Shutdown(); return; } - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Attempt to Shutdown on a shut down executor."; } } // namespace linux diff --git a/internal/platform/implementation/linux/stream.cc b/internal/platform/implementation/linux/stream.cc index edfb1da2..1b75daca 100644 --- a/internal/platform/implementation/linux/stream.cc +++ b/internal/platform/implementation/linux/stream.cc @@ -36,7 +36,7 @@ ExceptionOr InputStream::Read(std::int64_t size) { return ExceptionOr(ByteArray()); } if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": error reading from fd: " << std::strerror(errno); return {Exception::kIo}; } @@ -58,7 +58,7 @@ Exception OutputStream::Write(const ByteArray &data) { while (written < data.size()) { ssize_t ret = write(fd_.get(), data.data(), data.size()); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": error writing to fd: " << std::strerror(errno); return Exception{Exception::kIo}; } diff --git a/internal/platform/implementation/linux/submittable_executor.cc b/internal/platform/implementation/linux/submittable_executor.cc index ecf6e634..9c8ee920 100644 --- a/internal/platform/implementation/linux/submittable_executor.cc +++ b/internal/platform/implementation/linux/submittable_executor.cc @@ -30,7 +30,7 @@ bool SubmittableExecutor::DoSubmit(Runnable&& wrapped_callable) { return true; } - NEARBY_LOGS(ERROR) << "Error: " << __func__ + LOG(ERROR) << "Error: " << __func__ << ": Attempt to DoSubmit on a shutdown executor."; return false; @@ -41,7 +41,7 @@ void SubmittableExecutor::Execute(Runnable&& runnable) { if (!shut_down_) { executor_->Execute(std::move(runnable)); } else { - NEARBY_LOGS(ERROR) << "Error: " << __func__ + LOG(ERROR) << "Error: " << __func__ << ": Attempt to Execute on a shutdown executor."; } } @@ -54,7 +54,7 @@ void SubmittableExecutor::Shutdown() { return; } - NEARBY_LOGS(ERROR) << "Error: " << __func__ + LOG(ERROR) << "Error: " << __func__ << ": Attempt to Shutdown on a shutdown executor."; } diff --git a/internal/platform/implementation/linux/tcp_server_socket.h b/internal/platform/implementation/linux/tcp_server_socket.h index 764360c9..a2e983d7 100644 --- a/internal/platform/implementation/linux/tcp_server_socket.h +++ b/internal/platform/implementation/linux/tcp_server_socket.h @@ -37,12 +37,12 @@ class TCPSocket { int port) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error opening socket: " << std::strerror(errno); return std::nullopt; } - NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" + LOG(INFO) << __func__ << ": Connecting to " << ip_address << ":" << port; struct sockaddr_in addr; addr.sin_addr.s_addr = inet_addr(ip_address.c_str()); @@ -52,7 +52,7 @@ class TCPSocket { auto ret = connect(sock, reinterpret_cast(&addr), sizeof(addr)); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " + LOG(ERROR) << __func__ << ": Error connecting to socket: " << std::strerror(errno); return std::nullopt; } @@ -89,7 +89,7 @@ class TCPServerSocket { int port) { auto sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error opening socket: " << std::strerror(errno); return std::nullopt; } @@ -106,14 +106,14 @@ class TCPServerSocket { auto ret = bind(sock, reinterpret_cast(&addr), sizeof(addr)); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error binding to socket: " + LOG(ERROR) << __func__ << ": Error binding to socket: " << std::strerror(errno); return std::nullopt; } ret = listen(sock, 0); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " + LOG(ERROR) << __func__ << ": Error listening on socket: " << std::strerror(errno); return std::nullopt; } @@ -127,7 +127,7 @@ class TCPServerSocket { auto conn = accept(fd_.get(), reinterpret_cast(&addr), &len); if (conn < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error accepting incoming connections on socket " << fd_.get() << ": " << std::strerror(errno); return std::nullopt; @@ -141,7 +141,7 @@ class TCPServerSocket { shutdown(fd, SHUT_RDWR); auto ret = close(fd); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error closing socket " << fd << ": " + LOG(ERROR) << __func__ << ": Error closing socket " << fd << ": " << std::strerror(errno); return {Exception::kFailed}; } @@ -155,7 +155,7 @@ class TCPServerSocket { auto ret = getsockname(fd_.get(), reinterpret_cast(&sin), &len); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error getting information for socket " << fd_.get() << ": " << std::strerror(errno); return 0; diff --git a/internal/platform/implementation/linux/thread_pool.cc b/internal/platform/implementation/linux/thread_pool.cc index 8c37dcd9..7f6ccd6c 100644 --- a/internal/platform/implementation/linux/thread_pool.cc +++ b/internal/platform/implementation/linux/thread_pool.cc @@ -42,7 +42,7 @@ bool ThreadPool::Start() { if (shut_down_) { return; } - NEARBY_LOGS(WARNING) << __func__ << ": Tried to run a null task."; + LOG(WARNING) << __func__ << ": Tried to run a null task."; continue; } task(); @@ -51,11 +51,11 @@ bool ThreadPool::Start() { absl::MutexLock l(&threads_mutex_); if (!threads_.empty()) { - NEARBY_LOGS(ERROR) << __func__ << "thread pool is already active"; + LOG(ERROR) << __func__ << "thread pool is already active"; return false; } - NEARBY_LOGS(INFO) << __func__ << ": Starting thread pool with " + LOG(INFO) << __func__ << ": Starting thread pool with " << max_pool_size_ << " threads"; for (size_t i = 0; i < max_pool_size_; i++) { @@ -67,14 +67,14 @@ bool ThreadPool::Start() { bool ThreadPool::Run(Runnable &&task) { if (shut_down_) { - NEARBY_LOGS(ERROR) << __func__ << "thread pool has shut down"; + LOG(ERROR) << __func__ << "thread pool has shut down"; return false; } { absl::ReaderMutexLock l(&threads_mutex_); if (threads_.empty()) { - NEARBY_LOGS(ERROR) << __func__ << ": thread pool is not active"; + LOG(ERROR) << __func__ << ": thread pool is not active"; return false; } } diff --git a/internal/platform/implementation/linux/timer.cc b/internal/platform/implementation/linux/timer.cc index ab4cf74e..6f5fce5f 100644 --- a/internal/platform/implementation/linux/timer.cc +++ b/internal/platform/implementation/linux/timer.cc @@ -37,7 +37,7 @@ Timer::~Timer() { absl::MutexLock l(&mutex_); if (timerid_.has_value()) if (timer_delete(*timerid_) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error deleting POSIX timer: " + LOG(ERROR) << __func__ << ": Error deleting POSIX timer: " << std::strerror(errno); } } @@ -45,14 +45,14 @@ Timer::~Timer() { bool Timer::Create(int delay, int interval, absl::AnyInvocable callback) { if (delay < 0 || interval < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Delay and interval cannot be negative."; return false; } absl::MutexLock l(&mutex_); if (timerid_.has_value()) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << "Timer has already been created and armed."; return false; } @@ -74,16 +74,16 @@ bool Timer::Create(int delay, int interval, spec.it_interval.tv_sec = 0; if (timer_create(CLOCK_MONOTONIC, &ev, &timerid) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error creating POSIX timer: " + LOG(ERROR) << __func__ << ": Error creating POSIX timer: " << std::strerror(errno); return false; } if (timer_settime(&timerid, 0, &spec, nullptr) < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error arming POSIX timer: " + LOG(ERROR) << __func__ << ": Error arming POSIX timer: " << std::strerror(errno); if (!timer_delete(&timerid)) { - NEARBY_LOGS(ERROR) << __func__ << ": error deleting POSIX timer: " + LOG(ERROR) << __func__ << ": error deleting POSIX timer: " << std::strerror(errno); } return false; @@ -96,12 +96,12 @@ bool Timer::Create(int delay, int interval, bool Timer::Stop() { absl::MutexLock l(&mutex_); if (!timerid_.has_value()) { - NEARBY_LOGS(WARNING) << __func__ << ": no timer created"; + LOG(WARNING) << __func__ << ": no timer created"; return true; } if (!timer_delete(&*timerid_)) { - NEARBY_LOGS(ERROR) << __func__ << ": error deleting POSIX timer: " + LOG(ERROR) << __func__ << ": error deleting POSIX timer: " << std::strerror(errno); return false; } @@ -111,24 +111,5 @@ bool Timer::Stop() { return true; } -bool Timer::FireNow() { - absl::MutexLock lock(&mutex_); - if (!timerid_.has_value()) { - NEARBY_LOGS(ERROR) << __func__ << ": No timer has been created"; - return false; - } - if (callback_ == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": No callback has been set"; - return false; - } - if (task_executor_ == nullptr) { - task_executor_ = std::make_unique(); - } - - task_executor_->Execute([&]() { callback_(); }); - - return true; -} - } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/timer.h b/internal/platform/implementation/linux/timer.h index b19ecbe2..3a2e24c3 100644 --- a/internal/platform/implementation/linux/timer.h +++ b/internal/platform/implementation/linux/timer.h @@ -37,7 +37,6 @@ class Timer : public api::Timer { absl::AnyInvocable callback) override ABSL_LOCKS_EXCLUDED(mutex_); bool Stop() override ABSL_LOCKS_EXCLUDED(mutex_); - bool FireNow() override ABSL_LOCKS_EXCLUDED(mutex_); private: absl::Mutex mutex_; diff --git a/internal/platform/implementation/linux/utils.cc b/internal/platform/implementation/linux/utils.cc index 9de6ebd2..f882741b 100644 --- a/internal/platform/implementation/linux/utils.cc +++ b/internal/platform/implementation/linux/utils.cc @@ -56,7 +56,7 @@ std::optional NewUuidStr() { sd_id128_t id; char id_cstr[SD_ID128_UUID_STRING_MAX]; if (auto ret = sd_id128_randomize(&id); ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": could not generate a random UUID: " + LOG(ERROR) << __func__ << ": could not generate a random UUID: " << std::strerror(ret); return std::nullopt; } diff --git a/internal/platform/implementation/linux/wifi_direct.cc b/internal/platform/implementation/linux/wifi_direct.cc index 37ef709b..712e45e0 100644 --- a/internal/platform/implementation/linux/wifi_direct.cc +++ b/internal/platform/implementation/linux/wifi_direct.cc @@ -47,7 +47,7 @@ NetworkManagerWifiDirectMedium::ListenForService(int port) { auto ip4addresses = active_connection->GetIP4Addresses(); if (ip4addresses.empty()) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << "Could not find any IPv4 addresses for active connection " << active_connection->getObjectPath(); @@ -64,7 +64,7 @@ NetworkManagerWifiDirectMedium::ListenForService(int port) { bool NetworkManagerWifiDirectMedium::ConnectWifiDirect( WifiDirectCredentials *wifi_direct_credentials) { if (wifi_direct_credentials == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": hotspot_credentials cannot be null"; + LOG(ERROR) << __func__ << ": hotspot_credentials cannot be null"; return false; } @@ -78,7 +78,7 @@ bool NetworkManagerWifiDirectMedium::ConnectWifiDirect( bool NetworkManagerWifiDirectMedium::DisconnectWifiDirect() { if (!ConnectedToWifi()) { - NEARBY_LOGS(ERROR) << __func__ << ": Not connected to a WiFi hotspot"; + LOG(ERROR) << __func__ << ": Not connected to a WiFi hotspot"; return false; } diff --git a/internal/platform/implementation/linux/wifi_direct_server_socket.cc b/internal/platform/implementation/linux/wifi_direct_server_socket.cc index 395f412b..36c7ac46 100644 --- a/internal/platform/implementation/linux/wifi_direct_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_direct_server_socket.cc @@ -24,7 +24,7 @@ namespace linux { std::string NetworkManagerWifiDirectServerSocket::GetIPAddress() const { auto ip4addresses = active_conn_->GetIP4Addresses(); if (ip4addresses.empty()) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Could not find any IPv4 addresses for active connection " << active_conn_->getObjectPath(); diff --git a/internal/platform/implementation/linux/wifi_hotspot.cc b/internal/platform/implementation/linux/wifi_hotspot.cc index 1ce8059d..03c27dba 100644 --- a/internal/platform/implementation/linux/wifi_hotspot.cc +++ b/internal/platform/implementation/linux/wifi_hotspot.cc @@ -36,7 +36,7 @@ NetworkManagerWifiHotspotMedium::ConnectToService( absl::string_view ip_address, int port, CancellationFlag *cancellation_flag) { if (!ConnectedToWifi()) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Cannot connect to service without an active WiFi hotspot"; return nullptr; @@ -44,12 +44,12 @@ NetworkManagerWifiHotspotMedium::ConnectToService( int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error opening socket: " << std::strerror(errno); return nullptr; } - NEARBY_LOGS(VERBOSE) << __func__ << ": Connecting to " << ip_address << ":" + LOG(INFO) << __func__ << ": Connecting to " << ip_address << ":" << port; struct sockaddr_in addr {}; addr.sin_addr.s_addr = inet_addr(std::string(ip_address).c_str()); @@ -59,7 +59,7 @@ NetworkManagerWifiHotspotMedium::ConnectToService( auto ret = connect(sock, reinterpret_cast(&addr), sizeof(addr)); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error connecting to socket: " + LOG(ERROR) << __func__ << ": Error connecting to socket: " << std::strerror(errno); return nullptr; } @@ -70,7 +70,7 @@ NetworkManagerWifiHotspotMedium::ConnectToService( std::unique_ptr NetworkManagerWifiHotspotMedium::ListenForService(int port) { if (!WifiHotspotActive()) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Cannot connect to service without an active WiFi hotspot"; return nullptr; @@ -83,7 +83,7 @@ NetworkManagerWifiHotspotMedium::ListenForService(int port) { auto ip4addresses = active_connection->GetIP4Addresses(); if (ip4addresses.empty()) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << "Could not find any IPv4 addresses for active connection " << active_connection->getObjectPath(); @@ -92,7 +92,7 @@ NetworkManagerWifiHotspotMedium::ListenForService(int port) { auto sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error opening socket: " << std::strerror(errno); return nullptr; } @@ -105,18 +105,18 @@ NetworkManagerWifiHotspotMedium::ListenForService(int port) { auto ret = bind(sock, reinterpret_cast(&addr), sizeof(addr)); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error binding to socket: " << std::strerror(errno); return nullptr; } - NEARBY_LOGS(VERBOSE) << __func__ << ": Listening for services on " + LOG(INFO) << __func__ << ": Listening for services on " << ip4addresses[0] << ":" << port << " on device " << wireless_device_->getObjectPath(); ret = listen(sock, 0); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error listening on socket: " + LOG(ERROR) << __func__ << ": Error listening on socket: " << std::strerror(errno); return nullptr; } @@ -128,7 +128,7 @@ NetworkManagerWifiHotspotMedium::ListenForService(int port) { bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( HotspotCredentials *hotspot_credentials) { if (WifiHotspotActive()) { - NEARBY_LOGS(ERROR) << __func__ << ": " << wireless_device_->getObjectPath() + LOG(ERROR) << __func__ << ": " << wireless_device_->getObjectPath() << ": cannot start WiFi hotspot, a hotspot is already " "active on this device"; return false; @@ -142,7 +142,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( auto connection_id = NewUuidStr(); if (!connection_id.has_value()) { - NEARBY_LOGS(ERROR) << __func__ << ": could not generate a connection UUID"; + LOG(ERROR) << __func__ << ": could not generate a connection UUID"; return false; } @@ -189,7 +189,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( auto [reason, timeout] = active_conn->WaitForConnection(); if (timeout) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": " << ": timed out while waiting for connection " << active_conn->getObjectPath() @@ -199,7 +199,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( return false; } - NEARBY_LOGS(INFO) << __func__ << ": Started a WiFi hotspot on device " + LOG(INFO) << __func__ << ": Started a WiFi hotspot on device " << wireless_device_->getObjectPath() << " at " << active_conn->getObjectPath(); return true; @@ -207,7 +207,7 @@ bool NetworkManagerWifiHotspotMedium::StartWifiHotspot( bool NetworkManagerWifiHotspotMedium::StopWifiHotspot() { if (!WifiHotspotActive()) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": " << wireless_device_->getObjectPath() << ": Cannot stop WiFi hotspot as a WiFi hotspot is not active"; } @@ -218,7 +218,7 @@ bool NetworkManagerWifiHotspotMedium::StopWifiHotspot() { try { active_ap_path = wireless_device_->ActiveAccessPoint(); if (active_ap_path.empty()) { - NEARBY_LOGS(ERROR) << __func__ << ": No active access points on " + LOG(ERROR) << __func__ << ": No active access points on " << wireless_device_->getObjectPath(); return false; } @@ -229,14 +229,14 @@ bool NetworkManagerWifiHotspotMedium::StopWifiHotspot() { auto object_manager = networkmanager::ObjectManager(system_bus_); auto active_connection = wireless_device_->GetActiveConnection(); if (active_connection == nullptr) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Could not find an active connection using the access point " << active_ap_path; return false; } - NEARBY_LOGS(INFO) << __func__ << ": " << wireless_device_->getObjectPath() + LOG(INFO) << __func__ << ": " << wireless_device_->getObjectPath() << ": Deactivating active connection " << active_connection->getObjectPath(); @@ -253,7 +253,7 @@ bool NetworkManagerWifiHotspotMedium::StopWifiHotspot() { bool NetworkManagerWifiHotspotMedium::ConnectWifiHotspot( HotspotCredentials *hotspot_credentials) { if (hotspot_credentials == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": hotspot_credentials cannot be null"; + LOG(ERROR) << __func__ << ": hotspot_credentials cannot be null"; return false; } @@ -267,7 +267,7 @@ bool NetworkManagerWifiHotspotMedium::ConnectWifiHotspot( bool NetworkManagerWifiHotspotMedium::DisconnectWifiHotspot() { if (!ConnectedToWifi()) { - NEARBY_LOGS(ERROR) << __func__ << ": Not connected to a WiFi hotspot"; + LOG(ERROR) << __func__ << ": Not connected to a WiFi hotspot"; return false; } diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc index 88d7e5d0..dde673bd 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc @@ -24,7 +24,7 @@ namespace linux { std::string NetworkManagerWifiHotspotServerSocket::GetIPAddress() const { auto ip4addresses = active_conn_->GetIP4Addresses(); if (ip4addresses.empty()) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Could not find any IPv4 addresses for active connection " << active_conn_->getObjectPath(); @@ -39,7 +39,7 @@ int NetworkManagerWifiHotspotServerSocket::GetPort() const { auto ret = getsockname(fd_.get(), reinterpret_cast(&sin), &len); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Error getting information for socket " + LOG(ERROR) << __func__ << ": Error getting information for socket " << fd_.get() << ": " << std::strerror(errno); return 0; } @@ -55,7 +55,7 @@ NetworkManagerWifiHotspotServerSocket::Accept() { auto conn = accept(fd_.get(), reinterpret_cast(&addr), &len); if (conn < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error accepting incoming connections on socket " << fd_.get() << ": " << std::strerror(errno); return nullptr; @@ -69,7 +69,7 @@ Exception NetworkManagerWifiHotspotServerSocket::Close() { shutdown(fd, SHUT_RDWR); auto ret = close(fd_.release()); if (ret < 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Error closing socket: " << std::strerror(errno); return {Exception::kFailed}; } diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 7e825497..56befda9 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -54,13 +54,13 @@ std::optional> entry_group_key( const NsdServiceInfo &nsd_service_info) { auto name = nsd_service_info.GetServiceName(); if (name.empty()) { - NEARBY_LOGS(ERROR) << __func__ << ": service name cannot be empty"; + LOG(ERROR) << __func__ << ": service name cannot be empty"; return std::nullopt; } auto type = nsd_service_info.GetServiceType(); if (type.empty()) { - NEARBY_LOGS(ERROR) << __func__ << ": service type cannot be empty"; + LOG(ERROR) << __func__ << ": service type cannot be empty"; return std::nullopt; } @@ -76,7 +76,7 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { { absl::ReaderMutexLock l(&entry_groups_mutex_); if (entry_groups_.count(*key) == 1) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": advertising is already active for this service"; return false; } @@ -110,7 +110,7 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { std::string(), std::string(), nsd_service_info.GetPort(), txt_records); entry_group->Commit(); } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) << __func__ << ": Got error '" << e.getName() + LOG(ERROR) << __func__ << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while adding service"; return false; @@ -130,7 +130,7 @@ bool WifiLanMedium::StopAdvertising(const NsdServiceInfo &nsd_service_info) { absl::MutexLock l(&entry_groups_mutex_); if (entry_groups_.count(*key) == 0) { - NEARBY_LOGS(ERROR) << __func__ + LOG(ERROR) << __func__ << ": Advertising is already inactive for this service."; return false; } @@ -146,7 +146,7 @@ bool WifiLanMedium::StartDiscovery( absl::ReaderMutexLock l(&service_browsers_mutex_); if (service_browsers_.count(service_type) != 0) { auto &object = service_browsers_[service_type]; - NEARBY_LOGS(ERROR) << __func__ << ": A service browser for service type " + LOG(ERROR) << __func__ << ": A service browser for service type " << service_type << " already exists at " << object->getObjectPath(); return false; @@ -158,7 +158,7 @@ bool WifiLanMedium::StartDiscovery( avahi_->ServiceBrowserPrepare(-1, // AVAHI_IF_UNSPEC -1, // AVAHI_PROTO_UNSPED service_type, std::string(), 0); - NEARBY_LOGS(VERBOSE) + LOG(INFO) << __func__ << ": Created a new org.freedesktop.Avahi.ServiceBrowser object at " << browser_object_path; @@ -178,7 +178,7 @@ bool WifiLanMedium::StartDiscovery( service_browsers_mutex_.ReaderUnlock(); try { - NEARBY_LOGS(VERBOSE) << __func__ << ": Starting service discovery for " + LOG(INFO) << __func__ << ": Starting service discovery for " << browser->getObjectPath(); browser->Start(); } catch (const sdbus::Error &e) { @@ -193,7 +193,7 @@ bool WifiLanMedium::StopDiscovery(const std::string &service_type) { absl::MutexLock l(&service_browsers_mutex_); if (service_browsers_.count(service_type) == 0) { - NEARBY_LOGS(ERROR) << __func__ << ": Service type " << service_type + LOG(ERROR) << __func__ << ": Service type " << service_type << " has not been registered for discovery"; return false; } diff --git a/internal/platform/implementation/linux/wifi_lan_server_socket.cc b/internal/platform/implementation/linux/wifi_lan_server_socket.cc index cffde75c..3e5accff 100644 --- a/internal/platform/implementation/linux/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_lan_server_socket.cc @@ -68,7 +68,7 @@ std::string WifiLanServerSocket::GetIPAddress() const { } } - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Could not find any active IP addresses for this device"; return std::string(); } diff --git a/internal/platform/implementation/linux/wifi_medium.cc b/internal/platform/implementation/linux/wifi_medium.cc index e9c33d2d..454ccdaa 100644 --- a/internal/platform/implementation/linux/wifi_medium.cc +++ b/internal/platform/implementation/linux/wifi_medium.cc @@ -94,12 +94,12 @@ api::WifiInformation &NetworkManagerWifiMedium::GetInformation() { information_.ip_address_4_bytes = std::string(addr_bytes, 4); } } else { - NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() + LOG(ERROR) << __func__ << ": " << getObjectPath() << ": Could not find the Ip4Config object for " << active_access_point->getObjectPath(); } } catch (const sdbus::Error &e) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": " << getObjectPath() << ": Got error '" << e.getName() << "' with message '" << e.getMessage() << "' while populating network information for access point " @@ -166,7 +166,7 @@ NetworkManagerWifiMedium::SearchBySSID(absl::string_view ssid, return ap; } - NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath() << ": SSID " << ssid + LOG(INFO) << __func__ << ": " << getObjectPath() << ": SSID " << ssid << " not currently known by device " << getObjectPath() << ", requesting a scan"; @@ -194,13 +194,13 @@ NetworkManagerWifiMedium::SearchBySSID(absl::string_view ssid, last_scan_lock_.ReaderUnlock(); if (!success) { - NEARBY_LOGS(WARNING) << __func__ << ": " << getObjectPath() + LOG(WARNING) << __func__ << ": " << getObjectPath() << ": timed out waiting for scan to finish"; } ap = SearchBySSIDNoScan(ssid_bytes); if (ap == nullptr) { - NEARBY_LOGS(WARNING) << __func__ << ": " << getObjectPath() + LOG(WARNING) << __func__ << ": " << getObjectPath() << ": Couldn't find SSID " << ssid; } @@ -225,14 +225,14 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( api::WifiAuthType auth_type) { auto ap = SearchBySSID(ssid); if (ap == nullptr) { - NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() + LOG(ERROR) << __func__ << ": " << getObjectPath() << ": Couldn't find SSID " << ssid; return api::WifiConnectionStatus::kConnectionFailure; } auto connection_id = NewUuidStr(); if (!connection_id.has_value()) { - NEARBY_LOGS(ERROR) << __func__ << ": could not generate a connection UUID"; + LOG(ERROR) << __func__ << ": could not generate a connection UUID"; return api::WifiConnectionStatus::kUnknown; } @@ -276,13 +276,13 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( return api::WifiConnectionStatus::kUnknown; } - NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath() + LOG(INFO) << __func__ << ": " << getObjectPath() << ": Added a new connection at " << connection_path; auto active_connection = networkmanager::ActiveConnection(system_bus_, active_conn_path); auto [reason, timeout] = active_connection.WaitForConnection(); if (timeout) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": " << getObjectPath() << ": timed out while waiting for connection " << active_conn_path << " to be activated, last NMActiveConnectionStateReason: " @@ -291,7 +291,7 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( } if (reason.has_value()) { - NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() << ": connection " + LOG(ERROR) << __func__ << ": " << getObjectPath() << ": connection " << active_conn_path << " failed to activate, NMActiveConnectionStateReason:" << reason->ToString(); @@ -304,7 +304,7 @@ api::WifiConnectionStatus NetworkManagerWifiMedium::ConnectToNetwork( return api::WifiConnectionStatus::kAuthFailure; } - NEARBY_LOGS(INFO) << __func__ << ": Activated connection " << connection_path; + LOG(INFO) << __func__ << ": Activated connection " << connection_path; return api::WifiConnectionStatus::kConnected; } @@ -330,7 +330,7 @@ NetworkManagerWifiMedium::GetActiveConnection() { try { active_ap_path = ActiveAccessPoint(); if (active_ap_path.empty()) { - NEARBY_LOGS(ERROR) << __func__ << ": No active access points on " + LOG(ERROR) << __func__ << ": No active access points on " << getObjectPath(); return nullptr; } @@ -344,7 +344,7 @@ NetworkManagerWifiMedium::GetActiveConnection() { getObjectPath()); if (conn == nullptr) { - NEARBY_LOGS(ERROR) + LOG(ERROR) << __func__ << ": Could not find an active connection using the access point " << active_ap_path << " and device " << getObjectPath(); From 8f6086345d739a3429ec589f8e2edbb9abad1796 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Mon, 29 Dec 2025 16:35:50 +0000 Subject: [PATCH 174/201] updated device_info to latest API --- .../implementation/linux/device_info.cc | 50 ++++++------------- .../implementation/linux/device_info.h | 22 +++----- 2 files changed, 23 insertions(+), 49 deletions(-) diff --git a/internal/platform/implementation/linux/device_info.cc b/internal/platform/implementation/linux/device_info.cc index 7462f1c5..d0955a71 100644 --- a/internal/platform/implementation/linux/device_info.cc +++ b/internal/platform/implementation/linux/device_info.cc @@ -63,12 +63,10 @@ DeviceInfo::DeviceInfo(std::shared_ptr system_bus) current_user_session_(std::make_unique(*system_bus_)), login_manager_(std::make_unique(*system_bus_)) {} -std::optional DeviceInfo::GetOsDeviceName() const { +std::optional DeviceInfo::GetOsDeviceName() const { avahi::Server avahi(*system_bus_); try { - std::string hostname = avahi.GetHostNameFqdn(); - std::wstring_convert, char16_t> convert; - return convert.from_bytes(hostname); + return avahi.GetHostNameFqdn(); } catch (const sdbus::Error &e) { DBUS_LOG_PROPERTY_GET_ERROR(&avahi, "GetHostNameFqdn", e); return std::nullopt; @@ -94,58 +92,42 @@ api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { } } -std::optional DeviceInfo::GetFullName() const { - struct passwd *pwd = getpwuid(getuid()); - if (pwd == nullptr) { - return std::nullopt; - } - char *name = strtok(pwd->pw_gecos, ","); - std::wstring_convert, char16_t> convert; - return convert.from_bytes(name != nullptr ? name : pwd->pw_gecos); -} - -std::optional DeviceInfo::GetProfileUserName() const { - char *logname = secure_getenv("LOGNAME"); - return logname == nullptr ? std::nullopt - : std::optional(std::string(logname)); -} - -std::optional DeviceInfo::GetDownloadPath() const { +std::optional DeviceInfo::GetDownloadPath() const { char *dir = getenv("XDG_DOWNLOAD_DIR"); - return std::filesystem::path(std::string(dir)); + return FilePath(std::string(dir)); } -std::optional DeviceInfo::GetLocalAppDataPath() const { +std::optional DeviceInfo::GetLocalAppDataPath() const { char *dir = getenv("XDG_CONFIG_HOME"); if (dir == nullptr) { - return std::filesystem::path("/tmp"); + return FilePath("/tmp"); } - return std::filesystem::path(std::string(dir)) / "Google Nearby"; + return FilePath(std::string((std::filesystem::path(std::string(dir)) / "Google Nearby"))); } -std::optional DeviceInfo::GetTemporaryPath() const { +std::optional DeviceInfo::GetTemporaryPath() const { char *dir = getenv("XDG_RUNTIME_PATH"); if (dir == nullptr) { - return std::filesystem::path("/tmp"); + return FilePath("/tmp"); } - return std::filesystem::path(std::string(dir)) / "Google Nearby"; + return FilePath(std::string(std::filesystem::path(std::string(dir)) / "Google Nearby")); } -std::optional DeviceInfo::GetLogPath() const { +std::optional DeviceInfo::GetLogPath() const { char *dir = getenv("XDG_STATE_HOME"); if (dir == nullptr) { - return std::filesystem::path("/tmp"); + return FilePath("/tmp"); } - return std::filesystem::path(std::string(dir)) / "Google Nearby" / "logs"; + return FilePath(std::string(std::filesystem::path(std::string(dir)) / "Google Nearby" / "logs")); } -std::optional DeviceInfo::GetCrashDumpPath() const { +std::optional DeviceInfo::GetCrashDumpPath() const { char *dir = getenv("XDG_STATE_HOME"); if (dir == nullptr) { - return std::filesystem::path("/tmp"); + return FilePath("/tmp"); } - return std::filesystem::path(std::string(dir)) / "Google Nearby" / "crashes"; + return FilePath(std::string(std::filesystem::path(std::string(dir)) / "Google Nearby" / "crashes")); } bool DeviceInfo::IsScreenLocked() const { diff --git a/internal/platform/implementation/linux/device_info.h b/internal/platform/implementation/linux/device_info.h index f864117d..a3e256f8 100644 --- a/internal/platform/implementation/linux/device_info.h +++ b/internal/platform/implementation/linux/device_info.h @@ -121,28 +121,20 @@ class DeviceInfo final : public api::DeviceInfo { public: explicit DeviceInfo(std::shared_ptr system_bus); - std::optional GetOsDeviceName() const override; + std::optional GetOsDeviceName() const override; api::DeviceInfo::DeviceType GetDeviceType() const override; api::DeviceInfo::OsType GetOsType() const override { return api::DeviceInfo::OsType::kWindows; // Or ChromeOS? } - std::optional GetFullName() const override; - std::optional GetGivenName() const override { - return GetFullName(); - } - std::optional GetLastName() const override { - return GetFullName(); - } - std::optional GetProfileUserName() const override; - std::optional GetDownloadPath() const override; - std::optional GetLocalAppDataPath() const override; - std::optional GetCommonAppDataPath() const override { + std::optional GetDownloadPath() const override; + std::optional GetLocalAppDataPath() const override; + std::optional GetCommonAppDataPath() const override { return std::nullopt; }; - std::optional GetTemporaryPath() const override; - std::optional GetLogPath() const override; - std::optional GetCrashDumpPath() const override; + std::optional GetTemporaryPath() const override; + std::optional GetLogPath() const override; + std::optional GetCrashDumpPath() const override; bool IsScreenLocked() const override; void RegisterScreenLockedListener( From dd21d80dc85e46638d2cad728e075574bbcc1ade Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Fri, 2 Jan 2026 12:29:54 +0000 Subject: [PATCH 175/201] bugfixes and fixes to race conditions. bluetooth advertising only / discovery only works now. linux -> android conn. initiation works. android -> linux doesnt work. android doesn't seem to recognise linux. linux <-> linux works. but each devices have to be in discover/advert modes. can't be both --- MODULE.bazel | 2 +- internal/platform/implementation/linux/BUILD | 49 +++--- .../linux/bluetooth_bluez_profile.cc | 41 +++-- .../linux/bluetooth_classic_device.cc | 9 +- .../linux/bluetooth_classic_device.h | 33 ++-- .../linux/bluetooth_classic_medium.cc | 9 +- .../implementation/linux/bluetooth_devices.cc | 2 + .../implementation/linux/bluetooth_devices.h | 10 ++ .../platform/implementation/linux/platform.cc | 153 +++++++++--------- .../linux/preferences_manager.cc | 12 +- 10 files changed, 183 insertions(+), 137 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 87aa443b..b330092f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -71,7 +71,7 @@ cc_library( hdrs = glob([ "include/nlohmann/**/*.hpp", ]), - includes = ["include"], + strip_include_prefix = "include", visibility = ["//visibility:public"], alwayslink = True, )""", diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 189d7715..0590144e 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -79,22 +79,22 @@ cc_library( # "bluez_gatt_service_server.h", # "bluez_le_advertisement.h", "dbus.h", - "network_manager.h", - "network_manager_active_connection.h", - "network_manager_access_point.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", +# "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", @@ -157,8 +157,8 @@ cc_library( # "bluez_le_advertisement.cc", "dbus.cc", "executor.cc", - "network_manager.cc", - "network_manager_active_connection.cc", +# "network_manager.cc", +# "network_manager_active_connection.cc", "platform.cc", "preferences_manager.cc", "preferences_repository.cc", @@ -168,14 +168,15 @@ cc_library( "system_clock.cc", "thread_pool.cc", "utils.cc", - "wifi_direct.cc", - "wifi_direct_server_socket.cc", - "wifi_hotspot.cc", - "wifi_hotspot_server_socket.cc", - "wifi_lan.cc", - "wifi_lan_server_socket.cc", - "wifi_medium.cc", +# "wifi_direct.cc", +# "wifi_direct_server_socket.cc", +# "wifi_hotspot.cc", +# "wifi_hotspot_server_socket.cc", +# "wifi_lan.cc", +# "wifi_lan_server_socket.cc", +# "wifi_medium.cc", ], + linkopts = ["-lcurl"], visibility = [ "//connections:__subpackages__", "//fastpair:__subpackages__", diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 25e0f3f9..4ad513aa 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -33,6 +33,7 @@ #include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/logging.h" +#include "absl/strings/str_cat.h" namespace nearby { namespace linux { @@ -70,12 +71,20 @@ void Profile::NewConnection( auto alias = device->GetName(); auto mac_addr = device->GetAddress(); LOG(INFO) << __func__ << ": " << getObjectPath() - << ": Connected to " << mac_addr; + << ": Connected to " << mac_addr.ToString(); FDProperties props(fd_props); - absl::MutexLock l(&connections_lock_); - connections_[mac_addr].push_back(std::pair(fd, props)); + LOG(INFO) << "PUSH key(GetAddress.ToString)=" << mac_addr.ToString() + << " alias=" << alias; + LOG(INFO) << "PUSH_ENTER profile=" << this + << " mutex=" << &connections_lock_ + << " obj=" << getObjectPath() + << " path=" << device_object_path; + { + absl::MutexLock l(&connections_lock_); + connections_[mac_addr.ToString()].push_back(std::pair(fd, props)); + } } void Profile::RequestDisconnection( @@ -100,7 +109,6 @@ void Profile::RequestDisconnection( << ": Disconnection requested, but we are not connected to this device"; return; } - connections_.erase(mac_addr); } @@ -185,24 +193,35 @@ std::optional ProfileManager::GetServiceRecordFD( std::unique_ptr cancel_listener; if (cancellation_flag != nullptr) cancel_listener = std::make_unique( - cancellation_flag, [&profile]() { - profile->connections_lock_.Lock(); - profile->connections_lock_.Unlock(); - }); + cancellation_flag, [profile]() { + if (profile->connections_lock_.TryLock()) { + profile->connections_lock_.Unlock(); + } +} +); LOG(INFO) << __func__ << ": " << profile->getObjectPath() << ": Attempting to get a FD for service " << service_uuid << " on device " << mac_addr; + LOG(INFO) << "WAIT profile=" << profile.get() + << " mutex=" << &profile->connections_lock_ + << " obj=" << profile->getObjectPath() + << " key=" << mac_addr; auto cond = [mac_addr, profile, cancellation_flag]() { - profile->connections_lock_.AssertReaderHeld(); + profile->connections_lock_.AssertHeld(); + LOG(INFO) << "connections_lock_ is held by: " << mac_addr; return profile->connections_.count(mac_addr) != 0 || (cancellation_flag != nullptr && cancellation_flag->Cancelled()); }; + // BUG: Race condition. Hangs here + LOG(INFO) << "WAIT key(GetMacAddress)=" << mac_addr; + LOG(INFO) << "connections_ size" << profile -> connections_.size(); absl::MutexLock connections_lock(&profile->connections_lock_, absl::Condition(&cond)); - + LOG(INFO) << "WAIT_ACQUIRED " + << " map_size=" << profile->connections_.size(); if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) { LOG(INFO) << __func__ << ": " << profile->getObjectPath() << ": " @@ -214,7 +233,9 @@ std::optional ProfileManager::GetServiceRecordFD( 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); diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index b094df62..544a1746 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -29,6 +29,7 @@ namespace nearby { namespace linux { BluetoothDevice::BluetoothDevice(std::shared_ptr device) : lost_(false), device_(device) { + LOG(INFO) << "Created BluetoothDevice for: " << device -> Address(); try { last_known_name_ = device->Alias(); } catch (const sdbus::Error &e) { @@ -43,7 +44,7 @@ BluetoothDevice::BluetoothDevice(std::shared_ptr device) } std::string BluetoothDevice::GetName() const { - auto device = device_.lock(); + auto device = device_; if (device == nullptr) { absl::ReaderMutexLock l(&properties_mutex_); return last_known_name_; @@ -63,7 +64,7 @@ std::string BluetoothDevice::GetName() const { } std::string BluetoothDevice::GetMacAddress() const { - auto device = device_.lock(); + auto device = device_; if (device == nullptr) { absl::ReaderMutexLock l(&properties_mutex_); return last_known_name_; @@ -83,7 +84,7 @@ std::string BluetoothDevice::GetMacAddress() const { } bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { - auto device = device_.lock(); + auto device = device_; if (device == nullptr) return false; try { device->ConnectProfile(std::string(service_uuid)); @@ -98,7 +99,7 @@ MonitoredBluetoothDevice::MonitoredBluetoothDevice( std::shared_ptr system_bus, std::shared_ptr device, ObserverList &observers) - : BluetoothDevice(std::move(device)), + : BluetoothDevice(device), ProxyInterfaces(*system_bus, bluez::SERVICE_DEST, device->getObjectPath()), system_bus_(std::move(system_bus)), diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index d87d4239..e6e91703 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -40,8 +40,7 @@ namespace linux { // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. // TODO: This used to inherit from ble_v2::BlePeripheral. Removed that since APIs have now changed -class BluetoothDevice : public api::BluetoothDevice - { +class BluetoothDevice : public api::BluetoothDevice { public: using UniqueId = std::uint64_t; @@ -49,21 +48,17 @@ class BluetoothDevice : public api::BluetoothDevice BluetoothDevice(BluetoothDevice &&) = delete; BluetoothDevice &operator=(const BluetoothDevice &) = delete; BluetoothDevice &operator=(BluetoothDevice &&) = delete; + explicit BluetoothDevice(std::shared_ptr 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; MacAddress GetAddress() const override { return last_known_address_; } - // BlePeripheral methods - //UniqueId GetUniqueId() const override { return unique_id_; }; std::optional> ServiceData() { - auto device = device_.lock(); - if (device == nullptr) return std::nullopt; + auto device = device_; + if (!device) return std::nullopt; try { return device->ServiceData(); @@ -72,9 +67,10 @@ class BluetoothDevice : public api::BluetoothDevice return std::nullopt; } } + bool Bonded() { - auto device = device_.lock(); - if (device == nullptr) return false; + auto device = device_; + if (!device) return false; try { return device->Bonded(); @@ -85,8 +81,8 @@ class BluetoothDevice : public api::BluetoothDevice } std::optional Pair() { - auto device = device_.lock(); - if (device == nullptr) return std::nullopt; + auto device = device_; + if (!device) return std::nullopt; try { return device->Pair(); @@ -97,8 +93,8 @@ class BluetoothDevice : public api::BluetoothDevice } bool CancelPairing() { - auto device = device_.lock(); - if (device == nullptr) return false; + auto device = device_; + if (!device) return false; try { device->CancelPairing(); @@ -110,8 +106,8 @@ class BluetoothDevice : public api::BluetoothDevice } void SetPairReplyCallback(absl::AnyInvocable cb) { - auto device = device_.lock(); - if (device != nullptr) device->SetPairReplyCallback(std::move(cb)); + auto device = device_; + if (device) device->SetPairReplyCallback(std::move(cb)); } bool ConnectToProfile(absl::string_view service_uuid); @@ -126,7 +122,8 @@ class BluetoothDevice : public api::BluetoothDevice mutable absl::Mutex properties_mutex_; mutable std::string last_known_name_ ABSL_GUARDED_BY(properties_mutex_); mutable MacAddress last_known_address_ ABSL_GUARDED_BY(properties_mutex_); - mutable std::weak_ptr device_; + + std::shared_ptr device_; }; class MonitoredBluetoothDevice final diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 6ef9c7ab..d23f6347 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -45,9 +45,9 @@ BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter) bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { device_watcher_ = std::make_unique( - *system_bus_, adapter_.GetObjectPath(), devices_, + *system_bus_, adapter_.GetObjectPath(), devices_, // BUG: this is getting called with devices_ being a nullptr std::make_unique(std::move(discovery_callback)), - observers_); + observers_); // BUG: observers_ is a nullptr std::map filter; filter["Transport"] = "auto"; @@ -103,8 +103,9 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( } } - auto address = remote_device.GetMacAddress(); - auto device = devices_->get_device_by_address(address); + // who is passing this here? + auto address = remote_device.GetMacAddress(); //BUG: this returns the last known name instead of mac address + auto device = devices_->get_device_by_address(address); //BUG: this returns nullptr. WHy? who knows if (device == nullptr) { LOG(ERROR) << __func__ << ": Device " << address << " is no longer known"; diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index f311491b..b1b3677b 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -159,6 +159,7 @@ void DeviceWatcher::onInterfacesRemoved( } void DeviceWatcher::notifyExistingDevices() { + // NOTE: Existing devices don't get identified as endpoints. They only std::map>> objects; @@ -177,6 +178,7 @@ void DeviceWatcher::notifyExistingDevices() { interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1; }); + for (; device_it != objects.end(); device_it++) { LOG(INFO) << __func__ << ": Adding existing device " << device_it->first; diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index d5b3f241..19966b92 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -65,6 +65,16 @@ class BluetoothDevices final { ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); void cleanup_lost_peripherals() ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); + // DEBUG + void dump_devices() ABSL_LOCKS_EXCLUDED(devices_by_path_lock_) { + absl::ReaderMutexLock lock(&devices_by_path_lock_); + LOG(INFO) << "Dumping BluetoothDevices:"; + for (const auto& [path, device] : devices_by_path_) { + LOG(INFO) << " - Device path: " << path << " , Name: " << device->GetName(); + } + } + + private: std::shared_ptr system_bus_; ObserverList &observers_; diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 1b90f7ee..4ade4f66 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -40,10 +40,10 @@ #include "internal/platform/implementation/linux/preferences_manager.h" #include "internal/platform/implementation/linux/submittable_executor.h" #include "internal/platform/implementation/linux/timer.h" -#include "internal/platform/implementation/linux/wifi_direct.h" -#include "internal/platform/implementation/linux/wifi_hotspot.h" -#include "internal/platform/implementation/linux/wifi_lan.h" -#include "internal/platform/implementation/linux/wifi_medium.h" +// #include "internal/platform/implementation/linux/wifi_direct.h" +// #include "internal/platform/implementation/linux/wifi_hotspot.h" +// #include "internal/platform/implementation/linux/wifi_lan.h" +// #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/platform.h" #include "absl/strings/str_cat.h" @@ -210,89 +210,94 @@ ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { } namespace { -static std::unique_ptr createWifiMedium( - std::shared_ptr nm) { - std::vector device_paths; - - try { - device_paths = nm->GetAllDevices(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(nm, "GetAllDevices", e); - return nullptr; - } - - auto manager = linux::networkmanager::ObjectManager(nm->GetConnection()); - - std::map>> - objects; - try { - objects = manager.GetManagedObjects(); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(nm, "GetManagedObjects", e); - return nullptr; - } - - for (auto &device_path : device_paths) { - if (objects.count(device_path) == 1) { - auto device = objects[device_path]; - if (device.count(org::freedesktop::NetworkManager::Device:: - Wireless_proxy::INTERFACE_NAME) == 1) { - LOG(INFO) << __func__ - << ": Found a wireless device at :" << device_path; - return std::make_unique(nm, - device_path); - } - } - } - - LOG(ERROR) << __func__ - << ": couldn't find a wireless device on this system"; - return nullptr; -} +// static std::unique_ptr createWifiMedium( +// std::shared_ptr nm) { +// return nullptr; +// std::vector device_paths; +// +// try { +// device_paths = nm->GetAllDevices(); +// } catch (const sdbus::Error &e) { +// DBUS_LOG_METHOD_CALL_ERROR(nm, "GetAllDevices", e); +// return nullptr; +// } +// +// auto manager = linux::networkmanager::ObjectManager(nm->GetConnection()); +// +// std::map>> +// objects; +// try { +// objects = manager.GetManagedObjects(); +// } catch (const sdbus::Error &e) { +// DBUS_LOG_METHOD_CALL_ERROR(nm, "GetManagedObjects", e); +// return nullptr; +// } +// +// for (auto &device_path : device_paths) { +// if (objects.count(device_path) == 1) { +// auto device = objects[device_path]; +// if (device.count(org::freedesktop::NetworkManager::Device:: +// Wireless_proxy::INTERFACE_NAME) == 1) { +// LOG(INFO) << __func__ +// << ": Found a wireless device at :" << device_path; +// return std::make_unique(nm, +// device_path); +// } +// } +// } +// +// LOG(ERROR) << __func__ +// << ": couldn't find a wireless device on this system"; +// return nullptr; +// } } // namespace std::unique_ptr ImplementationPlatform::CreateWifiMedium() { - auto nm = - std::make_shared(linux::getSystemBusConnection()); - return createWifiMedium(nm); + return nullptr; + // auto nm = + // std::make_shared(linux::getSystemBusConnection()); + // return createWifiMedium(nm); } std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { - auto nm = - std::make_shared(linux::getSystemBusConnection()); - return std::make_unique(nm); + return nullptr; + // auto nm = + // std::make_shared(linux::getSystemBusConnection()); + // return std::make_unique(nm); } std::unique_ptr ImplementationPlatform::CreateWifiHotspotMedium() { - auto nm = - std::make_shared(linux::getSystemBusConnection()); - auto wifiMedium = createWifiMedium(nm); - - if (wifiMedium == nullptr) { - LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; - return nullptr; - } - - return std::make_unique( - nm, std::move(wifiMedium)); + return nullptr; + // auto nm = + // std::make_shared(linux::getSystemBusConnection()); + // auto wifiMedium = createWifiMedium(nm); + // + // if (wifiMedium == nullptr) { + // LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; + // return nullptr; + // } + // + // return std::make_unique( + // nm, std::move(wifiMedium)); } std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { - auto nm = - std::make_shared(linux::getSystemBusConnection()); - auto wifiMedium = createWifiMedium(nm); - - if (wifiMedium == nullptr) { - LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; - return nullptr; - } - - return std::make_unique( - nm, std::move(wifiMedium)); + return nullptr; + // auto nm = + // std::make_shared(linux::getSystemBusConnection()); + // auto wifiMedium = createWifiMedium(nm); + // + // if (wifiMedium == nullptr) { + // LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; + // return nullptr; + // } + // + // return std::make_unique( + // nm, std::move(wifiMedium)); } std::unique_ptr ImplementationPlatform::CreateTimer() { @@ -303,6 +308,10 @@ std::unique_ptr ImplementationPlatform::CreateDeviceInfo() { return std::make_unique(linux::getSystemBusConnection()); } + std::unique_ptr ImplementationPlatform::CreateAwdlMedium() { + return nullptr; +} + absl::StatusOr ImplementationPlatform::SendRequest( const WebRequest &request) { if (request.body.size() >= (8 * 1024 * 1024)) { diff --git a/internal/platform/implementation/linux/preferences_manager.cc b/internal/platform/implementation/linux/preferences_manager.cc index 0c598a2b..392ee425 100644 --- a/internal/platform/implementation/linux/preferences_manager.cc +++ b/internal/platform/implementation/linux/preferences_manager.cc @@ -21,8 +21,12 @@ #include "absl/strings/string_view.h" #include "internal/platform/implementation/linux/preferences_manager.h" + +#include "absl/strings/str_cat.h" + #include "internal/platform/implementation/linux/preferences_repository.h" #include "internal/platform/logging.h" +#include "internal/platform/implementation/platform.h" #include "nlohmann/json.hpp" #include "nlohmann/json_fwd.hpp" @@ -33,15 +37,15 @@ using json = ::nlohmann::json; } // namespace PreferencesManager::PreferencesManager(absl::string_view file_path) - : api::PreferencesManager(file_path) { - std::optional path = + : api::PreferencesManager() { + std::optional path = nearby::api::ImplementationPlatform::CreateDeviceInfo() ->GetLocalAppDataPath(); if (!path.has_value()) { - path = std::filesystem::temp_directory_path(); + path = FilePath("/tmp"); } - std::filesystem::path full_path = *path / std::string(file_path); + std::filesystem::path full_path = std::filesystem::path(path->ToString()) / std::string(file_path); preferences_repository_ = std::make_unique(full_path.string()); value_ = preferences_repository_->LoadPreferences(); From ac5a22eb55e3c44bd434be68a2c9f8daaa9c3505 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 3 Jan 2026 14:39:50 +0000 Subject: [PATCH 176/201] Fixed race conditions with simultaneous connections --- .../linux/bluetooth_bluez_profile.cc | 77 ++++++++++++++++--- .../linux/bluetooth_bluez_profile.h | 10 ++- .../linux/bluetooth_classic_medium.cc | 28 ++++++- .../linux/bluetooth_classic_medium.h | 4 +- .../linux/bluetooth_classic_server_socket.cc | 1 + .../implementation/linux/bluetooth_devices.cc | 1 + 6 files changed, 106 insertions(+), 15 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc index 4ad513aa..edfe81e0 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.cc +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.cc @@ -174,7 +174,7 @@ void ProfileManager::Unregister(absl::string_view service_uuid) { } // Get a service record FD for a connected profile (identified by service_uuid) -// to the given device. +// to the given device. Only fires when we're requesting a new connection. i.e: we're the client std::optional ProfileManager::GetServiceRecordFD( api::BluetoothDevice &remote_device, absl::string_view service_uuid, CancellationFlag *cancellation_flag) { @@ -210,7 +210,7 @@ std::optional ProfileManager::GetServiceRecordFD( << " key=" << mac_addr; auto cond = [mac_addr, profile, cancellation_flag]() { profile->connections_lock_.AssertHeld(); - LOG(INFO) << "connections_lock_ is held by: " << mac_addr; + LOG(INFO) << "connections_lock_ is held by: " << mac_addr << " with ptr: " << &profile -> connections_lock_; return profile->connections_.count(mac_addr) != 0 || (cancellation_flag != nullptr && cancellation_flag->Cancelled()); }; @@ -222,6 +222,10 @@ std::optional ProfileManager::GetServiceRecordFD( absl::Condition(&cond)); LOG(INFO) << "WAIT_ACQUIRED " << " map_size=" << profile->connections_.size(); + + // Clean up pending tracking + profile->pending_outgoing_.erase(mac_addr); + if (cancellation_flag != nullptr && cancellation_flag->Cancelled()) { LOG(INFO) << __func__ << ": " << profile->getObjectPath() << ": " @@ -242,7 +246,7 @@ std::optional ProfileManager::GetServiceRecordFD( } // Listen for a connected profile on any device, returning the connected device -// with its FD. +// with its FD. Only fires when another device requests connection from us. i.e. we're the server std::optional, sdbus::UnixFd>> ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, CancellationFlag *cancellation_flag) { @@ -272,8 +276,15 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, profile->connections_lock_.Lock(); auto cond = [profile, &cancellation_flag]() { profile->connections_lock_.AssertReaderHeld(); - return !profile->connections_.empty() || - (cancellation_flag != nullptr && cancellation_flag->Cancelled()); + + // Only accept connections that DON'T have pending outgoing attempts + for (const auto& [mac, fds] : profile->connections_) { + if (profile->pending_outgoing_.count(mac) == 0) { + return true; // Found a connection without pending outgoing + } + } + + return cancellation_flag != nullptr && cancellation_flag->Cancelled(); }; profile->connections_lock_.Await(absl::Condition(&cond)); @@ -285,13 +296,35 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, 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); + // Find first connection without pending outgoing + std::string mac_addr; + sdbus::UnixFd fd; + bool found = false; + + for (auto it = profile->connections_.begin(); it != profile->connections_.end(); ++it) { + if (profile->pending_outgoing_.count(it->first) == 0) { + mac_addr = it->first; + auto& fds = it->second; + // Use auto to avoid accessing private FDProperties type + auto [fd_tmp, properties] = fds.back(); + fd = std::move(fd_tmp); + fds.pop_back(); + if (fds.empty()) { + profile->connections_.erase(it); + } + found = true; + break; + } + } + + LOG(INFO) << __func__ << " Cleared connections"; profile->connections_lock_.Unlock(); + if (!found) { + LOG(ERROR) << __func__ << ": No eligible connection found"; + return std::nullopt; + } + auto device = devices_.get_device_by_address(mac_addr); if (device == nullptr) { LOG(ERROR) << __func__ << ": Device " << mac_addr @@ -301,6 +334,30 @@ ProfileManager::GetServiceRecordFD(absl::string_view service_uuid, return std::pair(device, std::move(fd)); } + void ProfileManager::MarkPendingOutgoing(absl::string_view service_uuid, + const std::string& mac_address) { + absl::ReaderMutexLock lock(®istered_service_uuids_mutex_); + if (registered_services_.count(std::string(service_uuid)) == 0) { + return; + } + auto profile = registered_services_[std::string(service_uuid)]; + absl::MutexLock l(&profile->connections_lock_); + profile->pending_outgoing_.insert(mac_address); + LOG(INFO) << __func__ << ": Marked " << mac_address + << " as pending outgoing for " << service_uuid; +} + void ProfileManager::ClearPendingOutgoing(absl::string_view service_uuid, + const std::string& mac_address) { + absl::ReaderMutexLock lock(®istered_service_uuids_mutex_); + if (registered_services_.count(std::string(service_uuid)) == 0) { + return; + } + auto profile = registered_services_[std::string(service_uuid)]; + absl::MutexLock l(&profile->connections_lock_); + profile->pending_outgoing_.erase(mac_address); + LOG(INFO) << __func__ << ": Cleared " << mac_address + << " as pending outgoing for " << service_uuid; +} } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_bluez_profile.h b/internal/platform/implementation/linux/bluetooth_bluez_profile.h index 85ec7717..d0f83995 100644 --- a/internal/platform/implementation/linux/bluetooth_bluez_profile.h +++ b/internal/platform/implementation/linux/bluetooth_bluez_profile.h @@ -96,6 +96,9 @@ class Profile final std::map>> connections_ ABSL_GUARDED_BY(connections_lock_); + // Track pending outgoing connection attempts to avoid race with incoming + std::set pending_outgoing_ ABSL_GUARDED_BY(connections_lock_); + BluetoothDevices &devices_; }; @@ -133,7 +136,12 @@ class ProfileManager final GetServiceRecordFD(absl::string_view service_uuid, CancellationFlag *cancellation_flag) ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); - + void MarkPendingOutgoing(absl::string_view service_uuid, + const std::string& mac_address) + ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); + void ClearPendingOutgoing(absl::string_view service_uuid, + const std::string& mac_address) + ABSL_LOCKS_EXCLUDED(registered_service_uuids_mutex_); private: BluetoothDevices &devices_; // Maps service UUIDs to RegisteredService diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index d23f6347..00449b77 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -25,6 +25,8 @@ #include "internal/platform/implementation/linux/bluetooth_bluez_profile.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_classic_medium.h" + +#include "bluez_agent.h" #include "internal/platform/implementation/linux/bluetooth_classic_server_socket.h" #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" #include "internal/platform/implementation/linux/bluetooth_pairing.h" @@ -39,6 +41,7 @@ BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter) devices_(std::make_shared( system_bus_, adapter.GetObjectPath(), *observers_)), device_watcher_(nullptr), + agent_manager_(std::make_unique(*system_bus_)), profile_manager_( std::make_unique(*system_bus_, *devices_)) {} @@ -103,16 +106,24 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( } } - // who is passing this here? - auto address = remote_device.GetMacAddress(); //BUG: this returns the last known name instead of mac address - auto device = devices_->get_device_by_address(address); //BUG: this returns nullptr. WHy? who knows + auto address = remote_device.GetMacAddress(); + auto device = devices_->get_device_by_address(address); if (device == nullptr) { LOG(ERROR) << __func__ << ": Device " << address << " is no longer known"; return nullptr; } + if (!device -> Bonded()) + { + + LOG(ERROR) << __func__ << ": Device " << address + << " is not Bonded"; + } + // Mark as pending BEFORE calling ConnectToProfile to win the race + profile_manager_->MarkPendingOutgoing(service_uuid, address); if (!device->ConnectToProfile(service_uuid)) { + profile_manager_->ClearPendingOutgoing(service_uuid, address); return nullptr; } @@ -132,6 +143,17 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( std::unique_ptr BluetoothClassicMedium::ListenForService(const std::string &service_name, const std::string &service_uuid) { + LOG(INFO) << __func__ << ": Creating bluez agent on path: " << "/com/example/bluez_agent" ; + + if (!agent_manager_ -> AgentRegistered("/com/example/bluez_agent")) + { + if (!agent_manager_ -> Register(std::nullopt, "/com/example/bluez_agent")) + { + LOG(ERROR) << __func__ << ": Could not register agent " << service_name << " " + << service_uuid; + return nullptr; + } + } if (!profile_manager_->ProfileRegistered(service_uuid)) { if (!profile_manager_->Register(service_name, service_uuid)) { LOG(ERROR) << __func__ << ": Could not register profile " diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index b8fd3b93..16d0e842 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -26,6 +26,7 @@ #include #include +#include "bluez_agent.h" #include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" @@ -34,7 +35,7 @@ namespace nearby { namespace linux { -// Container of operations that can be performed over the Bluetooth Classic + // Container of operations that can be performed over the Bluetooth Classic // medium. class BluetoothClassicMedium : public api::BluetoothClassicMedium { public: @@ -106,6 +107,7 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium { std::shared_ptr devices_; std::unique_ptr device_watcher_; + std::unique_ptr agent_manager_; std::unique_ptr profile_manager_; }; diff --git a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc index 8657997d..22bfad0a 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_server_socket.cc @@ -41,6 +41,7 @@ std::unique_ptr BluetoothServerSocket::Accept() { } auto [device, fd] = *pair; + LOG(INFO) << __func__ << ": accepted incoming connection for service uuid " << service_uuid_; return std::make_unique(device, std::move(fd)); } diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index b1b3677b..822abe9f 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -173,6 +173,7 @@ void DeviceWatcher::notifyExistingDevices() { 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; From 43c6c38a550b998a0c7e835aa3b9ce8b2491fed6 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 3 Jan 2026 14:40:02 +0000 Subject: [PATCH 177/201] Fixed race conditions with simultaneous connections --- internal/platform/implementation/linux/BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 0590144e..bddf73d1 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -70,6 +70,7 @@ cc_library( "bluetooth_pairing.h", "bluez.h", "bluez_device.h", + "bluez_agent.h", # "bluez_advertisement_monitor.h", # "bluez_advertisement_monitor_manager.h", # "bluez_gatt_characteristic_client.h", @@ -150,6 +151,7 @@ cc_library( "bluetooth_devices.cc", "bluetooth_pairing.cc", "bluez.cc", + "bluez_agent.cc", # "bluez_advertisement_monitor.cc", # "bluez_gatt_characteristic_client.cc", # "bluez_gatt_characteristic_server.cc", From 08e8b50aeead357c216b55567d2154dcca0f6981 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 3 Jan 2026 16:45:45 +0000 Subject: [PATCH 178/201] fixed crash on bt socket close --- .../linux/bluetooth_classic_socket.cc | 35 ++++++++++++++++--- .../linux/bluetooth_classic_socket.h | 7 ++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index d8e7d3bd..2bc6a03c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -51,8 +51,13 @@ Exception Poller::Ready() { } ExceptionOr BluetoothInputStream::Read(std::int64_t size) { - if (!fd_.isValid()) return Exception{Exception::kIo}; + // Check if FD is valid before proceeding + { + absl::MutexLock lock(&fd_mutex_); + if (!fd_.isValid()) return Exception{Exception::kIo}; + } + // Create poller while we still have the FD (copy the fd value) auto poller = Poller::CreateInputPoller(fd_); std::string buffer; @@ -68,11 +73,21 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { auto bytes_read = read(fd_.get(), &data[total_read], (size - total_read)); if (bytes_read < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + if (errno == EBADF) { + // FD was closed by another thread + LOG(INFO) << __func__ << ": socket was closed during read"; + return {Exception::kIo}; + } LOG(ERROR) << __func__ << ": error reading data on bluetooth socket: " << std::strerror(errno); return {Exception::kIo}; } + if (bytes_read == 0) { + // EOF - socket closed + LOG(INFO) << __func__ << ": socket closed (EOF)"; + return {Exception::kIo}; + } total_read += bytes_read; } @@ -80,14 +95,20 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { } Exception BluetoothInputStream::Close() { - if (!fd_.isValid()) return {Exception::kIo}; + absl::MutexLock lock(&fd_mutex_); + if (!fd_.isValid()) return {Exception::kSuccess}; // Already closed fd_.reset(); return {Exception::kSuccess}; } Exception BluetoothOutputStream::Write(const ByteArray &data) { - if (!fd_.isValid()) return Exception{Exception::kIo}; + // Check if FD is valid before proceeding + { + absl::MutexLock lock(&fd_mutex_); + if (!fd_.isValid()) return Exception{Exception::kIo}; + } + // Create poller while we still have the FD (copy the fd value) auto poller = Poller::CreateOutputPoller(fd_); size_t total_wrote = 0; @@ -101,6 +122,11 @@ Exception BluetoothOutputStream::Write(const ByteArray &data) { write(fd_.get(), &buf[total_wrote], (data.size() - total_wrote)); if (wrote < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + if (errno == EBADF || errno == EPIPE) { + // FD was closed by another thread + LOG(INFO) << __func__ << ": socket was closed during write"; + return {Exception::kIo}; + } LOG(ERROR) << __func__ << ": error writing data on bluetooth socket: " << std::strerror(errno); @@ -114,7 +140,8 @@ Exception BluetoothOutputStream::Write(const ByteArray &data) { } Exception BluetoothOutputStream::Close() { - if (!fd_.isValid()) return {Exception::kIo}; + absl::MutexLock lock(&fd_mutex_); + if (!fd_.isValid()) return {Exception::kSuccess}; // Already closed fd_.reset(); return {Exception::kSuccess}; } diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index 58ffa2c8..8aac4053 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -22,6 +22,7 @@ #include #include +#include "absl/synchronization/mutex.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" @@ -62,7 +63,8 @@ class BluetoothInputStream final : public nearby::InputStream { Exception Close() override; private: - sdbus::UnixFd fd_; + mutable absl::Mutex fd_mutex_; + sdbus::UnixFd fd_ ABSL_GUARDED_BY(fd_mutex_); }; class BluetoothOutputStream : public nearby::OutputStream { @@ -74,7 +76,8 @@ class BluetoothOutputStream : public nearby::OutputStream { Exception Close() override; private: - sdbus::UnixFd fd_; + mutable absl::Mutex fd_mutex_; + sdbus::UnixFd fd_ ABSL_GUARDED_BY(fd_mutex_); }; class BluetoothSocket final : public api::BluetoothSocket { From e2256ca83df31abd8e225cb8a5b69adca6455e81 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sun, 4 Jan 2026 17:14:27 +0000 Subject: [PATCH 179/201] endpoints advertised on bluetooth are immediately detected now. bluetooth socket underlying fd type auto detection added. Fixed segfault with download paths --- .../linux/bluetooth_classic_medium.cc | 4 +- .../linux/bluetooth_classic_socket.cc | 226 +++++++++++++++--- .../linux/bluetooth_classic_socket.h | 4 + .../implementation/linux/bluetooth_devices.cc | 60 +++-- .../implementation/linux/bluetooth_devices.h | 8 +- .../platform/implementation/linux/platform.cc | 59 ++++- 6 files changed, 303 insertions(+), 58 deletions(-) diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 00449b77..117518e4 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -48,9 +48,9 @@ BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter) bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { device_watcher_ = std::make_unique( - *system_bus_, adapter_.GetObjectPath(), devices_, // BUG: this is getting called with devices_ being a nullptr + *system_bus_, adapter_.GetObjectPath(), adapter_, devices_, std::make_unique(std::move(discovery_callback)), - observers_); // BUG: observers_ is a nullptr + observers_); std::map filter; filter["Transport"] = "auto"; diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 2bc6a03c..6991b89c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -25,6 +25,36 @@ #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" #include "internal/platform/logging.h" +#include +#include +#include +#include +#include + +struct SocketWriteCaps { + int so_type = 0; // SOCK_STREAM / SOCK_SEQPACKET / SOCK_DGRAM + size_t max_chunk = 0; // 0 => unknown/unlimited + bool packet_based = false; +}; + +static SocketWriteCaps DetectCapsNoBtHeaders(int fd) { + SocketWriteCaps caps{}; + + socklen_t len = sizeof(caps.so_type); + if (::getsockopt(fd, SOL_SOCKET, SO_TYPE, &caps.so_type, &len) != 0) { + // If we can't detect, behave conservatively like stream. + caps.so_type = SOCK_STREAM; + } + + caps.packet_based = (caps.so_type == SOCK_SEQPACKET || caps.so_type == SOCK_DGRAM); + + // Initial guess for packet-based sockets. This will be refined on EMSGSIZE. + if (caps.packet_based) caps.max_chunk = 1024; // start guess + else caps.max_chunk = 0; // unlimited/stream + + return caps; +} + namespace nearby { namespace linux { Exception Poller::Ready() { @@ -50,45 +80,124 @@ Exception Poller::Ready() { } } -ExceptionOr BluetoothInputStream::Read(std::int64_t size) { - // Check if FD is valid before proceeding - { - absl::MutexLock lock(&fd_mutex_); - if (!fd_.isValid()) return Exception{Exception::kIo}; - } - // Create poller while we still have the FD (copy the fd value) +ExceptionOr BluetoothInputStream::Read(std::int64_t size) { + absl::MutexLock lock(&fd_mutex_); + if (!fd_.isValid()) return Exception{Exception::kIo}; + auto poller = Poller::CreateInputPoller(fd_); + int so_type = 0; + socklen_t sl = sizeof(so_type); + if (::getsockopt(fd_.get(), SOL_SOCKET, SO_TYPE, &so_type, &sl) != 0) { + // If unknown, default to stream-ish behavior. + so_type = SOCK_STREAM; + } + const bool packet_based = (so_type == SOCK_SEQPACKET || so_type == SOCK_DGRAM); + + // Sanity: avoid negative / zero sizes + if (size <= 0) return ExceptionOr{ByteArray(std::string())}; + + // ---- Packet-based: read ONE message (recommended) ---- + if (packet_based) { + // Wait for readability + while (true) { + auto result = poller.Ready(); + if (result.Raised()) return result; + + // Peek the next message length without consuming it. + // For seqpacket/dgram, MSG_TRUNC makes recv() return the *full* message length + // even if the buffer is smaller. + ssize_t msg_len = ::recv(fd_.get(), nullptr, 0, MSG_PEEK | MSG_TRUNC); + if (msg_len < 0) { + if (errno == EINTR) continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + if (errno == EBADF) { + LOG(INFO) << __func__ << ": socket was closed during read"; + return {Exception::kIo}; + } + LOG(ERROR) << __func__ << ": error peeking message length: " + << std::strerror(errno); + return {Exception::kIo}; + } + if (msg_len == 0) { + LOG(INFO) << __func__ << ": socket closed (EOF)"; + return {Exception::kIo}; + } + + // Decide how much we will actually read/return. + // If caller asked for 'size', cap to that. + size_t want = static_cast(msg_len); + size_t cap = static_cast(size); + size_t to_read = std::min(want, cap); + + std::string buffer; + buffer.resize(to_read); + + // Now read/consume the message. If the message is larger than to_read, + // the remainder will be discarded by the kernel for seqpacket/dgram. + // We can detect that and treat it as an error (or choose a different policy). + ssize_t n = ::recv(fd_.get(), buffer.data(), to_read, 0); + if (n < 0) { + if (errno == EINTR) continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + if (errno == EBADF) { + LOG(INFO) << __func__ << ": socket was closed during read"; + return {Exception::kIo}; + } + LOG(ERROR) << __func__ << ": error reading data on bluetooth socket: " + << std::strerror(errno); + return {Exception::kIo}; + } + if (n == 0) { + LOG(INFO) << __func__ << ": socket closed (EOF)"; + return {Exception::kIo}; + } + + buffer.resize(static_cast(n)); + + // Detect truncation: if msg_len > size, we truncated/discarded remainder. + if (want > cap) { + LOG(ERROR) << __func__ + << ": incoming packet (" << want + << " bytes) exceeds requested size (" << cap + << "). Packet truncated."; + return {Exception::kIo}; + } + + return ExceptionOr{ByteArray(std::move(buffer))}; + } + } + + // ---- Stream-based: read exactly 'size' bytes (your original behavior) ---- std::string buffer; - buffer.resize(size); - char *data = buffer.data(); + buffer.resize(static_cast(size)); + char* data = buffer.data(); size_t total_read = 0; - - while (total_read < size) { + while (total_read < static_cast(size)) { auto result = poller.Ready(); if (result.Raised()) return result; - auto bytes_read = read(fd_.get(), &data[total_read], (size - total_read)); + ssize_t bytes_read = ::read(fd_.get(), + data + total_read, + static_cast(size) - total_read); if (bytes_read < 0) { + if (errno == EINTR) continue; if (errno == EAGAIN || errno == EWOULDBLOCK) continue; if (errno == EBADF) { - // FD was closed by another thread LOG(INFO) << __func__ << ": socket was closed during read"; return {Exception::kIo}; } - LOG(ERROR) << __func__ - << ": error reading data on bluetooth socket: " - << std::strerror(errno); + LOG(ERROR) << __func__ << ": error reading data on bluetooth socket: " + << std::strerror(errno); return {Exception::kIo}; } if (bytes_read == 0) { - // EOF - socket closed LOG(INFO) << __func__ << ": socket closed (EOF)"; return {Exception::kIo}; } - total_read += bytes_read; + total_read += static_cast(bytes_read); } return ExceptionOr{ByteArray(std::move(buffer))}; @@ -102,38 +211,93 @@ Exception BluetoothInputStream::Close() { } Exception BluetoothOutputStream::Write(const ByteArray &data) { - // Check if FD is valid before proceeding - { - absl::MutexLock lock(&fd_mutex_); - if (!fd_.isValid()) return Exception{Exception::kIo}; - } + absl::MutexLock lock(&fd_mutex_); + if (!fd_.isValid()) return Exception{Exception::kIo}; - // Create poller while we still have the FD (copy the fd value) auto poller = Poller::CreateOutputPoller(fd_); size_t total_wrote = 0; + int so_type = 0; + socklen_t sl = sizeof(so_type); + if (::getsockopt(fd_.get(), SOL_SOCKET, SO_TYPE, &so_type, &sl) != 0) { + // If we can’t detect, assume stream semantics (no per-message MTU). + so_type = SOCK_STREAM; + } + + const bool packet_based = (so_type == SOCK_SEQPACKET || so_type == SOCK_DGRAM); + + // Initialize a reasonable starting guess for packet-based sockets. + // This will be refined down on EMSGSIZE. + if (packet_based && max_chunk_ == 0) max_chunk_ = 1024; + + LOG(INFO) << "SO_TYPE=" << so_type + << (so_type == SOCK_SEQPACKET ? " (SEQPACKET)" : + so_type == SOCK_STREAM ? " (STREAM)" : + so_type == SOCK_DGRAM ? " (DGRAM)" : " (other)") + << (packet_based ? absl::StrFormat(" max_chunk=%zu", max_chunk_) : ""); + while (total_wrote < data.size()) { - auto result = poller.Ready(); + auto result = poller.Ready(); // should wait for POLLOUT/EPOLLOUT if (result.Raised()) return result; const char *buf = data.data(); - auto wrote = - write(fd_.get(), &buf[total_wrote], (data.size() - total_wrote)); + size_t remaining = data.size() - total_wrote; + + size_t to_write = remaining; + if (packet_based) { + // For SEQPACKET/DGRAM, one send() == one packet. + // Cap to discovered “MTU-like” limit to avoid EMSGSIZE. + to_write = std::min(to_write, max_chunk_); + } + + // Prefer send() to avoid SIGPIPE (MSG_NOSIGNAL is Linux). + ssize_t wrote = ::send(fd_.get(), + buf + total_wrote, + to_write, +#ifdef MSG_NOSIGNAL + MSG_NOSIGNAL +#else + 0 +#endif + ); + + // If send() isn’t appropriate in your environment, you can swap back to write(). + // ssize_t wrote = ::write(fd_.get(), buf + total_wrote, to_write); + if (wrote < 0) { + if (errno == EINTR) continue; if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + + if (errno == EMSGSIZE && packet_based) { + // Our packet is too large; shrink max_chunk_ and retry. + if (max_chunk_ > 1) { + max_chunk_ = std::max(1, max_chunk_ / 2); + LOG(INFO) << __func__ << ": EMSGSIZE; reducing max_chunk_ to " << max_chunk_; + continue; // retry with smaller chunk + } + LOG(ERROR) << __func__ << ": EMSGSIZE even at 1 byte"; + return {Exception::kIo}; + } + if (errno == EBADF || errno == EPIPE) { - // FD was closed by another thread LOG(INFO) << __func__ << ": socket was closed during write"; return {Exception::kIo}; } + LOG(ERROR) << __func__ - << ": error writing data on bluetooth socket: " - << std::strerror(errno); + << ": error writing data on bluetooth socket: " + << std::strerror(errno); return {Exception::kIo}; } - total_wrote += wrote; + if (wrote == 0) { + // For sockets, 0 usually means peer closed. + LOG(INFO) << __func__ << ": peer closed during write"; + return {Exception::kIo}; + } + + total_wrote += static_cast(wrote); } return {Exception::kSuccess}; diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index 8aac4053..7b3b93db 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -78,6 +78,10 @@ class BluetoothOutputStream : public nearby::OutputStream { private: mutable absl::Mutex fd_mutex_; sdbus::UnixFd fd_ ABSL_GUARDED_BY(fd_mutex_); + + // For packet sockets, discovered max payload per send/write. + // 0 means "unknown", we’ll initialize on first packet write. + size_t max_chunk_ ABSL_GUARDED_BY(fd_mutex_) = 0; }; class BluetoothSocket final : public api::BluetoothSocket { diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 822abe9f..259a24ab 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -21,6 +21,7 @@ #include "absl/strings/substitute.h" #include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" @@ -159,7 +160,6 @@ void DeviceWatcher::onInterfacesRemoved( } void DeviceWatcher::notifyExistingDevices() { - // NOTE: Existing devices don't get identified as endpoints. They only std::map>> objects; @@ -169,23 +169,53 @@ void DeviceWatcher::notifyExistingDevices() { 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; + std::vector existing_device_paths; - return device_path.find( - absl::Substitute("$0/dev_", adapter_object_path_)) == 0 && - interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1; - }); + for (const auto& [device_path, interfaces] : objects) { + if (device_path.find(absl::Substitute("$0/dev_", adapter_object_path_)) == 0 && + interfaces.count(org::bluez::Device1_proxy::INTERFACE_NAME) == 1) { + + // Don't remove bonded, paired, connected, or trusted devices + bool should_skip = false; + auto device_interface_it = interfaces.find(org::bluez::Device1_proxy::INTERFACE_NAME); + if (device_interface_it != interfaces.end()) { + const auto& properties = device_interface_it->second; + + auto check_bool_property = [&properties](const std::string& prop_name) -> bool { + auto it = properties.find(prop_name); + if (it != properties.end()) { + try { + return it->second.get(); + } catch (...) { + return false; + } + } + return false; + }; + + if (check_bool_property("Bonded") || + check_bool_property("Paired") || + check_bool_property("Connected") || + check_bool_property("Trusted")) { + should_skip = true; + LOG(INFO) << __func__ << ": Skipping device " << device_path + << " (bonded/paired/connected/trusted)"; + } + } + + if (!should_skip) { + existing_device_paths.push_back(device_path); + } + } + } - - for (; device_it != objects.end(); device_it++) { - LOG(INFO) << __func__ << ": Adding existing device " - << device_it->first; - auto device = devices_->add_new_device(device_it->first); - if (discovery_cb_ != nullptr) { - device->SetDiscoveryCallback(discovery_cb_); + // Remove existing devices - they will be immediately re-discovered + // This triggers InterfacesAdded signals which properly invoke discovery callbacks + for (const auto& device_path : existing_device_paths) { + LOG(INFO) << __func__ << ": Refreshing existing device " << device_path; + if (!adapter_.RemoveDeviceByObjectPath(device_path)) { + LOG(WARNING) << __func__ << ": Failed to remove device " << device_path; } } } diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 19966b92..a18ac126 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -34,6 +34,8 @@ namespace nearby { namespace linux { +class BluetoothAdapter; + class BluetoothDevices final { public: BluetoothDevices( @@ -97,6 +99,7 @@ class DeviceWatcher final : sdbus::ProxyInterfaces { DeviceWatcher( sdbus::IConnection &system_bus, const sdbus::ObjectPath &adapter_object_path, + BluetoothAdapter &adapter, std::shared_ptr devices, std::unique_ptr discovery_callback, @@ -104,6 +107,7 @@ class DeviceWatcher final : sdbus::ProxyInterfaces { observers) : ProxyInterfaces(system_bus, "org.bluez", "/"), adapter_object_path_(adapter_object_path), + adapter_(adapter), devices_(std::move(devices)), discovery_cb_(std::move(discovery_callback)), observers_(std::move(observers)) { @@ -112,8 +116,9 @@ class DeviceWatcher final : sdbus::ProxyInterfaces { } DeviceWatcher(sdbus::IConnection &system_bus, const sdbus::ObjectPath &adapter_object_path, + BluetoothAdapter &adapter, std::shared_ptr devices) - : DeviceWatcher(system_bus, adapter_object_path, std::move(devices), + : DeviceWatcher(system_bus, adapter_object_path, adapter, std::move(devices), nullptr, nullptr) {} ~DeviceWatcher() { unregisterProxy(); } @@ -128,6 +133,7 @@ class DeviceWatcher final : sdbus::ProxyInterfaces { void notifyExistingDevices(); sdbus::ObjectPath adapter_object_path_; + BluetoothAdapter &adapter_; std::shared_ptr devices_; std::shared_ptr discovery_cb_; std::shared_ptr> diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 4ade4f66..e95107b0 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -61,27 +61,68 @@ namespace api { std::string ImplementationPlatform::GetCustomSavePath( const std::string &parent_folder, const std::string &file_name) { auto fs = std::filesystem::path(parent_folder); - return fs / file_name; + return (fs / file_name).string(); } std::string ImplementationPlatform::GetDownloadPath( const std::string &parent_folder, const std::string &file_name) { - auto downloads = std::filesystem::path(getenv("XDG_DOWNLOAD_DIR")); - - return downloads / std::filesystem::path(parent_folder).filename() / - std::filesystem::path(file_name).filename(); + std::filesystem::path downloads; + const char* download_dir = getenv("XDG_DOWNLOAD_DIR"); + + if (download_dir != nullptr) { + downloads = std::filesystem::path(download_dir); + } else { + // Fallback to ~/Downloads if XDG_DOWNLOAD_DIR is not set + const char* home = getenv("HOME"); + if (home != nullptr) { + downloads = std::filesystem::path(home) / "Downloads"; + } else { + downloads = "/tmp/Downloads"; + } + } + + return (downloads / std::filesystem::path(parent_folder).filename() / + std::filesystem::path(file_name).filename()).string(); } std::string ImplementationPlatform::GetDownloadPath( const std::string &file_name) { - auto downloads = std::filesystem::path(getenv("XDG_DOWNLOAD_DIR")); - return downloads / std::filesystem::path(file_name).filename(); + std::filesystem::path downloads; + const char* download_dir = getenv("XDG_DOWNLOAD_DIR"); + + if (download_dir != nullptr) { + downloads = std::filesystem::path(download_dir); + } else { + // Fallback to ~/Downloads if XDG_DOWNLOAD_DIR is not set + const char* home = getenv("HOME"); + if (home != nullptr) { + downloads = std::filesystem::path(home) / "Downloads"; + } else { + downloads = "/tmp/Downloads"; + } + } + + return (downloads / std::filesystem::path(file_name).filename()).string(); } std::string ImplementationPlatform::GetAppDataPath( const std::string &file_name) { - auto state = std::filesystem::path(getenv("XDG_STATE_HOME")); - return state / std::filesystem::path(file_name).filename(); + std::filesystem::path state; + const char* state_home = getenv("XDG_STATE_HOME"); + + if (state_home != nullptr) { + state = std::filesystem::path(state_home); + } else { + // Fallback to ~/.local/state if XDG_STATE_HOME is not set + const char* home = getenv("HOME"); + if (home != nullptr) { + state = std::filesystem::path(home) / ".local" / "state"; + } else { + state = "/tmp/state"; + } + } + + return (state / std::filesystem::path(file_name).filename()).string(); } OSName ImplementationPlatform::GetCurrentOS() { return OSName::kWindows; } From 0432c47542c1fba55b2628ddf4149d8aa25394ca Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Mon, 5 Jan 2026 14:17:26 +0000 Subject: [PATCH 180/201] Added wifi hotspot medium. Fixed mutex deadlock when bandwidth upgrade with bt classic socket --- internal/platform/implementation/linux/BUILD | 42 +++--- .../linux/bluetooth_classic_medium.cc | 13 +- .../linux/bluetooth_classic_medium.h | 4 +- .../linux/bluetooth_classic_socket.cc | 70 +++++---- .../linux/bluetooth_classic_socket.h | 23 ++- .../platform/implementation/linux/platform.cc | 139 +++++++++--------- .../linux/wifi_hotspot_server_socket.cc | 52 +++++-- .../linux/wifi_hotspot_server_socket.h | 6 +- .../implementation/linux/wifi_medium.h | 1 + 9 files changed, 206 insertions(+), 144 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index bddf73d1..4ec12fb9 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -70,7 +70,7 @@ cc_library( "bluetooth_pairing.h", "bluez.h", "bluez_device.h", - "bluez_agent.h", +# "bluez_agent.h", # "bluez_advertisement_monitor.h", # "bluez_advertisement_monitor_manager.h", # "bluez_gatt_characteristic_client.h", @@ -80,22 +80,22 @@ cc_library( # "bluez_gatt_service_server.h", # "bluez_le_advertisement.h", "dbus.h", -# "network_manager.h", -# "network_manager_active_connection.h", -# "network_manager_access_point.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", + "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", + "wifi_medium.h", + "wifi_socket.h", ], deps = [ "//internal/platform:base", @@ -151,7 +151,7 @@ cc_library( "bluetooth_devices.cc", "bluetooth_pairing.cc", "bluez.cc", - "bluez_agent.cc", + #"bluez_agent.cc", # "bluez_advertisement_monitor.cc", # "bluez_gatt_characteristic_client.cc", # "bluez_gatt_characteristic_server.cc", @@ -159,8 +159,8 @@ cc_library( # "bluez_le_advertisement.cc", "dbus.cc", "executor.cc", -# "network_manager.cc", -# "network_manager_active_connection.cc", + "network_manager.cc", + "network_manager_active_connection.cc", "platform.cc", "preferences_manager.cc", "preferences_repository.cc", @@ -170,13 +170,13 @@ cc_library( "system_clock.cc", "thread_pool.cc", "utils.cc", -# "wifi_direct.cc", -# "wifi_direct_server_socket.cc", -# "wifi_hotspot.cc", -# "wifi_hotspot_server_socket.cc", + "wifi_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", + "wifi_medium.cc", ], linkopts = ["-lcurl"], visibility = [ diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 117518e4..85e59aa1 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -26,7 +26,7 @@ #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_classic_medium.h" -#include "bluez_agent.h" +// #include "bluez_agent.h" #include "internal/platform/implementation/linux/bluetooth_classic_server_socket.h" #include "internal/platform/implementation/linux/bluetooth_classic_socket.h" #include "internal/platform/implementation/linux/bluetooth_pairing.h" @@ -41,7 +41,7 @@ BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter) devices_(std::make_shared( system_bus_, adapter.GetObjectPath(), *observers_)), device_watcher_(nullptr), - agent_manager_(std::make_unique(*system_bus_)), + // agent_manager_(std::make_unique(*system_bus_)), profile_manager_( std::make_unique(*system_bus_, *devices_)) {} @@ -145,15 +145,6 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, const std::string &service_uuid) { LOG(INFO) << __func__ << ": Creating bluez agent on path: " << "/com/example/bluez_agent" ; - if (!agent_manager_ -> AgentRegistered("/com/example/bluez_agent")) - { - if (!agent_manager_ -> Register(std::nullopt, "/com/example/bluez_agent")) - { - LOG(ERROR) << __func__ << ": Could not register agent " << service_name << " " - << service_uuid; - return nullptr; - } - } if (!profile_manager_->ProfileRegistered(service_uuid)) { if (!profile_manager_->Register(service_name, service_uuid)) { LOG(ERROR) << __func__ << ": Could not register profile " diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.h b/internal/platform/implementation/linux/bluetooth_classic_medium.h index 16d0e842..42edf168 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.h +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.h @@ -26,7 +26,7 @@ #include #include -#include "bluez_agent.h" +// #include "bluez_agent.h" #include "internal/base/observer_list.h" #include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" @@ -107,7 +107,7 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium { std::shared_ptr devices_; std::unique_ptr device_watcher_; - std::unique_ptr agent_manager_; + // std::unique_ptr agent_manager_; std::unique_ptr profile_manager_; }; diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.cc b/internal/platform/implementation/linux/bluetooth_classic_socket.cc index 6991b89c..f3ef9eaa 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.cc @@ -82,14 +82,14 @@ Exception Poller::Ready() { ExceptionOr BluetoothInputStream::Read(std::int64_t size) { - absl::MutexLock lock(&fd_mutex_); - if (!fd_.isValid()) return Exception{Exception::kIo}; + int fd = fd_raw_.load(); + if (fd < 0) return Exception{Exception::kIo}; - auto poller = Poller::CreateInputPoller(fd_); + auto poller = Poller::CreateInputPoller(fd); int so_type = 0; socklen_t sl = sizeof(so_type); - if (::getsockopt(fd_.get(), SOL_SOCKET, SO_TYPE, &so_type, &sl) != 0) { + if (::getsockopt(fd, SOL_SOCKET, SO_TYPE, &so_type, &sl) != 0) { // If unknown, default to stream-ish behavior. so_type = SOCK_STREAM; } @@ -102,13 +102,15 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { if (packet_based) { // Wait for readability while (true) { + if (fd_raw_.load() != fd) return {Exception::kIo}; auto result = poller.Ready(); if (result.Raised()) return result; + if (fd_raw_.load() != fd) return {Exception::kIo}; // Peek the next message length without consuming it. // For seqpacket/dgram, MSG_TRUNC makes recv() return the *full* message length // even if the buffer is smaller. - ssize_t msg_len = ::recv(fd_.get(), nullptr, 0, MSG_PEEK | MSG_TRUNC); + ssize_t msg_len = ::recv(fd, nullptr, 0, MSG_PEEK | MSG_TRUNC); if (msg_len < 0) { if (errno == EINTR) continue; if (errno == EAGAIN || errno == EWOULDBLOCK) continue; @@ -137,7 +139,8 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { // Now read/consume the message. If the message is larger than to_read, // the remainder will be discarded by the kernel for seqpacket/dgram. // We can detect that and treat it as an error (or choose a different policy). - ssize_t n = ::recv(fd_.get(), buffer.data(), to_read, 0); + if (fd_raw_.load() != fd) return {Exception::kIo}; + ssize_t n = ::recv(fd, buffer.data(), to_read, 0); if (n < 0) { if (errno == EINTR) continue; if (errno == EAGAIN || errno == EWOULDBLOCK) continue; @@ -176,10 +179,12 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { size_t total_read = 0; while (total_read < static_cast(size)) { + if (fd_raw_.load() != fd) return {Exception::kIo}; auto result = poller.Ready(); if (result.Raised()) return result; + if (fd_raw_.load() != fd) return {Exception::kIo}; - ssize_t bytes_read = ::read(fd_.get(), + ssize_t bytes_read = ::read(fd, data + total_read, static_cast(size) - total_read); if (bytes_read < 0) { @@ -204,23 +209,24 @@ ExceptionOr BluetoothInputStream::Read(std::int64_t size) { } Exception BluetoothInputStream::Close() { - absl::MutexLock lock(&fd_mutex_); - if (!fd_.isValid()) return {Exception::kSuccess}; // Already closed + int fd = fd_raw_.exchange(-1); + if (fd < 0) return {Exception::kSuccess}; // Already closed + ::shutdown(fd, SHUT_RDWR); fd_.reset(); return {Exception::kSuccess}; } Exception BluetoothOutputStream::Write(const ByteArray &data) { - absl::MutexLock lock(&fd_mutex_); - if (!fd_.isValid()) return Exception{Exception::kIo}; + int fd = fd_raw_.load(); + if (fd < 0) return Exception{Exception::kIo}; - auto poller = Poller::CreateOutputPoller(fd_); + auto poller = Poller::CreateOutputPoller(fd); size_t total_wrote = 0; int so_type = 0; socklen_t sl = sizeof(so_type); - if (::getsockopt(fd_.get(), SOL_SOCKET, SO_TYPE, &so_type, &sl) != 0) { + if (::getsockopt(fd, SOL_SOCKET, SO_TYPE, &so_type, &sl) != 0) { // If we can’t detect, assume stream semantics (no per-message MTU). so_type = SOCK_STREAM; } @@ -229,17 +235,23 @@ Exception BluetoothOutputStream::Write(const ByteArray &data) { // Initialize a reasonable starting guess for packet-based sockets. // This will be refined down on EMSGSIZE. - if (packet_based && max_chunk_ == 0) max_chunk_ = 1024; + if (packet_based) { + absl::MutexLock lock(&fd_mutex_); + if (max_chunk_ == 0) max_chunk_ = 1024; + } + + size_t max_chunk = 0; + if (packet_based) { + absl::MutexLock lock(&fd_mutex_); + max_chunk = max_chunk_; + } - LOG(INFO) << "SO_TYPE=" << so_type - << (so_type == SOCK_SEQPACKET ? " (SEQPACKET)" : - so_type == SOCK_STREAM ? " (STREAM)" : - so_type == SOCK_DGRAM ? " (DGRAM)" : " (other)") - << (packet_based ? absl::StrFormat(" max_chunk=%zu", max_chunk_) : ""); while (total_wrote < data.size()) { + if (fd_raw_.load() != fd) return {Exception::kIo}; auto result = poller.Ready(); // should wait for POLLOUT/EPOLLOUT if (result.Raised()) return result; + if (fd_raw_.load() != fd) return {Exception::kIo}; const char *buf = data.data(); size_t remaining = data.size() - total_wrote; @@ -248,11 +260,12 @@ Exception BluetoothOutputStream::Write(const ByteArray &data) { if (packet_based) { // For SEQPACKET/DGRAM, one send() == one packet. // Cap to discovered “MTU-like” limit to avoid EMSGSIZE. + absl::MutexLock lock(&fd_mutex_); to_write = std::min(to_write, max_chunk_); } // Prefer send() to avoid SIGPIPE (MSG_NOSIGNAL is Linux). - ssize_t wrote = ::send(fd_.get(), + ssize_t wrote = ::send(fd, buf + total_wrote, to_write, #ifdef MSG_NOSIGNAL @@ -271,10 +284,14 @@ Exception BluetoothOutputStream::Write(const ByteArray &data) { if (errno == EMSGSIZE && packet_based) { // Our packet is too large; shrink max_chunk_ and retry. - if (max_chunk_ > 1) { - max_chunk_ = std::max(1, max_chunk_ / 2); - LOG(INFO) << __func__ << ": EMSGSIZE; reducing max_chunk_ to " << max_chunk_; - continue; // retry with smaller chunk + { + absl::MutexLock lock(&fd_mutex_); + if (max_chunk_ > 1) { + max_chunk_ = std::max(1, max_chunk_ / 2); + LOG(INFO) << __func__ << ": EMSGSIZE; reducing max_chunk_ to " + << max_chunk_; + continue; // retry with smaller chunk + } } LOG(ERROR) << __func__ << ": EMSGSIZE even at 1 byte"; return {Exception::kIo}; @@ -304,8 +321,9 @@ Exception BluetoothOutputStream::Write(const ByteArray &data) { } Exception BluetoothOutputStream::Close() { - absl::MutexLock lock(&fd_mutex_); - if (!fd_.isValid()) return {Exception::kSuccess}; // Already closed + int fd = fd_raw_.exchange(-1); + if (fd < 0) return {Exception::kSuccess}; // Already closed + ::shutdown(fd, SHUT_RDWR); fd_.reset(); return {Exception::kSuccess}; } diff --git a/internal/platform/implementation/linux/bluetooth_classic_socket.h b/internal/platform/implementation/linux/bluetooth_classic_socket.h index 7b3b93db..96ec49d8 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_socket.h +++ b/internal/platform/implementation/linux/bluetooth_classic_socket.h @@ -15,6 +15,7 @@ #ifndef PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_ #define PLATFORM_IMPL_LINUX_BLUETOOTH_SOCKET_H_ +#include #include #include @@ -43,6 +44,10 @@ class Poller final { return Poller(fd, POLLOUT); } + static Poller CreateInputPoller(int fd) { return Poller(fd, POLLIN); } + + static Poller CreateOutputPoller(int fd) { return Poller(fd, POLLOUT); } + Exception Ready(); private: @@ -51,25 +56,32 @@ class Poller final { fds_[0].events = event; } + Poller(int fd, short event) : poll_event_(event) { + fds_[0].fd = fd; + fds_[0].events = event; + } + short poll_event_; struct pollfd fds_[1]; }; class BluetoothInputStream final : public nearby::InputStream { public: - explicit BluetoothInputStream(sdbus::UnixFd fd) : fd_(std::move(fd)){}; + explicit BluetoothInputStream(sdbus::UnixFd fd) + : fd_(std::move(fd)), fd_raw_(fd_.get()) {} ExceptionOr Read(std::int64_t size) override; Exception Close() override; private: - mutable absl::Mutex fd_mutex_; - sdbus::UnixFd fd_ ABSL_GUARDED_BY(fd_mutex_); + sdbus::UnixFd fd_; + std::atomic fd_raw_{-1}; }; class BluetoothOutputStream : public nearby::OutputStream { public: - explicit BluetoothOutputStream(sdbus::UnixFd fd) : fd_(std::move(fd)){}; + explicit BluetoothOutputStream(sdbus::UnixFd fd) + : fd_(std::move(fd)), fd_raw_(fd_.get()) {} Exception Write(const ByteArray &data) override; Exception Flush() override { return {Exception::kSuccess}; } @@ -77,7 +89,8 @@ class BluetoothOutputStream : public nearby::OutputStream { private: mutable absl::Mutex fd_mutex_; - sdbus::UnixFd fd_ ABSL_GUARDED_BY(fd_mutex_); + sdbus::UnixFd fd_; + std::atomic fd_raw_{-1}; // For packet sockets, discovered max payload per send/write. // 0 means "unknown", we’ll initialize on first packet write. diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index e95107b0..7659973c 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -55,6 +55,8 @@ #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/payload_id.h" #include "scheduled_executor.h" +#include "wifi_direct.h" +#include "wifi_hotspot.h" namespace nearby { namespace api { @@ -251,54 +253,54 @@ ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { } namespace { -// static std::unique_ptr createWifiMedium( -// std::shared_ptr nm) { -// return nullptr; -// std::vector device_paths; -// -// try { -// device_paths = nm->GetAllDevices(); -// } catch (const sdbus::Error &e) { -// DBUS_LOG_METHOD_CALL_ERROR(nm, "GetAllDevices", e); -// return nullptr; -// } -// -// auto manager = linux::networkmanager::ObjectManager(nm->GetConnection()); -// -// std::map>> -// objects; -// try { -// objects = manager.GetManagedObjects(); -// } catch (const sdbus::Error &e) { -// DBUS_LOG_METHOD_CALL_ERROR(nm, "GetManagedObjects", e); -// return nullptr; -// } -// -// for (auto &device_path : device_paths) { -// if (objects.count(device_path) == 1) { -// auto device = objects[device_path]; -// if (device.count(org::freedesktop::NetworkManager::Device:: -// Wireless_proxy::INTERFACE_NAME) == 1) { -// LOG(INFO) << __func__ -// << ": Found a wireless device at :" << device_path; -// return std::make_unique(nm, -// device_path); -// } -// } -// } -// -// LOG(ERROR) << __func__ -// << ": couldn't find a wireless device on this system"; -// return nullptr; -// } +static std::unique_ptr createWifiMedium( + std::shared_ptr nm) { + // return nullptr; + std::vector device_paths; + + try { + device_paths = nm->GetAllDevices(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(nm, "GetAllDevices", e); + return nullptr; + } + + auto manager = linux::networkmanager::ObjectManager(nm->GetConnection()); + + std::map>> + objects; + try { + objects = manager.GetManagedObjects(); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(nm, "GetManagedObjects", e); + return nullptr; + } + + for (auto &device_path : device_paths) { + if (objects.count(device_path) == 1) { + auto device = objects[device_path]; + if (device.count(org::freedesktop::NetworkManager::Device:: + Wireless_proxy::INTERFACE_NAME) == 1) { + LOG(INFO) << __func__ + << ": Found a wireless device at :" << device_path; + return std::make_unique(nm, + device_path); + } + } + } + + LOG(ERROR) << __func__ + << ": couldn't find a wireless device on this system"; + return nullptr; +} } // namespace std::unique_ptr ImplementationPlatform::CreateWifiMedium() { - return nullptr; - // auto nm = - // std::make_shared(linux::getSystemBusConnection()); - // return createWifiMedium(nm); + // return nullptr; + auto nm = + std::make_shared(linux::getSystemBusConnection()); + return createWifiMedium(nm); } std::unique_ptr @@ -311,34 +313,33 @@ ImplementationPlatform::CreateWifiLanMedium() { std::unique_ptr ImplementationPlatform::CreateWifiHotspotMedium() { - return nullptr; - // auto nm = - // std::make_shared(linux::getSystemBusConnection()); - // auto wifiMedium = createWifiMedium(nm); - // - // if (wifiMedium == nullptr) { - // LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; - // return nullptr; - // } - // - // return std::make_unique( - // nm, std::move(wifiMedium)); + auto nm = + std::make_shared(linux::getSystemBusConnection()); + auto wifiMedium = createWifiMedium(nm); + + if (wifiMedium == nullptr) { + LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; + return nullptr; + } + + return std::make_unique( + nm, std::move(wifiMedium)); } std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium() { - return nullptr; - // auto nm = - // std::make_shared(linux::getSystemBusConnection()); - // auto wifiMedium = createWifiMedium(nm); - // - // if (wifiMedium == nullptr) { - // LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; - // return nullptr; - // } - // - // return std::make_unique( - // nm, std::move(wifiMedium)); + // return nullptr; + auto nm = + std::make_shared(linux::getSystemBusConnection()); + auto wifiMedium = createWifiMedium(nm); + + if (wifiMedium == nullptr) { + LOG(ERROR) << __func__ << ": Could not create a WiFi medium"; + return nullptr; + } + + return std::make_unique( + nm, std::move(wifiMedium)); } std::unique_ptr ImplementationPlatform::CreateTimer() { diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc index dde673bd..f2a6a150 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.cc @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include #include "internal/platform/implementation/linux/wifi_hotspot_server_socket.h" @@ -52,22 +53,55 @@ NetworkManagerWifiHotspotServerSocket::Accept() { struct sockaddr_in addr {}; socklen_t len = sizeof(addr); - auto conn = - accept(fd_.get(), reinterpret_cast(&addr), &len); - if (conn < 0) { - LOG(ERROR) << __func__ - << ": Error accepting incoming connections on socket " - << fd_.get() << ": " << std::strerror(errno); - return nullptr; + // Poll with timeout to allow checking the closed flag periodically + while (!closed_.load()) { + struct pollfd pfd; + pfd.fd = fd_.get(); + pfd.events = POLLIN; + + // Poll with 1 second timeout + int poll_result = poll(&pfd, 1, 1000); + + if (poll_result < 0) { + if (errno == EINTR) { + continue; // Interrupted, try again + } + LOG(ERROR) << __func__ << ": Error polling socket " << fd_.get() << ": " + << std::strerror(errno); + return nullptr; + } + + if (poll_result == 0) { + // Timeout - check closed flag and continue + continue; + } + + // Data available, try to accept + auto conn = + accept(fd_.get(), reinterpret_cast(&addr), &len); + if (conn < 0) { + if (errno == EBADF || errno == EINVAL) { + // Socket was closed + return nullptr; + } + LOG(ERROR) << __func__ + << ": Error accepting incoming connections on socket " + << fd_.get() << ": " << std::strerror(errno); + return nullptr; + } + + return std::make_unique(conn); } - return std::make_unique(conn); + // Socket was closed + return nullptr; } Exception NetworkManagerWifiHotspotServerSocket::Close() { + closed_.store(true); int fd = fd_.release(); shutdown(fd, SHUT_RDWR); - auto ret = close(fd_.release()); + auto ret = close(fd); if (ret < 0) { LOG(ERROR) << __func__ << ": Error closing socket: " << std::strerror(errno); diff --git a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h index d6130aeb..3fbd62d7 100644 --- a/internal/platform/implementation/linux/wifi_hotspot_server_socket.h +++ b/internal/platform/implementation/linux/wifi_hotspot_server_socket.h @@ -15,6 +15,8 @@ #ifndef PLATFORM_IMPL_LINUX_WIFI_SERVER_SOCKET_H_ #define PLATFORM_IMPL_LINUX_WIFI_SERVER_SOCKET_H_ +#include + #include #include "internal/platform/implementation/linux/network_manager.h" @@ -31,7 +33,8 @@ class NetworkManagerWifiHotspotServerSocket std::shared_ptr network_manager) : fd_(socket), active_conn_(std::move(active_conn)), - network_manager_(std::move(network_manager)) {} + network_manager_(std::move(network_manager)), + closed_(false) {} std::string GetIPAddress() const override; int GetPort() const override; @@ -42,6 +45,7 @@ class NetworkManagerWifiHotspotServerSocket sdbus::UnixFd fd_; std::unique_ptr active_conn_; std::shared_ptr network_manager_; + std::atomic closed_; }; } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/wifi_medium.h b/internal/platform/implementation/linux/wifi_medium.h index 4c393a55..a9d43da8 100644 --- a/internal/platform/implementation/linux/wifi_medium.h +++ b/internal/platform/implementation/linux/wifi_medium.h @@ -28,6 +28,7 @@ #include #include "absl/synchronization/mutex.h" +#include "absl/container/flat_hash_map.h" #include "internal/platform/implementation/linux/generated/dbus/networkmanager/device_wireless_client.h" #include "internal/platform/implementation/linux/network_manager.h" #include "internal/platform/implementation/linux/network_manager_access_point.h" From 0d7922dc898efc1a737ea049f8f79c19bf99022c Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Tue, 6 Jan 2026 05:24:48 +0000 Subject: [PATCH 181/201] Enabled wifi lan medium. fixed bug with returned service id in avahi onItemNew --- internal/platform/implementation/linux/avahi.cc | 2 +- internal/platform/implementation/linux/platform.cc | 9 ++++----- internal/platform/implementation/linux/wifi_lan.cc | 3 ++- internal/platform/wifi_lan.cc | 5 ++++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/internal/platform/implementation/linux/avahi.cc b/internal/platform/implementation/linux/avahi.cc index 3d601898..86517920 100644 --- a/internal/platform/implementation/linux/avahi.cc +++ b/internal/platform/implementation/linux/avahi.cc @@ -46,7 +46,7 @@ void ServiceBrowser::onItemNew(const int32_t &interface, info.SetServiceName(r_name); info.SetIPAddress(r_address); info.SetPort(r_port); - info.SetServiceType(r_type); + info.SetServiceType(r_type + "."); // discovery callback expects an extra period at t for (auto &attr : r_txt) { auto attr_str = std::string(attr.begin(), attr.end()); size_t pos = attr_str.find('='); diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 7659973c..43f9bdf1 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -42,7 +42,7 @@ #include "internal/platform/implementation/linux/timer.h" // #include "internal/platform/implementation/linux/wifi_direct.h" // #include "internal/platform/implementation/linux/wifi_hotspot.h" -// #include "internal/platform/implementation/linux/wifi_lan.h" +#include "internal/platform/implementation/linux/wifi_lan.h" // #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/platform.h" @@ -305,10 +305,9 @@ std::unique_ptr ImplementationPlatform::CreateWifiMedium() { std::unique_ptr ImplementationPlatform::CreateWifiLanMedium() { - return nullptr; - // auto nm = - // std::make_shared(linux::getSystemBusConnection()); - // return std::make_unique(nm); + auto nm = std::make_shared( + linux::getSystemBusConnection()); + return std::make_unique(nm); } std::unique_ptr diff --git a/internal/platform/implementation/linux/wifi_lan.cc b/internal/platform/implementation/linux/wifi_lan.cc index 56befda9..1415a06c 100644 --- a/internal/platform/implementation/linux/wifi_lan.cc +++ b/internal/platform/implementation/linux/wifi_lan.cc @@ -101,6 +101,7 @@ bool WifiLanMedium::StartAdvertising(const NsdServiceInfo &nsd_service_info) { auto entry_group = std::make_unique(*system_bus_, entry_group_path); + LOG(INFO) << __func__ << ": Adding avahi service with service type: " << nsd_service_info.GetServiceType(); try { entry_group->AddService( @@ -161,7 +162,7 @@ bool WifiLanMedium::StartDiscovery( LOG(INFO) << __func__ << ": Created a new org.freedesktop.Avahi.ServiceBrowser object at " - << browser_object_path; + << browser_object_path << " for service_type: " << service_type; absl::MutexLock l(&service_browsers_mutex_); service_browsers_.emplace( diff --git a/internal/platform/wifi_lan.cc b/internal/platform/wifi_lan.cc index 92b760b4..6098ba67 100644 --- a/internal/platform/wifi_lan.cc +++ b/internal/platform/wifi_lan.cc @@ -155,7 +155,10 @@ bool WifiLanMedium::StartDiscovery(const std::string& service_id, service_type_to_services_map_.insert( {service_type, absl::flat_hash_set()}); } - + LOG(INFO)<< " : Before calling Start discovery"; + for (const auto& [key, value] : service_type_to_callback_map_) { + LOG(INFO) << "key=" << key << " value=" << value; + } bool success = impl_->StartDiscovery(service_type, std::move(api_callback)); if (!success) { // If failed, then revert back the insertion. From 2d98bab2f19e4677aeddfc88b7982e1a80ab9b59 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Tue, 6 Jan 2026 05:25:00 +0000 Subject: [PATCH 182/201] updated build --- internal/platform/implementation/linux/BUILD | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 4ec12fb9..7e583e14 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -91,9 +91,9 @@ cc_library( "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_lan.h", + "wifi_lan_server_socket.h", + "wifi_lan_socket.h", "wifi_medium.h", "wifi_socket.h", ], @@ -174,8 +174,8 @@ cc_library( "wifi_direct_server_socket.cc", "wifi_hotspot.cc", "wifi_hotspot_server_socket.cc", -# "wifi_lan.cc", -# "wifi_lan_server_socket.cc", + "wifi_lan.cc", + "wifi_lan_server_socket.cc", "wifi_medium.cc", ], linkopts = ["-lcurl"], From 52dfdd6a56a2101b9239694611e10078fd5b8305 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 10 Jan 2026 06:52:01 +0000 Subject: [PATCH 183/201] Enabled BLE advertisements with extended + GATT server. --- internal/platform/implementation/linux/BUILD | 34 ++-- .../implementation/linux/ble_gatt_server.h | 8 +- .../implementation/linux/ble_v2_medium.cc | 166 ++++++++++++------ .../implementation/linux/ble_v2_medium.h | 52 ++++-- .../linux/bluetooth_classic_device.h | 1 - .../platform/implementation/linux/bluez.cc | 4 +- .../linux/bluez_advertisement_monitor.cc | 2 +- .../linux/bluez_gatt_characteristic_server.cc | 110 ++++++------ .../linux/bluez_le_advertisement.cc | 14 +- .../linux/bluez_le_advertisement.h | 9 +- .../dbus/bluez/le_advertisement_server.h | 2 + .../platform/implementation/linux/platform.cc | 7 +- 12 files changed, 260 insertions(+), 149 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 7e583e14..ad0cdfdf 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -56,10 +56,10 @@ cc_library( hdrs = [ "avahi.h", "ble_gatt_server.h", - "ble_gatt_client.h", +# "ble_gatt_client.h", # "ble_medium.h", -# "ble_v2_medium.h", -# "ble_v2_server_socket.h", + "ble_v2_medium.h", + "ble_v2_server_socket.h", "bluetooth_adapter.h", "bluetooth_bluez_profile.h", "bluetooth_classic_device.h", @@ -71,14 +71,14 @@ cc_library( "bluez.h", "bluez_device.h", # "bluez_agent.h", -# "bluez_advertisement_monitor.h", -# "bluez_advertisement_monitor_manager.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_characteristic_server.h", + "bluez_gatt_manager.h", # "bluez_gatt_service_client.h", -# "bluez_gatt_service_server.h", -# "bluez_le_advertisement.h", + "bluez_gatt_service_server.h", + "bluez_le_advertisement.h", "dbus.h", "network_manager.h", "network_manager_active_connection.h", @@ -98,6 +98,7 @@ cc_library( "wifi_socket.h", ], deps = [ + ":crypto", "//internal/platform:base", "//internal/platform:comm", "//internal/platform:types", @@ -127,7 +128,7 @@ cc_library( srcs = [ "crypto.cc", ], - visibility = ["//visibility:private"], + visibility = ["//visibility:public"], deps = [ "//internal/platform:base", "//internal/platform/implementation:types", @@ -140,8 +141,9 @@ cc_library( srcs = [ "avahi.cc", # "ble_gatt_client.cc", -# "ble_gatt_server.cc", -# "ble_v2_medium.cc", + "ble_gatt_server.cc", +# "ble_medium.cc", + "ble_v2_medium.cc", "bluetooth_adapter.cc", "bluetooth_bluez_profile.cc", "bluetooth_classic_socket.cc", @@ -152,11 +154,11 @@ cc_library( "bluetooth_pairing.cc", "bluez.cc", #"bluez_agent.cc", -# "bluez_advertisement_monitor.cc", + "bluez_advertisement_monitor.cc", # "bluez_gatt_characteristic_client.cc", -# "bluez_gatt_characteristic_server.cc", -# "bluez_gatt_service_server.cc", -# "bluez_le_advertisement.cc", + "bluez_gatt_characteristic_server.cc", + "bluez_gatt_service_server.cc", + "bluez_le_advertisement.cc", "dbus.cc", "executor.cc", "network_manager.cc", diff --git a/internal/platform/implementation/linux/ble_gatt_server.h b/internal/platform/implementation/linux/ble_gatt_server.h index b7f38706..2f3b75b5 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.h +++ b/internal/platform/implementation/linux/ble_gatt_server.h @@ -16,6 +16,7 @@ #define PLATFORM_IMPL_LINUX_API_BLE_GATT_SERVER_H_ #include +#include #include @@ -35,7 +36,9 @@ namespace linux { class LocalBlePeripheral : public api::ble_v2::BlePeripheral { public: explicit LocalBlePeripheral(BluetoothAdapter& adapter) : adapter_(adapter) { - unique_id_ = BluetoothUtils::ToNumber(adapter_.GetMacAddress()); + // temp fix till everything transitions to GGetAddress() + unique_id_ = std::stoull(std::regex_replace(adapter_.GetMacAddress(), + std::regex("[:\\-]"), ""), nullptr, 16); } std::string GetAddress() const override { return adapter_.GetMacAddress(); } @@ -64,9 +67,6 @@ class GattServer : public api::ble_v2::GattServer { std::move(server_cb))) {} ~GattServer() override = default; - api::ble_v2::BlePeripheral& GetBlePeripheral() override { - return local_peripheral_; - } absl::optional CreateCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid, api::ble_v2::GattCharacteristic::Permission permission, diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index ee791021..a6d86523 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -20,9 +20,11 @@ #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_gatt_client.h" +// #include "internal/platform/implementation/linux/ble_gatt_server.h" #include "internal/platform/implementation/linux/ble_v2_medium.h" + +#include "ble_gatt_server.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" @@ -40,7 +42,7 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) adapter_(adapter), devices_(std::make_unique( system_bus_, adapter_.GetObjectPath(), observers_)), - gatt_discovery_(std::make_shared(system_bus_)), + // gatt_discovery_(std::make_shared(system_bus_)), root_object_manager_(std::make_unique(*system_bus_)), adv_monitor_manager_( bluez::AdvertisementMonitorManager:: @@ -59,12 +61,15 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) DBUS_LOG_METHOD_CALL_ERROR(adv_monitor_manager_, "RegisterMonitor", e); } } - if (gatt_discovery_->InitializeKnownServices()) { - LOG(ERROR) << __func__ - << ": Could not initialize known GATT services"; - } + // if (gatt_discovery_->InitializeKnownServices()) { + // LOG(ERROR) << __func__ + // << ": Could not initialize known GATT services"; + // } } + // sync api + // called twice. Once with extended regular advertisement ( when IsExtendedAdvertisementsAvailable() == true ) + // and another for GATT-backed header advertisement for legacy devices bool BleV2Medium::StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, api::ble_v2::AdvertiseParameters advertise_set_parameters) { @@ -80,24 +85,20 @@ bool BleV2Medium::StartAdvertising( return false; } - absl::MutexLock lock(&cur_adv_mutex_); - if (cur_adv_ != nullptr) { - LOG(ERROR) << __func__ - << "Advertising is already enabled for this medium."; - return false; - } + absl::MutexLock l (&advs_mutex_); + advs_.push_front(bluez::LEAdvertisement::CreateLEAdvertisement( + *system_bus_, advertising_data, advertise_set_parameters)); + auto it = advs_.begin(); - cur_adv_ = bluez::LEAdvertisement::CreateLEAdvertisement( - *system_bus_, advertising_data, advertise_set_parameters); - LOG(INFO) << __func__ << ": Registering advertisement " - << cur_adv_->getObjectPath() << " on bluetooth adapter " + LOG(INFO) << __func__ << ": Registering advertisement, is_extended: " << advertising_data.is_extended_advertisement + << " " << (*it) -> getObjectPath() << " on bluetooth adapter " << adapter_.GetObjectPath(); try { - adv_manager_->RegisterAdvertisement(cur_adv_->getObjectPath(), {}); + adv_manager_->RegisterAdvertisement((*it)->getObjectPath(), {}); } catch (const sdbus::Error &e) { - cur_adv_ = nullptr; + advs_.erase(it); DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "RegisterAdvertisement", e); return false; } @@ -106,25 +107,23 @@ bool BleV2Medium::StartAdvertising( } bool BleV2Medium::StopAdvertising() { - absl::MutexLock lock(&cur_adv_mutex_); - if (cur_adv_ == nullptr) { - LOG(ERROR) << __func__ << ": Advertising is not enabled."; - return false; - } - LOG(INFO) << __func__ << "Unregistering advertisement object " - << cur_adv_->getObjectPath(); - + absl::MutexLock l(&advs_mutex_); try { - adv_manager_->UnregisterAdvertisement(cur_adv_->getObjectPath()); + for (auto& adv: advs_) + { + adv_manager_->UnregisterAdvertisement(adv->getObjectPath()); + } } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "UnregisterAdvertisement", e); return false; } - cur_adv_ = nullptr; + advs_.clear(); return true; } + //async api + // this doesn't run. wonder why std::unique_ptr BleV2Medium::StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, @@ -201,26 +200,42 @@ BleV2Medium::StartAdvertising( advs_.erase(adv_it); return absl::OkStatus(); }; - return std::make_unique( api::ble_v2::BleMedium::AdvertisingSession{std::move(stop_adv)}); } std::unique_ptr BleV2Medium::StartGattServer( api::ble_v2::ServerGattConnectionCallback callback) { - return std::make_unique(*system_bus_, adapter_, devices_, - std::move(callback)); + (void)callback; + + return std::make_unique( + *system_bus_, adapter_, devices_,std::move(callback) + ); } std::unique_ptr BleV2Medium::ConnectToGattServer( - api::ble_v2::BlePeripheral &peripheral, + api::ble_v2::BlePeripheral::UniqueId peripheral_id, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::ClientGattConnectionCallback callback) { - auto path = bluez::device_object_path(adapter_.GetObjectPath(), - peripheral.GetAddress()); + (void)peripheral_id; + (void)tx_power_level; + (void)callback; + LOG(WARNING) << __func__ + << ": GATT client connection is not supported on Linux yet."; + return nullptr; +} - return std::make_unique(system_bus_, path, gatt_discovery_, - std::move(callback.disconnected_cb)); +std::unique_ptr BleV2Medium::Connect( + const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BlePeripheral::UniqueId peripheral_id, + CancellationFlag *cancellation_flag) { + (void)service_id; + (void)tx_power_level; + (void)peripheral_id; + (void)cancellation_flag; + LOG(WARNING) << __func__ + << ": BLE socket connection is not supported on Linux yet."; + return nullptr; } bool BleV2Medium::IsExtendedAdvertisementsAvailable() { @@ -305,9 +320,8 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, << "' and message '" << e.getMessage() << "'"; return false; } - auto device_watcher = std::make_unique( - *system_bus_, adapter_.GetObjectPath(), devices_); + *system_bus_, adapter_.GetObjectPath(), adapter_, devices_); if (!StartLEDiscovery()) { LOG(ERROR) << __func__ << ": Could not start LE discovery on adapter " @@ -325,6 +339,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, } return false; } + LOG(INFO) << __func__ << " :Started monitoring for service UUID: " << std::string(service_uuid); active_adv_monitors_[service_uuid] = std::make_pair(std::move(monitor), std::move(device_watcher)); @@ -348,7 +363,7 @@ bool BleV2Medium::StopScanning() { LOG(INFO) << __func__ << ": Stopping discovery for adapter " << adapter.getObjectPath(); try { - adapter.StopDiscovery(); + adapter.StopDiscovery(); // this will stop bluetooth classic discovery as well. do we want this? } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StopDiscovery", e); } @@ -403,7 +418,7 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, } auto device_watcher = std::make_unique( - *system_bus_, adapter_.GetObjectPath(), devices_); + *system_bus_, adapter_.GetObjectPath(),adapter_, devices_); if (!StartLEDiscovery()) { LOG(ERROR) << __func__ << ": Could not start LE discovery on adapter " @@ -461,20 +476,69 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, }}); } -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); +std::unique_ptr BleV2Medium::OpenServerSocket( + const std::string &service_id) { + LOG(INFO) << __func__ << ": Opening BLE server socket for service " + << service_id; + return std::make_unique(); +} + +std::unique_ptr +BleV2Medium::OpenL2capServerSocket(const std::string &service_id) { + LOG(WARNING) << __func__ << ": L2CAP server sockets not implemented on Linux"; + return nullptr; +} + +// std::unique_ptr BleV2Medium::Connect( +// const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, +// api::ble_v2::BlePeripheral &peripheral, +// CancellationFlag *cancellation_flag) { +// LOG(WARNING) << __func__ << ": BLE socket connections not implemented on Linux"; +// return nullptr; +// } + +std::unique_ptr BleV2Medium::ConnectOverL2cap( + int psm, const std::string &service_id, + api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BlePeripheral::UniqueId peripheral_id, + CancellationFlag *cancellation_flag) { + LOG(WARNING) << __func__ << ": L2CAP socket connections not implemented on Linux"; + return nullptr; +} + +bool BleV2Medium::StartMultipleServicesScanning( + const std::vector &service_uuids, + api::ble_v2::TxPowerLevel tx_power_level, ScanCallback callback) { + LOG(WARNING) << __func__ + << ": Multiple services scanning not implemented on Linux. " + << "Use single service scanning instead."; + return false; +} + +bool BleV2Medium::PauseMediumScanning() { + LOG(INFO) << __func__ << ": Pause scanning not implemented, returning success"; return true; } -bool BleV2Medium::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); +bool BleV2Medium::ResumeMediumScanning() { + LOG(INFO) << __func__ << ": Resume scanning not implemented, returning success"; return true; } + +void BleV2Medium::AddAlternateUuidForService(uint16_t uuid, + const std::string &service_id) { + LOG(INFO) << __func__ << ": Alternate UUID mapping not implemented. UUID: " + << uuid << ", service_id: " << service_id; +} + +std::optional +BleV2Medium::RetrieveBlePeripheralIdFromNativeId( + const std::string &ble_peripheral_native_id) { + LOG(WARNING) << __func__ + << ": Retrieval from native ID not implemented. Native ID: " + << ble_peripheral_native_id; + return std::nullopt; +} + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index c3a9f638..dea7cb22 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -16,6 +16,8 @@ #define PLATFORM_IMPL_LINUX_API_BLE_V2_MEDIUM_H_ #include +#include +#include #include @@ -23,7 +25,7 @@ #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_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" @@ -69,26 +71,48 @@ class BleV2Medium final : public api::ble_v2::BleMedium { api::ble_v2::ServerGattConnectionCallback callback) override; std::unique_ptr ConnectToGattServer( - api::ble_v2::BlePeripheral &peripheral, + api::ble_v2::BlePeripheral::UniqueId peripheral_id, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::ClientGattConnectionCallback callback) override; std::unique_ptr OpenServerSocket( - const std::string &service_id) override { - return std::make_unique(); - } + const std::string &service_id) override; + + std::unique_ptr OpenL2capServerSocket( + const std::string &service_id) override; std::unique_ptr Connect( const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, - api::ble_v2::BlePeripheral &peripheral, - CancellationFlag *cancellation_flag) override { - return nullptr; - } + api::ble_v2::BlePeripheral::UniqueId peripheral_id, + CancellationFlag *cancellation_flag) override; + + std::unique_ptr ConnectOverL2cap( + int psm, const std::string &service_id, + api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BlePeripheral::UniqueId peripheral_id, + CancellationFlag *cancellation_flag) override; + + bool StartMultipleServicesScanning(const std::vector &service_uuids, + api::ble_v2::TxPowerLevel tx_power_level, + ScanCallback callback) override; + + bool PauseMediumScanning() override; + + bool ResumeMediumScanning() override; + bool IsExtendedAdvertisementsAvailable() override; - bool GetRemotePeripheral(const std::string &mac_address, - GetRemotePeripheralCallback callback) override; - bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, - GetRemotePeripheralCallback callback) override; + + void AddAlternateUuidForService(uint16_t uuid, + const std::string &service_id) override; + + std::optional + RetrieveBlePeripheralIdFromNativeId( + const std::string &ble_peripheral_native_id) override; + + // bool GetRemotePeripheral(const std::string &mac_address, + // GetRemotePeripheralCallback callback) override; + // bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id, + // GetRemotePeripheralCallback callback) override; private: bool StartLEDiscovery(); @@ -116,7 +140,7 @@ class BleV2Medium final : public api::ble_v2::BleMedium { BluetoothAdapter adapter_; ObserverList observers_ = {}; std::shared_ptr devices_; - std::shared_ptr gatt_discovery_; + // std::shared_ptr gatt_discovery_; std::unique_ptr root_object_manager_; std::unique_ptr adv_monitor_manager_; diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index e6e91703..8810f5c1 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -39,7 +39,6 @@ namespace nearby { namespace linux { // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html. - // TODO: This used to inherit from ble_v2::BlePeripheral. Removed that since APIs have now changed class BluetoothDevice : public api::BluetoothDevice { public: using UniqueId = std::uint64_t; diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index dd4755c1..ba20e853 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -68,9 +68,9 @@ int16_t TxPowerLevelDbm(api::ble_v2::TxPowerLevel level) { case api::ble_v2::TxPowerLevel::kLow: return 0; case api::ble_v2::TxPowerLevel::kMedium: - return 3; + return 5; case api::ble_v2::TxPowerLevel::kHigh: - return 6; + return 10; // Increased from 6 to 10 dBm (maximum for most adapters) } } diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc index 335e9ca7..9418d110 100644 --- a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc @@ -57,7 +57,7 @@ void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) { adv_data.service_data.emplace(*uuid, std::string(bytes.begin(), bytes.end())); } - scan_callback_.advertisement_found_cb(*peripheral, adv_data); + // scan_callback_.advertisement_found_cb(*peripheral, adv_data); } void AdvertisementMonitor::DeviceLost(const sdbus::ObjectPath &device) { diff --git a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc index 428c7071..e3dc8130 100644 --- a/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc +++ b/internal/platform/implementation/linux/bluez_gatt_characteristic_server.cc @@ -93,38 +93,39 @@ void GattCharacteristicServer::ReadValue( return; } auto characteristic = characteristic_; - server_cb_->on_characteristic_read_cb( - *device, characteristic, static_cast(offset), - [result = std::move(result), - this](absl::StatusOr data) { - const auto &status = data.status(); - if (status.ok()) { - auto str = data.value(); - std::vector 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()))); - } - }); + // TODO: enable the callback + // server_cb_->on_characteristic_read_cb( + // *device, characteristic, static_cast(offset), + // [result = std::move(result), + // this](absl::StatusOr data) { + // const auto &status = data.status(); + // if (status.ok()) { + // auto str = data.value(); + // std::vector 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( @@ -144,29 +145,30 @@ void GattCharacteristicServer::WriteValue( std::string data(value.begin(), value.end()); auto characteristic = characteristic_; + // TODO: enable the callback // TODO: Support writes without response. - server_cb_->on_characteristic_write_cb( - *device, characteristic, static_cast(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()))); - } - }); + // server_cb_->on_characteristic_write_cb( + // *device, characteristic, static_cast(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() { diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.cc b/internal/platform/implementation/linux/bluez_le_advertisement.cc index 1607ade0..ddf3264d 100644 --- a/internal/platform/implementation/linux/bluez_le_advertisement.cc +++ b/internal/platform/implementation/linux/bluez_le_advertisement.cc @@ -23,6 +23,14 @@ namespace nearby { namespace linux { namespace bluez { + std::string BytesToHexString(const std::vector& bytes) { + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (uint8_t b : bytes) { + oss << std::setw(2) << static_cast(b); + } + return oss.str(); + } LEAdvertisement::LEAdvertisement( sdbus::IConnection& system_bus, sdbus::ObjectPath path, const api::ble_v2::BleAdvertisementData& advertising_data, @@ -36,11 +44,15 @@ LEAdvertisement::LEAdvertisement( const auto* bytes = data.data(); service_uuids_.push_back(uuid_string); + // service_uuids_.push_back("0000FE2C-0000-1000-8000-00805F9B34FB"); + // service_uuids_.push_back("0000FE2C-0000-1000-8000-00805F9B34FB"); for (size_t i = 0; i < data.size(); i++) { data_bytes[i] = bytes[i]; } - + // LOG(INFO)<< __func__ << ": " << uuid_string; + // LOG(INFO)<< __func__ << ": " << BytesToHexString(data_bytes); service_data_.insert({uuid_string, std::move(data_bytes)}); + // service_data_.insert({"0000FE2C-0000-1000-8000-00805F9B34FB", std::move(data_bytes)}); } registerAdaptor(); diff --git a/internal/platform/implementation/linux/bluez_le_advertisement.h b/internal/platform/implementation/linux/bluez_le_advertisement.h index d4e8cc11..219e48a8 100644 --- a/internal/platform/implementation/linux/bluez_le_advertisement.h +++ b/internal/platform/implementation/linux/bluez_le_advertisement.h @@ -62,7 +62,7 @@ class LEAdvertisement final << ": LE Advertisement released: " << getObjectPath(); } - // Properties + // Properties std::string Type() override { return "peripheral"; } std::vector ServiceUUIDs() override { return service_uuids_; } std::map ManufacturerData() override { @@ -72,7 +72,12 @@ class LEAdvertisement final std::map ServiceData() override { return service_data_; } - std::vector Includes() override { return {}; } + std::map ScanResponseServiceData() override { + return {}; + } + std::vector Includes() override { + return {}; + } std::string LocalName() override { return {}; } uint16_t Duration() override { return 0; } uint16_t Timeout() override { return 0; } diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h index 89f6c0ef..9838e71a 100644 --- a/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h +++ b/internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h @@ -28,6 +28,7 @@ protected: object_.registerProperty("ManufacturerData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ManufacturerData(); }); object_.registerProperty("SolicitUUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SolicitUUIDs(); }); object_.registerProperty("ServiceData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ServiceData(); }); + object_.registerProperty("ScanResponseServiceData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ScanResponseServiceData(); }); object_.registerProperty("Includes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Includes(); }); object_.registerProperty("LocalName").onInterface(INTERFACE_NAME).withGetter([this](){ return this->LocalName(); }); object_.registerProperty("Duration").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Duration(); }); @@ -48,6 +49,7 @@ private: virtual std::map ManufacturerData() = 0; virtual std::vector SolicitUUIDs() = 0; virtual std::map ServiceData() = 0; + virtual std::map ScanResponseServiceData() = 0; virtual std::vector Includes() = 0; virtual std::string LocalName() = 0; virtual uint16_t Duration() = 0; diff --git a/internal/platform/implementation/linux/platform.cc b/internal/platform/implementation/linux/platform.cc index 43f9bdf1..91381dec 100644 --- a/internal/platform/implementation/linux/platform.cc +++ b/internal/platform/implementation/linux/platform.cc @@ -46,6 +46,7 @@ // #include "internal/platform/implementation/linux/wifi_medium.h" #include "internal/platform/implementation/platform.h" +#include "ble_v2_medium.h" #include "absl/strings/str_cat.h" #include "internal/platform/implementation/shared/count_down_latch.h" @@ -246,10 +247,10 @@ std::unique_ptr ImplementationPlatform::CreateBleMedium( std::unique_ptr ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter &adapter) { - return nullptr; + // return nullptr; // TODO: Enable BLEv2 once BlueZ support is added. - // return std::make_unique( - // dynamic_cast(adapter)); + return std::make_unique( + dynamic_cast(adapter)); } namespace { From 3d97a540b55703a6df6b78c3269b598dd007e004 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 10 Jan 2026 11:23:19 +0000 Subject: [PATCH 184/201] Enabled BLE advertisements with extended + GATT server. --- internal/platform/implementation/linux/ble_v2_medium.cc | 9 +++++++-- .../implementation/linux/bluez_advertisement_monitor.h | 8 +++++--- internal/platform/implementation/linux/dbus.h | 4 +++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index a6d86523..bf1b082f 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -53,10 +53,10 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) if (adv_monitor_manager_) { LOG(INFO) << __func__ - << ": Registering path / with AdvertisementMonitorManager at " + << ": Registering path /com/google/nearby/medium/ble/advertisement/monitor with AdvertisementMonitorManager at " << adv_monitor_manager_->getObjectPath(); try { - adv_monitor_manager_->RegisterMonitor("/"); + adv_monitor_manager_->RegisterMonitor("/com/google/nearby/medium/ble/advertisement/monitor"); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(adv_monitor_manager_, "RegisterMonitor", e); } @@ -251,6 +251,7 @@ bool BleV2Medium::IsExtendedAdvertisementsAvailable() { bool BleV2Medium::StartLEDiscovery() { std::map filter; filter["Transport"] = "auto"; + filter["DuplicateData"] = true; auto &adapter = adapter_.GetBluezAdapterObject(); try { @@ -310,8 +311,12 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, *system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, std::move(callback)); try { + // why is this emitted? monitor->emitInterfacesAddedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + + // adv_monitor_manager_ -> RegisterMonitor(monitor -> getObjectPath()); + LOG(INFO)<< __func__ << ": Registered advertisement monitor with path " << monitor -> getObjectPath(); } catch (const sdbus::Error &e) { LOG(ERROR) << __func__ diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.h b/internal/platform/implementation/linux/bluez_advertisement_monitor.h index 24e57696..ea251f85 100644 --- a/internal/platform/implementation/linux/bluez_advertisement_monitor.h +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.h @@ -53,6 +53,7 @@ class AdvertisementMonitor final // Methods void Release() override {} void Activate() override { + LOG(INFO) <<__func__ << ": bluez advertisement monitor activated at path: " << getObjectPath(); if (start_scanning_result_callback_ != nullptr) { start_scanning_result_callback_(absl::OkStatus()); } @@ -63,9 +64,9 @@ class AdvertisementMonitor final // Properties std::string Type() override { return type_; }; - int16_t RSSILowThreshold() override { return 0; }; + int16_t RSSILowThreshold() override { return 127; }; int16_t RSSIHighThreshold() override { - return bluez::TxPowerLevelDbm(tx_power_level_); + return 127; } uint16_t RSSISamplingPeriod() override { // The Windows implementation uses a sampling interval of 2 seconds. @@ -77,7 +78,8 @@ class AdvertisementMonitor final return {{0, 0x16, {static_cast(service_id_data[3] & 0xFF), - static_cast(service_id_data[2] & 0xFF)}}}; + static_cast(service_id_data[2] & 0xFF)} + }}; }; std::shared_ptr devices_; diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h index c0dfae9f..18e7ca4f 100644 --- a/internal/platform/implementation/linux/dbus.h +++ b/internal/platform/implementation/linux/dbus.h @@ -51,8 +51,10 @@ class RootObjectManager final : public sdbus::AdaptorInterfaces { public: + // only used in ble advertisement monitoring for now. + // TODO: Remove hardcodinged va explicit RootObjectManager(sdbus::IConnection &system_bus) - : AdaptorInterfaces(system_bus, "/") { + : AdaptorInterfaces(system_bus, "/com/google/nearby/medium/ble/advertisement/monitor") { registerAdaptor(); } ~RootObjectManager() { unregisterAdaptor(); } From 329f2ce2c948113262bfd3ab1faf84f14927e168 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Mon, 12 Jan 2026 08:17:05 +0000 Subject: [PATCH 185/201] Added GattProfile. Disabled fast adverts due to linux not supporting random mac addresses. --- internal/platform/implementation/linux/BUILD | 1 + .../implementation/linux/ble_gatt_server.cc | 24 ++++--- .../implementation/linux/ble_gatt_server.h | 9 +++ .../implementation/linux/ble_medium.cc | 33 ++++++++++ .../implementation/linux/ble_v2_medium.cc | 9 ++- .../implementation/linux/ble_v2_medium.h | 3 +- .../linux/bluetooth_classic_device.cc | 8 ++- .../platform/implementation/linux/bluez.cc | 8 ++- .../platform/implementation/linux/bluez.h | 5 +- .../linux/bluez_advertisement_monitor.cc | 7 ++- .../bluez_advertisement_monitor_manager.h | 14 +++-- .../implementation/linux/bluez_gatt_profile.h | 63 +++++++++++++++++++ internal/platform/implementation/linux/dbus.h | 6 +- .../dbus/bluez/gatt_profile_server.h | 48 ++++++++++++++ .../dbus/bluez/org.bluez.GattProfile1.xml | 8 +++ 15 files changed, 219 insertions(+), 27 deletions(-) create mode 100644 internal/platform/implementation/linux/ble_medium.cc create mode 100644 internal/platform/implementation/linux/bluez_gatt_profile.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/gatt_profile_server.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattProfile1.xml diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index ad0cdfdf..a427f35a 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -76,6 +76,7 @@ cc_library( # "bluez_gatt_characteristic_client.h", "bluez_gatt_characteristic_server.h", "bluez_gatt_manager.h", + "bluez_gatt_profile.h", # "bluez_gatt_service_client.h", "bluez_gatt_service_server.h", "bluez_le_advertisement.h", diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc index 927c6d62..0c2089ea 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.cc +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -54,18 +54,24 @@ GattServer::CreateCharacteristic( << "' and message '" << e.getMessage() << "'"; return std::nullopt; } + auto profile = std::make_unique (system_bus_, bluez::gatt_profile_object_path( + std::string(service_uuid)), std::string(service_uuid)); + profile -> emitInterfacesAddedSignal(); if (service->AddCharacteristic(service_uuid, characteristic_uuid, permission, property)) { - bluez::GattManager manager(system_bus_, adapter_.GetObjectPath()); - try { - LOG(INFO) << __func__ << ": registering service " - << service->getObjectPath(); - manager.RegisterApplication("/", {}); - } catch (const sdbus::Error& e) { - DBUS_LOG_METHOD_CALL_ERROR(&manager, "RegisterApplication", e); - return std::nullopt; - } + try { + LOG(INFO)<< __func__ << ": Registering service on gattmanager"; + gatt_manager_ -> RegisterApplication(gatt_service_root_object_manager -> getObjectPath(), {}); + } catch (const sdbus::Error& e) { + LOG(ERROR) + << __func__ + << ": error calling RegisterAplication for GattManager with object path " + << gatt_manager_->getObjectPath() << " with name '" << e.getName() + << "' and message '" << e.getMessage() << "'"; + return std::nullopt; + } + services_.insert({service_uuid, std::move(service)}); diff --git a/internal/platform/implementation/linux/ble_gatt_server.h b/internal/platform/implementation/linux/ble_gatt_server.h index 2f3b75b5..65a64390 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.h +++ b/internal/platform/implementation/linux/ble_gatt_server.h @@ -20,6 +20,8 @@ #include +#include "bluez_gatt_manager.h" +#include "bluez_gatt_profile.h" #include "absl/container/flat_hash_map.h" #include "absl/synchronization/mutex.h" #include "absl/types/optional.h" @@ -63,6 +65,8 @@ class GattServer : public api::ble_v2::GattServer { devices_(std::move(devices)), adapter_(adapter), local_peripheral_(adapter_), + gatt_service_root_object_manager(std::make_unique(system_bus_, "/com/google/nearby/medium/ble/gatt")), + gatt_manager_(std::make_unique(system_bus_, adapter_.GetObjectPath())), server_cb_(std::make_shared( std::move(server_cb))) {} ~GattServer() override = default; @@ -85,6 +89,11 @@ class GattServer : public api::ble_v2::GattServer { BluetoothAdapter adapter_; LocalBlePeripheral local_peripheral_; + std::unique_ptr gatt_service_root_object_manager; + absl::Mutex profiles_mutex_; + absl::flat_hash_map> gatt_profiles_; + ABSL_GUARDED_BY(profiles_mutex_) + std::unique_ptr gatt_manager_; std::shared_ptr server_cb_; absl::Mutex services_mutex_; absl::flat_hash_map> services_ diff --git a/internal/platform/implementation/linux/ble_medium.cc b/internal/platform/implementation/linux/ble_medium.cc new file mode 100644 index 00000000..2f4a3604 --- /dev/null +++ b/internal/platform/implementation/linux/ble_medium.cc @@ -0,0 +1,33 @@ +// 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_medium.h" + +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/ble.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_v2_medium.h" +#include "internal/platform/implementation/linux/bluetooth_adapter.h" +#include "internal/platform/logging.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { + + +} // namespace linux +} // namespace nearby \ No newline at end of file diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index bf1b082f..2cf555e1 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -43,7 +43,7 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) devices_(std::make_unique( system_bus_, adapter_.GetObjectPath(), observers_)), // gatt_discovery_(std::make_shared(system_bus_)), - root_object_manager_(std::make_unique(*system_bus_)), + root_object_manager_(std::make_unique(*system_bus_, "/com/google/nearby/medium/ble/advertisement/monitor")), adv_monitor_manager_( bluez::AdvertisementMonitorManager:: DiscoverAdvertisementMonitorManager(*system_bus_, adapter_)), @@ -56,7 +56,7 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) << ": Registering path /com/google/nearby/medium/ble/advertisement/monitor with AdvertisementMonitorManager at " << adv_monitor_manager_->getObjectPath(); try { - adv_monitor_manager_->RegisterMonitor("/com/google/nearby/medium/ble/advertisement/monitor"); + adv_monitor_manager_->RegisterMonitor(root_object_manager_->getObjectPath()); } catch (const sdbus::Error &e) { DBUS_LOG_METHOD_CALL_ERROR(adv_monitor_manager_, "RegisterMonitor", e); } @@ -73,6 +73,11 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) bool BleV2Medium::StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, api::ble_v2::AdvertiseParameters advertise_set_parameters) { + if (!advertising_data.is_extended_advertisement) + { + // can't send two LE advertisements at the same + return true; + } if (!adapter_.IsEnabled()) { LOG(WARNING) << "BLE cannot start advertising because the " "bluetooth adapter is not enabled."; diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index dea7cb22..a1187a3f 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -26,6 +26,7 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/ble_v2.h" // #include "internal/platform/implementation/linux/ble_gatt_client.h" +#include "bluez_gatt_manager.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" @@ -142,7 +143,7 @@ class BleV2Medium final : public api::ble_v2::BleMedium { std::shared_ptr devices_; // std::shared_ptr gatt_discovery_; - std::unique_ptr root_object_manager_; + std::unique_ptr root_object_manager_; std::unique_ptr adv_monitor_manager_; absl::Mutex active_adv_monitors_mutex_; absl::flat_hash_map< diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 544a1746..108a71bb 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -116,7 +116,8 @@ void MonitoredBluetoothDevice::onPropertiesChanged( } for (auto it = changedProperties.begin(); it != changedProperties.end(); - it++) { + it++) + { if (it->first == bluez::DEVICE_PROP_ADDRESS) { LOG(INFO) << __func__ << ": " << getObjectPath() << ": Notifying observers about address change"; @@ -124,6 +125,7 @@ void MonitoredBluetoothDevice::onPropertiesChanged( for (const auto &observer : observers_.GetObservers()) { observer->DeviceAddressChanged(*this, address); } + } else if (it->first == bluez::DEVICE_PROP_PAIRED) { LOG(INFO) << __func__ << ": " << getObjectPath() << "Notifying observers about paired status change."; @@ -137,7 +139,9 @@ void MonitoredBluetoothDevice::onPropertiesChanged( for (const auto &observer : observers_.GetObservers()) { observer->DeviceConnectedStateChanged(*this, it->second); } - } else if (it->first == bluez::DEVICE_NAME) { + } else if ( it -> first == "ServicesResolved"){ + LOG(INFO) << ": ServicesResolved"; + }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); diff --git a/internal/platform/implementation/linux/bluez.cc b/internal/platform/implementation/linux/bluez.cc index ba20e853..48c3532d 100644 --- a/internal/platform/implementation/linux/bluez.cc +++ b/internal/platform/implementation/linux/bluez.cc @@ -35,7 +35,13 @@ sdbus::ObjectPath profile_object_path(absl::string_view service_uuid) { absl::StrReplaceAll(service_uuid, {{"-", "_"}})); } -sdbus::ObjectPath adapter_object_path(absl::string_view name) { + sdbus::ObjectPath gatt_profile_object_path(absl::string_view service_uuid) { + return absl::Substitute( + "$0/profile_$1", + NEARBY_BLE_GATT_PROFILE_PATH_ROOT, + absl::StrReplaceAll(service_uuid, {{"-", "_"}})); +} + sdbus::ObjectPath adapter_object_path(absl::string_view name) { return absl::Substitute("/org/bluez/$0", name); } diff --git a/internal/platform/implementation/linux/bluez.h b/internal/platform/implementation/linux/bluez.h index 29ce772c..cd037f7b 100644 --- a/internal/platform/implementation/linux/bluez.h +++ b/internal/platform/implementation/linux/bluez.h @@ -49,10 +49,13 @@ 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, + static constexpr const char *NEARBY_BLE_GATT_PROFILE_PATH_ROOT = + "/com/google/nearby/medium/ble/gatt/profile"; + std::string device_object_path(const sdbus::ObjectPath &adapter_object_path, absl::string_view mac_address); sdbus::ObjectPath profile_object_path(absl::string_view service_uuid); sdbus::ObjectPath adapter_object_path(absl::string_view name); +sdbus::ObjectPath gatt_profile_object_path(absl::string_view service_uuid); sdbus::ObjectPath gatt_service_path(size_t num); sdbus::ObjectPath gatt_characteristic_path( const sdbus::ObjectPath &service_path, size_t num); diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc index 9418d110..2bc71f36 100644 --- a/internal/platform/implementation/linux/bluez_advertisement_monitor.cc +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor.cc @@ -1,4 +1,7 @@ #include "internal/platform/implementation/linux/bluez_advertisement_monitor.h" + +#include + #include "internal/platform/byte_array.h" #include "internal/platform/implementation/ble_v2.h" #include "internal/platform/implementation/linux/dbus.h" @@ -57,7 +60,9 @@ void AdvertisementMonitor::DeviceFound(const sdbus::ObjectPath &device) { adv_data.service_data.emplace(*uuid, std::string(bytes.begin(), bytes.end())); } - // scan_callback_.advertisement_found_cb(*peripheral, adv_data); + auto id = std::stoull(std::regex_replace(peripheral->GetMacAddress(), + std::regex("[:\\-]"), ""), nullptr, 16); + scan_callback_.advertisement_found_cb(id, adv_data); } void AdvertisementMonitor::DeviceLost(const sdbus::ObjectPath &device) { diff --git a/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h b/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h index 8a05e976..196b5e96 100644 --- a/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h +++ b/internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h @@ -31,10 +31,11 @@ class AdvertisementMonitorManager final org::bluez::AdvertisementMonitorManager1_proxy> { private: friend std::unique_ptr - std::make_unique(sdbus::IConnection &, - const BluetoothAdapter &); - AdvertisementMonitorManager(sdbus::IConnection &system_bus, - const BluetoothAdapter &adapter) + std::make_unique( + sdbus::IConnection &, const ::nearby::linux::BluetoothAdapter &); + AdvertisementMonitorManager( + sdbus::IConnection &system_bus, + const ::nearby::linux::BluetoothAdapter &adapter) : ProxyInterfaces(system_bus, "org.bluez", adapter.GetObjectPath()) { registerProxy(); } @@ -49,8 +50,9 @@ class AdvertisementMonitorManager final ~AdvertisementMonitorManager() { unregisterProxy(); } static std::unique_ptr - DiscoverAdvertisementMonitorManager(sdbus::IConnection &system_bus, - const BluetoothAdapter &adapter) { + DiscoverAdvertisementMonitorManager( + sdbus::IConnection &system_bus, + const ::nearby::linux::BluetoothAdapter &adapter) { bluez::BluezObjectManager manager(system_bus); std::map>> diff --git a/internal/platform/implementation/linux/bluez_gatt_profile.h b/internal/platform/implementation/linux/bluez_gatt_profile.h new file mode 100644 index 00000000..0c34063f --- /dev/null +++ b/internal/platform/implementation/linux/bluez_gatt_profile.h @@ -0,0 +1,63 @@ +// +// Created by root on 1/11/26. +// + +#ifndef WORKSPACE_BLUEZ_GATT_PROFILE_H +#define WORKSPACE_BLUEZ_GATT_PROFILE_H + +#include +#include +#include + +#include "generated/dbus/bluez/gatt_profile_server.h" +#include "internal/platform/logging.h" + +#include +#include +#include + +namespace nearby { + namespace linux { + namespace bluez { + class GattProfile + : public sdbus::AdaptorInterfaces { + public: + GattProfile(const GattProfile &) = delete; + GattProfile(GattProfile &&) = delete; + GattProfile &operator=(const GattProfile &) = delete; + GattProfile &operator=(GattProfile &&) = delete; + + GattProfile(sdbus::IConnection &system_bus, + sdbus::ObjectPath profile_path, std::string service_uuid) + : AdaptorInterfaces(system_bus, profile_path), + uuids_({service_uuid}) + + { + registerAdaptor(); + } + ~GattProfile() { unregisterAdaptor(); } + + void Release() override + { + LOG(INFO) << __func__ << ": Gatt profile released"; + }; + private: + std::string ToLowerAscii(std::string s) { + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); + return s; + } + std::vector UUIDs() override + { + LOG(INFO)<< __func__ << ": UUIDs called, returned: " << ToLowerAscii(uuids_[0]); + return uuids_; + }; + + std::vector uuids_; + + }; + } // namespace bluez + } // namespace linux +} // namespace nearby + +#endif //WORKSPACE_BLUEZ_GATT_PROFILE_H \ No newline at end of file diff --git a/internal/platform/implementation/linux/dbus.h b/internal/platform/implementation/linux/dbus.h index 18e7ca4f..ac48f5dd 100644 --- a/internal/platform/implementation/linux/dbus.h +++ b/internal/platform/implementation/linux/dbus.h @@ -51,10 +51,8 @@ class RootObjectManager final : public sdbus::AdaptorInterfaces { public: - // only used in ble advertisement monitoring for now. - // TODO: Remove hardcodinged va - explicit RootObjectManager(sdbus::IConnection &system_bus) - : AdaptorInterfaces(system_bus, "/com/google/nearby/medium/ble/advertisement/monitor") { + explicit RootObjectManager(sdbus::IConnection &system_bus, sdbus::ObjectPath path) + : AdaptorInterfaces(system_bus, path) { registerAdaptor(); } ~RootObjectManager() { unregisterAdaptor(); } diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/gatt_profile_server.h b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_profile_server.h new file mode 100644 index 00000000..865e76bd --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/gatt_profile_server.h @@ -0,0 +1,48 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_dbus_bluez_gatt_profile_server_h__adaptor__H__ +#define __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_dbus_bluez_gatt_profile_server_h__adaptor__H__ + +#include +#include +#include + +namespace org { +namespace bluez { + +class GattProfile1_adaptor +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.GattProfile1"; + +protected: + GattProfile1_adaptor(sdbus::IObject& object) + : object_(&object) + { + object_->registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); }); + object_->registerProperty("UUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUIDs(); }); + } + + GattProfile1_adaptor(const GattProfile1_adaptor&) = delete; + GattProfile1_adaptor& operator=(const GattProfile1_adaptor&) = delete; + GattProfile1_adaptor(GattProfile1_adaptor&&) = default; + GattProfile1_adaptor& operator=(GattProfile1_adaptor&&) = default; + + ~GattProfile1_adaptor() = default; + +private: + virtual void Release() = 0; + +private: + virtual std::vector UUIDs() = 0; + +private: + sdbus::IObject* object_; +}; + +}} // namespaces + +#endif diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattProfile1.xml b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattProfile1.xml new file mode 100644 index 00000000..83c46531 --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/org.bluez.GattProfile1.xml @@ -0,0 +1,8 @@ + + + + + + + From f14d0ee04dfdf6a61d187126b990e53a439383e3 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Mon, 12 Jan 2026 10:45:09 +0000 Subject: [PATCH 186/201] Implemented bluetooth socket stubs --- internal/platform/implementation/linux/BUILD | 3 ++ .../implementation/linux/ble_v2_medium.cc | 17 +++++---- .../linux/ble_v2_server_socket.h | 37 +++++++++++++------ .../linux/bluetooth_classic_device.cc | 12 ++++++ .../linux/bluetooth_classic_device.h | 1 + .../implementation/linux/bluetooth_devices.cc | 15 ++++++++ .../implementation/linux/bluetooth_devices.h | 8 +--- 7 files changed, 68 insertions(+), 25 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index a427f35a..f367abf3 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -60,6 +60,7 @@ cc_library( # "ble_medium.h", "ble_v2_medium.h", "ble_v2_server_socket.h", + "ble_v2_socket.h", "bluetooth_adapter.h", "bluetooth_bluez_profile.h", "bluetooth_classic_device.h", @@ -145,6 +146,8 @@ cc_library( "ble_gatt_server.cc", # "ble_medium.cc", "ble_v2_medium.cc", + "ble_v2_server_socket.cc", + "ble_v2_socket.cc", "bluetooth_adapter.cc", "bluetooth_bluez_profile.cc", "bluetooth_classic_socket.cc", diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 2cf555e1..518f44c7 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -13,8 +13,13 @@ // limitations under the License. #include +#include #include +#include +#include +#include +#include #include #include @@ -28,6 +33,8 @@ #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" +#include "internal/platform/mac_address.h" +#include "absl/types/span.h" #include "internal/platform/implementation/linux/bluez_advertisement_monitor.h" #include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h" #include "internal/platform/implementation/linux/bluez_le_advertisement.h" @@ -234,12 +241,8 @@ std::unique_ptr BleV2Medium::Connect( const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::BlePeripheral::UniqueId peripheral_id, CancellationFlag *cancellation_flag) { - (void)service_id; - (void)tx_power_level; - (void)peripheral_id; - (void)cancellation_flag; - LOG(WARNING) << __func__ - << ": BLE socket connection is not supported on Linux yet."; + auto device = devices_ -> get_device_by_unique_id(peripheral_id); + LOG(INFO) << __func__ << ": Resolved device with address " << device -> GetMacAddress(); return nullptr; } @@ -490,7 +493,7 @@ std::unique_ptr BleV2Medium::OpenServerSocket( const std::string &service_id) { LOG(INFO) << __func__ << ": Opening BLE server socket for service " << service_id; - return std::make_unique(); + return std::make_unique(service_id); } std::unique_ptr diff --git a/internal/platform/implementation/linux/ble_v2_server_socket.h b/internal/platform/implementation/linux/ble_v2_server_socket.h index ea6734c7..2ff2322b 100644 --- a/internal/platform/implementation/linux/ble_v2_server_socket.h +++ b/internal/platform/implementation/linux/ble_v2_server_socket.h @@ -15,27 +15,42 @@ #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 +#include +#include + +#include "absl/synchronization/mutex.h" #include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_v2_socket.h" namespace nearby { namespace linux { + class BleV2ServerSocket final : public api::ble_v2::BleServerSocket { public: - std::unique_ptr Accept() override { - stopped_.WaitForNotification(); - return nullptr; - } + explicit BleV2ServerSocket(const std::string& service_id) + : service_id_(service_id) {} + ~BleV2ServerSocket() override = default; - Exception Close() override { - if (stopped_.HasBeenNotified()) return {Exception::kIo}; - stopped_.Notify(); - return {Exception::kSuccess}; - } + std::unique_ptr Accept() override + ABSL_LOCKS_EXCLUDED(mutex_); + + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + void AddPendingSocket(std::unique_ptr socket) + ABSL_LOCKS_EXCLUDED(mutex_); + + std::string GetServiceId() const { return service_id_; } private: - absl::Notification stopped_; + std::string service_id_; + absl::Mutex mutex_; + absl::CondVar cond_; + bool closed_ ABSL_GUARDED_BY(mutex_) = false; + std::deque> pending_sockets_ + ABSL_GUARDED_BY(mutex_); }; + } // namespace linux } // namespace nearby diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 108a71bb..9805994c 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -83,6 +83,18 @@ std::string BluetoothDevice::GetMacAddress() const { } } +std::string BluetoothDevice::GetAddressType() const { + auto device = device_; + if (device == nullptr) return "public"; + + try { + return device->AddressType(); + } catch (const sdbus::Error& e) { + DBUS_LOG_PROPERTY_GET_ERROR(device, "AddressType", e); + return "public"; + } +} + bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { auto device = device_; if (device == nullptr) return false; diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index 8810f5c1..d4310644 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -52,6 +52,7 @@ class BluetoothDevice : public api::BluetoothDevice { std::string GetName() const override; std::string GetMacAddress() const override; + std::string GetAddressType() const; MacAddress GetAddress() const override { return last_known_address_; } diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 259a24ab..12ccce89 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -43,7 +43,22 @@ std::shared_ptr BluetoothDevices::get_device_by_path( return devices_by_path_[device_object_path]; } +std::shared_ptr BluetoothDevices::get_device_by_unique_id( + api::ble_v2::BlePeripheral::UniqueId id) +{ + // converting from stoull to mac again + id &= 0x0000FFFFFFFFFFFFULL; // keep 48 bits + std::ostringstream oss; + oss << std::hex << std::setfill('0') << std::setw(12) << id; + std::string hex = oss.str(); // e.g. "aabbccddeeff" + std::string mac; + for (int i = 0; i < 6; ++i) { + if (i) mac.push_back(':'); + mac.append(hex.substr(i * 2, 2)); + } + return get_device_by_address(mac); +} std::shared_ptr BluetoothDevices::get_device_by_address( const std::string &addr) { auto device_object_path = diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index a18ac126..45c8dc16 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -50,13 +50,7 @@ class BluetoothDevices final { ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); std::shared_ptr get_device_by_address(const std::string &); std::shared_ptr get_device_by_unique_id( - api::ble_v2::BlePeripheral::UniqueId id) { - // TODO: Should probably remove BlePeripheral stuff from here but we can keep it since we can convert to/from - // uint64_t - MacAddress tmp; - MacAddress::FromUint64(id, tmp); - return get_device_by_address(tmp.ToString()); - } + api::ble_v2::BlePeripheral::UniqueId id); std::shared_ptr add_new_device(sdbus::ObjectPath) ABSL_LOCKS_EXCLUDED(devices_by_path_lock_); From 4c3656b16007aa417a1914406c99dd56d12859f5 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Wed, 14 Jan 2026 13:15:49 +0000 Subject: [PATCH 187/201] ble_l2cap sockets implemented. NOT WORKING THOUGH. I suspect l2cap sockets over LE require pairing even though its said it doesn't need pairing if security level is set properly on socket. --- .../linux/ble_l2cap_server_socket.cc | 184 +++++++++ .../linux/ble_l2cap_server_socket.h | 65 ++++ .../implementation/linux/ble_l2cap_socket.cc | 364 ++++++++++++++++++ .../implementation/linux/ble_l2cap_socket.h | 88 +++++ .../linux/ble_l2cap_socket_test.cc | 117 ++++++ .../linux/ble_v2_socket_adapter.cc | 130 +++++++ .../linux/ble_v2_socket_adapter.h | 66 ++++ .../generated/dbus/bluez/le_bearer_client.h | 76 ++++ 8 files changed, 1090 insertions(+) create mode 100644 internal/platform/implementation/linux/ble_l2cap_server_socket.cc create mode 100644 internal/platform/implementation/linux/ble_l2cap_server_socket.h create mode 100644 internal/platform/implementation/linux/ble_l2cap_socket.cc create mode 100644 internal/platform/implementation/linux/ble_l2cap_socket.h create mode 100644 internal/platform/implementation/linux/ble_l2cap_socket_test.cc create mode 100644 internal/platform/implementation/linux/ble_v2_socket_adapter.cc create mode 100644 internal/platform/implementation/linux/ble_v2_socket_adapter.h create mode 100644 internal/platform/implementation/linux/generated/dbus/bluez/le_bearer_client.h diff --git a/internal/platform/implementation/linux/ble_l2cap_server_socket.cc b/internal/platform/implementation/linux/ble_l2cap_server_socket.cc new file mode 100644 index 00000000..e6c252ed --- /dev/null +++ b/internal/platform/implementation/linux/ble_l2cap_server_socket.cc @@ -0,0 +1,184 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/linux/ble_l2cap_server_socket.h" + +#include +#include +#include +#include + +#include +#include + +#include "internal/platform/logging.h" +#include "internal/platform/prng.h" + +namespace nearby { +namespace linux { + +BleL2capServerSocket::BleL2capServerSocket() : psm_(0) {} + +BleL2capServerSocket::BleL2capServerSocket(int psm) : psm_(psm) { +} + +BleL2capServerSocket::~BleL2capServerSocket() { Close(); } + +void BleL2capServerSocket::SetPSM(int psm) { psm_ = psm; } + +std::unique_ptr BleL2capServerSocket::Accept() { + if (stopped_.Cancelled()) { + LOG(ERROR) << __func__ << ": server socket has been stopped"; + return nullptr; + } + + absl::MutexLock lock(&mutex_); + + Prng prng; + psm_ = 0x80 + (prng.NextUint32() % 0x80); + + server_fd_ = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + int rcv = 1 << 20; // 1 MiB (kernel may clamp) + int snd = 1 << 20; + int err2 = setsockopt(server_fd_, SOL_SOCKET, SO_RCVBUF, &rcv, sizeof(rcv)); + int err3 = setsockopt(server_fd_, SOL_SOCKET, SO_SNDBUF, &snd, sizeof(snd)); + + LOG(INFO) << __func__ << ": Using server_fd: " << server_fd_; + if (server_fd_ < 0 or err2 == -1 or err3 == -1) { + LOG(ERROR) << "Failed to create L2CAP server socket: " + << std::strerror(errno); + return nullptr; + } + + struct sockaddr_l2 addr; + std::memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + addr.l2_psm = htobs(psm_); + addr.l2_cid = 0; + addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; + // Set BDADDR_ANY (all zeros) + std::memset(&addr.l2_bdaddr, 0, sizeof(addr.l2_bdaddr)); + + if (bind(server_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + LOG(ERROR) << "Failed to bind L2CAP server socket: " + << std::strerror(errno) << " (errno: " << errno << ")"; + close(server_fd_); + server_fd_ = -1; + return nullptr; + } + + if (listen(server_fd_, 5) < 0) { + LOG(ERROR) << "Failed to listen on L2CAP server socket: " + << std::strerror(errno); + close(server_fd_); + server_fd_ = -1; + return nullptr; + } + + socklen_t addr_len = sizeof(addr); + if (getsockname(server_fd_, (struct sockaddr*)&addr, &addr_len) == 0) { + psm_ = btohs(addr.l2_psm); + LOG(INFO) << "L2CAP server socket listening on PSM: " << psm_; + } else { + LOG(ERROR) << "Failed to get socket name: " << std::strerror(errno); + } + // // Return cached socket if it exists + // auto it = accepted_fds_.find(server_fd_); + // if (it != accepted_fds_.end()) { + // LOG(INFO) << __func__ << ": Socket exists. Returning cached socket"; + // return std::make_unique(it->second.first, it->second.second); // I hate how this looks + // } + + if (server_fd_ < 0) { + LOG(ERROR) << "Server socket not initialized"; + return nullptr; + } + + // Release the mutex while waiting for incoming connection + mutex_.Unlock(); + + struct sockaddr_l2 client_addr; + socklen_t client_len = sizeof(client_addr); + std::memset(&client_addr, 0, sizeof(client_addr)); + + LOG(INFO) << "Waiting for L2CAP connection on PSM " << psm_ << "..."; + int client_fd = accept(server_fd_, (struct sockaddr*)&client_addr, &client_len); + + // Re-acquire the mutex + mutex_.Lock(); + + if (client_fd < 0) { + if (errno == EINTR || errno == EAGAIN) { + LOG(WARNING) << "Accept interrupted, returning nullptr"; + return nullptr; + } + LOG(ERROR) << "Failed to accept L2CAP connection: " << std::strerror(errno); + return nullptr; + } + + if (closed_) { + close(client_fd); + return nullptr; + } + + char client_addr_str[18]; + ba2str(&client_addr.l2_bdaddr, client_addr_str); + LOG(INFO) << "Accepted L2CAP connection from " << client_addr_str + << " on PSM " << btohs(client_addr.l2_psm); + + LOG(INFO) << __func__ << ": Connected to client_fd: " << client_fd; + // Create a unique ID from the MAC address + api::ble_v2::BlePeripheral::UniqueId peripheral_id = 0; + for (int i = 0; i < 6; i++) { + peripheral_id = (peripheral_id << 8) | client_addr.l2_bdaddr.b[i]; + } + + accepted_fds_.emplace(server_fd_, std::pair(client_fd, peripheral_id)); + return std::make_unique(client_fd, peripheral_id); +} + +Exception BleL2capServerSocket::Close() { + LOG(ERROR) << __func__ << ": closing bluetooth server socket"; + stopped_.Cancel(); + + return DoClose(); +} + +Exception BleL2capServerSocket::DoClose() { + closed_ = true; + + if (server_fd_ >= 0) { + shutdown(server_fd_, SHUT_RDWR); + close(server_fd_); + server_fd_ = -1; + } + + if (close_notifier_) { + auto notifier = std::move(close_notifier_); + mutex_.Unlock(); + notifier(); + mutex_.Lock(); + } + + return {Exception::kSuccess}; +} + +void BleL2capServerSocket::SetCloseNotifier( + absl::AnyInvocable notifier) { + absl::MutexLock lock(&mutex_); + close_notifier_ = std::move(notifier); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/ble_l2cap_server_socket.h b/internal/platform/implementation/linux/ble_l2cap_server_socket.h new file mode 100644 index 00000000..8fb42433 --- /dev/null +++ b/internal/platform/implementation/linux/ble_l2cap_server_socket.h @@ -0,0 +1,65 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_BLE_L2CAP_SERVER_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_BLE_L2CAP_SERVER_SOCKET_H_ + +#include +#include + +#include "absl/functional/any_invocable.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/ble.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_l2cap_socket.h" +#include "absl/container/flat_hash_map.h" +namespace nearby { +namespace linux { + +class BleL2capServerSocket final : public api::ble_v2::BleL2capServerSocket { + public: + BleL2capServerSocket(); + explicit BleL2capServerSocket(int psm); + ~BleL2capServerSocket() override; + + int GetPSM() const override { return psm_; } + void SetPSM(int psm); + + std::unique_ptr Accept() override + ABSL_LOCKS_EXCLUDED(mutex_); + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + void SetCloseNotifier(absl::AnyInvocable notifier) + ABSL_LOCKS_EXCLUDED(mutex_); + + private: + Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + mutable absl::Mutex mutex_; + absl::CondVar cond_; + absl::AnyInvocable close_notifier_ ABSL_GUARDED_BY(mutex_); + bool closed_ ABSL_GUARDED_BY(mutex_) = false; + int psm_ = 0; + int server_fd_ ABSL_GUARDED_BY(mutex_) = -1; + + CancellationFlag stopped_; + // > + absl::flat_hash_map> accepted_fds_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_BLE_L2CAP_SERVER_SOCKET_H_ diff --git a/internal/platform/implementation/linux/ble_l2cap_socket.cc b/internal/platform/implementation/linux/ble_l2cap_socket.cc new file mode 100644 index 00000000..555cdbc5 --- /dev/null +++ b/internal/platform/implementation/linux/ble_l2cap_socket.cc @@ -0,0 +1,364 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/linux/ble_l2cap_socket.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "absl/strings/escaping.h" +#include "absl/strings/string_view.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/logging.h" +#include + +#include "bluetooth_classic_socket.h" + +namespace nearby { +namespace linux { + +namespace { +constexpr size_t kLogMaxBytes = 64; +constexpr size_t kDefaultBleL2capMtu = 23; + +size_t GetSocketMtu(int fd, int option_name) { + uint16_t mtu = 0; + socklen_t len = sizeof(mtu); + if (getsockopt(fd, SOL_BLUETOOTH, option_name, &mtu, &len) == 0 && + mtu > 0) { + return static_cast(mtu); + } + return 0; +} + +std::string HexPreview(const char* data, size_t size) { + size_t count = std::min(size, kLogMaxBytes); + std::string hex = + absl::BytesToHexString(absl::string_view(data, count)); + if (size > count) { + hex.append("..."); + } + return hex; +} + +size_t GetL2capOutputMtu(int fd) { + struct l2cap_options opts; + size_t mtu = GetSocketMtu(fd, BT_SNDMTU); + if (mtu > 0) { + return mtu; + } + return kDefaultBleL2capMtu; +} + +Exception PollSocket(int fd, short event) { + struct pollfd fds[1]; + fds[0].fd = fd; + fds[0].events = event; + + while (true) { + int ret = poll(fds, 1, -1); + if (ret < 0) { + if (errno == EINTR) continue; + LOG(ERROR) << "Error polling L2CAP socket: " << std::strerror(errno); + return {Exception::kIo}; + } + if ((fds[0].revents & event) != 0) { + return {Exception::kSuccess}; + } + if ((fds[0].revents & POLLHUP) != 0) { + LOG(ERROR) << "L2CAP socket disconnected"; + return {Exception::kIo}; + } + if ((fds[0].revents & (POLLERR | POLLNVAL)) != 0) { + LOG(ERROR) << "Error occurred on L2CAP socket"; + return {Exception::kIo}; + } + } +} +} // namespace + +BleL2capInputStream::BleL2capInputStream(int fd) : fd_(fd) {} + +BleL2capInputStream::~BleL2capInputStream() { Close(); } + +static size_t GetBleCocRcvMtu(int fd) { + // Prefer BT_RCVMTU for LE CoC, but fall back to L2CAP_OPTIONS if needed. + uint16_t mtu = 0; + socklen_t len = sizeof(mtu); + if (getsockopt(fd, SOL_BLUETOOTH, BT_RCVMTU, &mtu, &len) == 0 && mtu > 0) + return mtu; + + // Fallback ONLY (avoid 23 unless you're sure; 23 causes truncation if peer sends bigger SDUs). + return 512; +} + + static size_t NextPacketSize(int fd) { + int pending = 0; + if (ioctl(fd, FIONREAD, &pending) == 0 && pending > 0) { + return static_cast(pending); + } + return 0; // unknown +} +ExceptionOr BleL2capInputStream::Read(std::int64_t size) { + int fd = fd_.load(); + if (fd < 0) return Exception{Exception::kIo}; + + auto poller = Poller::CreateInputPoller(fd); + + // Wait for readability + while (true) { + if (fd_.load() != fd) return {Exception::kIo}; + auto result = poller.Ready(); + if (result.Raised()) return result; + if (fd_.load() != fd) return {Exception::kIo}; + + // Peek the next message length without consuming it. + // For seqpacket/dgram, MSG_TRUNC makes recv() return the *full* message length + // even if the buffer is smaller. + ssize_t msg_len = ::recv(fd, nullptr, 0, MSG_PEEK | MSG_TRUNC); + if (msg_len < 0) { + if (errno == EINTR) continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + if (errno == EBADF) { + LOG(INFO) << __func__ << ": socket was closed during read"; + return {Exception::kIo}; + } + LOG(ERROR) << __func__ << ": error peeking message length: " + << std::strerror(errno); + return {Exception::kIo}; + } + if (msg_len == 0) { + LOG(INFO) << __func__ << ": socket closed (EOF)"; + return {Exception::kIo}; + } + + // Decide how much we will actually read/return. + // If caller asked for 'size', cap to that. + size_t want = static_cast(msg_len); + size_t cap = static_cast(size); + size_t to_read = std::min(want, cap); + + std::string buffer; + buffer.resize(to_read); + + // Now read/consume the message. If the message is larger than to_read, + // the remainder will be discarded by the kernel for seqpacket/dgram. + // We can detect that and treat it as an error (or choose a different policy). + if (fd_.load() != fd) return {Exception::kIo}; + ssize_t n = ::recv(fd, buffer.data(), to_read, 0); + if (n < 0) { + if (errno == EINTR) continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + if (errno == EBADF) { + LOG(INFO) << __func__ << ": socket was closed during read"; + return {Exception::kIo}; + } + LOG(ERROR) << __func__ << ": error reading data on bluetooth socket: " + << std::strerror(errno); + return {Exception::kIo}; + } + if (n == 0) { + LOG(INFO) << __func__ << ": socket closed (EOF)"; + return {Exception::kIo}; + } + + buffer.resize(static_cast(n)); + + // Detect truncation: if msg_len > size, we truncated/discarded remainder. + if (want > cap) { + LOG(ERROR) << __func__ + << ": incoming packet (" << want + << " bytes) exceeds requested size (" << cap + << "). Packet truncated."; + return {Exception::kIo}; + } + + return ExceptionOr{ByteArray(std::move(buffer))}; + } +} + +Exception BleL2capInputStream::Close() { + int fd = fd_.exchange(-1); + if (fd < 0) return {Exception::kSuccess}; // Already closed + ::shutdown(fd, SHUT_RDWR); + return {Exception::kSuccess}; +} + +BleL2capOutputStream::BleL2capOutputStream(int fd) : fd_(fd) {} + +BleL2capOutputStream::~BleL2capOutputStream() { Close(); } + +Exception BleL2capOutputStream::Write(const ByteArray& data) { + int fd = fd_.load(); + if (fd < 0) return Exception{Exception::kIo}; + + auto poller = Poller::CreateOutputPoller(fd); + + size_t total_wrote = 0; + + if (data.Empty()) { + return {Exception::kSuccess}; + } + size_t max_chunk_size = GetL2capOutputMtu(fd); + if (max_chunk_size == 0) { + max_chunk_size = kDefaultBleL2capMtu; + } + LOG(INFO) << "BleL2capOutputStream::Write bytes=" << data.size() + << " mtu=" << max_chunk_size << " data=0x" + << HexPreview(data.data(), data.size()); + while (total_wrote < data.size()) { + if (fd_.load() != fd) return {Exception::kIo}; + auto result = poller.Ready(); // should wait for POLLOUT/EPOLLOUT + if (result.Raised()) return result; + if (fd_.load() != fd) return {Exception::kIo}; + + const char *buf = data.data(); + size_t remaining = data.size() - total_wrote; + + size_t to_write = remaining; + { + // For SEQPACKET/DGRAM, one send() == one packet. + // Cap to discovered “MTU-like” limit to avoid EMSGSIZE. + absl::MutexLock lock(&fd_mutex_); + to_write = std::min(to_write, max_chunk_size); + } + + // Prefer send() to avoid SIGPIPE (MSG_NOSIGNAL is Linux). + ssize_t wrote = ::send(fd, + buf + total_wrote, + to_write, +#ifdef MSG_NOSIGNAL + MSG_NOSIGNAL +#else + 0 +#endif + ); + + // If send() isn’t appropriate in your environment, you can swap back to write(). + // ssize_t wrote = ::write(fd_.get(), buf + total_wrote, to_write); + + if (wrote < 0) { + if (errno == EINTR) continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + + if (errno == EMSGSIZE) { + // Our packet is too large; shrink max_chunk_ and retry. + { + absl::MutexLock lock(&fd_mutex_); + if (max_chunk_size > 1) { + max_chunk_size = std::max(1, max_chunk_size / 2); + LOG(INFO) << __func__ << ": EMSGSIZE; reducing max_chunk_ to " + << max_chunk_size; + continue; // retry with smaller chunk + } + } + LOG(ERROR) << __func__ << ": EMSGSIZE even at 1 byte"; + return {Exception::kIo}; + } + + if (errno == EBADF || errno == EPIPE) { + LOG(INFO) << __func__ << ": socket was closed during write"; + return {Exception::kIo}; + } + + LOG(ERROR) << __func__ + << ": error writing data on bluetooth socket: " + << std::strerror(errno); + return {Exception::kIo}; + } + + if (wrote == 0) { + // For sockets, 0 usually means peer closed. + LOG(INFO) << __func__ << ": peer closed during write"; + return {Exception::kIo}; + } + + total_wrote += static_cast(wrote); + } + + return {Exception::kSuccess}; +} + +Exception BleL2capOutputStream::Close() { + int fd = fd_.exchange(-1); + if (fd < 0) return {Exception::kSuccess}; // Already closed + ::shutdown(fd, SHUT_RDWR); + return {Exception::kSuccess}; +} + +BleL2capSocket::BleL2capSocket(int fd, + api::ble_v2::BlePeripheral::UniqueId peripheral_id) + : peripheral_id_(peripheral_id), + input_stream_(std::make_unique(fd)), + output_stream_(std::make_unique(fd)) +{ + LOG(INFO) << "fd_ " << fd; + LOG(INFO) << "input_stream_ :" << input_stream_.get(); + LOG(INFO) << "output_stream_ :" << output_stream_.get(); + struct l2cap_options opts; + size_t snd_mtu = GetSocketMtu(fd, BT_SNDMTU); + size_t rcv_mtu = GetSocketMtu(fd, BT_RCVMTU); + LOG(INFO) << "BleL2capSocket MTU fallback snd_mtu=" << snd_mtu + << " rcv_mtu=" << rcv_mtu; +} + +BleL2capSocket::~BleL2capSocket() { Close(); } + +Exception BleL2capSocket::Close() { + absl::MutexLock lock(&mutex_); + if (closed_) { + return {Exception::kSuccess}; + } + DoClose(); + return {Exception::kSuccess}; +} + +void BleL2capSocket::DoClose() { + closed_ = true; + + if (input_stream_) { + input_stream_->Close(); + } + if (output_stream_) { + output_stream_->Close(); + } + + if (close_notifier_) { + auto notifier = std::move(close_notifier_); + mutex_.Unlock(); + notifier(); + mutex_.Lock(); + } +} + +void BleL2capSocket::SetCloseNotifier(absl::AnyInvocable notifier) { + absl::MutexLock lock(&mutex_); + close_notifier_ = std::move(notifier); +} + +bool BleL2capSocket::IsClosed() const { + absl::MutexLock lock(&mutex_); + return closed_; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/ble_l2cap_socket.h b/internal/platform/implementation/linux/ble_l2cap_socket.h new file mode 100644 index 00000000..c5bd4489 --- /dev/null +++ b/internal/platform/implementation/linux/ble_l2cap_socket.h @@ -0,0 +1,88 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_BLE_L2CAP_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_BLE_L2CAP_SOCKET_H_ + +#include +#include + +#include "absl/functional/any_invocable.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" + +namespace nearby { +namespace linux { + +class BleL2capInputStream final : public InputStream { + public: + explicit BleL2capInputStream(int fd); + ~BleL2capInputStream() override; + + ExceptionOr Read(std::int64_t size) override; + Exception Close() override; + + private: + std::atomic fd_{-1}; + std::string pending_; // holds unread bytes from full SDUs + }; + +class BleL2capOutputStream final : public OutputStream { + public: + explicit BleL2capOutputStream(int fd); + ~BleL2capOutputStream() override; + + Exception Write(const ByteArray& data) override; + Exception Flush() override { return {Exception::kSuccess}; } + Exception Close() override; + + private: + mutable absl::Mutex fd_mutex_; + std::atomic fd_{-1}; +}; + +class BleL2capSocket final : public api::ble_v2::BleL2capSocket { + public: + BleL2capSocket(int fd, api::ble_v2::BlePeripheral::UniqueId peripheral_id); + ~BleL2capSocket() override; + + InputStream& GetInputStream() override { return *input_stream_; } + OutputStream& GetOutputStream() override { return *output_stream_; } + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + void SetCloseNotifier(absl::AnyInvocable notifier) override + ABSL_LOCKS_EXCLUDED(mutex_); + api::ble_v2::BlePeripheral::UniqueId GetRemotePeripheralId() override { + return peripheral_id_; + } + + bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + + private: + void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + mutable absl::Mutex mutex_; + bool closed_ ABSL_GUARDED_BY(mutex_) = false; + std::unique_ptr input_stream_; + std::unique_ptr output_stream_; + api::ble_v2::BlePeripheral::UniqueId peripheral_id_; + absl::AnyInvocable close_notifier_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_BLE_L2CAP_SOCKET_H_ diff --git a/internal/platform/implementation/linux/ble_l2cap_socket_test.cc b/internal/platform/implementation/linux/ble_l2cap_socket_test.cc new file mode 100644 index 00000000..07107972 --- /dev/null +++ b/internal/platform/implementation/linux/ble_l2cap_socket_test.cc @@ -0,0 +1,117 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/linux/ble_l2cap_socket.h" + +#include +#include + +#include + +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "gtest/gtest.h" + +namespace nearby { +namespace linux { +namespace { + +class SocketPair final { + public: + SocketPair() { + int fds[2] = {-1, -1}; + ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds)); + left_ = fds[0]; + right_ = fds[1]; + } + + ~SocketPair() { + if (left_ >= 0) close(left_); + if (right_ >= 0) close(right_); + } + + int left() const { return left_; } + int right() const { return right_; } + + void CloseRight() { + if (right_ >= 0) { + close(right_); + right_ = -1; + } + } + + private: + int left_ = -1; + int right_ = -1; +}; + +TEST(BleL2capSocketTest, OutputStreamWritesData) { + SocketPair pair; + BleL2capSocket socket(pair.left(), /*peripheral_id=*/1); + + ByteArray payload("hello"); + Exception write_result = socket.GetOutputStream().Write(payload); + EXPECT_TRUE(write_result.Ok()); + + char buffer[5]; + ssize_t bytes_read = recv(pair.right(), buffer, sizeof(buffer), 0); + ASSERT_EQ(bytes_read, sizeof(buffer)); + EXPECT_EQ(std::string(buffer, sizeof(buffer)), "hello"); +} + +TEST(BleL2capSocketTest, InputStreamReadsData) { + SocketPair pair; + BleL2capSocket socket(pair.left(), /*peripheral_id=*/1); + + const char* payload = "world"; + ASSERT_EQ(send(pair.right(), payload, 5, 0), 5); + + ExceptionOr read_result = socket.GetInputStream().Read(5); + ASSERT_TRUE(read_result.ok()); + EXPECT_EQ(read_result.result().string_data(), "world"); +} + +TEST(BleL2capSocketTest, InputStreamReturnsEmptyOnPeerClose) { + SocketPair pair; + BleL2capSocket socket(pair.left(), /*peripheral_id=*/1); + + pair.CloseRight(); + ExceptionOr read_result = socket.GetInputStream().Read(4); + ASSERT_TRUE(read_result.ok()); + EXPECT_TRUE(read_result.result().Empty()); +} + +TEST(BleL2capSocketTest, OutputStreamWriteFailsAfterClose) { + SocketPair pair; + BleL2capSocket socket(pair.left(), /*peripheral_id=*/1); + + ASSERT_TRUE(socket.GetOutputStream().Close().Ok()); + Exception write_result = + socket.GetOutputStream().Write(ByteArray("data")); + EXPECT_EQ(write_result.value, Exception::kIo); +} + +TEST(BleL2capSocketTest, CloseNotifierInvoked) { + SocketPair pair; + BleL2capSocket socket(pair.left(), /*peripheral_id=*/1); + + bool notified = false; + socket.SetCloseNotifier([¬ified]() { notified = true; }); + ASSERT_TRUE(socket.Close().Ok()); + EXPECT_TRUE(notified); +} + +} // namespace +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/ble_v2_socket_adapter.cc b/internal/platform/implementation/linux/ble_v2_socket_adapter.cc new file mode 100644 index 00000000..e7245285 --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_socket_adapter.cc @@ -0,0 +1,130 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/linux/ble_v2_socket_adapter.h" + +#include "absl/status/status.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_v2_socket.h" +#include "internal/platform/logging.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { + +// Standard UUIDs for Nearby Connections GATT socket service +// RX: Remote writes to this, we read from it +constexpr uint64_t kRxCharMsb = 0x0000FE2C00001000ULL; +constexpr uint64_t kRxCharLsb = 0x800000805F9B34FBULL; + +// TX: We write to this (notify), remote reads from it +constexpr uint64_t kTxCharMsb = 0x0000FE2C00002000ULL; +constexpr uint64_t kTxCharLsb = 0x800000805F9B34FBULL; + +Uuid BleV2SocketAdapter::GetRxCharacteristicUuid() { + return Uuid(kRxCharMsb, kRxCharLsb); +} + +Uuid BleV2SocketAdapter::GetTxCharacteristicUuid() { + return Uuid(kTxCharMsb, kTxCharLsb); +} + +void BleV2SocketAdapter::RegisterSocket( + api::ble_v2::BlePeripheral::UniqueId device_id, BleV2Socket* socket) { + absl::MutexLock lock(&mutex_); + device_sockets_[device_id] = socket; + LOG(INFO) << "Registered socket for device " << device_id; +} + +void BleV2SocketAdapter::UnregisterSocket( + api::ble_v2::BlePeripheral::UniqueId device_id) { + absl::MutexLock lock(&mutex_); + device_sockets_.erase(device_id); + LOG(INFO) << "Unregistered socket for device " << device_id; +} + +api::ble_v2::ServerGattConnectionCallback +BleV2SocketAdapter::CreateServerCallbacks() { + api::ble_v2::ServerGattConnectionCallback callbacks; + + // Handle subscription to TX characteristic (remote wants to receive data) + callbacks.characteristic_subscription_cb = + [](const api::ble_v2::GattCharacteristic& characteristic) { + LOG(INFO) << "Remote subscribed to characteristic: " + << std::string(characteristic.uuid); + }; + + // Handle unsubscription + callbacks.characteristic_unsubscription_cb = + [](const api::ble_v2::GattCharacteristic& characteristic) { + LOG(INFO) << "Remote unsubscribed from characteristic: " + << std::string(characteristic.uuid); + }; + + // Handle read requests (not typically used for socket data transfer) + callbacks.on_characteristic_read_cb = + [](api::ble_v2::BlePeripheral::UniqueId remote_device_id, + const api::ble_v2::GattCharacteristic& characteristic, int offset, + api::ble_v2::ServerGattConnectionCallback::ReadValueCallback + callback) { + LOG(INFO) << "Read request from device " << remote_device_id + << " on characteristic " + << std::string(characteristic.uuid); + // Return empty data for reads + callback(absl::string_view("")); + }; + + // Handle write requests - THIS IS WHERE DATA COMES IN + callbacks.on_characteristic_write_cb = + [this](api::ble_v2::BlePeripheral::UniqueId remote_device_id, + const api::ble_v2::GattCharacteristic& characteristic, int offset, + absl::string_view data, + api::ble_v2::ServerGattConnectionCallback::WriteValueCallback + callback) { + LOG(INFO) << "Write request from device " << remote_device_id + << " on characteristic " + << std::string(characteristic.uuid) << ", data size: " + << data.size(); + + // Find the socket for this device + BleV2Socket* socket = nullptr; + { + absl::MutexLock lock(&mutex_); + auto it = device_sockets_.find(remote_device_id); + if (it != device_sockets_.end()) { + socket = it->second; + } + } + + if (socket) { + // Route the data to the socket's input stream + ByteArray byte_data(data.data(), data.size()); + socket->ReceiveData(byte_data); + callback(absl::OkStatus()); + LOG(INFO) << "Routed " << data.size() + << " bytes to socket input stream"; + } else { + LOG(WARNING) << "No socket registered for device " + << remote_device_id; + callback(absl::NotFoundError("No socket for device")); + } + }; + + return callbacks; +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/ble_v2_socket_adapter.h b/internal/platform/implementation/linux/ble_v2_socket_adapter.h new file mode 100644 index 00000000..1654d4fd --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_socket_adapter.h @@ -0,0 +1,66 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_ADAPTER_H_ +#define PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_ADAPTER_H_ + +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_v2_socket.h" +#include "internal/platform/uuid.h" + +namespace nearby { +namespace linux { + +// Helper class to adapt GATT server callbacks to socket data streams +// This wires up the ServerGattConnectionCallback to feed data into BleV2Socket +class BleV2SocketAdapter { + public: + BleV2SocketAdapter() = default; + ~BleV2SocketAdapter() = default; + + // Create GATT server callbacks that will route data to/from sockets + api::ble_v2::ServerGattConnectionCallback CreateServerCallbacks(); + + // Register a socket for a specific remote device + // When GATT writes come from this device, data is routed to this socket + void RegisterSocket(api::ble_v2::BlePeripheral::UniqueId device_id, + BleV2Socket* socket) ABSL_LOCKS_EXCLUDED(mutex_); + + // Unregister a socket + void UnregisterSocket(api::ble_v2::BlePeripheral::UniqueId device_id) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Get the RX characteristic UUID (for receiving data from remote) + static Uuid GetRxCharacteristicUuid(); + + // Get the TX characteristic UUID (for sending data to remote) + static Uuid GetTxCharacteristicUuid(); + + private: + absl::Mutex mutex_; + // Map of device ID to socket for routing incoming GATT writes + absl::flat_hash_map + device_sockets_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_ADAPTER_H_ diff --git a/internal/platform/implementation/linux/generated/dbus/bluez/le_bearer_client.h b/internal/platform/implementation/linux/generated/dbus/bluez/le_bearer_client.h new file mode 100644 index 00000000..55d2d46b --- /dev/null +++ b/internal/platform/implementation/linux/generated/dbus/bluez/le_bearer_client.h @@ -0,0 +1,76 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_dbus_bluez_le_bearer_client_h__proxy__H__ +#define __sdbuscpp___home_lasan_Dev_nearby_latest_internal_platform_implementation_linux_generated_dbus_bluez_le_bearer_client_h__proxy__H__ + +#include +#include +#include + +namespace org { +namespace bluez { +namespace Bearer { + +class LE1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.bluez.Bearer.LE1"; + +protected: + LE1_proxy(sdbus::IProxy& proxy) + : proxy_(&proxy) + { + proxy_->uponSignal("Disconnected").onInterface(INTERFACE_NAME).call([this](const std::string& reason, const std::string& message){ this->onDisconnected(reason, message); }); + } + + LE1_proxy(const LE1_proxy&) = delete; + LE1_proxy& operator=(const LE1_proxy&) = delete; + LE1_proxy(LE1_proxy&&) = default; + LE1_proxy& operator=(LE1_proxy&&) = default; + + ~LE1_proxy() = default; + + virtual void onDisconnected(const std::string& reason, const std::string& message) = 0; + +public: + void Connect() + { + proxy_->callMethod("Connect").onInterface(INTERFACE_NAME); + } + + void Disconnect() + { + proxy_->callMethod("Disconnect").onInterface(INTERFACE_NAME); + } + +public: + sdbus::ObjectPath Adapter() + { + return proxy_->getProperty("Adapter").onInterface(INTERFACE_NAME); + } + + bool Paired() + { + return proxy_->getProperty("Paired").onInterface(INTERFACE_NAME); + } + + bool Bonded() + { + return proxy_->getProperty("Bonded").onInterface(INTERFACE_NAME); + } + + bool Connected() + { + return proxy_->getProperty("Connected").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy* proxy_; +}; + +}}} // namespaces + +#endif From a61607360ce826096c75f2910fa060b187d4cbec Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Wed, 14 Jan 2026 13:17:13 +0000 Subject: [PATCH 188/201] Implemented gatt discovery and setting gatt characteristics --- .../implementation/linux/ble_gatt_client.cc | 84 ++++-- .../implementation/linux/ble_gatt_client.h | 2 +- .../implementation/linux/ble_gatt_server.cc | 5 +- .../implementation/linux/ble_v2_medium.cc | 68 ++++- .../implementation/linux/ble_v2_medium.h | 5 +- .../linux/ble_v2_server_socket.cc | 86 ++++++ .../implementation/linux/ble_v2_socket.cc | 264 ++++++++++++++++++ .../implementation/linux/ble_v2_socket.h | 138 +++++++++ .../linux/bluetooth_classic_device.cc | 15 +- .../linux/bluetooth_classic_device.h | 2 + .../linux/bluez_le_bearer_client.h | 79 ++++++ 11 files changed, 708 insertions(+), 40 deletions(-) create mode 100644 internal/platform/implementation/linux/ble_v2_server_socket.cc create mode 100644 internal/platform/implementation/linux/ble_v2_socket.cc create mode 100644 internal/platform/implementation/linux/ble_v2_socket.h create mode 100644 internal/platform/implementation/linux/bluez_le_bearer_client.h diff --git a/internal/platform/implementation/linux/ble_gatt_client.cc b/internal/platform/implementation/linux/ble_gatt_client.cc index d3fd0451..e7b02732 100644 --- a/internal/platform/implementation/linux/ble_gatt_client.cc +++ b/internal/platform/implementation/linux/ble_gatt_client.cc @@ -219,20 +219,29 @@ bool BluezGattDiscovery::InitializeKnownServices() { 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; +for (; chr_it != objects.cend(); ++chr_it) { + const auto& [path, ifaces] = *chr_it; - 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)); + auto iface_it = ifaces.find(org::bluez::GattCharacteristic1_proxy::INTERFACE_NAME); + if (iface_it == ifaces.end()) { + // Not a GattCharacteristic1 object (or interfaces map incomplete) -> skip + continue; } + const auto& properties = iface_it->second; + + auto maybe_props = characteristicProperties(path, properties); + if (!maybe_props.has_value()) continue; + + auto [chr_uuid, service_uuid, device_path] = *maybe_props; + + discovered_characteristics_.emplace( + std::make_tuple(chr_uuid, service_uuid, device_path), path); + + characteristics_properties_.emplace( + path, std::make_tuple(chr_uuid, service_uuid, device_path)); +} + return true; } @@ -282,6 +291,8 @@ bool BluezGattDiscovery::DiscoverServiceAndCharacteristics( }; absl::ReaderMutexLock lock(&mutex_, absl::Condition(&discovered)); + + LOG(INFO) << __func__ << ": Finished discovering gatt services and characteristics"; return !cancel.Cancelled(); } @@ -331,7 +342,7 @@ BluezGattDiscovery::GetSubscribedCharacteristic( std::optional> BluezGattDiscovery::characteristicProperties( - const sdbus::ObjectPath &path, + const sdbus::ObjectPath &char_path, const std::map &properties) { mutex_.AssertHeld(); @@ -339,31 +350,41 @@ BluezGattDiscovery::characteristicProperties( auto chr_uuid = UuidFromString(chr_uuid_str); if (!chr_uuid.has_value()) { LOG(ERROR) << ": Couldn't parse UUID '" << chr_uuid_str - << "' in characteristic " << path; + << "' in characteristic " << char_path; return std::nullopt; } const sdbus::ObjectPath &service_path = properties.at("Service"); if (cached_services_.count(service_path) == 0) { cached_services_.emplace( - path, std::make_unique(system_bus_, path)); + service_path, std::make_unique(system_bus_, service_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()) { - LOG(ERROR) << ": Couldn't parse UUID '" << service_uuid_str - << "' in service " << service_path; - return std::nullopt; - } - service_uuid = *service_uuid_maybe; - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(service, "UUID", e); +auto it = cached_services_.find(service_path); +if (it == cached_services_.end() || it->second == nullptr) { + LOG(ERROR) << ": cached_services_ missing service " << service_path + << " (from characteristic " << char_path << ")"; + return std::nullopt; +} + + LOG(INFO) << ": Found service path " << service_path + << " (from characteristic " << char_path << ")"; + auto* service = it->second.get(); // service is GattServiceClient* +nearby::Uuid service_uuid; +try { + std::string service_uuid_str = service->UUID(); // copy (safe) + auto service_uuid_maybe = UuidFromString(service_uuid_str); + + if (!service_uuid_maybe.has_value()) { + LOG(ERROR) << ": Couldn't parse UUID '" << service_uuid_str + << "' in service " << service_path; return std::nullopt; } + service_uuid = *service_uuid_maybe; +} catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(service, "UUID", e); + return std::nullopt; +} sdbus::ObjectPath device_path; try { @@ -417,7 +438,14 @@ void BluezGattDiscovery::onInterfacesRemoved( if (chr_it != end) { absl::MutexLock lock(&mutex_); { - auto &props = characteristics_properties_.at(objectPath); + auto it = characteristics_properties_.find(objectPath); + if (it == characteristics_properties_.end()) { + // Not tracked / already removed / never added. + // return; // or just `break;` / `continue;` depending on your context + return; + } + + auto &props = it->second; discovered_characteristics_.erase(props); } characteristics_properties_.erase(objectPath); diff --git a/internal/platform/implementation/linux/ble_gatt_client.h b/internal/platform/implementation/linux/ble_gatt_client.h index f86f9970..452b79a0 100644 --- a/internal/platform/implementation/linux/ble_gatt_client.h +++ b/internal/platform/implementation/linux/ble_gatt_client.h @@ -76,7 +76,7 @@ class BluezGattDiscovery final : public bluez::BluezObjectManager { private: std::optional> characteristicProperties( - const sdbus::ObjectPath &path, + const sdbus::ObjectPath &char_path, const std::map &properties) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); diff --git a/internal/platform/implementation/linux/ble_gatt_server.cc b/internal/platform/implementation/linux/ble_gatt_server.cc index 0c2089ea..1c94361c 100644 --- a/internal/platform/implementation/linux/ble_gatt_server.cc +++ b/internal/platform/implementation/linux/ble_gatt_server.cc @@ -61,7 +61,9 @@ GattServer::CreateCharacteristic( if (service->AddCharacteristic(service_uuid, characteristic_uuid, permission, property)) { try { - LOG(INFO)<< __func__ << ": Registering service on gattmanager"; + LOG(INFO)<< __func__ << ": Registering service on gattmanager with characteristic_uuid: " + << std::string(characteristic_uuid) << " and service_uuid: " << std::string(service_uuid); + gatt_manager_ -> RegisterApplication(gatt_service_root_object_manager -> getObjectPath(), {}); } catch (const sdbus::Error& e) { LOG(ERROR) @@ -75,6 +77,7 @@ GattServer::CreateCharacteristic( services_.insert({service_uuid, std::move(service)}); + api::ble_v2::GattCharacteristic characteristic{ characteristic_uuid, service_uuid, permission, property}; return characteristic; diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 518f44c7..2be204b0 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include #include @@ -29,11 +31,16 @@ // #include "internal/platform/implementation/linux/ble_gatt_server.h" #include "internal/platform/implementation/linux/ble_v2_medium.h" +#include "ble_gatt_client.h" #include "ble_gatt_server.h" +#include "ble_l2cap_server_socket.h" +#include "ble_l2cap_socket.h" +#include "bluez_le_bearer_client.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/mac_address.h" +#include "internal/platform/prng.h" #include "absl/types/span.h" #include "internal/platform/implementation/linux/bluez_advertisement_monitor.h" #include "internal/platform/implementation/linux/bluez_advertisement_monitor_manager.h" @@ -219,6 +226,7 @@ BleV2Medium::StartAdvertising( std::unique_ptr BleV2Medium::StartGattServer( api::ble_v2::ServerGattConnectionCallback callback) { (void)callback; + return nullptr; return std::make_unique( *system_bus_, adapter_, devices_,std::move(callback) @@ -236,13 +244,12 @@ std::unique_ptr BleV2Medium::ConnectToGattServer( << ": GATT client connection is not supported on Linux yet."; return nullptr; } - + // This is supposed to be for a socket on top of Weave protocol. std::unique_ptr BleV2Medium::Connect( const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::BlePeripheral::UniqueId peripheral_id, CancellationFlag *cancellation_flag) { - auto device = devices_ -> get_device_by_unique_id(peripheral_id); - LOG(INFO) << __func__ << ": Resolved device with address " << device -> GetMacAddress(); + LOG(INFO) << __func__ << ": Not implemented on linux "; return nullptr; } @@ -498,8 +505,16 @@ std::unique_ptr BleV2Medium::OpenServerSocket( std::unique_ptr BleV2Medium::OpenL2capServerSocket(const std::string &service_id) { - LOG(WARNING) << __func__ << ": L2CAP server sockets not implemented on Linux"; - return nullptr; + LOG(INFO) << __func__ << ": Opening L2CAP server socket for service " + << service_id; + + Prng prng; + auto psm = 0x80 + (prng.NextUint32() % 0x80); + auto server_socket = std::make_unique(psm); + + LOG(INFO) << __func__ << ": L2CAP server socket created with PSM: " + << server_socket->GetPSM(); + return server_socket; } // std::unique_ptr BleV2Medium::Connect( @@ -515,8 +530,47 @@ std::unique_ptr BleV2Medium::ConnectOverL2cap( api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::BlePeripheral::UniqueId peripheral_id, CancellationFlag *cancellation_flag) { - LOG(WARNING) << __func__ << ": L2CAP socket connections not implemented on Linux"; - return nullptr; + auto device = devices_->get_device_by_unique_id(peripheral_id); + if (!device) { + LOG(ERROR) << __func__ << ": Failed to find device with unique ID " + << peripheral_id; + return nullptr; + } + + LOG(INFO) << __func__ << ": Connecting to L2CAP PSM " << psm + << " on device " << device->GetMacAddress(); + + + int fd = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (fd < 0) { + LOG(ERROR) << __func__ << ": Failed to create L2CAP socket: " + << std::strerror(errno); + return nullptr; + } + + struct sockaddr_l2 addr; + std::memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + addr.l2_psm = htobs(psm); + addr.l2_cid = 0; + addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; + + std::string mac_addr = device->GetMacAddress(); + if (str2ba(mac_addr.c_str(), &addr.l2_bdaddr) < 0) { + LOG(ERROR) << __func__ << ": Invalid Bluetooth address: " << mac_addr; + close(fd); + return nullptr; + } + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + LOG(ERROR) << __func__ << ": Failed to connect to L2CAP socket: " + << std::strerror(errno); + close(fd); + return nullptr; + } + + LOG(INFO) << __func__ << ": Successfully connected to L2CAP socket"; + return std::make_unique(fd, peripheral_id); } bool BleV2Medium::StartMultipleServicesScanning( diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index a1187a3f..fdbcce1b 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -26,7 +26,10 @@ #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/ble_v2.h" // #include "internal/platform/implementation/linux/ble_gatt_client.h" +#include "ble_gatt_client.h" #include "bluez_gatt_manager.h" +#include "internal/platform/implementation/linux/ble_l2cap_server_socket.h" +#include "internal/platform/implementation/linux/ble_l2cap_socket.h" #include "internal/platform/implementation/linux/ble_v2_server_socket.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" @@ -141,7 +144,7 @@ class BleV2Medium final : public api::ble_v2::BleMedium { BluetoothAdapter adapter_; ObserverList observers_ = {}; std::shared_ptr devices_; - // std::shared_ptr gatt_discovery_; + std::shared_ptr gatt_discovery_; std::unique_ptr root_object_manager_; std::unique_ptr adv_monitor_manager_; diff --git a/internal/platform/implementation/linux/ble_v2_server_socket.cc b/internal/platform/implementation/linux/ble_v2_server_socket.cc new file mode 100644 index 00000000..240de1e0 --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_server_socket.cc @@ -0,0 +1,86 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/linux/ble_v2_server_socket.h" + +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/implementation/linux/ble_v2_socket.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +std::unique_ptr BleV2ServerSocket::Accept() { + absl::MutexLock lock(&mutex_); + LOG(INFO) << "BleV2ServerSocket::Accept waiting for connection"; + + while (!closed_ && pending_sockets_.empty()) { + cond_.Wait(&mutex_); + } + + if (closed_) { + LOG(INFO) << "BleV2ServerSocket::Accept socket is closed"; + return nullptr; + } + + std::unique_ptr socket = std::move(pending_sockets_.front()); + pending_sockets_.pop_front(); + + LOG(INFO) << "BleV2ServerSocket::Accept accepted connection"; + return socket; +} + +Exception BleV2ServerSocket::Close() { + absl::MutexLock lock(&mutex_); + LOG(INFO) << "BleV2ServerSocket::Close for service " << service_id_; + + if (closed_) { + return {Exception::kSuccess}; + } + + closed_ = true; + + // Close all pending sockets + for (auto& socket : pending_sockets_) { + if (socket) { + socket->Close(); + } + } + pending_sockets_.clear(); + + cond_.SignalAll(); + + return {Exception::kSuccess}; +} + +void BleV2ServerSocket::AddPendingSocket(std::unique_ptr socket) { + absl::MutexLock lock(&mutex_); + if (closed_) { + LOG(WARNING) + << "BleV2ServerSocket::AddPendingSocket socket is closed"; + return; + } + + pending_sockets_.push_back(std::move(socket)); + cond_.SignalAll(); + LOG(INFO) << "BleV2ServerSocket::AddPendingSocket added socket, " + << "pending count: " << pending_sockets_.size(); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/ble_v2_socket.cc b/internal/platform/implementation/linux/ble_v2_socket.cc new file mode 100644 index 00000000..b58303e2 --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_socket.cc @@ -0,0 +1,264 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "internal/platform/implementation/linux/ble_v2_socket.h" + +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +InputStream& BleV2Socket::GetInputStream() { return input_stream_; } + +OutputStream& BleV2Socket::GetOutputStream() { return output_stream_; } + +Exception BleV2Socket::Close() { + absl::MutexLock lock(&mutex_); + if (closed_) { + return {Exception::kSuccess}; + } + closed_ = true; + + // Close streams + input_stream_.NotifyClose(); + output_stream_.Close(); + + // Cleanup GATT resources + if (gatt_client_) { + LOG(INFO) << "Disconnecting GATT client for peripheral " + << peripheral_id_; + gatt_client_->Disconnect(); + gatt_client_.reset(); + } + + if (gatt_server_) { + LOG(INFO) << "Stopping GATT server for peripheral " + << peripheral_id_; + // Server cleanup is handled by the server itself + gatt_server_.reset(); + } + + return {Exception::kSuccess}; +} + +bool BleV2Socket::IsClosed() const { + absl::MutexLock lock(&mutex_); + return closed_; +} + +// BleInputStream implementation +ExceptionOr BleV2Socket::BleInputStream::Read(std::int64_t size) { + absl::MutexLock lock(&mutex_); + + while (buffer_.Empty() && !closed_) { + cond_.Wait(&mutex_); + } + + if (closed_ && buffer_.Empty()) { + return ExceptionOr(Exception::kIo); + } + + if (size < 0 || static_cast(size) >= buffer_.size()) { + ByteArray result = buffer_; + buffer_ = ByteArray(); + return ExceptionOr(result); + } + + ByteArray result(buffer_.data(), size); + buffer_ = ByteArray(buffer_.data() + size, buffer_.size() - size); + return ExceptionOr(result); +} + +Exception BleV2Socket::BleInputStream::Close() { + absl::MutexLock lock(&mutex_); + if (closed_) { + return {Exception::kSuccess}; + } + closed_ = true; + cond_.SignalAll(); + return {Exception::kSuccess}; +} + +void BleV2Socket::BleInputStream::ReceiveData(const ByteArray& data) { + absl::MutexLock lock(&mutex_); + if (closed_) { + return; + } + + if (buffer_.Empty()) { + buffer_ = data; + } else { + ByteArray combined(buffer_.size() + data.size()); + std::memcpy(combined.data(), buffer_.data(), buffer_.size()); + std::memcpy(combined.data() + buffer_.size(), data.data(), data.size()); + buffer_ = std::move(combined); + } + cond_.SignalAll(); +} + +void BleV2Socket::BleInputStream::NotifyClose() { + absl::MutexLock lock(&mutex_); + closed_ = true; + cond_.SignalAll(); +} + +// BleOutputStream implementation +Exception BleV2Socket::BleOutputStream::Write(const ByteArray& data) { + absl::MutexLock lock(&mutex_); + if (closed_) { + return {Exception::kIo}; + } + + if (!write_callback_) { + LOG(WARNING) << "BleOutputStream: No write callback set"; + return {Exception::kIo}; + } + + bool success = write_callback_(data); + return {success ? Exception::kSuccess : Exception::kIo}; +} + +Exception BleV2Socket::BleOutputStream::Flush() { + return {Exception::kSuccess}; +} + +Exception BleV2Socket::BleOutputStream::Close() { + absl::MutexLock lock(&mutex_); + if (closed_) { + return {Exception::kSuccess}; + } + closed_ = true; + write_callback_ = nullptr; + return {Exception::kSuccess}; +} + +void BleV2Socket::BleOutputStream::SetWriteCallback(WriteCallback callback) { + absl::MutexLock lock(&mutex_); + write_callback_ = std::move(callback); +} + +void BleV2Socket::SetGattServer( + std::unique_ptr gatt_server, + const api::ble_v2::GattCharacteristic& rx_char, + const api::ble_v2::GattCharacteristic& tx_char) { + absl::MutexLock lock(&mutex_); + + if (closed_) { + LOG(WARNING) << "Cannot set GATT server on closed socket"; + return; + } + + gatt_server_ = std::move(gatt_server); + rx_char_ = rx_char; + tx_char_ = tx_char; + + // Set up write callback to use GATT server notifications + output_stream_.SetWriteCallback( + [this](const ByteArray& data) -> bool { + absl::MutexLock lock(&mutex_); + if (!gatt_server_) { + LOG(ERROR) << "GATT server not available for write"; + return false; + } + + if (closed_) { + LOG(WARNING) << "Socket is closed, cannot write"; + return false; + } + + // Notify remote device via TX characteristic + absl::Status status = gatt_server_->NotifyCharacteristicChanged( + tx_char_, /*confirm=*/false, data); + + if (!status.ok()) { + LOG(WARNING) << "Failed to notify TX characteristic: " + << status.message(); + return false; + } + return true; + }); + + LOG(INFO) << "BLE socket configured with GATT server, RX: " + << std::string(rx_char.uuid) + << ", TX: " << std::string(tx_char.uuid); +} + +void BleV2Socket::SetGattClient( + std::unique_ptr gatt_client, + const api::ble_v2::GattCharacteristic& rx_char, + const api::ble_v2::GattCharacteristic& tx_char) { + absl::MutexLock lock(&mutex_); + + if (closed_) { + LOG(WARNING) << "Cannot set GATT client on closed socket"; + return; + } + + gatt_client_ = std::move(gatt_client); + rx_char_ = rx_char; + tx_char_ = tx_char; + + // Set up write callback to use GATT client writes + output_stream_.SetWriteCallback( + [this](const ByteArray& data) -> bool { + absl::MutexLock lock(&mutex_); + if (!gatt_client_) { + LOG(ERROR) << "GATT client not available for write"; + return false; + } + + if (closed_) { + LOG(WARNING) << "Socket is closed, cannot write"; + return false; + } + + // Write to TX characteristic on remote device + std::string data_str(data.data(), data.size()); + bool success = gatt_client_->WriteCharacteristic( + tx_char_, data_str, + api::ble_v2::GattClient::WriteType::kWithoutResponse); + + if (!success) { + LOG(WARNING) << "Failed to write to TX characteristic"; + return false; + } + return true; + }); + + // Subscribe to RX characteristic to receive data + bool subscribed = gatt_client_->SetCharacteristicSubscription( + rx_char_, /*enable=*/true, + [this](absl::string_view value) { + if (!IsClosed()) { + ByteArray data(value.data(), value.size()); + input_stream_.ReceiveData(data); + } + }); + + if (!subscribed) { + LOG(ERROR) << "Failed to subscribe to RX characteristic"; + } + + LOG(INFO) << "BLE socket configured with GATT client, RX: " + << std::string(rx_char.uuid) + << ", TX: " << std::string(tx_char.uuid); +} + +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/ble_v2_socket.h b/internal/platform/implementation/linux/ble_v2_socket.h new file mode 100644 index 00000000..82ea93c2 --- /dev/null +++ b/internal/platform/implementation/linux/ble_v2_socket.h @@ -0,0 +1,138 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_H_ +#define PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_H_ + +#include +#include + +#include "absl/synchronization/mutex.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/ble_v2.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" + +namespace nearby { +namespace linux { + +// BLE v2 Socket implementation using GATT characteristics for data transfer +// +// Data flow: +// - Server side: +// * RX characteristic: Remote writes -> our InputStream reads +// * TX characteristic: Our OutputStream writes -> remote reads via notifications +// - Client side: +// * TX characteristic: Our OutputStream writes -> remote reads +// * RX characteristic: Remote writes (notifications) -> our InputStream reads +class BleV2Socket : public api::ble_v2::BleSocket { + public: + BleV2Socket() = default; + explicit BleV2Socket(api::ble_v2::BlePeripheral::UniqueId peripheral_id) + : peripheral_id_(peripheral_id) {} + ~BleV2Socket() override { Close(); } + + InputStream& GetInputStream() override; + OutputStream& GetOutputStream() override; + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + api::ble_v2::BlePeripheral::UniqueId GetRemotePeripheralId() override { + return peripheral_id_; + } + + bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_); + + // GATT integration: Allow external code to feed data to input stream + // Called when remote device writes to RX characteristic + void ReceiveData(const ByteArray& data) { input_stream_.ReceiveData(data); } + + // GATT integration: Set callback for output stream writes + // Callback should write to TX characteristic (notify remote) + void SetWriteCallback( + absl::AnyInvocable callback) { + output_stream_.SetWriteCallback(std::move(callback)); + } + + // Set the GATT server and characteristics for server-side socket + void SetGattServer(std::unique_ptr gatt_server, + const api::ble_v2::GattCharacteristic& rx_char, + const api::ble_v2::GattCharacteristic& tx_char) + ABSL_LOCKS_EXCLUDED(mutex_); + + // Set the GATT client and characteristics for client-side socket + void SetGattClient(std::unique_ptr gatt_client, + const api::ble_v2::GattCharacteristic& rx_char, + const api::ble_v2::GattCharacteristic& tx_char) + ABSL_LOCKS_EXCLUDED(mutex_); + + private: + class BleInputStream : public InputStream { + public: + BleInputStream() = default; + ~BleInputStream() override = default; + + ExceptionOr Read(std::int64_t size) override + ABSL_LOCKS_EXCLUDED(mutex_); + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + void ReceiveData(const ByteArray& data) ABSL_LOCKS_EXCLUDED(mutex_); + void NotifyClose() ABSL_LOCKS_EXCLUDED(mutex_); + + private: + absl::Mutex mutex_; + absl::CondVar cond_; + ByteArray buffer_ ABSL_GUARDED_BY(mutex_); + bool closed_ ABSL_GUARDED_BY(mutex_) = false; + }; + + class BleOutputStream : public OutputStream { + public: + BleOutputStream() = default; + ~BleOutputStream() override = default; + + Exception Write(const ByteArray& data) override + ABSL_LOCKS_EXCLUDED(mutex_); + Exception Flush() override; + Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_); + + using WriteCallback = absl::AnyInvocable; + void SetWriteCallback(WriteCallback callback) + ABSL_LOCKS_EXCLUDED(mutex_); + + private: + absl::Mutex mutex_; + WriteCallback write_callback_ ABSL_GUARDED_BY(mutex_); + bool closed_ ABSL_GUARDED_BY(mutex_) = false; + }; + + mutable absl::Mutex mutex_; + bool closed_ ABSL_GUARDED_BY(mutex_) = false; + BleInputStream input_stream_; + BleOutputStream output_stream_; + api::ble_v2::BlePeripheral::UniqueId peripheral_id_ = 0; + + // GATT resources (only one of these will be set) + std::unique_ptr gatt_server_ ABSL_GUARDED_BY(mutex_); + std::unique_ptr gatt_client_ ABSL_GUARDED_BY(mutex_); + + // Characteristics for data transfer + api::ble_v2::GattCharacteristic rx_char_ ABSL_GUARDED_BY(mutex_); + api::ble_v2::GattCharacteristic tx_char_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_API_BLE_V2_SOCKET_H_ diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.cc b/internal/platform/implementation/linux/bluetooth_classic_device.cc index 9805994c..007b1909 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_device.cc @@ -107,7 +107,18 @@ bool BluetoothDevice::ConnectToProfile(absl::string_view service_uuid) { } } -MonitoredBluetoothDevice::MonitoredBluetoothDevice( + bool BluetoothDevice::Connect() { + auto device = device_; + if (device == nullptr) return false; + try { + device->Connect(); + return true; + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(device, "Connect", e); + return false; + } +} + MonitoredBluetoothDevice::MonitoredBluetoothDevice( std::shared_ptr system_bus, std::shared_ptr device, ObserverList &observers) @@ -152,7 +163,7 @@ void MonitoredBluetoothDevice::onPropertiesChanged( observer->DeviceConnectedStateChanged(*this, it->second); } } else if ( it -> first == "ServicesResolved"){ - LOG(INFO) << ": ServicesResolved"; + LOG(INFO) << ": ServicesResolved :" << std::string(it->second); }else if (it->first == bluez::DEVICE_NAME) { auto callback = GetDiscoveryCallback(); if (callback != nullptr && callback->device_name_changed_cb != nullptr) diff --git a/internal/platform/implementation/linux/bluetooth_classic_device.h b/internal/platform/implementation/linux/bluetooth_classic_device.h index d4310644..27d0b7e7 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_device.h +++ b/internal/platform/implementation/linux/bluetooth_classic_device.h @@ -111,9 +111,11 @@ class BluetoothDevice : public api::BluetoothDevice { } bool ConnectToProfile(absl::string_view service_uuid); + bool Connect(); void MarkLost() { lost_ = true; } void UnmarkLost() { lost_ = false; } bool Lost() const { return lost_; } + sdbus::ObjectPath GetObjectPath() {return device_->getObjectPath();} private: UniqueId unique_id_; diff --git a/internal/platform/implementation/linux/bluez_le_bearer_client.h b/internal/platform/implementation/linux/bluez_le_bearer_client.h new file mode 100644 index 00000000..571bcf6d --- /dev/null +++ b/internal/platform/implementation/linux/bluez_le_bearer_client.h @@ -0,0 +1,79 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef PLATFORM_IMPL_LINUX_LE_BEARER_CLIENT_H_ +#define PLATFORM_IMPL_LINUX_LE_BEARER_CLIENT_H_ + +#include +#include + +#include +#include +#include + +#include "absl/functional/any_invocable.h" +#include "absl/synchronization/mutex.h" +#include "internal/platform/implementation/linux/generated/dbus/bluez/le_bearer_client.h" + +namespace nearby { +namespace linux { +namespace bluez { + +class LEBearerClient + : public sdbus::ProxyInterfaces { + public: + LEBearerClient(std::shared_ptr system_bus, + sdbus::ObjectPath bearer_path) + : ProxyInterfaces(*system_bus, "org.bluez", std::move(bearer_path)), + system_bus_(std::move(system_bus)) { + registerProxy(); + } + ~LEBearerClient() { unregisterProxy(); } + + void SetDisconnectedCallback( + absl::AnyInvocable cb) + ABSL_LOCKS_EXCLUDED(disconnect_callback_lock_) { + absl::MutexLock l(&disconnect_callback_lock_); + on_disconnected_cb_ = std::move(cb); + } + + void ResetDisconnectedCallback() + ABSL_LOCKS_EXCLUDED(disconnect_callback_lock_) { + absl::MutexLock l(&disconnect_callback_lock_); + on_disconnected_cb_ = nullptr; + } + + protected: + void onDisconnected(const std::string& reason, + const std::string& message) override + ABSL_LOCKS_EXCLUDED(disconnect_callback_lock_) { + absl::ReaderMutexLock l(&disconnect_callback_lock_); + if (on_disconnected_cb_ != nullptr) { + on_disconnected_cb_(reason, message); + } + } + + private: + std::shared_ptr system_bus_; + absl::Mutex disconnect_callback_lock_; + absl::AnyInvocable + on_disconnected_cb_ ABSL_GUARDED_BY(disconnect_callback_lock_) = nullptr; +}; + +} // namespace bluez +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_LE_BEARER_CLIENT_H_ From a8f706c8018d71dbb9abd06fb64c6c64c36414d9 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 17 Jan 2026 08:15:17 +0000 Subject: [PATCH 189/201] Fixed a segfault with dangling listeners --- connections/core.cc | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/connections/core.cc b/connections/core.cc index 61b77422..84e733c8 100644 --- a/connections/core.cc +++ b/connections/core.cc @@ -15,6 +15,7 @@ #include "connections/core.h" #include +#include #include #include #include @@ -215,13 +216,15 @@ void Core::StartAdvertisingV3(absl::string_view service_id, const NearbyDevice& local_device, v3::ConnectionListener listener, ResultCallback callback) { + auto listener_ptr = + std::make_shared(std::move(listener)); ConnectionListener old_listener = { .initiated_cb = - [&listener](const std::string& endpoint_id, - const ConnectionResponseInfo& info) { + [listener_ptr](const std::string& endpoint_id, + const ConnectionResponseInfo& info) { auto remote_device = v3::ConnectionsDevice( endpoint_id, info.remote_endpoint_info.AsStringView(), {}); - listener.initiated_cb( + listener_ptr->initiated_cb( remote_device, v3::InitialConnectionInfo{ .authentication_digits = info.authentication_token, @@ -231,7 +234,7 @@ void Core::StartAdvertisingV3(absl::string_view service_id, }); }, .accepted_cb = - [v3_cb = listener.result_cb](const std::string& endpoint_id) { + [v3_cb = listener_ptr->result_cb](const std::string& endpoint_id) { auto remote_device = v3::ConnectionsDevice(endpoint_id, "", {}); v3_cb(remote_device, v3::ConnectionResult{.status = Status{ @@ -239,23 +242,23 @@ void Core::StartAdvertisingV3(absl::string_view service_id, }}); }, .rejected_cb = - [v3_cb = listener.result_cb](const std::string& endpoint_id, - Status status) { + [v3_cb = listener_ptr->result_cb](const std::string& endpoint_id, + Status status) { auto remote_device = v3::ConnectionsDevice(endpoint_id, "", {}); v3_cb(remote_device, v3::ConnectionResult{ .status = status, }); }, .disconnected_cb = - [&listener](const std::string& endpoint_id) { + [listener_ptr](const std::string& endpoint_id) { auto remote_device = v3::ConnectionsDevice(endpoint_id, "", {}); - listener.disconnected_cb(remote_device); + listener_ptr->disconnected_cb(remote_device); }, .bandwidth_changed_cb = - [&listener](const std::string& endpoint_id, Medium medium) { + [listener_ptr](const std::string& endpoint_id, Medium medium) { auto remote_device = v3::ConnectionsDevice(endpoint_id, "", {}); - listener.bandwidth_changed_cb(remote_device, - v3::BandwidthInfo{.medium = medium}); + listener_ptr->bandwidth_changed_cb( + remote_device, v3::BandwidthInfo{.medium = medium}); }}; ByteArray local_endpoint_info; if (local_device.GetType() == NearbyDevice::kConnectionsDevice) { From d12be6731954a8dad0cc66f20ff46bff2daba399 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 17 Jan 2026 08:46:49 +0000 Subject: [PATCH 190/201] Made ble_v2_medium and bluetooth_classic_medium share a devices_ --- .../implementation/linux/ble_v2_medium.cc | 118 ++++++++++-------- .../implementation/linux/ble_v2_medium.h | 4 +- .../linux/bluetooth_classic_medium.cc | 26 ++-- .../implementation/linux/bluetooth_devices.cc | 25 ++++ .../implementation/linux/bluetooth_devices.h | 10 ++ 5 files changed, 118 insertions(+), 65 deletions(-) diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index 2be204b0..d04f5181 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -54,8 +54,7 @@ namespace linux { BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) : system_bus_(adapter.GetConnection()), adapter_(adapter), - devices_(std::make_unique( - system_bus_, adapter_.GetObjectPath(), observers_)), + devices_(nullptr), // gatt_discovery_(std::make_shared(system_bus_)), root_object_manager_(std::make_unique(*system_bus_, "/com/google/nearby/medium/ble/advertisement/monitor")), adv_monitor_manager_( @@ -64,6 +63,10 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) adv_manager_(std::make_unique(*system_bus_, adapter)), cur_adv_(nullptr) { + auto shared = + GetSharedBluetoothDevices(system_bus_, adapter_.GetObjectPath()); + observers_ = shared->observers; + devices_ = shared->devices; if (adv_monitor_manager_) { LOG(INFO) << __func__ @@ -279,7 +282,12 @@ bool BleV2Medium::StartLEDiscovery() { try { LOG(INFO) << __func__ << ": Starting LE discovery on " << adapter.getObjectPath(); - adapter.StartDiscovery(); + if (!adapter.Discovering()) + { + LOG(INFO)<< __func__ << ": Not discovering. Starting discovery"; + adapter.StartDiscovery(); + } + } catch (const sdbus::Error &e) { if (e.getName() != "org.bluez.Error.InProgress") { DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); @@ -505,16 +513,17 @@ std::unique_ptr BleV2Medium::OpenServerSocket( std::unique_ptr BleV2Medium::OpenL2capServerSocket(const std::string &service_id) { - LOG(INFO) << __func__ << ": Opening L2CAP server socket for service " - << service_id; - - Prng prng; - auto psm = 0x80 + (prng.NextUint32() % 0x80); - auto server_socket = std::make_unique(psm); - - LOG(INFO) << __func__ << ": L2CAP server socket created with PSM: " - << server_socket->GetPSM(); - return server_socket; + return nullptr; + // LOG(INFO) << __func__ << ": Opening L2CAP server socket for service " + // << service_id; + // + // Prng prng; + // auto psm = 0x80 + (prng.NextUint32() % 0x80); + // auto server_socket = std::make_unique(psm); + // + // LOG(INFO) << __func__ << ": L2CAP server socket created with PSM: " + // << server_socket->GetPSM(); + // return server_socket; } // std::unique_ptr BleV2Medium::Connect( @@ -530,47 +539,48 @@ std::unique_ptr BleV2Medium::ConnectOverL2cap( api::ble_v2::TxPowerLevel tx_power_level, api::ble_v2::BlePeripheral::UniqueId peripheral_id, CancellationFlag *cancellation_flag) { - auto device = devices_->get_device_by_unique_id(peripheral_id); - if (!device) { - LOG(ERROR) << __func__ << ": Failed to find device with unique ID " - << peripheral_id; - return nullptr; - } - - LOG(INFO) << __func__ << ": Connecting to L2CAP PSM " << psm - << " on device " << device->GetMacAddress(); - - - int fd = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); - if (fd < 0) { - LOG(ERROR) << __func__ << ": Failed to create L2CAP socket: " - << std::strerror(errno); - return nullptr; - } - - struct sockaddr_l2 addr; - std::memset(&addr, 0, sizeof(addr)); - addr.l2_family = AF_BLUETOOTH; - addr.l2_psm = htobs(psm); - addr.l2_cid = 0; - addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; - - std::string mac_addr = device->GetMacAddress(); - if (str2ba(mac_addr.c_str(), &addr.l2_bdaddr) < 0) { - LOG(ERROR) << __func__ << ": Invalid Bluetooth address: " << mac_addr; - close(fd); - return nullptr; - } - - if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { - LOG(ERROR) << __func__ << ": Failed to connect to L2CAP socket: " - << std::strerror(errno); - close(fd); - return nullptr; - } - - LOG(INFO) << __func__ << ": Successfully connected to L2CAP socket"; - return std::make_unique(fd, peripheral_id); + return nullptr; + // auto device = devices_->get_device_by_unique_id(peripheral_id); + // if (!device) { + // LOG(ERROR) << __func__ << ": Failed to find device with unique ID " + // << peripheral_id; + // return nullptr; + // } + // + // LOG(INFO) << __func__ << ": Connecting to L2CAP PSM " << psm + // << " on device " << device->GetMacAddress(); + // + // + // int fd = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + // if (fd < 0) { + // LOG(ERROR) << __func__ << ": Failed to create L2CAP socket: " + // << std::strerror(errno); + // return nullptr; + // } + // + // struct sockaddr_l2 addr; + // std::memset(&addr, 0, sizeof(addr)); + // addr.l2_family = AF_BLUETOOTH; + // addr.l2_psm = htobs(psm); + // addr.l2_cid = 0; + // addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; + // + // std::string mac_addr = device->GetMacAddress(); + // if (str2ba(mac_addr.c_str(), &addr.l2_bdaddr) < 0) { + // LOG(ERROR) << __func__ << ": Invalid Bluetooth address: " << mac_addr; + // close(fd); + // return nullptr; + // } + // + // if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + // LOG(ERROR) << __func__ << ": Failed to connect to L2CAP socket: " + // << std::strerror(errno); + // close(fd); + // return nullptr; + // } + // + // LOG(INFO) << __func__ << ": Successfully connected to L2CAP socket"; + // return std::make_unique(fd, peripheral_id); } bool BleV2Medium::StartMultipleServicesScanning( diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index fdbcce1b..01be22f2 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -142,7 +142,9 @@ class BleV2Medium final : public api::ble_v2::BleMedium { std::shared_ptr system_bus_; BluetoothAdapter adapter_; - ObserverList observers_ = {}; + // Why do we have observers her + std::shared_ptr> + observers_; std::shared_ptr devices_; std::shared_ptr gatt_discovery_; diff --git a/internal/platform/implementation/linux/bluetooth_classic_medium.cc b/internal/platform/implementation/linux/bluetooth_classic_medium.cc index 85e59aa1..cd854b22 100644 --- a/internal/platform/implementation/linux/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/linux/bluetooth_classic_medium.cc @@ -34,16 +34,21 @@ namespace nearby { namespace linux { -BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter) - : system_bus_(adapter.GetConnection()), - adapter_(adapter), - observers_(std::make_shared>()), - devices_(std::make_shared( - system_bus_, adapter.GetObjectPath(), *observers_)), - device_watcher_(nullptr), - // agent_manager_(std::make_unique(*system_bus_)), - profile_manager_( - std::make_unique(*system_bus_, *devices_)) {} +BluetoothClassicMedium::BluetoothClassicMedium(BluetoothAdapter &adapter) + : system_bus_(adapter.GetConnection()), + adapter_(adapter), + observers_(nullptr), + devices_(nullptr), + device_watcher_(nullptr), + // agent_manager_(std::make_unique(*system_bus_)), + profile_manager_(nullptr) { + auto shared = + GetSharedBluetoothDevices(system_bus_, adapter_.GetObjectPath()); + observers_ = shared->observers; + devices_ = shared->devices; + profile_manager_ = + std::make_unique(*system_bus_, *devices_); +} bool BluetoothClassicMedium::StartDiscovery( DiscoveryCallback discovery_callback) { @@ -160,6 +165,7 @@ BluetoothClassicMedium::ListenForService(const std::string &service_name, api::BluetoothDevice *BluetoothClassicMedium::GetRemoteDevice( MacAddress mac_address) { + // When BLE is discovering, it looks for remote devices to connect to using BT classic. If only auto device = devices_->get_device_by_address(mac_address.ToString()); if (device == nullptr) return nullptr; diff --git a/internal/platform/implementation/linux/bluetooth_devices.cc b/internal/platform/implementation/linux/bluetooth_devices.cc index 12ccce89..b702556c 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.cc +++ b/internal/platform/implementation/linux/bluetooth_devices.cc @@ -16,9 +16,11 @@ #include #include #include +#include #include +#include "absl/container/flat_hash_map.h" #include "absl/strings/substitute.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" @@ -32,6 +34,29 @@ namespace nearby { namespace linux { static constexpr std::chrono::minutes kLostPeripheralsCleanupMinFreq(5); +absl::Mutex g_shared_devices_lock; +absl::flat_hash_map> + g_shared_devices ABSL_GUARDED_BY(g_shared_devices_lock); + +std::shared_ptr GetSharedBluetoothDevices( + std::shared_ptr system_bus, + const sdbus::ObjectPath& adapter_object_path) { + const std::string key = adapter_object_path; + absl::MutexLock lock(&g_shared_devices_lock); + auto it = g_shared_devices.find(key); + if (it != g_shared_devices.end()) { + if (auto existing = it->second.lock()) { + return existing; + } + } + auto shared = std::make_shared(); + shared->observers = + std::make_shared>(); + shared->devices = std::make_shared( + std::move(system_bus), adapter_object_path, *shared->observers); + g_shared_devices[key] = shared; + return shared; +} std::shared_ptr BluetoothDevices::get_device_by_path( const sdbus::ObjectPath &device_object_path) { diff --git a/internal/platform/implementation/linux/bluetooth_devices.h b/internal/platform/implementation/linux/bluetooth_devices.h index 45c8dc16..9454ed37 100644 --- a/internal/platform/implementation/linux/bluetooth_devices.h +++ b/internal/platform/implementation/linux/bluetooth_devices.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -83,6 +84,15 @@ class BluetoothDevices final { ABSL_GUARDED_BY(devices_by_path_lock_); }; +struct SharedBluetoothDevices { + std::shared_ptr devices; + std::shared_ptr> observers; +}; + +std::shared_ptr GetSharedBluetoothDevices( + std::shared_ptr system_bus, + const sdbus::ObjectPath& adapter_object_path); + class DeviceWatcher final : sdbus::ProxyInterfaces { public: DeviceWatcher(const DeviceWatcher &) = delete; From f4be67850bd0e2e560622407b9e9b9f7b1fd27a3 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 17 Jan 2026 10:12:13 +0000 Subject: [PATCH 191/201] Reverted shared devices_ between blev2 and bt classic --- internal/platform/implementation/linux/BUILD | 10 +- .../implementation/linux/ble_v2_medium.cc | 411 +++++++++--------- .../implementation/linux/ble_v2_medium.h | 2 - 3 files changed, 206 insertions(+), 217 deletions(-) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index f367abf3..433efd6e 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -56,7 +56,7 @@ cc_library( hdrs = [ "avahi.h", "ble_gatt_server.h", -# "ble_gatt_client.h", + "ble_gatt_client.h", # "ble_medium.h", "ble_v2_medium.h", "ble_v2_server_socket.h", @@ -74,11 +74,11 @@ cc_library( # "bluez_agent.h", "bluez_advertisement_monitor.h", "bluez_advertisement_monitor_manager.h", -# "bluez_gatt_characteristic_client.h", + "bluez_gatt_characteristic_client.h", "bluez_gatt_characteristic_server.h", "bluez_gatt_manager.h", "bluez_gatt_profile.h", -# "bluez_gatt_service_client.h", + "bluez_gatt_service_client.h", "bluez_gatt_service_server.h", "bluez_le_advertisement.h", "dbus.h", @@ -142,7 +142,7 @@ cc_library( name = "linux", srcs = [ "avahi.cc", -# "ble_gatt_client.cc", + "ble_gatt_client.cc", "ble_gatt_server.cc", # "ble_medium.cc", "ble_v2_medium.cc", @@ -159,7 +159,7 @@ cc_library( "bluez.cc", #"bluez_agent.cc", "bluez_advertisement_monitor.cc", -# "bluez_gatt_characteristic_client.cc", + "bluez_gatt_characteristic_client.cc", "bluez_gatt_characteristic_server.cc", "bluez_gatt_service_server.cc", "bluez_le_advertisement.cc", diff --git a/internal/platform/implementation/linux/ble_v2_medium.cc b/internal/platform/implementation/linux/ble_v2_medium.cc index d04f5181..31a50420 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.cc +++ b/internal/platform/implementation/linux/ble_v2_medium.cc @@ -33,15 +33,13 @@ #include "ble_gatt_client.h" #include "ble_gatt_server.h" -#include "ble_l2cap_server_socket.h" -#include "ble_l2cap_socket.h" -#include "bluez_le_bearer_client.h" #include "internal/platform/implementation/linux/bluetooth_classic_device.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/mac_address.h" #include "internal/platform/prng.h" #include "absl/types/span.h" +#include "internal/base/observer_list.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" @@ -52,21 +50,19 @@ namespace nearby { namespace linux { BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) - : system_bus_(adapter.GetConnection()), - adapter_(adapter), - devices_(nullptr), - // gatt_discovery_(std::make_shared(system_bus_)), - root_object_manager_(std::make_unique(*system_bus_, "/com/google/nearby/medium/ble/advertisement/monitor")), - adv_monitor_manager_( - bluez::AdvertisementMonitorManager:: - DiscoverAdvertisementMonitorManager(*system_bus_, adapter_)), - adv_manager_(std::make_unique(*system_bus_, - adapter)), - cur_adv_(nullptr) { - auto shared = - GetSharedBluetoothDevices(system_bus_, adapter_.GetObjectPath()); - observers_ = shared->observers; - devices_ = shared->devices; + : system_bus_(adapter.GetConnection()), + adapter_(adapter), + // gatt_discovery_(std::make_shared(system_bus_)), + observers_(std::make_shared>()), + devices_(std::make_unique( + system_bus_, adapter_.GetObjectPath(), *observers_)), + root_object_manager_(std::make_unique(*system_bus_, "/com/google/nearby/medium/ble/advertisement/monitor")), + adv_monitor_manager_( + bluez::AdvertisementMonitorManager:: + DiscoverAdvertisementMonitorManager(*system_bus_, adapter_)), + adv_manager_(std::make_unique(*system_bus_, + adapter)), + cur_adv_(nullptr) { if (adv_monitor_manager_) { LOG(INFO) << __func__ @@ -87,70 +83,54 @@ BleV2Medium::BleV2Medium(BluetoothAdapter &adapter) // sync api // called twice. Once with extended regular advertisement ( when IsExtendedAdvertisementsAvailable() == true ) // and another for GATT-backed header advertisement for legacy devices -bool BleV2Medium::StartAdvertising( + bool BleV2Medium::StartAdvertising( const api::ble_v2::BleAdvertisementData &advertising_data, api::ble_v2::AdvertiseParameters advertise_set_parameters) { - if (!advertising_data.is_extended_advertisement) - { - // can't send two LE advertisements at the same - return true; - } - if (!adapter_.IsEnabled()) { - LOG(WARNING) << "BLE cannot start advertising because the " + if (!advertising_data.is_extended_advertisement) + { + // can't send two LE advertisements at the same + return true; + } + if (!adapter_.IsEnabled()) { + LOG(WARNING) << "BLE cannot start advertising because the " "bluetooth adapter is not enabled."; - return false; - } + return false; + } - if (advertising_data.service_data.empty()) { - LOG(WARNING) + if (advertising_data.service_data.empty()) { + LOG(WARNING) << "BLE cannot start to advertise due to invalid service data."; - return false; - } + return false; + } - absl::MutexLock l (&advs_mutex_); - advs_.push_front(bluez::LEAdvertisement::CreateLEAdvertisement( + absl::MutexLock l (&advs_mutex_); + advs_.push_front(bluez::LEAdvertisement::CreateLEAdvertisement( *system_bus_, advertising_data, advertise_set_parameters)); - auto it = advs_.begin(); + auto it = advs_.begin(); - LOG(INFO) << __func__ << ": Registering advertisement, is_extended: " << advertising_data.is_extended_advertisement + LOG(INFO) << __func__ << ": Registering advertisement, is_extended: " << advertising_data.is_extended_advertisement << " " << (*it) -> getObjectPath() << " on bluetooth adapter " << adapter_.GetObjectPath(); - try { - adv_manager_->RegisterAdvertisement((*it)->getObjectPath(), {}); - } catch (const sdbus::Error &e) { - advs_.erase(it); - DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "RegisterAdvertisement", e); - return false; - } - - return true; -} - -bool BleV2Medium::StopAdvertising() { - absl::MutexLock l(&advs_mutex_); - try { - for (auto& adv: advs_) - { - adv_manager_->UnregisterAdvertisement(adv->getObjectPath()); + try { + adv_manager_->RegisterAdvertisement((*it)->getObjectPath(), {}); + } catch (const sdbus::Error &e) { + advs_.erase(it); + DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "RegisterAdvertisement", e); + return false; } - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "UnregisterAdvertisement", e); - return false; + + return true; } - advs_.clear(); - return true; -} - - //async api - // this doesn't run. wonder why +//async api +// this doesn't run. wonder why std::unique_ptr BleV2Medium::StartAdvertising( - const api::ble_v2::BleAdvertisementData &advertising_data, - api::ble_v2::AdvertiseParameters advertise_set_parameters, - AdvertisingCallback callback) { + const api::ble_v2::BleAdvertisementData &advertising_data, + api::ble_v2::AdvertiseParameters advertise_set_parameters, + AdvertisingCallback callback) { if (!adapter_.IsEnabled()) { LOG(WARNING) << ": BLE cannot start advertising because the " "bluetooth adapter is not enabled."; @@ -164,50 +144,50 @@ BleV2Medium::StartAdvertising( } std::shared_ptr proxy = - sdbus::createProxy(*system_bus_, "org.bluez", adapter_.GetObjectPath()); + sdbus::createProxy(*system_bus_, "org.bluez", adapter_.GetObjectPath()); proxy->finishRegistration(); std::shared_ptr shared_cb = - std::make_shared(std::move(callback)); + std::make_shared(std::move(callback)); absl::MutexLock lock(&advs_mutex_); advs_.push_front(bluez::LEAdvertisement::CreateLEAdvertisement( - *system_bus_, advertising_data, advertise_set_parameters)); + *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{}) - .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; + proxy->callMethodAsync("RegisterAdvertisement") + .onInterface(org::bluez::LEAdvertisingManager1_proxy::INTERFACE_NAME) + .withArguments((*adv_it)->getObjectPath(), + std::map{}) + .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()); - } - }); + 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 stop_adv = [&, adv_it]() { LOG(INFO) << __func__ << ": Unregistering advertisement object " @@ -223,80 +203,24 @@ BleV2Medium::StartAdvertising( return absl::OkStatus(); }; return std::make_unique( - api::ble_v2::BleMedium::AdvertisingSession{std::move(stop_adv)}); + api::ble_v2::BleMedium::AdvertisingSession{std::move(stop_adv)}); } -std::unique_ptr BleV2Medium::StartGattServer( - api::ble_v2::ServerGattConnectionCallback callback) { - (void)callback; - return nullptr; - - return std::make_unique( - *system_bus_, adapter_, devices_,std::move(callback) - ); -} - -std::unique_ptr BleV2Medium::ConnectToGattServer( - api::ble_v2::BlePeripheral::UniqueId peripheral_id, - api::ble_v2::TxPowerLevel tx_power_level, - api::ble_v2::ClientGattConnectionCallback callback) { - (void)peripheral_id; - (void)tx_power_level; - (void)callback; - LOG(WARNING) << __func__ - << ": GATT client connection is not supported on Linux yet."; - return nullptr; -} - // This is supposed to be for a socket on top of Weave protocol. -std::unique_ptr BleV2Medium::Connect( - const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, - api::ble_v2::BlePeripheral::UniqueId peripheral_id, - CancellationFlag *cancellation_flag) { - LOG(INFO) << __func__ << ": Not implemented on linux "; - return nullptr; -} - -bool BleV2Medium::IsExtendedAdvertisementsAvailable() { - try { - auto supported_channels = adv_manager_->SupportedSecondaryChannels(); - return !supported_channels.empty(); - } catch (const sdbus::Error &e) { - DBUS_LOG_PROPERTY_GET_ERROR(adv_manager_, "SupportedSecondaryChannels", e); - return false; - } -} - -bool BleV2Medium::StartLEDiscovery() { - std::map filter; - filter["Transport"] = "auto"; - filter["DuplicateData"] = true; - auto &adapter = adapter_.GetBluezAdapterObject(); - - try { - adapter.SetDiscoveryFilter(filter); - } catch (const sdbus::Error &e) { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e); - return false; - } - - try { - LOG(INFO) << __func__ << ": Starting LE discovery on " - << adapter.getObjectPath(); - if (!adapter.Discovering()) - { - LOG(INFO)<< __func__ << ": Not discovering. Starting discovery"; - adapter.StartDiscovery(); - } - - } catch (const sdbus::Error &e) { - if (e.getName() != "org.bluez.Error.InProgress") { - DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); + bool BleV2Medium::StopAdvertising() { + absl::MutexLock l(&advs_mutex_); + try { + for (auto& adv: advs_) + { + adv_manager_->UnregisterAdvertisement(adv->getObjectPath()); + } + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(adv_manager_, "UnregisterAdvertisement", e); return false; } - } - return true; -} + advs_.clear(); + return true; + } bool BleV2Medium::StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level, @@ -331,12 +255,12 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, } auto monitor = std::make_unique( - *system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, - std::move(callback)); + *system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, + std::move(callback)); try { // why is this emitted? monitor->emitInterfacesAddedSignal( - {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); // adv_monitor_manager_ -> RegisterMonitor(monitor -> getObjectPath()); LOG(INFO)<< __func__ << ": Registered advertisement monitor with path " << monitor -> getObjectPath(); @@ -349,7 +273,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, return false; } auto device_watcher = std::make_unique( - *system_bus_, adapter_.GetObjectPath(), adapter_, devices_); + *system_bus_, adapter_.GetObjectPath(), adapter_, devices_); if (!StartLEDiscovery()) { LOG(ERROR) << __func__ << ": Could not start LE discovery on adapter " @@ -357,7 +281,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, device_watcher = nullptr; try { monitor->emitInterfacesRemovedSignal( - {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { LOG(ERROR) << __func__ @@ -370,7 +294,7 @@ bool BleV2Medium::StartScanning(const Uuid &service_uuid, LOG(INFO) << __func__ << " :Started monitoring for service UUID: " << std::string(service_uuid); active_adv_monitors_[service_uuid] = - std::make_pair(std::move(monitor), std::move(device_watcher)); + std::make_pair(std::move(monitor), std::move(device_watcher)); cur_monitored_service_uuid_ = service_uuid; return true; } @@ -406,68 +330,67 @@ bool BleV2Medium::StopScanning() { LOG(INFO) << __func__ << ": Removing advertising monitor " << adv_monitor->getObjectPath(); adv_monitor->emitInterfacesRemovedSignal( - {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); } active_adv_monitors_.erase(monitor_it); cur_monitored_service_uuid_ = std::nullopt; return true; } + std::unique_ptr + 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; + } -std::unique_ptr -BleV2Medium::StartScanning(const Uuid &service_uuid, - api::ble_v2::TxPowerLevel tx_power_level, - ScanningCallback callback) { - if (adv_monitor_manager_ == nullptr) { - // TODO: Implement manual monitoring. - return nullptr; - } - - absl::MutexLock lock(&active_adv_monitors_mutex_); - if (active_adv_monitors_.count(service_uuid) == 1) { - LOG(ERROR) << __func__ << ": Service " << std::string{service_uuid} + absl::MutexLock lock(&active_adv_monitors_mutex_); + if (active_adv_monitors_.count(service_uuid) == 1) { + LOG(ERROR) << __func__ << ": Service " << std::string{service_uuid} << " is already being advertised"; - return nullptr; - } + return nullptr; + } - auto monitor = std::make_unique( + auto monitor = std::make_unique( *system_bus_, service_uuid, tx_power_level, "or_patterns", devices_, std::move(callback)); - try { - monitor->emitInterfacesAddedSignal( + try { + monitor->emitInterfacesAddedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); - } catch (const sdbus::Error &e) { - LOG(ERROR) + } catch (const sdbus::Error &e) { + LOG(ERROR) << __func__ << ": error emitting InterfacesAdded signal for object path " << monitor->getObjectPath() << " with name '" << e.getName() << "' and message '" << e.getMessage() << "'"; - return nullptr; - } + return nullptr; + } - auto device_watcher = std::make_unique( + auto device_watcher = std::make_unique( *system_bus_, adapter_.GetObjectPath(),adapter_, devices_); - if (!StartLEDiscovery()) { - LOG(ERROR) << __func__ + if (!StartLEDiscovery()) { + LOG(ERROR) << __func__ << ": Could not start LE discovery on adapter " << adapter_.GetObjectPath(); - try { - monitor->emitInterfacesRemovedSignal( + try { + monitor->emitInterfacesRemovedSignal( {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); - } catch (const sdbus::Error &e) { - LOG(ERROR) + } catch (const sdbus::Error &e) { + LOG(ERROR) << __func__ << ": error emitting InterfacesRemoved signal for object path " << monitor->getObjectPath() << " with name '" << e.getName() << "' and message '" << e.getMessage() << "'"; + } + return nullptr; } - return nullptr; - } - active_adv_monitors_[service_uuid] = + active_adv_monitors_[service_uuid] = std::make_pair(std::move(monitor), std::move(device_watcher)); - return std::make_unique( + return std::make_unique( ScanningSession{.stop_scanning = [this, service_uuid]() { absl::MutexLock lock(&active_adv_monitors_mutex_); if (active_adv_monitors_.count(service_uuid) == 0) { @@ -475,13 +398,13 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, << __func__ << ": Advertising monitor for service " << std::string{service_uuid} << " does not exist anymore"; return absl::NotFoundError( - "Advertising monitor for this service does not exist"); + "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}); + {org::bluez::AdvertisementMonitor1_adaptor::INTERFACE_NAME}); } catch (const sdbus::Error &e) { LOG(ERROR) << __func__ @@ -502,10 +425,32 @@ BleV2Medium::StartScanning(const Uuid &service_uuid, active_adv_monitors_.erase(service_uuid); return status; }}); + } + +std::unique_ptr BleV2Medium::StartGattServer( + api::ble_v2::ServerGattConnectionCallback callback) { + (void)callback; + return nullptr; + + return std::make_unique( + *system_bus_, adapter_, devices_,std::move(callback) + ); +} + +std::unique_ptr BleV2Medium::ConnectToGattServer( + api::ble_v2::BlePeripheral::UniqueId peripheral_id, + api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::ClientGattConnectionCallback callback) { + (void)peripheral_id; + (void)tx_power_level; + (void)callback; + LOG(WARNING) << __func__ + << ": GATT client connection is not supported on Linux yet."; + return nullptr; } std::unique_ptr BleV2Medium::OpenServerSocket( - const std::string &service_id) { + const std::string &service_id) { LOG(INFO) << __func__ << ": Opening BLE server socket for service " << service_id; return std::make_unique(service_id); @@ -526,6 +471,52 @@ BleV2Medium::OpenL2capServerSocket(const std::string &service_id) { // return server_socket; } +// This is supposed to be for a socket on top of Weave protocol. +std::unique_ptr BleV2Medium::Connect( + const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, + api::ble_v2::BlePeripheral::UniqueId peripheral_id, + CancellationFlag *cancellation_flag) { + LOG(INFO) << __func__ << ": Not implemented on linux "; + return nullptr; +} + +bool BleV2Medium::IsExtendedAdvertisementsAvailable() { + try { + auto supported_channels = adv_manager_->SupportedSecondaryChannels(); + return !supported_channels.empty(); + } catch (const sdbus::Error &e) { + DBUS_LOG_PROPERTY_GET_ERROR(adv_manager_, "SupportedSecondaryChannels", e); + return false; + } +} + +bool BleV2Medium::StartLEDiscovery() { + std::map filter; + filter["Transport"] = "auto"; + filter["DuplicateData"] = true; + auto &adapter = adapter_.GetBluezAdapterObject(); + + try { + adapter.SetDiscoveryFilter(filter); + } catch (const sdbus::Error &e) { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "SetDiscoveryFilter", e); + return false; + } + + try { + LOG(INFO) << __func__ << ": Starting LE discovery on " + << adapter.getObjectPath(); + adapter.StartDiscovery(); + } catch (const sdbus::Error &e) { + if (e.getName() != "org.bluez.Error.InProgress") { + DBUS_LOG_METHOD_CALL_ERROR(&adapter, "StartDiscovery", e); + return false; + } + } + + return true; +} + // std::unique_ptr BleV2Medium::Connect( // const std::string &service_id, api::ble_v2::TxPowerLevel tx_power_level, // api::ble_v2::BlePeripheral &peripheral, diff --git a/internal/platform/implementation/linux/ble_v2_medium.h b/internal/platform/implementation/linux/ble_v2_medium.h index 01be22f2..5d3af920 100644 --- a/internal/platform/implementation/linux/ble_v2_medium.h +++ b/internal/platform/implementation/linux/ble_v2_medium.h @@ -28,8 +28,6 @@ // #include "internal/platform/implementation/linux/ble_gatt_client.h" #include "ble_gatt_client.h" #include "bluez_gatt_manager.h" -#include "internal/platform/implementation/linux/ble_l2cap_server_socket.h" -#include "internal/platform/implementation/linux/ble_l2cap_socket.h" #include "internal/platform/implementation/linux/ble_v2_server_socket.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluetooth_devices.h" From d516d0b3c16112c801f06ad4fc2851dfa1d39ab6 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 17 Jan 2026 10:14:35 +0000 Subject: [PATCH 192/201] Added file_share example app to connections --- connections/file_share/main.cc | 550 +++++++++++++++++++++++++++++++++ 1 file changed, 550 insertions(+) create mode 100644 connections/file_share/main.cc diff --git a/connections/file_share/main.cc b/connections/file_share/main.cc new file mode 100644 index 00000000..44b35113 --- /dev/null +++ b/connections/file_share/main.cc @@ -0,0 +1,550 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "absl/log/log.h" +#include "absl/synchronization/notification.h" +#include "connections/connection_options.h" +#include "connections/core.h" +#include "connections/payload_type.h" +#include "connections/v3/advertising_options.h" +#include "connections/v3/connections_device.h" +#include "connections/v3/discovery_options.h" +#include "connections/v3/listeners.h" +#include "connections/implementation/service_controller_router.h" +#include "internal/platform/file.h" + +namespace { +constexpr char kDefaultServiceId[] = "com.google.nearby.fileshare.cli"; + +absl::Notification g_shutdown; + +void QuitHandler(int, siginfo_t*, void*) { + if (!g_shutdown.HasBeenNotified()) { + g_shutdown.Notify(); + } +} + +struct Options { + bool advertise = false; + bool discover = false; + std::string service_id = kDefaultServiceId; + std::string save_dir; + std::vector send_paths; + nearby::connections::BooleanMediumSelector mediums = + nearby::connections::BooleanMediumSelector().SetAll(true); + nearby::connections::BooleanMediumSelector upgrade_mediums = + nearby::connections::BooleanMediumSelector().SetAll(true); + bool upgrade_mediums_set = false; +}; + +void PrintUsage(const char* prog) { + std::cerr + << "Usage: " << prog + << " [--advertise] [--discover] [--mediums=LIST]\n" + << " [--upgrade_mediums=LIST] [--send=PATH]\n" + << " [--save_dir=DIR] [--service_id=ID]\n" + << "Flags:\n" + << " --advertise Enable advertising\n" + << " --discover Enable discovery\n" + << " --mediums=LIST Comma-separated list of mediums to use for\n" + << " advertising + discovery\n" + << " --upgrade_mediums=LIST Comma-separated list of mediums to use for\n" + << " upgrade (defaults to --mediums)\n" + << " (bluetooth,ble,wifi_lan,wifi_hotspot,wifi_direct,\n" + << " web_rtc,web_rtc_non_cellular,awdl,all)\n" + << " --send=PATH File to send after connection (repeatable)\n" + << " --save_dir=DIR Directory for received files\n" + << " --service_id=ID Override service ID\n" + << " -h, --help Show this help\n" + << "Examples:\n" + << " " << prog + << " --advertise --discover --mediums=ble --upgrade_mediums=wifi_lan\n" + << " --send=/tmp/hello.txt\n" + << " " << prog << " --discover --mediums=wifi_lan --save_dir=/tmp\n"; +} + +bool StartsWith(std::string_view input, std::string_view prefix) { + return input.size() >= prefix.size() && + input.substr(0, prefix.size()) == prefix; +} + +std::string Trim(std::string_view input) { + size_t start = 0; + size_t end = input.size(); + while (start < end && std::isspace(static_cast(input[start]))) { + ++start; + } + while (end > start && + std::isspace(static_cast(input[end - 1]))) { + --end; + } + return std::string(input.substr(start, end - start)); +} + +std::vector SplitCommaList(std::string_view input) { + std::vector tokens; + size_t start = 0; + while (start <= input.size()) { + size_t comma = input.find(',', start); + if (comma == std::string_view::npos) comma = input.size(); + tokens.push_back(Trim(input.substr(start, comma - start))); + start = comma + 1; + } + return tokens; +} + +bool ApplyMediumToken(nearby::connections::BooleanMediumSelector& selector, + const std::string& token, std::string* error) { + if (token.empty()) { + return true; + } + if (token == "all") { + selector.SetAll(true); + return true; + } + if (token == "bluetooth") { + selector.bluetooth = true; + return true; + } + if (token == "ble") { + selector.ble = true; + return true; + } + if (token == "wifi_lan") { + selector.wifi_lan = true; + return true; + } + if (token == "wifi_hotspot") { + selector.wifi_hotspot = true; + return true; + } + if (token == "wifi_direct") { + selector.wifi_direct = true; + return true; + } + if (token == "web_rtc") { + selector.web_rtc = true; + selector.web_rtc_no_cellular = true; + return true; + } + if (token == "web_rtc_non_cellular") { + selector.web_rtc_no_cellular = true; + return true; + } + if (token == "awdl") { + selector.awdl = true; + return true; + } + if (error != nullptr) { + *error = "Unknown medium: " + token; + } + return false; +} + +bool ParseMediums(const std::string& list, + nearby::connections::BooleanMediumSelector* selector, + std::string* error) { + selector->SetAll(false); + for (const auto& token : SplitCommaList(list)) { + if (!ApplyMediumToken(*selector, token, error)) { + return false; + } + } + if (!selector->Any(true)) { + if (error != nullptr) { + *error = "No valid mediums specified"; + } + return false; + } + return true; +} + +bool ReadValueFlag(std::string_view arg, std::string_view name, int* index, + int argc, char** argv, std::string* out) { + if (arg == name) { + if (*index + 1 >= argc) { + return false; + } + *out = argv[++(*index)]; + return true; + } + std::string prefix = std::string(name) + "="; + if (StartsWith(arg, prefix)) { + *out = std::string(arg.substr(prefix.size())); + return true; + } + return false; +} + +std::string MakeEndpointInfo() { + std::string name; + name.reserve(5); + for (int i = 0; i < 5; ++i) { + name.push_back('0' + (std::rand() % 10)); + } + return name; +} + +} // namespace + +class FileShareApp { + public: + explicit FileShareApp(Options options) + : options_(std::move(options)), + router_(std::make_unique()), + core_(std::make_unique(router_.get())), + local_device_(nearby::connections::v3::ConnectionsDevice( + MakeEndpointInfo(), {})) {} + + void Start() { + if (!options_.save_dir.empty()) { + std::error_code error; + std::filesystem::create_directories(options_.save_dir, error); + if (error) { + LOG(WARNING) << "Failed to create save dir: " << options_.save_dir + << " error=" << error.message(); + } + core_->SetCustomSavePath( + options_.save_dir, + [](nearby::connections::Status status) { + LOG(INFO) << "SetCustomSavePath status: " << status.ToString(); + }); + } + + if (options_.advertise) { + StartAdvertising(); + } + if (options_.discover) { + StartDiscovery(); + } + } + + private: + void StartAdvertising() { + nearby::connections::v3::AdvertisingOptions advertising; + advertising.strategy = nearby::connections::Strategy::kP2pCluster; + advertising.advertising_mediums = options_.mediums; + advertising.upgrade_mediums = + options_.upgrade_mediums_set ? options_.upgrade_mediums + : options_.mediums; + + core_->StartAdvertisingV3( + options_.service_id, advertising, local_device_, + MakeConnectionListener(), + [](nearby::connections::Status status) { + LOG(INFO) << "Advertising status: " << status.ToString(); + }); + } + + void StartDiscovery() { + nearby::connections::v3::DiscoveryOptions discovery; + discovery.strategy = nearby::connections::Strategy::kP2pCluster; + discovery.discovery_mediums = options_.mediums; + + core_->StartDiscoveryV3( + options_.service_id, discovery, MakeDiscoveryListener(), + [](nearby::connections::Status status) { + LOG(INFO) << "Discovery status: " << status.ToString(); + }); + } + + nearby::connections::v3::ConnectionListener MakeConnectionListener() { + nearby::connections::v3::ConnectionListener listener; + listener.initiated_cb = + [this](const nearby::NearbyDevice& remote_device, + const nearby::connections::v3::InitialConnectionInfo& info) { + LOG(INFO) << "Connection initiated with " + << remote_device.GetEndpointId() + << " auth_digits=" << info.authentication_digits; + core_->AcceptConnectionV3( + remote_device, MakePayloadListener(), + [](nearby::connections::Status status) { + LOG(INFO) << "AcceptConnection status: " << status.ToString(); + }); + }; + + listener.result_cb = + [this](const nearby::NearbyDevice& remote_device, + nearby::connections::v3::ConnectionResult result) { + LOG(INFO) << "Connection result for " + << remote_device.GetEndpointId() + << ": " << result.status.ToString(); + if (result.status.Ok()) { + SendFilesTo(remote_device); + } + }; + + listener.disconnected_cb = + [this](const nearby::NearbyDevice& remote_device) { + LOG(INFO) << "Disconnected from " << remote_device.GetEndpointId(); + }; + return listener; + } + + nearby::connections::v3::DiscoveryListener MakeDiscoveryListener() { + nearby::connections::v3::DiscoveryListener listener; + listener.endpoint_found_cb = + [this](const nearby::NearbyDevice& remote_device, + const absl::string_view service_id) { + LOG(INFO) << "Found endpoint " << remote_device.GetEndpointId() + << " service_id=" << service_id; + nearby::connections::ConnectionOptions options; + options.strategy = nearby::connections::Strategy::kP2pCluster; + options.allowed = options_.upgrade_mediums_set + ? options_.upgrade_mediums + : options_.mediums; + options.auto_upgrade_bandwidth = true; + auto device = CacheDiscoveredDevice(remote_device); + core_->RequestConnectionV3( + local_device_, *device, options, MakeConnectionListener(), + [](nearby::connections::Status status) { + LOG(INFO) << "RequestConnection status: " << status.ToString(); + }); + }; + listener.endpoint_lost_cb = + [](const nearby::NearbyDevice& remote_device) { + LOG(INFO) << "Lost endpoint " << remote_device.GetEndpointId(); + }; + return listener; + } + + nearby::connections::v3::PayloadListener MakePayloadListener() { + nearby::connections::v3::PayloadListener listener; + listener.payload_received_cb = + [this](const nearby::NearbyDevice& remote_device, + nearby::connections::Payload payload) { + LOG(INFO) << "Payload received from " + << remote_device.GetEndpointId() + << " id=" << payload.GetId(); + if (payload.GetType() == nearby::connections::PayloadType::kFile) { + if (auto* file = payload.AsFile()) { + std::lock_guard lock(incoming_mutex_); + incoming_files_[payload.GetId()] = file->GetFilePath(); + } + } + }; + + listener.payload_progress_cb = + [this](const nearby::NearbyDevice& remote_device, + const nearby::connections::PayloadProgressInfo& info) { + if (info.status == + nearby::connections::PayloadProgressInfo::Status::kSuccess) { + std::string path; + { + std::lock_guard lock(incoming_mutex_); + auto it = incoming_files_.find(info.payload_id); + if (it != incoming_files_.end()) { + path = it->second; + incoming_files_.erase(it); + } + } + if (!path.empty()) { + LOG(INFO) << "Received file from " + << remote_device.GetEndpointId() << " path=" << path; + } else { + LOG(INFO) << "Received file from " + << remote_device.GetEndpointId() + << " payload_id=" << info.payload_id; + } + } else if (info.status == + nearby::connections::PayloadProgressInfo::Status::kFailure) { + LOG(WARNING) << "Payload failed from " + << remote_device.GetEndpointId() + << " payload_id=" << info.payload_id; + } + }; + return listener; + } + + std::optional BuildFilePayload( + const std::string& path) { + std::error_code error; + std::filesystem::path fs_path(path); + if (!std::filesystem::exists(fs_path, error)) { + LOG(ERROR) << "File does not exist: " << path; + return std::nullopt; + } + auto size = std::filesystem::file_size(fs_path, error); + if (error) { + LOG(ERROR) << "Failed to get file size: " << path + << " error=" << error.message(); + return std::nullopt; + } + std::string file_name = fs_path.filename().string(); + if (file_name.empty()) { + LOG(ERROR) << "Invalid file name: " << path; + return std::nullopt; + } + nearby::InputFile input_file(path, static_cast(size)); + return nearby::connections::Payload("", file_name, std::move(input_file)); + } + + void SendFilesTo(const nearby::NearbyDevice& remote_device) { + if (options_.send_paths.empty()) { + return; + } + const std::string endpoint_id = remote_device.GetEndpointId(); + { + std::lock_guard lock(sent_mutex_); + if (!sent_to_.insert(endpoint_id).second) { + return; + } + } + for (const auto& path : options_.send_paths) { + auto payload = BuildFilePayload(path); + if (!payload.has_value()) { + continue; + } + core_->SendPayloadV3( + remote_device, std::move(payload.value()), + [endpoint_id](nearby::connections::Status status) { + LOG(INFO) << "SendPayload to " << endpoint_id + << " status=" << status.ToString(); + }); + } + } + + std::shared_ptr + CacheDiscoveredDevice(const nearby::NearbyDevice& remote_device) { + const std::string endpoint_id = remote_device.GetEndpointId(); + std::lock_guard lock(discovered_mutex_); + auto it = discovered_devices_.find(endpoint_id); + if (it != discovered_devices_.end()) { + return it->second; + } + std::string endpoint_info; + if (remote_device.GetType() == + nearby::NearbyDevice::Type::kConnectionsDevice) { + auto* connections_device = + dynamic_cast( + &remote_device); + if (connections_device != nullptr) { + endpoint_info = connections_device->GetEndpointInfo(); + } + } + auto device = std::make_shared( + endpoint_id, endpoint_info, remote_device.GetConnectionInfos()); + discovered_devices_.emplace(endpoint_id, device); + return device; + } + + Options options_; + std::unique_ptr router_; + std::unique_ptr core_; + nearby::connections::v3::ConnectionsDevice local_device_; + std::mutex discovered_mutex_; + std::unordered_map> + discovered_devices_; + std::mutex incoming_mutex_; + std::unordered_map incoming_files_; + std::mutex sent_mutex_; + std::unordered_set sent_to_; +}; + +int main(int argc, char** argv) { + std::srand(static_cast(std::time(nullptr))); + + Options options; + bool mediums_override = false; + + for (int i = 1; i < argc; ++i) { + std::string_view arg(argv[i]); + if (arg == "--advertise" || arg == "--advert") { + options.advertise = true; + continue; + } + if (arg == "--discover" || arg == "--scan") { + options.discover = true; + continue; + } + if (arg == "-h" || arg == "--help") { + PrintUsage(argv[0]); + return 0; + } + std::string value; + if (ReadValueFlag(arg, "--mediums", &i, argc, argv, &value)) { + std::string error; + nearby::connections::BooleanMediumSelector selector; + if (!ParseMediums(value, &selector, &error)) { + std::cerr << "Error: " << error << "\n"; + return 2; + } + options.mediums = selector; + mediums_override = true; + continue; + } + if (ReadValueFlag(arg, "--upgrade_mediums", &i, argc, argv, &value)) { + std::string error; + nearby::connections::BooleanMediumSelector selector; + if (!ParseMediums(value, &selector, &error)) { + std::cerr << "Error: " << error << "\n"; + return 2; + } + options.upgrade_mediums = selector; + options.upgrade_mediums_set = true; + continue; + } + if (ReadValueFlag(arg, "--send", &i, argc, argv, &value)) { + if (value.empty()) { + std::cerr << "Error: --send requires a path\n"; + return 2; + } + options.send_paths.push_back(value); + continue; + } + if (ReadValueFlag(arg, "--save_dir", &i, argc, argv, &value)) { + options.save_dir = value; + continue; + } + if (ReadValueFlag(arg, "--service_id", &i, argc, argv, &value)) { + options.service_id = value; + continue; + } + std::cerr << "Unknown argument: " << arg << "\n"; + PrintUsage(argv[0]); + return 2; + } + + if (!options.advertise && !options.discover) { + std::cerr << "Error: specify at least one of --advertise or --discover\n"; + PrintUsage(argv[0]); + return 2; + } + + if (mediums_override && !options.mediums.Any(true)) { + std::cerr << "Error: no mediums enabled\n"; + return 2; + } + if (options.upgrade_mediums_set && !options.upgrade_mediums.Any(true)) { + std::cerr << "Error: no upgrade mediums enabled\n"; + return 2; + } + + struct sigaction action {}; + action.sa_sigaction = QuitHandler; + action.sa_flags = SA_SIGINFO; + sigaction(SIGINT, &action, nullptr); + sigaction(SIGTERM, &action, nullptr); + + FileShareApp app(std::move(options)); + app.Start(); + + g_shutdown.WaitForNotification(); + LOG(INFO) << "Shutting down"; + return 0; +} From eb76c38bb4cdee3dc1f2cc8423721ea0a948e730 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 17 Jan 2026 18:10:13 +0000 Subject: [PATCH 193/201] Added devcontainers --- .devcontainer/bazel/Dockerfile | 50 +++++++++++++++++ .devcontainer/bazel/devcontainer.json | 26 +++++++++ .devcontainer/bazelclion/Dockerfile | 47 ++++++++++++++++ .devcontainer/bazelclion/devcontainer.json | 52 ++++++++++++++++++ .devcontainer/bazelclion/reinstall-cmake.sh | 59 +++++++++++++++++++++ 5 files changed, 234 insertions(+) create mode 100755 .devcontainer/bazel/Dockerfile create mode 100755 .devcontainer/bazel/devcontainer.json create mode 100755 .devcontainer/bazelclion/Dockerfile create mode 100755 .devcontainer/bazelclion/devcontainer.json create mode 100755 .devcontainer/bazelclion/reinstall-cmake.sh diff --git a/.devcontainer/bazel/Dockerfile b/.devcontainer/bazel/Dockerfile new file mode 100755 index 00000000..0f8f6f5b --- /dev/null +++ b/.devcontainer/bazel/Dockerfile @@ -0,0 +1,50 @@ +FROM ubuntu:24.04 + +RUN apt-get update && apt-get install -y \ + build-essential \ + clang \ + cmake \ + git \ + curl \ + libsdbus-c++-dev \ + libssl-dev \ + libsystemd-dev \ + libcurlpp-dev \ + apt-transport-https \ + gnupg \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Installing bazel +RUN curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor >bazel-archive-keyring.gpg && mv bazel-archive-keyring.gpg /usr/share/keyrings \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list \ + && apt update && apt install -y bazel + +RUN apt-get install -y pkg-config libasound2-dev + +RUN apt-get install -y libunistring-dev libldap-dev libkrb5-dev libgpg-error-dev gdb libc6-dbg libgtest-dev libbluetooth-dev + +#gtest +RUN apt-get update && apt-get install -y \ + googletest cmake g++ make \ + && rm -rf /var/lib/apt/lists/* \ + && cd /usr/src/googletest \ + && cmake -S . -B build \ + && cmake --build build -j"$(nproc)" \ + && cmake --install build + +# bash history +RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ + && echo "$SNIPPET" >> "/root/.bashrc" + +RUN apt-get install -y libunistring-dev libldap-dev libkrb5-dev libgpg-error-dev ca-certificates tzdata curl && update-ca-certificates && date + +WORKDIR /workspace + + +ENTRYPOINT ["/bin/bash"] +# [Optional] Uncomment this section to install additional vcpkg ports. +# RUN su vscode -c "${VCPKG_ROOT}/vcpkg install " + +# [Optional] Uncomment this section to install additional packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends diff --git a/.devcontainer/bazel/devcontainer.json b/.devcontainer/bazel/devcontainer.json new file mode 100755 index 00000000..d5ca6a17 --- /dev/null +++ b/.devcontainer/bazel/devcontainer.json @@ -0,0 +1,26 @@ +{ + "name": "Bazel Dev Container", + "dockerFile": "Dockerfile", + "customizations": { + "vscode": { + "settings": { + "C_Cpp.default.configurationProvider": "ms-vscode.cpptools", + "C_Cpp.intelliSenseEngine": "Default" + }, + "extensions": [ + "ms-vscode.cpptools", + "bazelbuild.vscode-bazel", + "ms-vscode.cpptools-extension-pack" + ], + + } + }, + "mounts": [ + "source=${localWorkspaceFolder},target=/workspace,type=bind", + "source=bashhistory,target=/commandhistory,type=volume", + "source=${localWorkspaceFolder}/bazel-output,target=/bazel-output,type=bind", + "source=/run/dbus,target=/run/dbus,type=bind" + // "source=${localWorkspaceFolder}/build-bin,target=/workspace/bazel-bin,type=bind", + // "source=${localWorkspaceFolder}/build-out,target=/workspace/bazel-out,type=bind" + ] +} diff --git a/.devcontainer/bazelclion/Dockerfile b/.devcontainer/bazelclion/Dockerfile new file mode 100755 index 00000000..5eab4c65 --- /dev/null +++ b/.devcontainer/bazelclion/Dockerfile @@ -0,0 +1,47 @@ +FROM ubuntu:24.04 + +RUN apt-get update && apt-get install -y \ + build-essential \ + clang \ + cmake \ + git \ + curl \ + libsdbus-c++-dev \ + libssl-dev \ + libsystemd-dev \ + libcurlpp-dev \ + apt-transport-https \ + gnupg \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Installing bazel +RUN curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor >bazel-archive-keyring.gpg && mv bazel-archive-keyring.gpg /usr/share/keyrings \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list \ + && apt update && apt install -y bazel + +RUN apt-get install -y pkg-config libasound2-dev + +RUN apt-get install -y libunistring-dev libldap-dev libkrb5-dev libgpg-error-dev gdb libc6-dbg googletest + +#gtest +RUN cd /usr/src/googletest +RUN cmake -S . -B build +RUN cmake --build build -j +RUN cmake --install build + +# bash history +RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ + && echo "$SNIPPET" >> "/root/.bashrc" + +RUN apt-get install -y libunistring-dev libldap-dev libkrb5-dev libgpg-error-dev ca-certificates tzdata curl && update-ca-certificates && date + +WORKDIR /workspace + + +ENTRYPOINT ["/bin/bash"] +# [Optional] Uncomment this section to install additional vcpkg ports. +# RUN su vscode -c "${VCPKG_ROOT}/vcpkg install " + +# [Optional] Uncomment this section to install additional packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends diff --git a/.devcontainer/bazelclion/devcontainer.json b/.devcontainer/bazelclion/devcontainer.json new file mode 100755 index 00000000..0fafd692 --- /dev/null +++ b/.devcontainer/bazelclion/devcontainer.json @@ -0,0 +1,52 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "C++ Latest", + "build": { + "dockerfile": "Dockerfile" + }, + "mounts": [ + { + "source": "bashhistory", + "target": "/commandhistory", + "type": "volume" + }, + { + "source": "/run/dbus", + "target": "/run/dbus", + "type": "bind" + }, + { + "source": "${localWorkspaceFolder}/bazel-output", + "target": "/bazel-output", + "type": "bind" + } + ], + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind", + "workspaceFolder": "/workspace", + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "gcc -v", + + // Configure tool-specific properties. + "customizations" : { + "jetbrains" : { + "backend" : "CLion", + //"plugins":[ + // "com.google.idea.bazel.clwb", + // "com.github.copilot" + //] + } + }, + "runArgs": [ + "--network=host", + "--dns=1.1.1.1", + "--dns=8.8.8.8" + ] +} diff --git a/.devcontainer/bazelclion/reinstall-cmake.sh b/.devcontainer/bazelclion/reinstall-cmake.sh new file mode 100755 index 00000000..408b81d2 --- /dev/null +++ b/.devcontainer/bazelclion/reinstall-cmake.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- +# +set -e + +CMAKE_VERSION=${1:-"none"} + +if [ "${CMAKE_VERSION}" = "none" ]; then + echo "No CMake version specified, skipping CMake reinstallation" + exit 0 +fi + +# Cleanup temporary directory and associated files when exiting the script. +cleanup() { + EXIT_CODE=$? + set +e + if [[ -n "${TMP_DIR}" ]]; then + echo "Executing cleanup of tmp files" + rm -Rf "${TMP_DIR}" + fi + exit $EXIT_CODE +} +trap cleanup EXIT + + +echo "Installing CMake..." +apt-get -y purge --auto-remove cmake +mkdir -p /opt/cmake + +architecture=$(dpkg --print-architecture) +case "${architecture}" in + arm64) + ARCH=aarch64 ;; + amd64) + ARCH=x86_64 ;; + *) + echo "Unsupported architecture ${architecture}." + exit 1 + ;; +esac + +CMAKE_BINARY_NAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh" +CMAKE_CHECKSUM_NAME="cmake-${CMAKE_VERSION}-SHA-256.txt" +TMP_DIR=$(mktemp -d -t cmake-XXXXXXXXXX) + +echo "${TMP_DIR}" +cd "${TMP_DIR}" + +curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_BINARY_NAME}" -O +curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_CHECKSUM_NAME}" -O + +sha256sum -c --ignore-missing "${CMAKE_CHECKSUM_NAME}" +sh "${TMP_DIR}/${CMAKE_BINARY_NAME}" --prefix=/opt/cmake --skip-license + +ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake +ln -s /opt/cmake/bin/ctest /usr/local/bin/ctest From 08092be40a255f7c14fec4f69f8f21644b8bfc0f Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 17 Jan 2026 18:10:45 +0000 Subject: [PATCH 194/201] Added Build for file_share --- connections/file_share/BUILD | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 connections/file_share/BUILD diff --git a/connections/file_share/BUILD b/connections/file_share/BUILD new file mode 100644 index 00000000..701e91ba --- /dev/null +++ b/connections/file_share/BUILD @@ -0,0 +1,27 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +cc_binary( + name = "file_share", + srcs = ["main.cc"], + deps = [ + "//connections:core", + "//connections:core_types", + "//internal/crypto_cros:crypto_cros", + "//internal/platform/implementation/linux:linux", + "@com_google_protobuf//:protobuf", + ], +) From bac1ffe00ea7307f315ec2d279ce1f83e0cadace Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Sat, 17 Jan 2026 18:11:07 +0000 Subject: [PATCH 195/201] Added hedron compile command extractor to MODULE.bazel and BUILD in linux --- MODULE.bazel | 11 +++++++++++ internal/platform/implementation/linux/BUILD | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/MODULE.bazel b/MODULE.bazel index b330092f..8d609ece 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -18,6 +18,17 @@ git_repository( remote = "https://beto-core.googlesource.com/beto-core", ) +# Hedron's Compile Commands Extractor for Bazel +# https://github.com/hedronvision/bazel-compile-commands-extractor +# Hedron's Compile Commands Extractor for Bazel +# https://github.com/hedronvision/bazel-compile-commands-extractor +bazel_dep(name = "hedron_compile_commands", dev_dependency = True) +git_override( + module_name = "hedron_compile_commands", + remote = "https://github.com/mikael-s-persson/bazel-compile-commands-extractor", + commit = "02d15621b528efd877f5d5657c4b738523a0eb17" +) + rust = use_extension("@rules_rust//rust:extensions.bzl", "rust") rust.toolchain( edition = "2021", diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 433efd6e..3e189266 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -14,6 +14,23 @@ licenses(["notice"]) +load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands") + +refresh_compile_commands( + name = "refresh_compile_commands", + + # Specify the targets of interest. + # For example, specify a dict of targets and any flags required to build. + targets = { + ":linux": "-s --check_visibility=false --spawn_strategy=standalone --verbose_failures --strip=never --copt=-O0 --copt=-g --copt=-fno-omit-frame-pointer", + }, + # No need to add flags already in .bazelrc. They're automatically picked up. + # If you don't need flags, a list of targets is also okay, as is a single target string. + # Wildcard patterns, like //... for everything, *are* allowed here, just like a build. + # As are additional targets (+) and subtractions (-), like in bazel query https://docs.bazel.build/versions/main/query.html#expressions + # And if you're working on a header-only library, specify a test or binary target that compiles it. +) + cc_library( name = "types", hdrs = [ From 7db967277628028aa4cb0b7e2f40f87734f1220e Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Mon, 19 Jan 2026 01:52:56 +0000 Subject: [PATCH 196/201] initial linux nearby_sharing_service implementation. untested --- sharing/linux/nearby_sharing_service_linux.cc | 1002 +++++++++++++++++ sharing/linux/nearby_sharing_service_linux.h | 229 ++++ 2 files changed, 1231 insertions(+) create mode 100644 sharing/linux/nearby_sharing_service_linux.cc create mode 100644 sharing/linux/nearby_sharing_service_linux.h diff --git a/sharing/linux/nearby_sharing_service_linux.cc b/sharing/linux/nearby_sharing_service_linux.cc new file mode 100644 index 00000000..42af1563 --- /dev/null +++ b/sharing/linux/nearby_sharing_service_linux.cc @@ -0,0 +1,1002 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "nearby_sharing_service_linux.h" +#include "sharing/proto/enums.pb.h" + +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "connections/advertising_options.h" +#include "connections/connection_options.h" +#include "connections/discovery_options.h" +#include "connections/listeners.h" +#include "connections/medium_selector.h" +#include "connections/payload.h" +#include "connections/status.h" +#include "connections/strategy.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/file.h" +#include "internal/platform/logging.h" +#include "sharing/certificates/common.h" + +namespace nearby::sharing::linux { +namespace { +constexpr char kServiceId[] = "NearbySharing"; +const connections::Strategy kStrategy = connections::Strategy::kP2pPointToPoint; +constexpr uint8_t kAdvertisementSaltSize = 2; +constexpr uint8_t kAdvertisementMetadataKeySize = 14; +constexpr uint8_t kAdvertisementVersion = 0; +constexpr uint8_t kVersionBitmask = 0b111; +constexpr uint8_t kDeviceTypeBitmask = 0b111; +constexpr uint8_t kVisibilityBitmask = 0b1; +constexpr uint8_t kTlvMinLength = 2; +constexpr uint8_t kVendorIdLength = 1; + +enum class TlvTypes : uint8_t { + kUnknown = 0, + kQrCode = 1, + kVendorId = 2, +}; + +uint8_t EncodeHeaderByte(bool has_device_name, ShareTargetType device_type) { + uint8_t version = static_cast((kAdvertisementVersion & kVersionBitmask) << 5); + uint8_t visibility = static_cast(((has_device_name ? 0 : 1) & kVisibilityBitmask) << 4); + uint8_t type = static_cast((static_cast(device_type) & kDeviceTypeBitmask) << 1); + return static_cast(version | visibility | type); +} + +bool ShouldIncludeDeviceName(const std::optional& device_name) { + return device_name.has_value() && !device_name->empty(); +} + +TransferMetadata::Status StatusFromPayloadStatus( + connections::PayloadProgressInfo::Status status) { + switch (status) { + case connections::PayloadProgressInfo::Status::kInProgress: + return TransferMetadata::Status::kInProgress; + case connections::PayloadProgressInfo::Status::kSuccess: + return TransferMetadata::Status::kComplete; + case connections::PayloadProgressInfo::Status::kFailure: + return TransferMetadata::Status::kFailed; + case connections::PayloadProgressInfo::Status::kCanceled: + return TransferMetadata::Status::kCancelled; + } + return TransferMetadata::Status::kUnknown; +} + +} // namespace + +NearbySharingServiceLinux::NearbySharingServiceLinux() + : device_info_(::nearby::api::ImplementationPlatform::CreateDeviceInfo()), + router_(std::make_unique()), + core_(std::make_unique(router_.get())) { + if (device_info_) { + auto name = device_info_->GetOsDeviceName(); + if (name.has_value()) { + device_name_override_ = *name; + } + } +} + +NearbySharingServiceLinux::NearbySharingServiceLinux( + std::string device_name_override) + : device_name_override_(std::move(device_name_override)), + device_info_(::nearby::api::ImplementationPlatform::CreateDeviceInfo()), + router_(std::make_unique()), + core_(std::make_unique(router_.get())) {} + +NearbySharingServiceLinux::~NearbySharingServiceLinux() = default; + +void NearbySharingServiceLinux::AddObserver(Observer* observer) { + if (!observer) { + return; + } + observers_.insert(observer); +} + +void NearbySharingServiceLinux::RemoveObserver(Observer* observer) { + observers_.erase(observer); +} + +void NearbySharingServiceLinux::Shutdown( + std::function + status_codes_callback) { + StopDiscovery(); + StopAdvertising(); + endpoint_to_target_.clear(); + target_id_to_endpoint_.clear(); + active_transfers_.clear(); + is_transferring_ = false; + std::move(status_codes_callback)(StatusCodes::kOk); +} + +void NearbySharingServiceLinux::RegisterSendSurface( + TransferUpdateCallback* transfer_callback, + ShareTargetDiscoveredCallback* discovery_callback, SendSurfaceState state, + Advertisement::BlockedVendorId blocked_vendor_id, + bool disable_wifi_hotspot, + std::function + status_codes_callback) { + static_cast(blocked_vendor_id); + if (!transfer_callback) { + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; + } + + send_surfaces_[transfer_callback] = SendSurface{ + .discovery_callback = discovery_callback, + .state = state, + .disable_wifi_hotspot = disable_wifi_hotspot, + }; + + StartDiscoveryIfNeeded(); + std::move(status_codes_callback)(StatusCodes::kOk); +} + +void NearbySharingServiceLinux::UnregisterSendSurface( + TransferUpdateCallback* transfer_callback, + std::function + status_codes_callback) { + if (!transfer_callback) { + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; + } + + send_surfaces_.erase(transfer_callback); + if (send_surfaces_.empty()) { + StopDiscovery(); + } + + std::move(status_codes_callback)(StatusCodes::kOk); +} + +void NearbySharingServiceLinux::RegisterReceiveSurface( + TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, + Advertisement::BlockedVendorId vendor_id, + std::function + status_codes_callback) { + if (!transfer_callback) { + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; + } + + receive_surfaces_[transfer_callback] = ReceiveSurface{ + .state = state, + .vendor_id = vendor_id, + }; + + StartAdvertisingIfNeeded(); + std::move(status_codes_callback)(StatusCodes::kOk); +} + +void NearbySharingServiceLinux::UnregisterReceiveSurface( + TransferUpdateCallback* transfer_callback, + std::function + status_codes_callback) { + if (!transfer_callback) { + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; + } + + receive_surfaces_.erase(transfer_callback); + if (receive_surfaces_.empty()) { + StopAdvertising(); + } else { + StartAdvertisingIfNeeded(); + } + + std::move(status_codes_callback)(StatusCodes::kOk); +} + +void NearbySharingServiceLinux::ClearForegroundReceiveSurfaces( + std::function + status_codes_callback) { + for (auto it = receive_surfaces_.begin(); it != receive_surfaces_.end();) { + if (it->second.state == ReceiveSurfaceState::kForeground) { + it = receive_surfaces_.erase(it); + } else { + ++it; + } + } + + if (receive_surfaces_.empty()) { + StopAdvertising(); + } else { + StartAdvertisingIfNeeded(); + } + + std::move(status_codes_callback)(StatusCodes::kOk); +} + +bool NearbySharingServiceLinux::IsTransferring() const { + return is_transferring_; +} + +bool NearbySharingServiceLinux::IsScanning() const { return is_scanning_; } + +bool NearbySharingServiceLinux::IsBluetoothPresent() const { + return bluetooth_adapter_.IsValid(); +} + +bool NearbySharingServiceLinux::IsBluetoothPowered() const { + return bluetooth_adapter_.IsValid() && bluetooth_adapter_.IsEnabled(); +} + +bool NearbySharingServiceLinux::IsExtendedAdvertisingSupported() const { + return false; +} + +bool NearbySharingServiceLinux::IsLanConnected() const { return false; } + +std::string NearbySharingServiceLinux::GetQrCodeUrl() const { return ""; } + +void NearbySharingServiceLinux::SendAttachments( + int64_t share_target_id, + std::unique_ptr + attachment_container, + std::function + status_codes_callback) { + auto endpoint_id = GetEndpointIdForTarget(share_target_id); + if (!endpoint_id.has_value() || !attachment_container || + !attachment_container->HasAttachments()) { + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; + } + + TransferUpdateCallback* callback = PickSendTransferCallback(); + if (!callback) { + std::move(status_codes_callback)(StatusCodes::kOutOfOrderApiCall); + return; + } + + TransferState transfer_state; + transfer_state.attachments = *attachment_container; + transfer_state.callback = callback; + transfer_state.is_incoming = false; + active_transfers_[*endpoint_id] = transfer_state; + + TransferMetadata metadata = + TransferMetadataBuilder().set_status(TransferMetadata::Status::kConnecting) + .set_progress(0) + .set_total_attachments_count( + attachment_container->GetAttachmentCount()) + .build(); + if (auto share_target = GetShareTarget(*endpoint_id)) { + NotifyTransferUpdate(*share_target, transfer_state, metadata); + } + + connections::ConnectionOptions options; + options.strategy = kStrategy; + options.allowed.SetAll(true); + + std::optional device_name = + device_name_override_.empty() + ? std::optional(std::nullopt) + : std::optional(device_name_override_); + if (!device_name.has_value() && device_info_) { + auto name = device_info_->GetOsDeviceName(); + if (name.has_value()) { + device_name = *name; + } + } + + ShareTargetType device_type = ShareTargetType::kUnknown; + if (device_info_) { + device_type = + static_cast(device_info_->GetDeviceType()); + } + + std::vector endpoint_info = + BuildAdvertisement(device_name, device_type, + static_cast( + Advertisement::BlockedVendorId::kNone)); + connections::ConnectionRequestInfo request_info; + request_info.endpoint_info = + ByteArray(std::string(endpoint_info.begin(), endpoint_info.end())); + request_info.listener.initiated_cb = + [this](const std::string& id, + const connections::ConnectionResponseInfo& info) { + HandleOutgoingConnectionInitiated(id, info); + }; + request_info.listener.accepted_cb = [this](const std::string& id) { + HandleConnectionAccepted(id, /*is_incoming=*/false); + }; + request_info.listener.rejected_cb = + [this](const std::string& id, connections::Status status) { + HandleConnectionRejected(id, status, /*is_incoming=*/false); + }; + request_info.listener.disconnected_cb = [this](const std::string& id) { + HandleConnectionDisconnected(id); + }; + + core_->RequestConnection(*endpoint_id, request_info, options, + [this, cb = std::move(status_codes_callback)]( + connections::Status status) mutable { + cb(StatusFromConnections(status)); + }); +} + +void NearbySharingServiceLinux::Accept( + int64_t share_target_id, + std::function + status_codes_callback) { + auto endpoint_id = GetEndpointIdForTarget(share_target_id); + if (!endpoint_id.has_value()) { + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; + } + + core_->AcceptConnection(*endpoint_id, MakePayloadListener(true), + [this, cb = std::move(status_codes_callback)]( + connections::Status status) mutable { + cb(StatusFromConnections(status)); + }); +} + +void NearbySharingServiceLinux::Reject( + int64_t share_target_id, + std::function + status_codes_callback) { + auto endpoint_id = GetEndpointIdForTarget(share_target_id); + if (!endpoint_id.has_value()) { + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; + } + + core_->RejectConnection(*endpoint_id, + [this, cb = std::move(status_codes_callback)]( + connections::Status status) mutable { + cb(StatusFromConnections(status)); + }); +} + +void NearbySharingServiceLinux::Cancel( + int64_t share_target_id, + std::function + status_codes_callback) { + auto endpoint_id = GetEndpointIdForTarget(share_target_id); + if (!endpoint_id.has_value()) { + std::move(status_codes_callback)(StatusCodes::kInvalidArgument); + return; + } + + core_->DisconnectFromEndpoint( + *endpoint_id, + [this, cb = std::move(status_codes_callback)](connections::Status status) mutable { + cb(StatusFromConnections(status)); + }); +} + +void NearbySharingServiceLinux::SetVisibility( + proto::DeviceVisibility visibility, absl::Duration expiration, + absl::AnyInvocable callback) { + static_cast(visibility); + static_cast(expiration); + std::move(callback)(StatusCodes::kOk); +} + +std::string NearbySharingServiceLinux::Dump() const { + std::stringstream ss; + ss << "NearbySharingServiceLinux"; + ss << " advertising=" << (is_advertising_ ? "true" : "false"); + ss << " scanning=" << (is_scanning_ ? "true" : "false"); + ss << " transfers=" << active_transfers_.size(); + ss << " targets=" << endpoint_to_target_.size(); + return ss.str(); +} + +void NearbySharingServiceLinux::UpdateFilePathsInProgress( + bool update_file_paths) {} + +NearbyShareSettings* NearbySharingServiceLinux::GetSettings() { + return nullptr; +} + +NearbyShareLocalDeviceDataManager* +NearbySharingServiceLinux::GetLocalDeviceDataManager() { + return nullptr; +} + +NearbyShareContactManager* NearbySharingServiceLinux::GetContactManager() { + return nullptr; +} + +NearbyShareCertificateManager* +NearbySharingServiceLinux::GetCertificateManager() { + return nullptr; +} + +AccountManager* NearbySharingServiceLinux::GetAccountManager() { + return nullptr; +} + +Clock& NearbySharingServiceLinux::GetClock() { return clock_; } + +void NearbySharingServiceLinux::SetAlternateServiceUuidForDiscovery( + uint16_t alternate_service_uuid) { + alternate_service_uuid_ = alternate_service_uuid; + if (is_scanning_) { + StopDiscovery(); + StartDiscoveryIfNeeded(); + } +} + +void NearbySharingServiceLinux::StartAdvertisingIfNeeded() { + if (receive_surfaces_.empty()) { + StopAdvertising(); + return; + } + + bool has_foreground = false; + uint8_t vendor_id = 0; + for (const auto& [callback, surface] : receive_surfaces_) { + if (surface.state == ReceiveSurfaceState::kForeground) { + has_foreground = true; + vendor_id = static_cast(surface.vendor_id); + break; + } + } + + std::optional device_name = std::nullopt; + if (has_foreground) { + if (!device_name_override_.empty()) { + device_name = device_name_override_; + } else if (device_info_) { + auto name = device_info_->GetOsDeviceName(); + if (name.has_value()) { + device_name = *name; + } + } + } + + ShareTargetType device_type = ShareTargetType::kUnknown; + if (device_info_) { + device_type = + static_cast(device_info_->GetDeviceType()); + } + + if (is_advertising_ && has_foreground == last_advertise_with_name_ && + vendor_id == last_advertise_vendor_id_) { + return; + } + + if (is_advertising_) { + StopAdvertising(); + } + + std::vector endpoint_info = + BuildAdvertisement(device_name, device_type, vendor_id); + + connections::AdvertisingOptions options; + options.strategy = kStrategy; + options.allowed.SetAll(true); + options.use_stable_endpoint_id = has_foreground; + + connections::ConnectionRequestInfo request_info; + request_info.endpoint_info = + ByteArray(std::string(endpoint_info.begin(), endpoint_info.end())); + request_info.listener.initiated_cb = + [this](const std::string& id, + const connections::ConnectionResponseInfo& info) { + HandleIncomingConnectionInitiated(id, info); + }; + request_info.listener.accepted_cb = [this](const std::string& id) { + HandleConnectionAccepted(id, /*is_incoming=*/true); + }; + request_info.listener.rejected_cb = + [this](const std::string& id, connections::Status status) { + HandleConnectionRejected(id, status, /*is_incoming=*/true); + }; + request_info.listener.disconnected_cb = [this](const std::string& id) { + HandleConnectionDisconnected(id); + }; + + core_->StartAdvertising( + kServiceId, options, std::move(request_info), + [this, has_foreground, vendor_id](connections::Status status) { + is_advertising_ = status.Ok(); + if (is_advertising_) { + last_advertise_with_name_ = has_foreground; + last_advertise_vendor_id_ = vendor_id; + } + }); +} + +void NearbySharingServiceLinux::StopAdvertising() { + if (!is_advertising_) { + return; + } + is_advertising_ = false; + core_->StopAdvertising([this](connections::Status status) { + static_cast(status); + }); +} + +void NearbySharingServiceLinux::StartDiscoveryIfNeeded() { + bool needs_scanning = false; + for (const auto& [callback, surface] : send_surfaces_) { + if (surface.state == SendSurfaceState::kForeground) { + needs_scanning = true; + break; + } + } + + if (!needs_scanning) { + StopDiscovery(); + return; + } + + if (is_scanning_) { + return; + } + + connections::DiscoveryOptions options; + options.strategy = kStrategy; + options.allowed.SetAll(true); + if (alternate_service_uuid_.has_value()) { + options.ble_options.alternate_uuid = *alternate_service_uuid_; + } + + connections::DiscoveryListener listener; + listener.endpoint_found_cb = + [this](const std::string& endpoint_id, const ByteArray& endpoint_info, + const std::string& service_id) { + static_cast(service_id); + std::string info_string = std::string(endpoint_info); + std::vector info_bytes(info_string.begin(), info_string.end()); + ParsedAdvertisement parsed; + if (auto parsed_opt = ParseAdvertisement(info_bytes)) { + parsed = *parsed_opt; + } + + ShareTarget target; + target.id = next_share_target_id_++; + if (parsed.device_name.has_value()) { + target.device_name = *parsed.device_name; + } else { + target.device_name = endpoint_id; + } + target.type = parsed.device_type; + target.is_incoming = false; + target.vendor_id = parsed.vendor_id; + + auto existing = endpoint_to_target_.find(endpoint_id); + if (existing == endpoint_to_target_.end()) { + endpoint_to_target_[endpoint_id] = target; + target_id_to_endpoint_[target.id] = endpoint_id; + NotifyShareTargetDiscovered(target); + } else { + target.id = existing->second.id; + endpoint_to_target_[endpoint_id] = target; + NotifyShareTargetUpdated(target); + } + }; + listener.endpoint_lost_cb = [this](const std::string& endpoint_id) { + auto it = endpoint_to_target_.find(endpoint_id); + if (it == endpoint_to_target_.end()) { + return; + } + ShareTarget target = it->second; + endpoint_to_target_.erase(it); + target_id_to_endpoint_.erase(target.id); + NotifyShareTargetLost(target); + }; + + core_->StartDiscovery( + kServiceId, options, std::move(listener), + [this](connections::Status status) { is_scanning_ = status.Ok(); }); +} + +void NearbySharingServiceLinux::StopDiscovery() { + if (!is_scanning_) { + return; + } + core_->StopDiscovery([this](connections::Status status) { + if (status.Ok()) { + is_scanning_ = false; + } + }); +} + +std::vector NearbySharingServiceLinux::BuildAdvertisement( + const std::optional& device_name, ShareTargetType device_type, + uint8_t vendor_id) const { + const bool has_device_name = ShouldIncludeDeviceName(device_name); + std::vector salt = GenerateRandomBytes(kAdvertisementSaltSize); + std::vector metadata_key = + GenerateRandomBytes(kAdvertisementMetadataKeySize); + + size_t size = 1 + salt.size() + metadata_key.size(); + if (has_device_name) { + size += 1 + device_name->size(); + } + if (vendor_id != 0) { + size += kTlvMinLength + kVendorIdLength; + } + + std::vector endpoint_info; + endpoint_info.reserve(size); + endpoint_info.push_back(EncodeHeaderByte(has_device_name, device_type)); + endpoint_info.insert(endpoint_info.end(), salt.begin(), salt.end()); + endpoint_info.insert(endpoint_info.end(), metadata_key.begin(), + metadata_key.end()); + + if (has_device_name) { + endpoint_info.push_back( + static_cast(device_name->size() & 0xff)); + endpoint_info.insert(endpoint_info.end(), device_name->begin(), + device_name->end()); + } + + if (vendor_id != 0) { + endpoint_info.push_back(static_cast(TlvTypes::kVendorId)); + endpoint_info.push_back(kVendorIdLength); + endpoint_info.push_back(vendor_id); + } + + return endpoint_info; +} + +std::optional +NearbySharingServiceLinux::ParseAdvertisement( + absl::Span endpoint_info) const { + ParsedAdvertisement parsed; + const size_t minimum_size = + 1 + kAdvertisementSaltSize + kAdvertisementMetadataKeySize; + if (endpoint_info.size() < minimum_size) { + return std::nullopt; + } + + size_t offset = 0; + uint8_t header = endpoint_info[offset++]; + bool has_device_name = ((header >> 4) & kVisibilityBitmask) == 0; + uint8_t type = (header >> 1) & kDeviceTypeBitmask; + if (type <= static_cast(ShareTargetType::kXR)) { + parsed.device_type = static_cast(type); + } else { + parsed.device_type = ShareTargetType::kUnknown; + } + + offset += kAdvertisementSaltSize + kAdvertisementMetadataKeySize; + if (has_device_name) { + if (offset >= endpoint_info.size()) { + return parsed; + } + uint8_t name_length = endpoint_info[offset++]; + if (name_length == 0 || offset + name_length > endpoint_info.size()) { + return parsed; + } + parsed.device_name = std::string( + reinterpret_cast(endpoint_info.data() + offset), + name_length); + offset += name_length; + } + + while (offset + kTlvMinLength <= endpoint_info.size()) { + uint8_t tlv_type = endpoint_info[offset++]; + uint8_t tlv_length = endpoint_info[offset++]; + if (offset + tlv_length > endpoint_info.size()) { + break; + } + if (tlv_type == static_cast(TlvTypes::kVendorId) && + tlv_length == kVendorIdLength) { + parsed.vendor_id = endpoint_info[offset]; + } + offset += tlv_length; + } + + return parsed; +} + +void NearbySharingServiceLinux::NotifyShareTargetDiscovered( + const ShareTarget& share_target) { + for (const auto& [transfer_callback, surface] : send_surfaces_) { + if (surface.state != SendSurfaceState::kForeground || + surface.discovery_callback == nullptr) { + continue; + } + surface.discovery_callback->OnShareTargetDiscovered(share_target); + } +} + +void NearbySharingServiceLinux::NotifyShareTargetUpdated( + const ShareTarget& share_target) { + for (const auto& [transfer_callback, surface] : send_surfaces_) { + if (surface.state != SendSurfaceState::kForeground || + surface.discovery_callback == nullptr) { + continue; + } + surface.discovery_callback->OnShareTargetUpdated(share_target); + } +} + +void NearbySharingServiceLinux::NotifyShareTargetLost( + const ShareTarget& share_target) { + for (const auto& [transfer_callback, surface] : send_surfaces_) { + if (surface.state != SendSurfaceState::kForeground || + surface.discovery_callback == nullptr) { + continue; + } + surface.discovery_callback->OnShareTargetLost(share_target); + } +} + +void NearbySharingServiceLinux::NotifyTransferUpdate( + const ShareTarget& share_target, const TransferState& transfer_state, + const TransferMetadata& metadata) { + if (!transfer_state.callback) { + return; + } + transfer_state.callback->OnTransferUpdate(share_target, + transfer_state.attachments, + metadata); +} + +TransferUpdateCallback* NearbySharingServiceLinux::PickSendTransferCallback() + const { + if (send_surfaces_.empty()) { + return nullptr; + } + return send_surfaces_.begin()->first; +} + +TransferUpdateCallback* NearbySharingServiceLinux::PickReceiveTransferCallback() + const { + if (receive_surfaces_.empty()) { + return nullptr; + } + return receive_surfaces_.begin()->first; +} + +std::optional NearbySharingServiceLinux::GetEndpointIdForTarget( + int64_t share_target_id) const { + auto it = target_id_to_endpoint_.find(share_target_id); + if (it == target_id_to_endpoint_.end()) { + return std::nullopt; + } + return it->second; +} + +std::optional NearbySharingServiceLinux::GetShareTarget( + absl::string_view endpoint_id) const { + auto it = endpoint_to_target_.find(std::string(endpoint_id)); + if (it == endpoint_to_target_.end()) { + return std::nullopt; + } + return it->second; +} + +void NearbySharingServiceLinux::HandleIncomingConnectionInitiated( + const std::string& endpoint_id, + const connections::ConnectionResponseInfo& info) { + static_cast(info); + std::vector info_bytes(info.remote_endpoint_info.begin(), + info.remote_endpoint_info.end()); + ParsedAdvertisement parsed; + if (auto parsed_opt = ParseAdvertisement(info_bytes)) { + parsed = *parsed_opt; + } + + ShareTarget target; + target.id = next_share_target_id_++; + target.device_name = parsed.device_name.value_or(endpoint_id); + target.type = parsed.device_type; + target.is_incoming = true; + target.vendor_id = parsed.vendor_id; + + auto existing = endpoint_to_target_.find(endpoint_id); + if (existing == endpoint_to_target_.end()) { + endpoint_to_target_[endpoint_id] = target; + target_id_to_endpoint_[target.id] = endpoint_id; + } else { + target.id = existing->second.id; + endpoint_to_target_[endpoint_id] = target; + } + + TransferState transfer_state; + transfer_state.attachments = AttachmentContainer(); + transfer_state.callback = PickReceiveTransferCallback(); + transfer_state.is_incoming = true; + active_transfers_[endpoint_id] = transfer_state; + + TransferMetadata metadata = TransferMetadataBuilder() + .set_status(TransferMetadata::Status::kAwaitingLocalConfirmation) + .set_progress(0) + .build(); + NotifyTransferUpdate(target, transfer_state, metadata); +} + +void NearbySharingServiceLinux::HandleOutgoingConnectionInitiated( + const std::string& endpoint_id, + const connections::ConnectionResponseInfo& info) { + static_cast(info); + core_->AcceptConnection(endpoint_id, MakePayloadListener(false), + [this, endpoint_id](connections::Status status) { + if (!status.Ok()) { + HandleConnectionRejected(endpoint_id, status, + /*is_incoming=*/false); + } + }); + + auto share_target = GetShareTarget(endpoint_id); + auto transfer_it = active_transfers_.find(endpoint_id); + if (share_target && transfer_it != active_transfers_.end()) { + TransferMetadata metadata = + TransferMetadataBuilder() + .set_status(TransferMetadata::Status::kAwaitingRemoteAcceptance) + .set_progress(0) + .build(); + NotifyTransferUpdate(*share_target, transfer_it->second, metadata); + } +} + +void NearbySharingServiceLinux::HandleConnectionAccepted( + const std::string& endpoint_id, bool is_incoming) { + auto transfer_it = active_transfers_.find(endpoint_id); + if (transfer_it == active_transfers_.end()) { + return; + } + + auto share_target = GetShareTarget(endpoint_id); + if (share_target) { + TransferMetadata metadata = TransferMetadataBuilder() + .set_status(TransferMetadata::Status::kInProgress) + .set_progress(0) + .set_total_attachments_count( + transfer_it->second.attachments.GetAttachmentCount()) + .build(); + NotifyTransferUpdate(*share_target, transfer_it->second, metadata); + } + + if (!is_incoming) { + const AttachmentContainer& attachments = transfer_it->second.attachments; + std::unique_ptr payload; + if (!attachments.GetTextAttachments().empty()) { + std::string text = + std::string(attachments.GetTextAttachments()[0].text_body()); + payload = std::make_unique(ByteArray(text)); + } else if (!attachments.GetFileAttachments().empty()) { + const auto& file_attachment = attachments.GetFileAttachments()[0]; + if (file_attachment.file_path().has_value()) { + std::string file_path = file_attachment.file_path()->ToString(); + nearby::InputFile input_file(file_path, file_attachment.size()); + payload = std::make_unique( + std::string(file_attachment.parent_folder()), + std::string(file_attachment.file_name()), std::move(input_file)); + } + } + + if (payload) { + std::vector endpoints; + endpoints.push_back(endpoint_id); + core_->SendPayload( + endpoints, std::move(*payload), + [this](connections::Status status) { + if (!status.Ok()) { + is_transferring_ = false; + } + }); + } + } + + is_transferring_ = true; +} + +void NearbySharingServiceLinux::HandleConnectionRejected( + const std::string& endpoint_id, connections::Status status, + bool is_incoming) { + static_cast(status); + static_cast(is_incoming); + auto transfer_it = active_transfers_.find(endpoint_id); + if (transfer_it == active_transfers_.end()) { + return; + } + auto share_target = GetShareTarget(endpoint_id); + if (share_target) { + TransferMetadata metadata = TransferMetadataBuilder() + .set_status(TransferMetadata::Status::kRejected) + .set_progress(0) + .build(); + NotifyTransferUpdate(*share_target, transfer_it->second, metadata); + } + active_transfers_.erase(transfer_it); + is_transferring_ = false; +} + +void NearbySharingServiceLinux::HandleConnectionDisconnected( + const std::string& endpoint_id) { + active_transfers_.erase(endpoint_id); + if (active_transfers_.empty()) { + is_transferring_ = false; + } +} + +connections::PayloadListener NearbySharingServiceLinux::MakePayloadListener( + bool is_incoming) { + static_cast(is_incoming); + connections::PayloadListener listener; + listener.payload_cb = + [this, is_incoming](absl::string_view endpoint_id, + connections::Payload payload) { + auto transfer_it = active_transfers_.find(std::string(endpoint_id)); + if (transfer_it == active_transfers_.end()) { + return; + } + auto share_target = GetShareTarget(endpoint_id); + if (!share_target) { + return; + } + + TransferMetadata metadata = TransferMetadataBuilder() + .set_status(TransferMetadata::Status::kInProgress) + .set_progress(0) + .build(); + NotifyTransferUpdate(*share_target, transfer_it->second, metadata); + }; + + listener.payload_progress_cb = + [this, is_incoming](absl::string_view endpoint_id, + const connections::PayloadProgressInfo& info) { + auto transfer_it = active_transfers_.find(std::string(endpoint_id)); + if (transfer_it == active_transfers_.end()) { + return; + } + auto share_target = GetShareTarget(endpoint_id); + if (!share_target) { + return; + } + + float progress = 0.0f; + if (info.total_bytes > 0) { + progress = static_cast(info.bytes_transferred) / + static_cast(info.total_bytes); + } + + TransferMetadata metadata = + TransferMetadataBuilder() + .set_status(StatusFromPayloadStatus(info.status)) + .set_progress(progress) + .set_transferred_bytes(info.bytes_transferred) + .build(); + + NotifyTransferUpdate(*share_target, transfer_it->second, metadata); + + if (TransferMetadata::IsFinalStatus(metadata.status())) { + active_transfers_.erase(transfer_it); + if (active_transfers_.empty()) { + is_transferring_ = false; + } + } + }; + return listener; +} + +NearbySharingService::StatusCodes NearbySharingServiceLinux::StatusFromConnections( + connections::Status status) const { + if (status.Ok()) { + return StatusCodes::kOk; + } + if (status.value == connections::Status::kOutOfOrderApiCall) { + return StatusCodes::kOutOfOrderApiCall; + } + return StatusCodes::kError; +} + +} // namespace nearby::sharing::linux diff --git a/sharing/linux/nearby_sharing_service_linux.h b/sharing/linux/nearby_sharing_service_linux.h new file mode 100644 index 00000000..bbfc0beb --- /dev/null +++ b/sharing/linux/nearby_sharing_service_linux.h @@ -0,0 +1,229 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef THIRD_PARTY_NEARBY_SHARING_LINUX_NEARBY_SHARING_SERVICE_LINUX_H_ +#define THIRD_PARTY_NEARBY_SHARING_LINUX_NEARBY_SHARING_SERVICE_LINUX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" +#include "connections/advertising_options.h" +#include "connections/connection_options.h" +#include "connections/core.h" +#include "connections/discovery_options.h" +#include "connections/implementation/service_controller_router.h" +#include "connections/listeners.h" +#include "connections/payload.h" +#include "connections/status.h" +#include "connections/strategy.h" +#include "internal/platform/bluetooth_adapter.h" +#include "internal/platform/clock_impl.h" +#include "internal/platform/implementation/platform.h" +#include "sharing/attachment_container.h" +#include "sharing/nearby_sharing_service.h" +#include "sharing/share_target.h" +#include "sharing/share_target_discovered_callback.h" +#include "sharing/transfer_metadata.h" +#include "sharing/transfer_metadata_builder.h" + +namespace nearby::sharing::linux { + +class NearbySharingServiceLinux : public NearbySharingService { + public: + using StatusCodes = NearbySharingService::StatusCodes; + + NearbySharingServiceLinux(); + explicit NearbySharingServiceLinux(std::string device_name_override); + ~NearbySharingServiceLinux() override; + + void AddObserver(Observer* observer) override; + void RemoveObserver(Observer* observer) override; + + void Shutdown( + std::function status_codes_callback) override; + + void RegisterSendSurface( + TransferUpdateCallback* transfer_callback, + ShareTargetDiscoveredCallback* discovery_callback, SendSurfaceState state, + Advertisement::BlockedVendorId blocked_vendor_id, + bool disable_wifi_hotspot, + std::function status_codes_callback) override; + + void UnregisterSendSurface( + TransferUpdateCallback* transfer_callback, + std::function status_codes_callback) override; + + void RegisterReceiveSurface( + TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, + Advertisement::BlockedVendorId vendor_id, + std::function status_codes_callback) override; + + void UnregisterReceiveSurface( + TransferUpdateCallback* transfer_callback, + std::function status_codes_callback) override; + + void ClearForegroundReceiveSurfaces( + std::function status_codes_callback) override; + + bool IsTransferring() const override; + bool IsScanning() const override; + bool IsBluetoothPresent() const override; + bool IsBluetoothPowered() const override; + bool IsExtendedAdvertisingSupported() const override; + bool IsLanConnected() const override; + std::string GetQrCodeUrl() const override; + + void SendAttachments( + int64_t share_target_id, + std::unique_ptr + attachment_container, + std::function status_codes_callback) override; + + void Accept(int64_t share_target_id, + std::function + status_codes_callback) override; + + void Reject(int64_t share_target_id, + std::function + status_codes_callback) override; + + void Cancel(int64_t share_target_id, + std::function + status_codes_callback) override; + + void SetVisibility(proto::DeviceVisibility visibility, + absl::Duration expiration, + absl::AnyInvocable + callback) override; + + std::string Dump() const override; + void UpdateFilePathsInProgress(bool update_file_paths) override; + + NearbyShareSettings* GetSettings() override; + NearbyShareLocalDeviceDataManager* GetLocalDeviceDataManager() override; + NearbyShareContactManager* GetContactManager() override; + NearbyShareCertificateManager* GetCertificateManager() override; + AccountManager* GetAccountManager() override; + Clock& GetClock() override; + void SetAlternateServiceUuidForDiscovery( + uint16_t alternate_service_uuid) override; + + private: + struct SendSurface { + ShareTargetDiscoveredCallback* discovery_callback = nullptr; + SendSurfaceState state = SendSurfaceState::kUnknown; + bool disable_wifi_hotspot = false; + }; + + struct ReceiveSurface { + ReceiveSurfaceState state = ReceiveSurfaceState::kUnknown; + Advertisement::BlockedVendorId vendor_id = + Advertisement::BlockedVendorId::kNone; + }; + + struct TransferState { + nearby::sharing::AttachmentContainer attachments; + TransferUpdateCallback* callback = nullptr; + bool is_incoming = false; + }; + + struct ParsedAdvertisement { + ShareTargetType device_type = ShareTargetType::kUnknown; + std::optional device_name; + uint8_t vendor_id = 0; + }; + + void StartAdvertisingIfNeeded(); + void StopAdvertising(); + void StartDiscoveryIfNeeded(); + void StopDiscovery(); + + std::vector BuildAdvertisement( + const std::optional& device_name, + ShareTargetType device_type, uint8_t vendor_id) const; + + std::optional ParseAdvertisement( + absl::Span endpoint_info) const; + + void NotifyShareTargetDiscovered(const ShareTarget& share_target); + void NotifyShareTargetUpdated(const ShareTarget& share_target); + void NotifyShareTargetLost(const ShareTarget& share_target); + void NotifyTransferUpdate(const ShareTarget& share_target, + const TransferState& transfer_state, + const TransferMetadata& metadata); + + TransferUpdateCallback* PickSendTransferCallback() const; + TransferUpdateCallback* PickReceiveTransferCallback() const; + + std::optional GetEndpointIdForTarget( + int64_t share_target_id) const; + + std::optional GetShareTarget( + absl::string_view endpoint_id) const; + + void HandleIncomingConnectionInitiated( + const std::string& endpoint_id, + const connections::ConnectionResponseInfo& info); + + void HandleOutgoingConnectionInitiated( + const std::string& endpoint_id, + const connections::ConnectionResponseInfo& info); + + void HandleConnectionAccepted(const std::string& endpoint_id, + bool is_incoming); + void HandleConnectionRejected(const std::string& endpoint_id, + connections::Status status, bool is_incoming); + void HandleConnectionDisconnected(const std::string& endpoint_id); + + connections::PayloadListener MakePayloadListener(bool is_incoming); + + StatusCodes StatusFromConnections(connections::Status status) const; + + std::string device_name_override_; + std::unique_ptr<::nearby::api::DeviceInfo> device_info_; + BluetoothAdapter bluetooth_adapter_; + ClockImpl clock_; + + std::unique_ptr router_; + std::unique_ptr core_; + + std::unordered_set observers_; + std::unordered_map send_surfaces_; + std::unordered_map receive_surfaces_; + + std::unordered_map endpoint_to_target_; + std::unordered_map target_id_to_endpoint_; + std::unordered_map active_transfers_; + + std::optional alternate_service_uuid_; + bool is_scanning_ = false; + bool is_advertising_ = false; + bool is_transferring_ = false; + int64_t next_share_target_id_ = 1; + bool last_advertise_with_name_ = false; + uint8_t last_advertise_vendor_id_ = 0; +}; + +} // namespace nearby::sharing::linux + +#endif // THIRD_PARTY_NEARBY_SHARING_LINUX_NEARBY_SHARING_SERVICE_LINUX_H_ From a209c46fa3b6a9faa9fd8a8c186f201f318ee268 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Wed, 21 Jan 2026 07:50:24 +0530 Subject: [PATCH 197/201] added nearby_sharing_app implementing nearby_sharing_service for linxu --- connections/file_share/main.cc | 5 + sharing/linux/BUILD | 104 +++++ sharing/linux/IMPLEMENTATION_GUIDE.md | 592 +++++++++++++++++++++++++ sharing/linux/QUICK_REFERENCE.md | 300 +++++++++++++ sharing/linux/README.md | 348 +++++++++++++++ sharing/linux/nearby_sharing_app.cc | 394 ++++++++++++++++ sharing/linux/nearby_sharing_app_BUILD | 28 ++ sharing/linux/simple_example.cc | 251 +++++++++++ 8 files changed, 2022 insertions(+) create mode 100644 sharing/linux/BUILD create mode 100644 sharing/linux/IMPLEMENTATION_GUIDE.md create mode 100644 sharing/linux/QUICK_REFERENCE.md create mode 100644 sharing/linux/README.md create mode 100644 sharing/linux/nearby_sharing_app.cc create mode 100644 sharing/linux/nearby_sharing_app_BUILD create mode 100644 sharing/linux/simple_example.cc diff --git a/connections/file_share/main.cc b/connections/file_share/main.cc index 44b35113..edeb3970 100644 --- a/connections/file_share/main.cc +++ b/connections/file_share/main.cc @@ -309,6 +309,11 @@ class FileShareApp { : options_.mediums; options.auto_upgrade_bandwidth = true; auto device = CacheDiscoveredDevice(remote_device); + // disable advertising + core_ -> StopAdvertisingV3( + [](nearby::connections::Status status) { + LOG(INFO) << "StopAdvertising status: " << status.ToString(); + }); core_->RequestConnectionV3( local_device_, *device, options, MakeConnectionListener(), [](nearby::connections::Status status) { diff --git a/sharing/linux/BUILD b/sharing/linux/BUILD new file mode 100644 index 00000000..b5942abe --- /dev/null +++ b/sharing/linux/BUILD @@ -0,0 +1,104 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +cc_library( + name = "nearby_sharing_service_linux", + srcs = [ + "nearby_sharing_service_linux.cc", + "//sharing:nearby_sharing_service.cc", + "//sharing:transfer_metadata.cc", + "//sharing:transfer_metadata_builder.cc", + '//sharing/certificates:nearby_share_certificate_manager.cc', + '//sharing/certificates:nearby_share_decrypted_public_certificate.cc', + '//sharing/certificates:nearby_share_encrypted_metadata_key.cc', + '//sharing/certificates:nearby_share_private_certificate.cc', + '//sharing/local_device_data:nearby_share_local_device_data_manager.cc', + '//sharing:nearby_sharing_settings.cc', + '//sharing/analytics:analytics_recorder.cc', + '//sharing:thread_timer.cc', + '//sharing/certificates:common.cc', + '//sharing/common:nearby_share_prefs.cc', + ], + hdrs = [ + "nearby_sharing_service_linux.h", + "//sharing:transfer_metadata.h", + "//sharing:transfer_metadata_builder.h", + '//sharing:nearby_sharing_service.h', + '//sharing/common:nearby_share_prefs.h', + '//sharing/certificates:nearby_share_certificate_manager.h', + '//sharing/certificates:nearby_share_decrypted_public_certificate.h', + '//sharing/certificates:nearby_share_encrypted_metadata_key.h', + '//sharing/certificates:nearby_share_private_certificate.h', + '//sharing/internal/api:private_certificate_data.h', + '//sharing/local_device_data:nearby_share_local_device_data_manager.h', + '//sharing:nearby_sharing_settings.h', + '//sharing/analytics:analytics_recorder.h', + '//sharing/analytics:analytics_device_settings.h', + '//sharing/analytics:analytics_information.h', + '//sharing/internal/api:preference_manager.h', + '//sharing/internal/public:context.h', + '//sharing/internal/public:pref_names.h', + '//sharing/internal/api:bluetooth_adapter.h', + '//sharing/internal/api:fast_initiation_manager.h', + '//sharing/internal/api:fast_init_ble_beacon.h', + '//sharing/internal/public:connectivity_manager.h', + '//sharing:thread_timer.h', + '//sharing:share_target_discovered_callback.h', + '//sharing:transfer_update_callback.h', + '//sharing/certificates:common.h', + '//sharing/certificates:constants.h', + ], + visibility = ["//visibility:public"], + deps = [ + "//connections:core", + "//connections:core_types", + "//internal/platform:base", + "//internal/platform:comm", + "//internal/platform:types", + "//internal/platform/implementation:platform", + "//internal/platform/implementation/linux:linux", + "//sharing:attachments", + "//sharing:types", + "//sharing/proto:share_cc_proto", + "@com_google_absl//absl/strings", + ], +) + +cc_binary( + name = "nearby_sharing_app", + srcs = ["nearby_sharing_app.cc"], + deps = [ + ":nearby_sharing_service_linux", + "//sharing:attachments", + "//sharing:types", + "//internal/platform:base", + "@com_google_absl//absl/strings", + ], + visibility = ["//visibility:public"], +) + +cc_binary( + name = "simple_example", + srcs = ["simple_example.cc"], + deps = [ + ":nearby_sharing_service_linux", + "//sharing:attachments", + "//sharing:types", + "//internal/platform:base", + "@com_google_absl//absl/strings", + ], + visibility = ["//visibility:public"], +) diff --git a/sharing/linux/IMPLEMENTATION_GUIDE.md b/sharing/linux/IMPLEMENTATION_GUIDE.md new file mode 100644 index 00000000..02b69089 --- /dev/null +++ b/sharing/linux/IMPLEMENTATION_GUIDE.md @@ -0,0 +1,592 @@ +# Nearby Sharing Service Linux - Architecture & Implementation Guide + +## Table of Contents +1. [Architecture Overview](#architecture-overview) +2. [How It Works](#how-it-works) +3. [Implementation Guide](#implementation-guide) +4. [Code Examples](#code-examples) +5. [Best Practices](#best-practices) + +## Architecture Overview + +### Component Hierarchy + +``` +NearbySharingServiceLinux +├── Connections Core (nearby connections layer) +│ ├── ServiceControllerRouter +│ └── Medium Management (BLE, WiFi) +├── Observers (UI/App notifications) +├── Send Surfaces (outgoing transfers) +│ ├── Transfer Callbacks +│ └── Discovery Callbacks +├── Receive Surfaces (incoming transfers) +│ └── Transfer Callbacks +└── Active Transfers + ├── Endpoint Mapping + ├── Transfer State + └── Attachment Container +``` + +### Key Classes + +**NearbySharingServiceLinux**: Main service class +- Manages discovery, advertising, and transfers +- Built on top of Nearby Connections Core +- Handles lifecycle of send/receive surfaces + +**TransferUpdateCallback**: Interface for transfer notifications +- Called on status changes (connecting, in-progress, complete) +- Provides progress information +- Reports errors and completion + +**ShareTargetDiscoveredCallback**: Interface for discovery notifications +- Called when devices are found +- Called when devices are lost +- Called when device info updates + +**AttachmentContainer**: Container for files and text +- Manages multiple attachments +- Supports files, text, and WiFi credentials +- Handles attachment lifecycle + +## How It Works + +### 1. Discovery & Advertising Flow + +#### Sender (Discovers devices): +``` +RegisterSendSurface (Foreground) + ↓ +StartDiscoveryIfNeeded() + ↓ +core_->StartDiscovery() + ↓ +[BLE Scanning Starts] + ↓ +endpoint_found_cb → ParseAdvertisement() + ↓ +ShareTarget created + ↓ +OnShareTargetDiscovered() callback +``` + +#### Receiver (Advertises availability): +``` +RegisterReceiveSurface (Foreground) + ↓ +StartAdvertisingIfNeeded() + ↓ +BuildAdvertisement() + ↓ +core_->StartAdvertising() + ↓ +[BLE Advertising Starts] + ↓ +[Visible to nearby senders] +``` + +### 2. Connection Establishment + +``` +Sender Receiver + | | + | RequestConnection() | + |------------------------------->| + | | connection_initiated_cb + | | (auto or manual accept) + | connection_initiated_cb | + |<-------------------------------| + | | + | AcceptConnection() | AcceptConnection() + |------------------------------->| + |<-------------------------------| + | | + | connection_accepted_cb | connection_accepted_cb + | | + [Connected - Ready for transfer] +``` + +### 3. File Transfer Flow + +``` +Sender Receiver + | | + | SendAttachments() | + | - Create AttachmentContainer | + | - Add FileAttachment | + | | + | RequestConnection() | + |------------------------------->| + | Status: kAwaitingLocalConfirmation + | | + | | Accept() + | | + | AcceptConnection() | AcceptConnection() + | + PayloadListener | + PayloadListener + | | + | Status: kConnecting | + | | + | Send Payloads | + |=============================> | + | (File data chunks) | + | | + | Status: kInProgress | + | Progress: 0% → 100% | + | | + | payload_progress_cb | payload_progress_cb + | | + | Status: kComplete | + | | +``` + +### 4. Advertisement Format + +The service creates custom BLE advertisements with device information: + +``` +Byte Layout: +[0] Header Byte + - Bits 7-5: Version (3 bits) + - Bit 4: Visibility (0=visible, 1=hidden) + - Bits 3-1: Device Type (3 bits) + - Bit 0: Reserved + +[1-2] Salt (2 random bytes) + +[3-16] Metadata Key (14 bytes - for encryption) + +[17+] TLV Fields (Type-Length-Value) + - Vendor ID (1 byte) + - QR Code data (variable) + - Other metadata + +[N+] Device Name (optional, UTF-8) +``` + +**Device Types:** +- 0: Unknown +- 1: Phone +- 2: Tablet +- 3: Laptop +- 4: Unknown + +### 5. State Management + +```cpp +struct TransferState { + AttachmentContainer attachments; // Files/text being transferred + TransferUpdateCallback* callback; // Where to send updates + bool is_incoming; // Direction of transfer +}; + +// Mappings +endpoint_to_target_ // endpoint_id → ShareTarget +target_id_to_endpoint_ // share_target_id → endpoint_id +active_transfers_ // endpoint_id → TransferState +``` + +## Implementation Guide + +### Step 1: Create Service Instance + +```cpp +#include "sharing/linux/nearby_sharing_service_linux.h" + +// Create service with custom device name +NearbySharingServiceLinux service("MyLinuxDevice"); + +// Or let it auto-detect from system +NearbySharingServiceLinux service; +``` + +### Step 2: Implement Callbacks + +```cpp +class MyTransferCallback : public TransferUpdateCallback { + public: + void OnTransferUpdate(const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) override { + // Handle transfer status changes + switch (transfer_metadata.status()) { + case TransferMetadata::Status::kAwaitingLocalConfirmation: + // Incoming transfer - need to accept/reject + HandleIncomingRequest(share_target); + break; + + case TransferMetadata::Status::kInProgress: + // Show progress + UpdateProgress(transfer_metadata.progress()); + break; + + case TransferMetadata::Status::kComplete: + // Transfer done - access attachments + HandleCompletedTransfer(attachment_container); + break; + + case TransferMetadata::Status::kFailed: + // Handle error + HandleError(); + break; + } + } +}; + +class MyDiscoveryCallback : public ShareTargetDiscoveredCallback { + public: + void OnShareTargetDiscovered(const ShareTarget& share_target) override { + // New device found + devices_.push_back(share_target); + NotifyUI(); + } + + void OnShareTargetLost(const ShareTarget& share_target) override { + // Device went away + RemoveDevice(share_target.id); + } + + void OnShareTargetUpdated(const ShareTarget& share_target) override { + // Device info changed + UpdateDevice(share_target); + } +}; +``` + +### Step 3: Register Surfaces + +```cpp +MyTransferCallback transfer_callback; +MyDiscoveryCallback discovery_callback; + +// To receive files +service.RegisterReceiveSurface( + &transfer_callback, + NearbySharingService::ReceiveSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + [](auto status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "Now advertising to nearby devices" << std::endl; + } + }); + +// To send files +service.RegisterSendSurface( + &transfer_callback, + &discovery_callback, + NearbySharingService::SendSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + false, // don't disable wifi hotspot + [](auto status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "Now scanning for nearby devices" << std::endl; + } + }); +``` + +### Step 4: Send Content + +```cpp +// Send a file +void SendFile(int64_t target_id, const std::string& file_path) { + auto container = std::make_unique(); + + FileAttachment attachment(FilePath(file_path)); + container->AddFileAttachment(std::move(attachment)); + + service.SendAttachments(target_id, std::move(container), + [](auto status) { + std::cout << "Send status: " + << NearbySharingService::StatusCodeToString(status) + << std::endl; + }); +} + +// Send text +void SendText(int64_t target_id, const std::string& text) { + auto container = std::make_unique(); + + TextAttachment attachment( + TextAttachment::Type::TEXT, + text, + std::nullopt, // no title + std::nullopt // no mime type + ); + container->AddTextAttachment(std::move(attachment)); + + service.SendAttachments(target_id, std::move(container), + [](auto status) { /* ... */ }); +} +``` + +### Step 5: Handle Incoming Transfers + +```cpp +void HandleIncomingRequest(const ShareTarget& target) { + // Show confirmation dialog to user + std::cout << "Accept file from " << target.device_name << "? (y/n): "; + char choice; + std::cin >> choice; + + if (choice == 'y') { + service.Accept(target.id, [](auto status) { + std::cout << "Accepted!" << std::endl; + }); + } else { + service.Reject(target.id, [](auto status) { + std::cout << "Rejected!" << std::endl; + }); + } +} + +void HandleCompletedTransfer(const AttachmentContainer& container) { + // Process received files + for (const auto& file : container.GetFileAttachments()) { + std::cout << "Received: " << file.file_name() << std::endl; + if (file.file_path().has_value()) { + std::cout << "Saved to: " << file.file_path()->string() << std::endl; + } + } + + // Process received text + for (const auto& text : container.GetTextAttachments()) { + std::cout << "Received text: " << text.text_body() << std::endl; + } +} +``` + +## Code Examples + +### Example 1: Simple File Sender + +```cpp +#include "sharing/linux/nearby_sharing_service_linux.h" +#include "sharing/file_attachment.h" +#include + +int main() { + NearbySharingServiceLinux service("FileSender"); + + // Setup callbacks + class SimpleCallback : public TransferUpdateCallback { + void OnTransferUpdate(...) override { + std::cout << "Progress: " << transfer_metadata.progress() * 100 << "%" << std::endl; + } + } transfer_cb; + + class SimpleDiscovery : public ShareTargetDiscoveredCallback { + int64_t target_id = -1; + void OnShareTargetDiscovered(const ShareTarget& t) override { + target_id = t.id; + std::cout << "Found: " << t.device_name << std::endl; + } + void OnShareTargetLost(...) override {} + void OnShareTargetUpdated(...) override {} + } discovery_cb; + + // Start scanning + service.RegisterSendSurface(&transfer_cb, &discovery_cb, + NearbySharingService::SendSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, false, [](auto) {}); + + // Wait for discovery + std::this_thread::sleep_for(std::chrono::seconds(5)); + + if (discovery_cb.target_id != -1) { + // Send file + auto container = std::make_unique(); + container->AddFileAttachment(FileAttachment(FilePath("/path/to/file.txt"))); + service.SendAttachments(discovery_cb.target_id, std::move(container), [](auto) {}); + + // Wait for completion + std::this_thread::sleep_for(std::chrono::seconds(10)); + } + + return 0; +} +``` + +### Example 2: Auto-Accepting Receiver + +```cpp +class AutoAcceptCallback : public TransferUpdateCallback { + public: + AutoAcceptCallback(NearbySharingServiceLinux* service) : service_(service) {} + + void OnTransferUpdate(const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) override { + // Auto-accept all incoming transfers + if (transfer_metadata.status() == TransferMetadata::Status::kAwaitingLocalConfirmation) { + service_->Accept(share_target.id, [](auto) {}); + } + + // Save received files + if (transfer_metadata.status() == TransferMetadata::Status::kComplete) { + for (const auto& file : attachment_container.GetFileAttachments()) { + std::cout << "Saved: " << file.file_name() << std::endl; + } + } + } + + private: + NearbySharingServiceLinux* service_; +}; + +int main() { + NearbySharingServiceLinux service("AutoReceiver"); + AutoAcceptCallback callback(&service); + + service.RegisterReceiveSurface(&callback, + NearbySharingService::ReceiveSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, [](auto) {}); + + // Keep running + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } +} +``` + +## Best Practices + +### 1. Callback Lifetime Management + +```cpp +// DON'T: Callbacks going out of scope +void BadExample() { + MyTransferCallback callback; // Stack allocated + service.RegisterSendSurface(&callback, ...); + // callback destroyed when function exits! +} + +// DO: Keep callbacks alive +class App { + MyTransferCallback callback_; // Member variable + + void Setup() { + service.RegisterSendSurface(&callback_, ...); + } +}; +``` + +### 2. Error Handling + +```cpp +service.SendAttachments(target_id, container, + [this](NearbySharingService::StatusCodes status) { + switch (status) { + case StatusCodes::kOk: + // Success + break; + case StatusCodes::kInvalidArgument: + // Bad target_id or empty container + LogError("Invalid arguments"); + break; + case StatusCodes::kNoAvailableConnectionMedium: + // Bluetooth/WiFi not available + NotifyUserToEnableBluetooth(); + break; + default: + LogError("Transfer failed"); + break; + } + }); +``` + +### 3. Resource Cleanup + +```cpp +class ProperCleanup { + public: + ~ProperCleanup() { + // Unregister surfaces before destroying callbacks + service_.UnregisterSendSurface(&transfer_callback_, [](auto) {}); + service_.UnregisterReceiveSurface(&transfer_callback_, [](auto) {}); + + // Shutdown service + service_.Shutdown([](auto) {}); + } + + private: + NearbySharingServiceLinux service_; + MyTransferCallback transfer_callback_; +}; +``` + +### 4. Thread Safety + +```cpp +// The service is NOT thread-safe +// All calls should be from the same thread or synchronized + +class ThreadSafeApp { + public: + void SendFromAnyThread(int64_t target_id, const std::string& file) { + task_runner_.PostTask([this, target_id, file]() { + // All service calls happen on same thread + auto container = std::make_unique(); + container->AddFileAttachment(FileAttachment(FilePath(file))); + service_.SendAttachments(target_id, std::move(container), [](auto) {}); + }); + } + + private: + NearbySharingServiceLinux service_; + TaskRunner task_runner_; // Your threading implementation +}; +``` + +### 5. State Tracking + +```cpp +class StatefulApp { + public: + void OnTransferUpdate(...) override { + current_state_ = transfer_metadata.status(); + + // Track progress + if (transfer_metadata.status() == Status::kInProgress) { + progress_map_[share_target.id] = transfer_metadata.progress(); + } + + // Cleanup on completion + if (TransferMetadata::IsFinalStatus(transfer_metadata.status())) { + progress_map_.erase(share_target.id); + } + } + + private: + TransferMetadata::Status current_state_; + std::unordered_map progress_map_; +}; +``` + +## Troubleshooting + +### Discovery Not Working +- Check Bluetooth is enabled: `IsBluetoothPowered()` +- Verify sender is in foreground state +- Ensure receiver is advertising +- Check for permission issues + +### Transfers Failing +- Verify file paths are valid and accessible +- Check available disk space on receiver +- Ensure stable Bluetooth connection +- Monitor transfer callbacks for specific error status + +### Connection Issues +- Devices must be within Bluetooth range (~10m) +- Minimize interference from other BLE devices +- Ensure both devices support required BLE features +- Check firewall settings for WiFi Direct + +## Performance Tips + +1. **Use appropriate surface states**: Background mode when not actively transferring +2. **Unregister when not needed**: Stop scanning/advertising to save battery +3. **Batch small files**: Combine into zip for better efficiency +4. **Monitor transfer progress**: Cancel stalled transfers +5. **Handle errors gracefully**: Retry with exponential backoff + diff --git a/sharing/linux/QUICK_REFERENCE.md b/sharing/linux/QUICK_REFERENCE.md new file mode 100644 index 00000000..22e17efa --- /dev/null +++ b/sharing/linux/QUICK_REFERENCE.md @@ -0,0 +1,300 @@ +# Nearby Sharing Linux - Quick Reference + +## Quick Start + +### Build +```bash +bazel build //sharing/linux:simple_example +bazel build //sharing/linux:nearby_sharing_app +``` + +### Run Simple Example +```bash +# Terminal 1 (Receiver) +./bazel-bin/sharing/linux/simple_example receiver + +# Terminal 2 (Sender) +./bazel-bin/sharing/linux/simple_example sender "Hello World!" +``` + +### Run Full App +```bash +./bazel-bin/sharing/linux/nearby_sharing_app [device_name] +``` + +## API Cheat Sheet + +### Include Headers +```cpp +#include "sharing/linux/nearby_sharing_service_linux.h" +#include "sharing/attachment_container.h" +#include "sharing/file_attachment.h" +#include "sharing/text_attachment.h" +#include "sharing/share_target.h" +#include "sharing/transfer_metadata.h" +``` + +### Create Service +```cpp +using namespace nearby::sharing::linux; +NearbySharingServiceLinux service("DeviceName"); +``` + +### Implement Callbacks +```cpp +// Transfer updates +class MyCallback : public TransferUpdateCallback { + void OnTransferUpdate(const ShareTarget& target, + const AttachmentContainer& attachments, + const TransferMetadata& metadata) override { + // Handle status changes + } +}; + +// Device discovery +class MyDiscovery : public ShareTargetDiscoveredCallback { + void OnShareTargetDiscovered(const ShareTarget& target) override { } + void OnShareTargetLost(const ShareTarget& target) override { } + void OnShareTargetUpdated(const ShareTarget& target) override { } +}; +``` + +### Register to Receive +```cpp +service.RegisterReceiveSurface( + &transfer_callback, + NearbySharingService::ReceiveSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + [](auto status) { /* callback */ }); +``` + +### Register to Send +```cpp +service.RegisterSendSurface( + &transfer_callback, + &discovery_callback, + NearbySharingService::SendSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + false, // disable_wifi_hotspot + [](auto status) { /* callback */ }); +``` + +### Send File +```cpp +auto container = std::make_unique(); +container->AddFileAttachment(FileAttachment(FilePath("/path/to/file"))); +service.SendAttachments(target_id, std::move(container), [](auto) {}); +``` + +### Send Text +```cpp +auto container = std::make_unique(); +container->AddTextAttachment(TextAttachment( + TextAttachment::Type::TEXT, "message", std::nullopt, std::nullopt)); +service.SendAttachments(target_id, std::move(container), [](auto) {}); +``` + +### Accept/Reject/Cancel +```cpp +service.Accept(target_id, [](auto status) {}); +service.Reject(target_id, [](auto status) {}); +service.Cancel(target_id, [](auto status) {}); +``` + +### Check Status +```cpp +bool scanning = service.IsScanning(); +bool transferring = service.IsTransferring(); +bool bt_present = service.IsBluetoothPresent(); +bool bt_powered = service.IsBluetoothPowered(); +``` + +### Shutdown +```cpp +service.Shutdown([](auto status) {}); +``` + +## Transfer Statuses + +| Status | Meaning | Action | +|--------|---------|--------| +| `kConnecting` | Establishing connection | Wait | +| `kAwaitingLocalConfirmation` | Need to accept/reject | Call Accept() or Reject() | +| `kAwaitingRemoteAcceptance` | Waiting for remote | Wait | +| `kInProgress` | Transferring data | Show progress | +| `kComplete` | Success | Access attachments | +| `kFailed` | Error occurred | Check logs | +| `kRejected` | User rejected | Retry or cancel | +| `kCancelled` | Transfer cancelled | Cleanup | +| `kTimedOut` | Connection timeout | Retry | + +## Status Codes + +| Code | Meaning | +|------|---------| +| `kOk` | Success | +| `kError` | General error | +| `kOutOfOrderApiCall` | API called incorrectly | +| `kTransferAlreadyInProgress` | Can't start new transfer | +| `kNoAvailableConnectionMedium` | No Bluetooth/WiFi | +| `kInvalidArgument` | Bad parameters | + +## Common Patterns + +### Auto-Accept Pattern +```cpp +class AutoAccept : public TransferUpdateCallback { + void OnTransferUpdate(...) override { + if (metadata.status() == Status::kAwaitingLocalConfirmation) { + service_->Accept(target.id, [](auto) {}); + } + } +}; +``` + +### Progress Tracking Pattern +```cpp +void OnTransferUpdate(...) override { + if (metadata.status() == Status::kInProgress) { + int percent = metadata.progress() * 100; + uint64_t bytes = metadata.transferred_bytes(); + std::cout << percent << "% (" << bytes << " bytes)" << std::endl; + } +} +``` + +### Device Selection Pattern +```cpp +std::vector devices; + +void OnShareTargetDiscovered(const ShareTarget& target) override { + devices.push_back(target); + std::cout << devices.size() << ". " << target.device_name << std::endl; +} + +void SendToDevice(size_t index) { + if (index < devices.size()) { + SendFile(devices[index].id, file_path); + } +} +``` + +### Error Handling Pattern +```cpp +service.SendAttachments(target_id, container, + [](NearbySharingService::StatusCodes status) { + if (status != StatusCodes::kOk) { + std::cerr << "Error: " + << NearbySharingService::StatusCodeToString(status) + << std::endl; + return; + } + std::cout << "Transfer initiated" << std::endl; + }); +``` + +## Debugging Tips + +### Enable Verbose Logging +```cpp +// Set environment variable +export NEARBY_LOGS=VERBOSE +``` + +### Check Bluetooth +```cpp +if (!service.IsBluetoothPresent()) { + std::cout << "No Bluetooth adapter found" << std::endl; +} +if (!service.IsBluetoothPowered()) { + std::cout << "Bluetooth is off" << std::endl; +} +``` + +### Dump Service State +```cpp +std::cout << service.Dump() << std::endl; +// Output: "NearbySharingServiceLinux advertising=true scanning=false ..." +``` + +### Monitor Callbacks +```cpp +void OnTransferUpdate(...) override { + std::cout << "[Transfer] " << target.device_name + << " - " << TransferMetadata::StatusToString(metadata.status()) + << " - " << (metadata.progress() * 100) << "%" << std::endl; +} +``` + +## File Locations + +- **Service**: `sharing/linux/nearby_sharing_service_linux.{h,cc}` +- **Simple Example**: `sharing/linux/simple_example.cc` +- **Full App**: `sharing/linux/nearby_sharing_app.cc` +- **README**: `sharing/linux/README.md` +- **Implementation Guide**: `sharing/linux/IMPLEMENTATION_GUIDE.md` +- **BUILD**: `sharing/linux/BUILD` + +## Common Issues + +### "No devices found" +- Ensure receiver is running and advertising +- Check Bluetooth is enabled on both devices +- Verify devices are within range (~10m) +- Try restarting Bluetooth + +### "Transfer failed" +- Check file permissions +- Verify disk space +- Ensure stable connection +- Check firewall settings + +### "Invalid argument" +- Verify target_id is valid +- Ensure container has attachments +- Check surface is registered + +### Callback not called +- Verify callback lifetime (must outlive service) +- Check registration was successful +- Ensure main thread/event loop is running + +## Example Workflows + +### Send File Workflow +``` +1. Create service +2. Create callbacks +3. RegisterSendSurface (foreground) +4. Wait for OnShareTargetDiscovered +5. Create AttachmentContainer +6. Add FileAttachment +7. SendAttachments(target_id, container) +8. Wait for kComplete in OnTransferUpdate +``` + +### Receive File Workflow +``` +1. Create service +2. Create callback +3. RegisterReceiveSurface (foreground) +4. Wait for kAwaitingLocalConfirmation +5. Call Accept(target_id) +6. Wait for kInProgress updates +7. Wait for kComplete +8. Access files from AttachmentContainer +``` + +## Performance Notes + +- **Scanning**: Consumes battery, stop when not needed +- **Advertising**: Minimal impact +- **Transfer**: WiFi Direct faster than Bluetooth +- **File Size**: Large files (>100MB) benefit from WiFi +- **Small Files**: Bluetooth sufficient for <10MB + +## Links + +- [README.md](README.md) - Overview and features +- [IMPLEMENTATION_GUIDE.md](IMPLEMENTATION_GUIDE.md) - Detailed architecture +- [nearby_sharing_service.h](../nearby_sharing_service.h) - Base interface diff --git a/sharing/linux/README.md b/sharing/linux/README.md new file mode 100644 index 00000000..9545e0a1 --- /dev/null +++ b/sharing/linux/README.md @@ -0,0 +1,348 @@ +# Nearby Sharing Linux Implementation + +This directory contains the Linux-specific implementation of Nearby Sharing and a sample application demonstrating its usage. + +## Overview + +Nearby Sharing is a feature that allows users to share files, text, and other content between nearby devices using Bluetooth Low Energy (BLE) and Wi-Fi Direct. This implementation provides a simplified Linux interface built on top of the Nearby Connections API. + +## Components + +### NearbySharingServiceLinux + +The main service class that provides nearby sharing functionality: + +- **Discovery & Advertising**: Find nearby devices and advertise your device's availability +- **File Transfer**: Send and receive files +- **Text Transfer**: Send and receive text messages +- **Connection Management**: Handle connection lifecycle (accept, reject, cancel) + +### Key Concepts + +#### 1. Send Surface +Represents the sending side of a transfer: +- **Foreground**: Actively scans for nearby devices +- **Background**: Only listens for transfer updates without scanning + +#### 2. Receive Surface +Represents the receiving side of a transfer: +- **Foreground**: Advertises to everyone, visible to all nearby devices +- **Background**: Advertises only to contacts (limited visibility) + +#### 3. Callbacks + +**TransferUpdateCallback**: Receives updates about ongoing transfers +- Status changes (connecting, in progress, complete, failed) +- Progress updates +- Transfer metadata (speed, bytes transferred, etc.) + +**ShareTargetDiscoveredCallback**: Receives notifications about discovered devices +- Device discovered +- Device lost (out of range) +- Device updated + +#### 4. Attachments + +**FileAttachment**: Represents a file to be transferred +- Requires a file path +- Automatically determines MIME type and size + +**TextAttachment**: Represents text content to be transferred +- Supports plain text, URLs, addresses, and phone numbers +- Includes optional title and MIME type + +## Sample Application + +The `nearby_sharing_app.cc` demonstrates how to use the service: + +### Building + +```bash +# Build the sample application +bazel build //sharing/linux:nearby_sharing_app +``` + +### Running + +```bash +# Run with default device name +./bazel-bin/sharing/linux/nearby_sharing_app + +# Run with custom device name +./bazel-bin/sharing/linux/nearby_sharing_app "MyCustomName" +``` + +### Features + +1. **Start as Receiver**: Advertise your device to receive files +2. **Start as Sender**: Discover nearby devices to send files +3. **List Discovered Devices**: View all devices found during scanning +4. **Send File**: Transfer a file to a discovered device +5. **Send Text**: Send text content to a discovered device +6. **Accept/Reject**: Handle incoming transfer requests +7. **Cancel Transfer**: Cancel an ongoing transfer +8. **Status Info**: View Bluetooth and service status + +## Usage Examples + +### Example 1: Send a File + +**Device A (Sender)**: +```cpp +NearbySharingApp app("Sender-Device"); + +// Start scanning for devices +app.StartAsSender(); + +// Wait for discovery... +std::this_thread::sleep_for(std::chrono::seconds(3)); + +// List discovered devices +app.ListDiscoveredDevices(); + +// Send file to target with ID 1 +app.SendFile(1, "/path/to/file.txt"); +``` + +**Device B (Receiver)**: +```cpp +NearbySharingApp app("Receiver-Device"); + +// Start advertising +app.StartAsReceiver(); + +// When connection is initiated (via callback), accept it +// This happens automatically when you see OnTransferUpdate with +// Status::kAwaitingLocalConfirmation +app.AcceptIncomingShare(target_id); +``` + +### Example 2: Send Text + +```cpp +NearbySharingApp app("Text-Sender"); + +// Start as sender +app.StartAsSender(); + +// Wait for device discovery +std::this_thread::sleep_for(std::chrono::seconds(2)); + +// Send text to discovered device +app.SendText(1, "Hello from Nearby Sharing!"); +``` + +### Example 3: Custom Callbacks + +```cpp +class CustomTransferCallback : public TransferUpdateCallback { + public: + void OnTransferUpdate(const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) override { + switch (transfer_metadata.status()) { + case TransferMetadata::Status::kAwaitingLocalConfirmation: + // Auto-accept incoming transfers + service_->Accept(share_target.id, [](auto status) { + std::cout << "Auto-accepted" << std::endl; + }); + break; + + case TransferMetadata::Status::kComplete: + std::cout << "Transfer completed!" << std::endl; + // Handle completed files from attachment_container + break; + + case TransferMetadata::Status::kFailed: + std::cout << "Transfer failed!" << std::endl; + break; + + default: + break; + } + } +}; +``` + +## Architecture + +### Service Initialization + +```cpp +NearbySharingServiceLinux service("DeviceName"); +``` + +The service initializes: +1. **Device Info**: Gets OS device name and type +2. **Bluetooth Adapter**: Checks BT availability +3. **Connections Core**: Sets up the Nearby Connections layer +4. **Service Controller Router**: Manages connection routing + +### Discovery Flow + +1. **Register Send Surface** (Foreground) +2. Service starts **scanning** for nearby devices +3. When device found: **OnShareTargetDiscovered** callback +4. Advertisement is **parsed** to extract device info +5. **ShareTarget** created with device details +6. User can **select target** and initiate transfer + +### Advertising Flow + +1. **Register Receive Surface** (Foreground/Background) +2. Service **builds advertisement** with device info +3. Service starts **advertising** via Bluetooth/Wi-Fi +4. When connection requested: **OnTransferUpdate** callback +5. User can **accept/reject** the incoming transfer + +### Transfer Flow + +#### Sending: +1. **SendAttachments()** with target ID and attachments +2. Service creates **connection request** +3. **Connection initiated** → Status: kConnecting +4. Connection **accepted** → Sends file/text payloads +5. **Payload transfer** → Status: kInProgress +6. **Transfer complete** → Status: kComplete + +#### Receiving: +1. **Incoming connection** → Status: kAwaitingLocalConfirmation +2. **Accept()** called → Connection accepted +3. **Receive payloads** → Status: kInProgress +4. **Payloads saved** to local storage +5. **Transfer complete** → Status: kComplete + +## Implementation Details + +### Advertisement Format + +The service uses a custom advertisement format: +- **Header byte**: Version, visibility, device type +- **Salt**: 2 random bytes +- **Metadata key**: 14 bytes (for encryption) +- **TLV fields**: Vendor ID, QR code, etc. +- **Device name** (optional): UTF-8 device name + +### Connection Strategy + +Uses `P2P_POINT_TO_POINT` strategy: +- Direct peer-to-peer connections +- Supports Bluetooth and Wi-Fi Direct +- Automatic medium selection based on availability + +### Medium Selection + +The service attempts to use available media: +1. **Bluetooth LE**: For discovery and initial connection +2. **Wi-Fi Direct**: For high-speed file transfer +3. **Wi-Fi LAN**: If devices on same network + +### Payload Types + +1. **BYTES**: For text content and metadata +2. **FILE**: For file transfers +3. **STREAM**: For real-time data + +## API Reference + +### Core Methods + +#### RegisterSendSurface +```cpp +void RegisterSendSurface( + TransferUpdateCallback* transfer_callback, + ShareTargetDiscoveredCallback* discovery_callback, + SendSurfaceState state, + Advertisement::BlockedVendorId blocked_vendor_id, + bool disable_wifi_hotspot, + std::function status_codes_callback); +``` + +#### RegisterReceiveSurface +```cpp +void RegisterReceiveSurface( + TransferUpdateCallback* transfer_callback, + ReceiveSurfaceState state, + Advertisement::BlockedVendorId vendor_id, + std::function status_codes_callback); +``` + +#### SendAttachments +```cpp +void SendAttachments( + int64_t share_target_id, + std::unique_ptr attachment_container, + std::function status_codes_callback); +``` + +#### Accept/Reject/Cancel +```cpp +void Accept(int64_t share_target_id, + std::function status_codes_callback); + +void Reject(int64_t share_target_id, + std::function status_codes_callback); + +void Cancel(int64_t share_target_id, + std::function status_codes_callback); +``` + +### Status Codes + +- **kOk**: Operation successful +- **kError**: General error +- **kOutOfOrderApiCall**: API called in wrong order +- **kTransferAlreadyInProgress**: Transfer already active +- **kNoAvailableConnectionMedium**: No BT/Wi-Fi available +- **kInvalidArgument**: Invalid parameter provided + +## Limitations + +Current implementation limitations: +- No settings persistence +- No contact management +- No certificate management +- No account integration +- Limited visibility control +- No Wi-Fi LAN detection +- No extended advertising support + +## Future Enhancements + +Potential improvements: +1. Add settings persistence (device name, visibility) +2. Implement contact management +3. Add certificate-based authentication +4. Support visibility time limits +5. Add Wi-Fi LAN connectivity detection +6. Implement file path updates during transfer +7. Add QR code generation for pairing +8. Support for extended advertising + +## Troubleshooting + +### Bluetooth Issues +```cpp +if (!service.IsBluetoothPresent()) { + std::cout << "Bluetooth adapter not found" << std::endl; +} +if (!service.IsBluetoothPowered()) { + std::cout << "Bluetooth is disabled" << std::endl; +} +``` + +### Discovery Not Working +- Ensure Bluetooth is enabled +- Check that sender is in foreground mode +- Verify receiver is advertising +- Check for Bluetooth permissions + +### Transfer Failures +- Verify file paths are accessible +- Check available disk space +- Ensure stable Bluetooth connection +- Monitor transfer callbacks for errors + +## License + +Copyright 2025 Google LLC. Licensed under Apache 2.0. diff --git a/sharing/linux/nearby_sharing_app.cc b/sharing/linux/nearby_sharing_app.cc new file mode 100644 index 00000000..828ea2c7 --- /dev/null +++ b/sharing/linux/nearby_sharing_app.cc @@ -0,0 +1,394 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#include "sharing/linux/nearby_sharing_service_linux.h" +#include "sharing/attachment_container.h" +#include "sharing/file_attachment.h" +#include "sharing/text_attachment.h" +#include "sharing/share_target.h" +#include "sharing/transfer_metadata.h" +#include "sharing/transfer_update_callback.h" +#include "sharing/share_target_discovered_callback.h" +#include "internal/base/file_path.h" + +using namespace nearby::sharing; +using namespace nearby::sharing::linux; + +class MyTransferUpdateCallback : public TransferUpdateCallback { + public: + void OnTransferUpdate(const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) override { + std::cout << "\n=== Transfer Update ===" << std::endl; + std::cout << "Device: " << share_target.device_name << std::endl; + std::cout << "Status: " << TransferMetadata::StatusToString(transfer_metadata.status()) << std::endl; + std::cout << "Progress: " << (transfer_metadata.progress() * 100) << "%" << std::endl; + std::cout << "Transferred: " << transfer_metadata.transferred_bytes() << " bytes" << std::endl; + std::cout << "Total attachments: " << transfer_metadata.total_attachments_count() << std::endl; + std::cout << "======================" << std::endl; + } +}; + +class MyShareTargetDiscoveredCallback : public ShareTargetDiscoveredCallback { + public: + void OnShareTargetDiscovered(const ShareTarget& share_target) override { + std::cout << "\n*** Device Discovered ***" << std::endl; + std::cout << "ID: " << share_target.id << std::endl; + std::cout << "Name: " << share_target.device_name << std::endl; + std::cout << "Vendor ID: " << static_cast(share_target.vendor_id) << std::endl; + std::cout << "*************************" << std::endl; + + discovered_targets_.push_back(share_target); + } + + void OnShareTargetLost(const ShareTarget& share_target) override { + std::cout << "\n*** Device Lost ***" << std::endl; + std::cout << "Name: " << share_target.device_name << std::endl; + std::cout << "*******************" << std::endl; + + for (auto it = discovered_targets_.begin(); it != discovered_targets_.end(); ++it) { + if (it->id == share_target.id) { + discovered_targets_.erase(it); + break; + } + } + } + + void OnShareTargetUpdated(const ShareTarget& share_target) override { + std::cout << "\n*** Device Updated ***" << std::endl; + std::cout << "Name: " << share_target.device_name << std::endl; + std::cout << "**********************" << std::endl; + } + + const std::vector& GetDiscoveredTargets() const { + return discovered_targets_; + } + + private: + std::vector discovered_targets_; +}; + +class NearbySharingApp { + public: + NearbySharingApp(const std::string& device_name) + : service_(std::make_unique(device_name)), + transfer_callback_(std::make_unique()), + discovery_callback_(std::make_unique()) { + std::cout << "Nearby Sharing Application initialized with device name: " + << device_name << std::endl; + } + + ~NearbySharingApp() { + Shutdown(); + } + + void StartAsReceiver() { + std::cout << "\n=== Starting as Receiver (Foreground) ===" << std::endl; + + service_->RegisterReceiveSurface( + transfer_callback_.get(), + NearbySharingService::ReceiveSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + [](NearbySharingService::StatusCodes status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "Successfully registered as receiver!" << std::endl; + } else { + std::cout << "Failed to register as receiver: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + + std::cout << "Advertising enabled. Waiting for incoming connections..." << std::endl; + } + + void StartAsSender() { + std::cout << "\n=== Starting as Sender (Foreground) ===" << std::endl; + + service_->RegisterSendSurface( + transfer_callback_.get(), + discovery_callback_.get(), + NearbySharingService::SendSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + false, // disable_wifi_hotspot + [](NearbySharingService::StatusCodes status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "Successfully registered as sender!" << std::endl; + } else { + std::cout << "Failed to register as sender: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + + std::cout << "Scanning for nearby devices..." << std::endl; + } + + void SendFile(int64_t target_id, const std::string& file_path) { + std::cout << "\n=== Sending File ===" << std::endl; + std::cout << "Target ID: " << target_id << std::endl; + std::cout << "File: " << file_path << std::endl; + + auto attachment_container = std::make_unique(); + + attachment_container->AddFileAttachment(FileAttachment(nearby::FilePath(file_path))); + + service_->SendAttachments( + target_id, + std::move(attachment_container), + [](NearbySharingService::StatusCodes status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "File send initiated successfully!" << std::endl; + } else { + std::cout << "Failed to send file: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + } + + void SendText(int64_t target_id, const std::string& text) { + std::cout << "\n=== Sending Text ===" << std::endl; + std::cout << "Target ID: " << target_id << std::endl; + std::cout << "Text: " << text << std::endl; + + auto attachment_container = std::make_unique(); + + attachment_container->AddTextAttachment(TextAttachment( + nearby::sharing::service::proto::TextMetadata::TEXT, + text, + std::nullopt, // text_title + std::nullopt // mime_type + )); + + service_->SendAttachments( + target_id, + std::move(attachment_container), + [](NearbySharingService::StatusCodes status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "Text send initiated successfully!" << std::endl; + } else { + std::cout << "Failed to send text: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + } + + void AcceptIncomingShare(int64_t target_id) { + std::cout << "\n=== Accepting Incoming Share ===" << std::endl; + std::cout << "Target ID: " << target_id << std::endl; + + service_->Accept( + target_id, + [](NearbySharingService::StatusCodes status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "Share accepted!" << std::endl; + } else { + std::cout << "Failed to accept share: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + } + + void RejectIncomingShare(int64_t target_id) { + std::cout << "\n=== Rejecting Incoming Share ===" << std::endl; + std::cout << "Target ID: " << target_id << std::endl; + + service_->Reject( + target_id, + [](NearbySharingService::StatusCodes status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "Share rejected!" << std::endl; + } else { + std::cout << "Failed to reject share: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + } + + void CancelTransfer(int64_t target_id) { + std::cout << "\n=== Canceling Transfer ===" << std::endl; + std::cout << "Target ID: " << target_id << std::endl; + + service_->Cancel( + target_id, + [](NearbySharingService::StatusCodes status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "Transfer cancelled!" << std::endl; + } else { + std::cout << "Failed to cancel transfer: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + } + + void ListDiscoveredDevices() { + std::cout << "\n=== Discovered Devices ===" << std::endl; + const auto& targets = discovery_callback_->GetDiscoveredTargets(); + + if (targets.empty()) { + std::cout << "No devices found." << std::endl; + } else { + for (const auto& target : targets) { + std::cout << "ID: " << target.id + << " | Name: " << target.device_name + << " | Vendor: " << static_cast(target.vendor_id) << std::endl; + } + } + std::cout << "==========================" << std::endl; + } + + void PrintStatus() { + std::cout << "\n=== Service Status ===" << std::endl; + std::cout << "Bluetooth Present: " << (service_->IsBluetoothPresent() ? "Yes" : "No") << std::endl; + std::cout << "Bluetooth Powered: " << (service_->IsBluetoothPowered() ? "Yes" : "No") << std::endl; + std::cout << "Is Scanning: " << (service_->IsScanning() ? "Yes" : "No") << std::endl; + std::cout << "Is Transferring: " << (service_->IsTransferring() ? "Yes" : "No") << std::endl; + std::cout << "======================" << std::endl; + } + + void Shutdown() { + std::cout << "\n=== Shutting Down ===" << std::endl; + service_->Shutdown([](NearbySharingService::StatusCodes status) { + std::cout << "Shutdown complete: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + }); + } + + private: + std::unique_ptr service_; + std::unique_ptr transfer_callback_; + std::unique_ptr discovery_callback_; +}; + +void PrintMenu() { + std::cout << "\n========== Nearby Sharing Menu ==========" << std::endl; + std::cout << "1. Start as Receiver (advertise)" << std::endl; + std::cout << "2. Start as Sender (discover)" << std::endl; + std::cout << "3. List discovered devices" << std::endl; + std::cout << "4. Send file to device" << std::endl; + std::cout << "5. Send text to device" << std::endl; + std::cout << "6. Accept incoming share" << std::endl; + std::cout << "7. Reject incoming share" << std::endl; + std::cout << "8. Cancel transfer" << std::endl; + std::cout << "9. Print status" << std::endl; + std::cout << "0. Exit" << std::endl; + std::cout << "=========================================" << std::endl; + std::cout << "Enter choice: "; +} + +int main(int argc, char* argv[]) { + std::string device_name = "MyLinuxDevice"; + + if (argc > 1) { + device_name = argv[1]; + } + + std::cout << "========================================" << std::endl; + std::cout << " Nearby Sharing Linux Application" << std::endl; + std::cout << "========================================" << std::endl; + + NearbySharingApp app(device_name); + + bool running = true; + while (running) { + PrintMenu(); + + int choice; + std::cin >> choice; + + switch (choice) { + case 1: + app.StartAsReceiver(); + break; + + case 2: + app.StartAsSender(); + std::this_thread::sleep_for(std::chrono::seconds(2)); + app.ListDiscoveredDevices(); + break; + + case 3: + app.ListDiscoveredDevices(); + break; + + case 4: { + int64_t target_id; + std::string file_path; + std::cout << "Enter target ID: "; + std::cin >> target_id; + std::cout << "Enter file path: "; + std::cin.ignore(); + std::getline(std::cin, file_path); + app.SendFile(target_id, file_path); + break; + } + + case 5: { + int64_t target_id; + std::string text; + std::cout << "Enter target ID: "; + std::cin >> target_id; + std::cout << "Enter text to send: "; + std::cin.ignore(); + std::getline(std::cin, text); + app.SendText(target_id, text); + break; + } + + case 6: { + int64_t target_id; + std::cout << "Enter target ID to accept: "; + std::cin >> target_id; + app.AcceptIncomingShare(target_id); + break; + } + + case 7: { + int64_t target_id; + std::cout << "Enter target ID to reject: "; + std::cin >> target_id; + app.RejectIncomingShare(target_id); + break; + } + + case 8: { + int64_t target_id; + std::cout << "Enter target ID to cancel: "; + std::cin >> target_id; + app.CancelTransfer(target_id); + break; + } + + case 9: + app.PrintStatus(); + break; + + case 0: + running = false; + break; + + default: + std::cout << "Invalid choice. Please try again." << std::endl; + break; + } + } + + std::cout << "\nGoodbye!" << std::endl; + return 0; +} diff --git a/sharing/linux/nearby_sharing_app_BUILD b/sharing/linux/nearby_sharing_app_BUILD new file mode 100644 index 00000000..80252d43 --- /dev/null +++ b/sharing/linux/nearby_sharing_app_BUILD @@ -0,0 +1,28 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +cc_binary( + name = "nearby_sharing_app", + srcs = ["nearby_sharing_app.cc"], + deps = [ + ":nearby_sharing_service_linux", + "//sharing:attachments", + "//sharing:types", + "//internal/platform:base", + "@com_google_absl//absl/strings", + ], + visibility = ["//visibility:public"], +) diff --git a/sharing/linux/simple_example.cc b/sharing/linux/simple_example.cc new file mode 100644 index 00000000..04a46151 --- /dev/null +++ b/sharing/linux/simple_example.cc @@ -0,0 +1,251 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Simple example: Send a text message to nearby device +// +// Usage: +// Terminal 1 (Receiver): ./simple_receiver +// Terminal 2 (Sender): ./simple_sender "Hello World" + +#include +#include +#include +#include +#include + +#include "sharing/linux/nearby_sharing_service_linux.h" +#include "sharing/attachment_container.h" +#include "sharing/text_attachment.h" +#include "sharing/share_target.h" +#include "sharing/transfer_metadata.h" +#include "sharing/transfer_update_callback.h" +#include "sharing/share_target_discovered_callback.h" + +using namespace nearby::sharing; +using namespace nearby::sharing::linux; + +// Simple callback that automatically accepts incoming transfers +class SimpleReceiverCallback : public TransferUpdateCallback { + public: + explicit SimpleReceiverCallback(NearbySharingServiceLinux* service) + : service_(service) {} + + void OnTransferUpdate(const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) override { + std::cout << "\n[Receiver] Transfer Update from: " << share_target.device_name << std::endl; + std::cout << "[Receiver] Status: " + << TransferMetadata::StatusToString(transfer_metadata.status()) << std::endl; + + // Auto-accept incoming transfers + if (transfer_metadata.status() == TransferMetadata::Status::kAwaitingLocalConfirmation) { + std::cout << "[Receiver] Auto-accepting transfer..." << std::endl; + service_->Accept(share_target.id, [](auto status) { + std::cout << "[Receiver] Accept status: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + }); + } + + // Show received content when complete + if (transfer_metadata.status() == TransferMetadata::Status::kComplete) { + std::cout << "\n[Receiver] ✓ Transfer Complete!" << std::endl; + + // Display received text + for (const auto& text : attachment_container.GetTextAttachments()) { + std::cout << "[Receiver] Received text: \"" << text.text_body() << "\"" << std::endl; + } + + // Display received files + for (const auto& file : attachment_container.GetFileAttachments()) { + std::cout << "[Receiver] Received file: " << file.file_name() << std::endl; + } + } + } + + private: + NearbySharingServiceLinux* service_; +}; + +// Callback for discovering nearby devices +class SimpleSenderCallback : public ShareTargetDiscoveredCallback { + public: + void OnShareTargetDiscovered(const ShareTarget& share_target) override { + std::cout << "\n[Sender] Found device: " << share_target.device_name + << " (ID: " << share_target.id << ")" << std::endl; + discovered_target_ = share_target; + has_target_ = true; + } + + void OnShareTargetLost(const ShareTarget& share_target) override { + std::cout << "[Sender] Lost device: " << share_target.device_name << std::endl; + if (has_target_ && discovered_target_.id == share_target.id) { + has_target_ = false; + } + } + + void OnShareTargetUpdated(const ShareTarget& share_target) override {} + + bool HasTarget() const { return has_target_; } + const ShareTarget& GetTarget() const { return discovered_target_; } + + private: + ShareTarget discovered_target_; + bool has_target_ = false; +}; + +// Transfer progress callback for sender +class SimpleSenderTransferCallback : public TransferUpdateCallback { + public: + void OnTransferUpdate(const ShareTarget& share_target, + const AttachmentContainer& attachment_container, + const TransferMetadata& transfer_metadata) override { + std::cout << "[Sender] Transfer to " << share_target.device_name + << ": " << TransferMetadata::StatusToString(transfer_metadata.status()) + << " (" << (transfer_metadata.progress() * 100) << "%)" << std::endl; + + if (transfer_metadata.status() == TransferMetadata::Status::kComplete) { + std::cout << "[Sender] ✓ Transfer Complete!" << std::endl; + transfer_complete_ = true; + } else if (transfer_metadata.status() == TransferMetadata::Status::kFailed) { + std::cout << "[Sender] ✗ Transfer Failed!" << std::endl; + transfer_complete_ = true; + } + } + + bool IsTransferComplete() const { return transfer_complete_; } + + private: + bool transfer_complete_ = false; +}; + +int main(int argc, char* argv[]) { + if (argc < 2) { + std::cout << "Usage: " << argv[0] << " [message]" << std::endl; + std::cout << "Examples:" << std::endl; + std::cout << " " << argv[0] << " receiver # Start as receiver" << std::endl; + std::cout << " " << argv[0] << " sender \"Hello!\" # Send text message" << std::endl; + return 1; + } + + std::string mode = argv[1]; + + if (mode == "receiver") { + // ============= RECEIVER MODE ============= + std::cout << "=== Nearby Sharing Receiver ===" << std::endl; + + NearbySharingServiceLinux service("Receiver-Device"); + SimpleReceiverCallback callback(&service); + + // Register as a receiver (advertise to nearby devices) + service.RegisterReceiveSurface( + &callback, + NearbySharingService::ReceiveSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + [](auto status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "[Receiver] ✓ Advertising started" << std::endl; + std::cout << "[Receiver] Waiting for incoming transfers..." << std::endl; + } else { + std::cout << "[Receiver] ✗ Failed to start: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + + // Keep running to receive transfers + std::cout << "\nPress Ctrl+C to exit..." << std::endl; + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + } else if (mode == "sender") { + // ============= SENDER MODE ============= + std::string message = "Hello from Nearby Sharing!"; + if (argc > 2) { + message = argv[2]; + } + + std::cout << "=== Nearby Sharing Sender ===" << std::endl; + std::cout << "[Sender] Message to send: \"" << message << "\"" << std::endl; + + NearbySharingServiceLinux service("Sender-Device"); + SimpleSenderCallback discovery_callback; + SimpleSenderTransferCallback transfer_callback; + + // Register as sender (scan for nearby devices) + service.RegisterSendSurface( + &transfer_callback, + &discovery_callback, + NearbySharingService::SendSurfaceState::kForeground, + Advertisement::BlockedVendorId::kNone, + false, + [](auto status) { + if (status == NearbySharingService::StatusCodes::kOk) { + std::cout << "[Sender] ✓ Scanning started" << std::endl; + } else { + std::cout << "[Sender] ✗ Failed to start: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + } + }); + + // Wait for device discovery + std::cout << "[Sender] Scanning for nearby devices..." << std::endl; + int wait_time = 0; + while (!discovery_callback.HasTarget() && wait_time < 10) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + wait_time++; + std::cout << "." << std::flush; + } + std::cout << std::endl; + + if (!discovery_callback.HasTarget()) { + std::cout << "[Sender] ✗ No devices found. Make sure receiver is running!" << std::endl; + return 1; + } + + // Create text attachment + auto attachment_container = std::make_unique(); + attachment_container->AddTextAttachment(TextAttachment( + nearby::sharing::service::proto::TextMetadata::TEXT, + message, + std::nullopt, + std::nullopt + )); + + // Send to discovered device + const auto& target = discovery_callback.GetTarget(); + std::cout << "\n[Sender] Sending to: " << target.device_name << std::endl; + + service.SendAttachments( + target.id, + std::move(attachment_container), + [](auto status) { + std::cout << "[Sender] Send initiated: " + << NearbySharingService::StatusCodeToString(status) << std::endl; + }); + + // Wait for transfer to complete + std::cout << "[Sender] Transferring..." << std::endl; + while (!transfer_callback.IsTransferComplete()) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + + std::cout << "\n[Sender] Done!" << std::endl; + + } else { + std::cout << "Invalid mode. Use 'receiver' or 'sender'" << std::endl; + return 1; + } + + return 0; +} From 21a11d1adc424c50b5e6ed6d341620ded1b52f6b Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Wed, 21 Jan 2026 02:34:50 +0000 Subject: [PATCH 198/201] Improved devcontainers --- .devcontainer/bazel/Dockerfile | 2 +- .devcontainer/bazel/devcontainer.json | 8 +------- .devcontainer/bazelclion/Dockerfile | 13 ++++++++----- .devcontainer/bazelclion/devcontainer.json | 5 ++++- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.devcontainer/bazel/Dockerfile b/.devcontainer/bazel/Dockerfile index 0f8f6f5b..a2f9f54c 100755 --- a/.devcontainer/bazel/Dockerfile +++ b/.devcontainer/bazel/Dockerfile @@ -21,7 +21,7 @@ RUN curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor >bazel- RUN apt-get install -y pkg-config libasound2-dev -RUN apt-get install -y libunistring-dev libldap-dev libkrb5-dev libgpg-error-dev gdb libc6-dbg libgtest-dev libbluetooth-dev +RUN apt-get install -y libunistring-dev libldap-dev libkrb5-dev libgpg-error-dev gdb libc6-dbg libgtest-dev libbluetooth-dev clangd #gtest RUN apt-get update && apt-get install -y \ diff --git a/.devcontainer/bazel/devcontainer.json b/.devcontainer/bazel/devcontainer.json index d5ca6a17..2e1782a8 100755 --- a/.devcontainer/bazel/devcontainer.json +++ b/.devcontainer/bazel/devcontainer.json @@ -4,15 +4,9 @@ "customizations": { "vscode": { "settings": { - "C_Cpp.default.configurationProvider": "ms-vscode.cpptools", "C_Cpp.intelliSenseEngine": "Default" }, - "extensions": [ - "ms-vscode.cpptools", - "bazelbuild.vscode-bazel", - "ms-vscode.cpptools-extension-pack" - ], - + "extensions": ["bazelbuild.vscode-bazel"] } }, "mounts": [ diff --git a/.devcontainer/bazelclion/Dockerfile b/.devcontainer/bazelclion/Dockerfile index 5eab4c65..a2f9f54c 100755 --- a/.devcontainer/bazelclion/Dockerfile +++ b/.devcontainer/bazelclion/Dockerfile @@ -21,13 +21,16 @@ RUN curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor >bazel- RUN apt-get install -y pkg-config libasound2-dev -RUN apt-get install -y libunistring-dev libldap-dev libkrb5-dev libgpg-error-dev gdb libc6-dbg googletest +RUN apt-get install -y libunistring-dev libldap-dev libkrb5-dev libgpg-error-dev gdb libc6-dbg libgtest-dev libbluetooth-dev clangd #gtest -RUN cd /usr/src/googletest -RUN cmake -S . -B build -RUN cmake --build build -j -RUN cmake --install build +RUN apt-get update && apt-get install -y \ + googletest cmake g++ make \ + && rm -rf /var/lib/apt/lists/* \ + && cd /usr/src/googletest \ + && cmake -S . -B build \ + && cmake --build build -j"$(nproc)" \ + && cmake --install build # bash history RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ diff --git a/.devcontainer/bazelclion/devcontainer.json b/.devcontainer/bazelclion/devcontainer.json index 0fafd692..62755804 100755 --- a/.devcontainer/bazelclion/devcontainer.json +++ b/.devcontainer/bazelclion/devcontainer.json @@ -47,6 +47,9 @@ "runArgs": [ "--network=host", "--dns=1.1.1.1", - "--dns=8.8.8.8" + "--dns=8.8.8.8", + "--memory=8g", + "--cpus=6", + "--shm-size=2g" ] } From 2c285eabb2f875892a42f07c90ad0d8899364b7f Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Wed, 21 Jan 2026 02:35:20 +0000 Subject: [PATCH 199/201] Added hedron targets for linux --- internal/platform/implementation/linux/BUILD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/platform/implementation/linux/BUILD b/internal/platform/implementation/linux/BUILD index 3e189266..8eec001e 100644 --- a/internal/platform/implementation/linux/BUILD +++ b/internal/platform/implementation/linux/BUILD @@ -23,6 +23,8 @@ refresh_compile_commands( # For example, specify a dict of targets and any flags required to build. targets = { ":linux": "-s --check_visibility=false --spawn_strategy=standalone --verbose_failures --strip=never --copt=-O0 --copt=-g --copt=-fno-omit-frame-pointer", + "//connections:core": "-s --check_visibility=false --spawn_strategy=standalone --verbose_failures --strip=never --copt=-O0 --copt=-g --copt=-fno-omit-frame-pointer", + "//connections/file_share:file_share": "-s --check_visibility=false --spawn_strategy=standalone --verbose_failures --strip=never --copt=-O0 --copt=-g --copt=-fno-omit-frame-pointer", }, # No need to add flags already in .bazelrc. They're automatically picked up. # If you don't need flags, a list of targets is also okay, as is a single target string. From 650c276f3fd0512578a321667713011b7a673d30 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Wed, 21 Jan 2026 02:45:22 +0000 Subject: [PATCH 200/201] Added .bazelproject for linux dev --- .bazelproject | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .bazelproject diff --git a/.bazelproject b/.bazelproject new file mode 100644 index 00000000..dc8814f2 --- /dev/null +++ b/.bazelproject @@ -0,0 +1,17 @@ +directories: + . + -bazel-* + +targets: + //internal/platform/implementation/linux/test:all + //internal/platform/implementation/linux:all + //internal/platform/implementation/windows:all + +derive_targets_from_directories: true + +additional_languages: + c++ + +# Ensure external dependencies are indexed +build_flags: + --keep_going From 2527f59547f30b29e8f86a8314dc870d44f53bc7 Mon Sep 17 00:00:00 2001 From: kidfromjupiter Date: Wed, 21 Jan 2026 03:16:20 +0000 Subject: [PATCH 201/201] Added readme for linux --- .gitignore | 2 +- LINUX_CONTRIBUTING.md | 69 +++++++++++++++++++++++++++++++++++++++++++ README.md | 35 +++++++++++++++------- 3 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 LINUX_CONTRIBUTING.md diff --git a/.gitignore b/.gitignore index f00588f4..202779b3 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,6 @@ bazel-* /.clwb/ # Devcontainers -/.devcontainer/ +# /.devcontainer/ /connections/walkietalkie/ /third_party/ diff --git a/LINUX_CONTRIBUTING.md b/LINUX_CONTRIBUTING.md new file mode 100644 index 00000000..92f9d3af --- /dev/null +++ b/LINUX_CONTRIBUTING.md @@ -0,0 +1,69 @@ +# Linux Contributor Guide + +This guide is for contributors working on the Linux platform implementation in this repo. It focuses on local development workflow, platform layout, and where to make changes for new or missing platform features. + +For general project contribution rules, see `CONTRIBUTING.md`. + +## Recommended development environment + +The fastest path to a consistent Linux development setup is to use the devcontainer at `.devcontainers/bazelclion` with CLion and Bazel. + +Notes: + +- Use CLion devcontainers. +- You do not have to use a devcontainer, but it avoids environment drift. +- The devcontainer mounts `/run/dbus`, and the Linux implementation primarily uses D-Bus for platform communication. +- Inside the devcontainer, install: + - `libbluetooth-dev` + - `libgtest-dev` + - `gdb` (optional but helpful) + +## CLion + Bazel setup + +Once the Bazel plugin loads in CLion, run a Bazel sync from the toolbar (top-right). This can take a while on first run. + +After the sync completes, you are ready to develop. + +## Source layout for Linux + +Linux platform implementation lives here: + +- `internal/platform/implementation/linux` + +Key entry points: + +- Platform contract: `internal/platform/implementation/platform.h` +- Linux implementation: `internal/platform/implementation/linux/platform.cc` + +The Linux implementation largely mirrors the Windows platform layout and behavior, so it is useful to compare with the Windows implementation for parity. + +## What the platform layer does + +The Linux platform layer provides abstractions over local network and Bluetooth hardware so Nearby Connections can perform radio operations. These abstractions are organized around Media and Mediums. Each Medium defines a set of functions that the platform must implement. + +If you are adding a feature or fixing a missing capability: + +- Start from `internal/platform/implementation/platform.h`. +- Follow the Medium definitions to understand the required interface. +- Implement or extend the Linux counterparts under `internal/platform/implementation/linux`. + +## About Nearby Sharing on Linux + +Nearby Sharing builds on top of Nearby Connections. The Linux implementation still uses the same platform abstractions described above. + +The example application for Nearby Sharing is located at: + +- `sharing/linux` + +## Nearby Connections examples + +Example applications for Nearby Connections are located at: + +- Walkie-talkie: `nearby/connection/walkietalkie` +- File share: `nearby/connections/file_share` + +## CLion project visibility + +The `.bazelproject` configuration limits which directories CLion shows by default. If you want all directories visible, change the project root setting to `.`. + +Be aware that enabling all directories can significantly impact performance and is not recommended for most machines. diff --git a/README.md b/README.md index 859c3483..7626abf6 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,40 @@ -# Nearby +# Unofficial Linux Nearby -Nearby is a collection of projects focused on connectivity that enable building cross-device experiences. +This repository is an unofficial Linux implementation of Google Nearby, forked from the official Nearby codebase. It focuses on Linux platform support for Nearby Connections, Nearby Sharing, and Nearby Presence. This is not an officially supported Google product. -## Projects +## What is included -### [Nearby Connections](connections/) +- Nearby Connections +- Nearby Sharing +- Nearby Presence -A peer-to-peer networking API that allows apps to easily discover, connect to, and exchange data with nearby devices in real-time, regardless of network connectivity. +## Linux platform support -### [Nearby Presence](presence/) +The Linux platform implementation provides abstraction layers over local networking and Bluetooth hardware to support Nearby radio operations. The current Linux implementation supports: -An extension to Nearby Connections that features an extensible identity model for authentication and restricted visibility, resource management for system health, and proximity detection through sensor fusion. +- BLE discovery and advertising +- GATT advertising and discovery +- Data transfer over Bluetooth Classic +- Wi-Fi LAN +- Wi-Fi Hotspot +- Wi-Fi Direct +- Wi-Fi LAN advertising and discovery -### [Nearby for Embedded Systems](embedded/) +## Example applications -A lightweight implementation of Fast Pair intended for embedded systems. +- Nearby Sharing service example: `sharing/linux` +- Nearby Connections examples: + - Walkie-talkie: `nearby/connection/walkietalkie` + - File share: `nearby/connections/file_share` ## Contributing -We encourage you to contribute to Nearby! Please check out the [Contributing to Nearby guide](CONTRIBUTING.md) for guidelines about how to proceed. +General contribution guidelines are in `CONTRIBUTING.md`. + +If you are working on the Linux platform, start with `LINUX_CONTRIBUTING.md`. ## License -Nearby is released under the [Apache License 2.0](LICENSE) +Nearby is released under the `LICENSE`.