nearby sdk refactor

PiperOrigin-RevId: 425434260
This commit is contained in:
hais
2022-02-02 11:56:39 -08:00
committed by hai007
parent 287f0d7174
commit f5fcd35ced
1879 changed files with 2485 additions and 2332 deletions
+132
View File
@@ -0,0 +1,132 @@
# 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",
testonly = True,
srcs = [
"log_message.cc",
"scheduled_executor.cc",
"system_clock.cc",
],
hdrs = [
"atomic_boolean.h",
"atomic_reference.h",
"condition_variable.h",
"log_message.h",
"multi_thread_executor.h",
"mutex.h",
"pipe.h",
"scheduled_executor.h",
"single_thread_executor.h",
],
visibility = ["//visibility:private"],
deps = [
"//base",
"//base:stringprintf",
"//internal/platform:base",
"//internal/platform:util",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/shared:posix_mutex",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"@com_google_nisaba//nisaba/port:thread_pool",
],
)
cc_library(
name = "comm",
testonly = True,
srcs = [
"ble.cc",
"bluetooth_adapter.cc",
"bluetooth_classic.cc",
"webrtc.cc",
"wifi_lan.cc",
],
hdrs = [
"ble.h",
"bluetooth_adapter.h",
"bluetooth_classic.h",
"webrtc.h",
"wifi_lan.h",
],
visibility = ["//visibility:private"],
deps = [
":types",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:logging",
"//internal/platform:test_util",
"//internal/platform/implementation:comm",
"//internal/platform/implementation/shared:count_down_latch",
"@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/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",
"//webrtc/api:create_peerconnection_factory", #buildcleaner: keep
"//webrtc/api:libjingle_peerconnection_api",
"//webrtc/api/task_queue:default_task_queue_factory",
],
)
cc_library(
name = "crypto",
testonly = True,
srcs = [
"crypto.cc",
],
visibility = ["//visibility:private"],
deps = [
"//internal/platform:base",
"//internal/platform/implementation:types",
"@com_google_absl//absl/strings",
"@boringssl//:crypto",
],
)
cc_library(
name = "g3",
testonly = True,
srcs = [
"platform.cc",
],
visibility = [
"//connections:__subpackages__",
"//internal/analytics:__subpackages__",
"//internal/platform:__subpackages__",
"//internal/proto/analytics:__subpackages__",
],
deps = [
":comm",
":crypto", # build_cleaner: keep
":types",
"//internal/platform:test_util",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/shared:file",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
],
)
@@ -0,0 +1,44 @@
// 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_G3_ATOMIC_BOOLEAN_H_
#define PLATFORM_IMPL_G3_ATOMIC_BOOLEAN_H_
#include <atomic>
#include "internal/platform/implementation/atomic_boolean.h"
namespace location {
namespace nearby {
namespace g3 {
// See documentation in
// cpp/platform/api/atomic_boolean.h
class AtomicBoolean : public api::AtomicBoolean {
public:
explicit AtomicBoolean(bool initial_value) : value_(initial_value) {}
~AtomicBoolean() override = default;
bool Get() const override { return value_.load(); }
bool Set(bool value) override { return value_.exchange(value); }
private:
std::atomic_bool value_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_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_G3_ATOMIC_REFERENCE_H_
#define PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_
#include <atomic>
#include <cstdint>
#include "internal/platform/implementation/atomic_reference.h"
namespace location {
namespace nearby {
namespace g3 {
class AtomicUint32 : public api::AtomicUint32 {
public:
explicit AtomicUint32(std::int32_t value) : value_(value) {}
~AtomicUint32() override = default;
std::uint32_t Get() const override { return value_; }
void Set(std::uint32_t value) override { value_ = value; }
private:
std::atomic<std::uint32_t> value_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_
+378
View File
@@ -0,0 +1,378 @@
// 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/g3/ble.h"
#include <iostream>
#include <memory>
#include <string>
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/cancellation_flag_listener.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/implementation/shared/count_down_latch.h"
namespace location {
namespace nearby {
namespace g3 {
BleSocket::~BleSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
void BleSocket::Connect(BleSocket& other) {
absl::MutexLock lock(&mutex_);
remote_socket_ = &other;
input_ = other.output_;
}
InputStream& BleSocket::GetInputStream() {
auto* remote_socket = GetRemoteSocket();
CHECK(remote_socket != nullptr);
return remote_socket->GetLocalInputStream();
}
OutputStream& BleSocket::GetOutputStream() { return GetLocalOutputStream(); }
BleSocket* BleSocket::GetRemoteSocket() {
absl::MutexLock lock(&mutex_);
return remote_socket_;
}
bool BleSocket::IsConnected() const {
absl::MutexLock lock(&mutex_);
return IsConnectedLocked();
}
bool BleSocket::IsClosed() const {
absl::MutexLock lock(&mutex_);
return closed_;
}
Exception BleSocket::Close() {
absl::MutexLock lock(&mutex_);
DoClose();
return {Exception::kSuccess};
}
BlePeripheral* BleSocket::GetRemotePeripheral() {
absl::MutexLock lock(&mutex_);
return peripheral_;
}
void BleSocket::DoClose() {
if (!closed_) {
remote_socket_ = nullptr;
output_->GetOutputStream().Close();
output_->GetInputStream().Close();
if (IsConnectedLocked()) {
input_->GetOutputStream().Close();
input_->GetInputStream().Close();
}
closed_ = true;
}
}
bool BleSocket::IsConnectedLocked() const { return input_ != nullptr; }
InputStream& BleSocket::GetLocalInputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetInputStream();
}
OutputStream& BleSocket::GetLocalOutputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetOutputStream();
}
std::unique_ptr<api::BleSocket> BleServerSocket::Accept(
BlePeripheral* peripheral) {
absl::MutexLock lock(&mutex_);
if (closed_) return {};
while (pending_sockets_.empty()) {
cond_.Wait(&mutex_);
if (closed_) break;
}
if (closed_) return {};
auto* remote_socket =
pending_sockets_.extract(pending_sockets_.begin()).value();
CHECK(remote_socket);
auto local_socket = std::make_unique<BleSocket>(peripheral);
local_socket->Connect(*remote_socket);
remote_socket->Connect(*local_socket);
cond_.SignalAll();
return local_socket;
}
bool BleServerSocket::Connect(BleSocket& socket) {
absl::MutexLock lock(&mutex_);
if (closed_) return false;
if (socket.IsConnected()) {
NEARBY_LOG(ERROR,
"Failed to connect to Ble 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 BleServerSocket::SetCloseNotifier(std::function<void()> notifier) {
absl::MutexLock lock(&mutex_);
close_notifier_ = std::move(notifier);
}
BleServerSocket::~BleServerSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
Exception BleServerSocket::Close() {
absl::MutexLock lock(&mutex_);
return DoClose();
}
Exception BleServerSocket::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};
}
BleMedium::BleMedium(api::BluetoothAdapter& adapter)
: adapter_(static_cast<BluetoothAdapter*>(&adapter)) {
adapter_->SetBleMedium(this);
auto& env = MediumEnvironment::Instance();
env.RegisterBleMedium(*this);
}
BleMedium::~BleMedium() {
adapter_->SetBleMedium(nullptr);
auto& env = MediumEnvironment::Instance();
env.UnregisterBleMedium(*this);
StopAdvertising(advertising_info_.service_id);
StopScanning(scanning_info_.service_id);
accept_loops_runner_.Shutdown();
NEARBY_LOG(INFO, "BleMedium dtor advertising_accept_thread_running_ = %d",
acceptance_thread_running_.load());
// If acceptance thread is still running, wait to finish.
if (acceptance_thread_running_) {
while (acceptance_thread_running_) {
shared::CountDownLatch latch(1);
close_accept_loops_runner_.Execute([&latch]() { latch.CountDown(); });
latch.Await();
}
}
}
bool BleMedium::StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) {
NEARBY_LOGS(INFO) << "G3 Ble StartAdvertising: service_id=" << service_id
<< ", advertisement bytes=" << advertisement_bytes.data()
<< "(" << advertisement_bytes.size() << "),"
<< " fast advertisement service uuid="
<< fast_advertisement_service_uuid;
auto& env = MediumEnvironment::Instance();
auto& peripheral = adapter_->GetPeripheral();
peripheral.SetAdvertisementBytes(service_id, advertisement_bytes);
bool fast_advertisement = !fast_advertisement_service_uuid.empty();
env.UpdateBleMediumForAdvertising(*this, peripheral, service_id,
fast_advertisement, true);
absl::MutexLock lock(&mutex_);
if (server_socket_ != nullptr) server_socket_.release();
server_socket_ = std::make_unique<BleServerSocket>();
acceptance_thread_running_.exchange(true);
accept_loops_runner_.Execute([&env, this, service_id]() mutable {
if (!accept_loops_runner_.InShutdown()) {
while (true) {
auto client_socket =
server_socket_->Accept(&(this->adapter_->GetPeripheral()));
if (client_socket == nullptr) break;
env.CallBleAcceptedConnectionCallback(*this, *(client_socket.release()),
service_id);
}
}
acceptance_thread_running_.exchange(false);
});
advertising_info_.service_id = service_id;
return true;
}
bool BleMedium::StopAdvertising(const std::string& service_id) {
NEARBY_LOGS(INFO) << "G3 Ble StopAdvertising: service_id=" << service_id;
{
absl::MutexLock lock(&mutex_);
if (advertising_info_.Empty()) {
NEARBY_LOGS(INFO) << "G3 Ble StopAdvertising: Can't stop advertising "
"because we never started advertising.";
return false;
}
advertising_info_.Clear();
}
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForAdvertising(*this, adapter_->GetPeripheral(),
service_id, /*fast_advertisement=*/false,
/*enabled=*/false);
accept_loops_runner_.Shutdown();
if (server_socket_ == nullptr) {
NEARBY_LOGS(ERROR) << "G3 Ble StopAdvertising: Failed to find Ble Server "
"socket: service_id="
<< service_id;
// Fall through for server socket not found.
return true;
}
if (!server_socket_->Close().Ok()) {
NEARBY_LOGS(INFO)
<< "G3 Ble StopAdvertising: Failed to close Ble server socket for "
<< service_id;
return false;
}
return true;
}
bool BleMedium::StartScanning(
const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
DiscoveredPeripheralCallback callback) {
NEARBY_LOGS(INFO) << "G3 Ble StartScanning: service_id=" << service_id;
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForScanning(*this, service_id,
fast_advertisement_service_uuid,
std::move(callback), true);
{
absl::MutexLock lock(&mutex_);
scanning_info_.service_id = service_id;
}
return true;
}
bool BleMedium::StopScanning(const std::string& service_id) {
NEARBY_LOGS(INFO) << "G3 Ble StopScanning: service_id=" << service_id;
{
absl::MutexLock lock(&mutex_);
if (scanning_info_.Empty()) {
NEARBY_LOGS(INFO) << "G3 Ble StopDiscovery: Can't stop scanning because "
"we never started scanning.";
return false;
}
scanning_info_.Clear();
}
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForScanning(*this, service_id, {}, {}, false);
return true;
}
bool BleMedium::StartAcceptingConnections(const std::string& service_id,
AcceptedConnectionCallback callback) {
NEARBY_LOGS(INFO) << "G3 Ble StartAcceptingConnections: service_id="
<< service_id;
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForAcceptedConnection(*this, service_id, callback);
return true;
}
bool BleMedium::StopAcceptingConnections(const std::string& service_id) {
NEARBY_LOGS(INFO) << "G3 Ble StopAcceptingConnections: service_id="
<< service_id;
auto& env = MediumEnvironment::Instance();
env.UpdateBleMediumForAcceptedConnection(*this, service_id, {});
return true;
}
std::unique_ptr<api::BleSocket> BleMedium::Connect(
api::BlePeripheral& remote_peripheral, const std::string& service_id,
CancellationFlag* cancellation_flag) {
NEARBY_LOG(INFO,
"G3 Ble Connect [self]: medium=%p, adapter=%p, peripheral=%p, "
"service_id=%s",
this, &GetAdapter(), &GetAdapter().GetPeripheral(),
service_id.c_str());
// First, find an instance of remote medium, that exposed this peripheral.
auto& adapter = static_cast<BlePeripheral&>(remote_peripheral).GetAdapter();
auto* medium = static_cast<BleMedium*>(adapter.GetBleMedium());
if (!medium) return {}; // Can't find medium. Bail out.
BleServerSocket* remote_server_socket = nullptr;
NEARBY_LOG(INFO,
"G3 Ble Connect [peer]: medium=%p, adapter=%p, peripheral=%p, "
"service_id=%s",
medium, &adapter, &remote_peripheral, service_id.c_str());
// Then, find our server socket context in this medium.
{
absl::MutexLock medium_lock(&medium->mutex_);
remote_server_socket = medium->server_socket_.get();
if (remote_server_socket == nullptr) {
NEARBY_LOGS(ERROR)
<< "G3 Ble Connect: Failed to find Ble Server socket: service_id="
<< service_id;
return {};
}
}
if (cancellation_flag->Cancelled()) {
NEARBY_LOGS(ERROR) << "G3 BLE Connect: Has been cancelled: "
"service_id="
<< service_id;
return {};
}
CancellationFlagListener listener(cancellation_flag, [this]() {
NEARBY_LOGS(INFO) << "G3 BLE Cancel Connect.";
if (server_socket_ != nullptr) server_socket_->Close();
});
BlePeripheral peripheral = static_cast<BlePeripheral&>(remote_peripheral);
auto socket = std::make_unique<BleSocket>(&peripheral);
// Finally, Request to connect to this socket.
if (!remote_server_socket->Connect(*socket)) {
NEARBY_LOGS(ERROR) << "G3 Ble Connect: Failed to connect to existing Ble "
"Server socket: service_id="
<< service_id;
return {};
}
NEARBY_LOG(INFO, "G3 Ble Connect: connected: socket=%p", socket.get());
return socket;
}
} // namespace g3
} // namespace nearby
} // namespace location
+228
View File
@@ -0,0 +1,228 @@
// 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_G3_BLE_H_
#define PLATFORM_IMPL_G3_BLE_H_
#include <memory>
#include <string>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/implementation/g3/bluetooth_adapter.h"
#include "internal/platform/implementation/g3/bluetooth_classic.h"
#include "internal/platform/implementation/g3/multi_thread_executor.h"
#include "internal/platform/implementation/g3/pipe.h"
namespace location {
namespace nearby {
namespace g3 {
class BleMedium;
class BleSocket : public api::BleSocket {
public:
BleSocket() = default;
explicit BleSocket(BlePeripheral* peripheral) : peripheral_(peripheral) {}
~BleSocket() override;
// Connect to another BleSocket, to form a functional low-level channel.
// from this point on, and until Close is called, connection exists.
void Connect(BleSocket& other) ABSL_LOCKS_EXCLUDED(mutex_);
// Returns the InputStream of this connected BleSocket.
InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns the OutputStream of this connected BleSocket.
// This stream is for local side to write.
OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns address of a remote BleSocket or nullptr.
BleSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if socket is closed.
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns valid BlePeripheral pointer if there is a connection, and
// nullptr otherwise.
BlePeripheral* GetRemotePeripheral() override ABSL_LOCKS_EXCLUDED(mutex_);
private:
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns InputStream of our side of a connection.
// This is what the remote side is supposed to read from.
// This is a helper for GetInputStream() method.
InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns OutputStream of our side of a connection.
// This is what the local size is supposed to write to.
// This is a helper for GetOutputStream() method.
OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Output pipe is initialized by constructor, it remains always valid, until
// it is closed. it represents output part of a local socket. Input part of a
// local socket comes from the peer socket, after connection.
std::shared_ptr<Pipe> output_{new Pipe};
std::shared_ptr<Pipe> input_;
mutable absl::Mutex mutex_;
BlePeripheral* peripheral_;
BleSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
class BleServerSocket {
public:
~BleServerSocket();
// 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 BleSocket to the server side.
// If not null, returned socket is connected to its remote (client-side) peer.
std::unique_ptr<api::BleSocket> Accept(BlePeripheral* peripheral)
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.
// Returns true, if socket is successfully connected.
bool Connect(BleSocket& socket) ABSL_LOCKS_EXCLUDED(mutex_);
// Called by the server side of a connection before passing ownership of
// BleServerSocker to user, to track validity of a pointer to this
// server socket,
void SetCloseNotifier(std::function<void()> 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() ABSL_LOCKS_EXCLUDED(mutex_);
private:
Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
absl::Mutex mutex_;
absl::CondVar cond_;
absl::flat_hash_set<BleSocket*> pending_sockets_ ABSL_GUARDED_BY(mutex_);
std::function<void()> close_notifier_ ABSL_GUARDED_BY(mutex_);
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
// Container of operations that can be performed over the BLE medium.
class BleMedium : public api::BleMedium {
public:
explicit BleMedium(api::BluetoothAdapter& adapter);
~BleMedium() override;
// Returns true once the Ble advertising has been initiated.
bool StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAdvertising(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once the Ble scanning has been initiated.
bool StartScanning(const std::string& service_id,
const std::string& fast_advertisement_service_uuid,
DiscoveredPeripheralCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
// 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
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once Ble socket connection requests to service_id can be
// accepted.
bool StartAcceptingConnections(const std::string& service_id,
AcceptedConnectionCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAcceptingConnections(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Connects to existing remote Ble peripheral.
//
// On success, returns a new BleSocket.
// On error, returns nullptr.
std::unique_ptr<api::BleSocket> Connect(
api::BlePeripheral& remote_peripheral, const std::string& service_id,
CancellationFlag* cancellation_flag) override ABSL_LOCKS_EXCLUDED(mutex_);
BluetoothAdapter& GetAdapter() { return *adapter_; }
private:
static constexpr int kMaxConcurrentAcceptLoops = 5;
struct AdvertisingInfo {
bool Empty() const { return service_id.empty(); }
void Clear() { service_id.clear(); }
std::string service_id;
};
struct ScanningInfo {
bool Empty() const { return service_id.empty(); }
void Clear() { service_id.clear(); }
std::string service_id;
};
absl::Mutex mutex_;
BluetoothAdapter* adapter_; // Our device adapter; read-only.
// A thread pool dedicated to running all the accept loops from
// StartAdvertising().
MultiThreadExecutor accept_loops_runner_{kMaxConcurrentAcceptLoops};
std::atomic_bool acceptance_thread_running_ = false;
// A thread pool dedicated to wait to complete the accept_loops_runner_.
MultiThreadExecutor close_accept_loops_runner_{kMaxConcurrentAcceptLoops};
// A server socket is established when start advertising.
std::unique_ptr<BleServerSocket> server_socket_;
AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_);
ScanningInfo scanning_info_ ABSL_GUARDED_BY(mutex_);
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_BLE_H_
@@ -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/g3/bluetooth_adapter.h"
#include <string>
#include "internal/platform/medium_environment.h"
#include "internal/platform/prng.h"
#include "internal/platform/implementation/g3/bluetooth_classic.h"
namespace location {
namespace nearby {
namespace g3 {
BlePeripheral::BlePeripheral(BluetoothAdapter* adapter) : adapter_(*adapter) {}
std::string BlePeripheral::GetName() const { return adapter_.GetName(); }
ByteArray BlePeripheral::GetAdvertisementBytes(
const std::string& service_id) const {
return advertisement_bytes_;
}
void BlePeripheral::SetAdvertisementBytes(
const std::string& service_id, const ByteArray& advertisement_bytes) {
advertisement_bytes_ = advertisement_bytes;
}
BluetoothDevice::BluetoothDevice(BluetoothAdapter* adapter)
: adapter_(*adapter) {}
std::string BluetoothDevice::GetName() const { return adapter_.GetName(); }
std::string BluetoothDevice::GetMacAddress() const {
return adapter_.GetMacAddress();
}
BluetoothAdapter::BluetoothAdapter() {
std::string mac_address;
mac_address.resize(6);
int64_t raw_mac_addr = Prng().NextInt64();
mac_address[0] = static_cast<char>(raw_mac_addr >> 40);
mac_address[1] = static_cast<char>(raw_mac_addr >> 32);
mac_address[2] = static_cast<char>(raw_mac_addr >> 24);
mac_address[3] = static_cast<char>(raw_mac_addr >> 16);
mac_address[4] = static_cast<char>(raw_mac_addr >> 8);
mac_address[5] = static_cast<char>(raw_mac_addr >> 0);
SetMacAddress(mac_address);
}
BluetoothAdapter::~BluetoothAdapter() { SetStatus(Status::kDisabled); }
void BluetoothAdapter::SetBluetoothClassicMedium(
api::BluetoothClassicMedium* medium) {
bluetooth_classic_medium_ = medium;
}
void BluetoothAdapter::SetBleMedium(api::BleMedium* medium) {
ble_medium_ = medium;
}
bool BluetoothAdapter::SetStatus(Status status) {
BluetoothAdapter::ScanMode mode;
bool enabled = status == Status::kEnabled;
std::string name;
{
absl::MutexLock lock(&mutex_);
enabled_ = enabled;
name = name_;
mode = mode_;
}
auto& env = MediumEnvironment::Instance();
env.OnBluetoothAdapterChangedState(*this, device_, name, enabled, mode);
return true;
}
bool BluetoothAdapter::IsEnabled() const {
absl::MutexLock lock(&mutex_);
return enabled_;
}
BluetoothAdapter::ScanMode BluetoothAdapter::GetScanMode() const {
absl::MutexLock lock(&mutex_);
return mode_;
}
bool BluetoothAdapter::SetScanMode(BluetoothAdapter::ScanMode mode) {
bool enabled;
std::string name;
{
absl::MutexLock lock(&mutex_);
mode_ = mode;
name = name_;
enabled = enabled_;
}
auto& env = MediumEnvironment::Instance();
env.OnBluetoothAdapterChangedState(*this, device_, std::move(name), enabled,
mode);
return true;
}
std::string BluetoothAdapter::GetName() const {
absl::MutexLock lock(&mutex_);
return name_;
}
bool BluetoothAdapter::SetName(absl::string_view name) {
BluetoothAdapter::ScanMode mode;
bool enabled;
{
absl::MutexLock lock(&mutex_);
name_ = name;
enabled = enabled_;
mode = mode_;
}
auto& env = MediumEnvironment::Instance();
env.OnBluetoothAdapterChangedState(*this, device_, std::string(name), enabled,
mode);
return true;
}
} // namespace g3
} // namespace nearby
} // namespace location
@@ -0,0 +1,142 @@
// 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_G3_BLUETOOTH_ADAPTER_H_
#define PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_
#include <string>
#include "absl/base/thread_annotations.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/g3/single_thread_executor.h"
namespace location {
namespace nearby {
namespace g3 {
// BluetoothDevice and BluetoothAdapter have a mutual dependency.
class BluetoothAdapter;
// Opaque wrapper over a Ble peripheral. Must contain enough data about a
// particular Ble device to connect to its GATT server.
class BlePeripheral : public api::BlePeripheral {
public:
~BlePeripheral() override = default;
std::string GetName() const override;
ByteArray GetAdvertisementBytes(const std::string& service_id) const override;
void SetAdvertisementBytes(const std::string& service_id,
const ByteArray& advertisement_bytes);
BluetoothAdapter& GetAdapter() { return adapter_; }
private:
// Only BluetoothAdapter may instantiate BlePeripheral.
friend class BluetoothAdapter;
explicit BlePeripheral(BluetoothAdapter* adapter);
BluetoothAdapter& adapter_;
ByteArray advertisement_bytes_;
};
// 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;
BluetoothAdapter& GetAdapter() { return adapter_; }
private:
// Only BluetoothAdapter may instantiate BluetoothDevice.
friend class BluetoothAdapter;
explicit BluetoothDevice(BluetoothAdapter* adapter);
BluetoothAdapter& adapter_;
};
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
class BluetoothAdapter : public api::BluetoothAdapter {
public:
using Status = api::BluetoothAdapter::Status;
using ScanMode = api::BluetoothAdapter::ScanMode;
BluetoothAdapter();
~BluetoothAdapter() override;
// Synchronously sets the status of the BluetoothAdapter to 'status', and
// returns true if the operation was a success.
bool SetStatus(Status status) override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if the BluetoothAdapter's current status is
// Status::Value::kEnabled.
bool IsEnabled() const override ABSL_LOCKS_EXCLUDED(mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getScanMode()
//
// Returns ScanMode::kUnknown on error.
ScanMode GetScanMode() const override ABSL_LOCKS_EXCLUDED(mutex_);
// Synchronously sets the scan mode of the adapter, and returns true if the
// operation was a success.
bool SetScanMode(ScanMode mode) override ABSL_LOCKS_EXCLUDED(mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
// Returns an empty string on error
std::string GetName() const override ABSL_LOCKS_EXCLUDED(mutex_);
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
bool SetName(absl::string_view name) override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns BT MAC address assigned to this adapter.
std::string GetMacAddress() const override { return mac_address_; }
BluetoothDevice& GetDevice() { return device_; }
void SetBluetoothClassicMedium(api::BluetoothClassicMedium* medium);
api::BluetoothClassicMedium* GetBluetoothClassicMedium() {
return bluetooth_classic_medium_;
}
BlePeripheral& GetPeripheral() { return peripheral_; }
void SetBleMedium(api::BleMedium* medium);
api::BleMedium* GetBleMedium() { return ble_medium_; }
void SetMacAddress(std::string& mac_address) { mac_address_ = mac_address; }
private:
mutable absl::Mutex mutex_;
BluetoothDevice device_{this};
BlePeripheral peripheral_{this};
api::BluetoothClassicMedium* bluetooth_classic_medium_ = nullptr;
api::BleMedium* ble_medium_ = nullptr;
std::string mac_address_;
ScanMode mode_ ABSL_GUARDED_BY(mutex_) = ScanMode::kNone;
std::string name_ ABSL_GUARDED_BY(mutex_) = "unknown G3 BT device";
bool enabled_ ABSL_GUARDED_BY(mutex_) = false;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_
@@ -0,0 +1,278 @@
// 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/g3/bluetooth_classic.h"
#include <memory>
#include <string>
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/cancellation_flag_listener.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/implementation/g3/bluetooth_adapter.h"
namespace location {
namespace nearby {
namespace g3 {
BluetoothSocket::~BluetoothSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
void BluetoothSocket::Connect(BluetoothSocket& other) {
absl::MutexLock lock(&mutex_);
remote_socket_ = &other;
input_ = other.output_;
}
bool BluetoothSocket::IsConnected() const {
absl::MutexLock lock(&mutex_);
return IsConnectedLocked();
}
bool BluetoothSocket::IsClosed() const {
absl::MutexLock lock(&mutex_);
return closed_;
}
bool BluetoothSocket::IsConnectedLocked() const { return input_ != nullptr; }
InputStream& BluetoothSocket::GetInputStream() {
auto* remote_socket = GetRemoteSocket();
CHECK(remote_socket != nullptr);
return remote_socket->GetLocalInputStream();
}
OutputStream& BluetoothSocket::GetOutputStream() {
return GetLocalOutputStream();
}
InputStream& BluetoothSocket::GetLocalInputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetInputStream();
}
OutputStream& BluetoothSocket::GetLocalOutputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetOutputStream();
}
Exception BluetoothSocket::Close() {
absl::MutexLock lock(&mutex_);
DoClose();
return {Exception::kSuccess};
}
void BluetoothSocket::DoClose() {
if (!closed_) {
remote_socket_ = nullptr;
output_->GetOutputStream().Close();
output_->GetInputStream().Close();
input_->GetOutputStream().Close();
input_->GetInputStream().Close();
closed_ = true;
}
}
BluetoothSocket* BluetoothSocket::GetRemoteSocket() {
absl::MutexLock lock(&mutex_);
return remote_socket_;
}
BluetoothDevice* BluetoothSocket::GetRemoteDevice() {
BluetoothAdapter* remote_adapter = nullptr;
{
absl::MutexLock lock(&mutex_);
if (remote_socket_ == nullptr || remote_socket_->adapter_ == nullptr) {
return nullptr;
}
remote_adapter = remote_socket_->adapter_;
}
return remote_adapter ? &remote_adapter->GetDevice() : nullptr;
}
std::unique_ptr<api::BluetoothSocket> 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<BluetoothSocket>(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()) {
NEARBY_LOGS(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(std::function<void()> 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};
}
BluetoothClassicMedium::BluetoothClassicMedium(api::BluetoothAdapter& adapter)
// TODO(apolyudov): implement and use downcast<> with static assertions.
: adapter_(static_cast<BluetoothAdapter*>(&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<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
api::BluetoothDevice& remote_device, const std::string& service_uuid,
CancellationFlag* cancellation_flag) {
NEARBY_LOGS(INFO) << "G3 ConnectToService [self]: medium=" << this
<< ", adapter=" << &GetAdapter()
<< ", device=" << &GetAdapter().GetDevice();
// First, find an instance of remote medium, that exposed this device.
auto& adapter = static_cast<BluetoothDevice&>(remote_device).GetAdapter();
auto* medium =
static_cast<BluetoothClassicMedium*>(adapter.GetBluetoothClassicMedium());
if (!medium) return {}; // Adapter is not bound to medium. Bail out.
BluetoothServerSocket* server_socket = nullptr;
NEARBY_LOGS(INFO) << "G3 ConnectToService [peer]: medium=" << medium
<< ", adapter=" << &adapter << ", device=" << &remote_device
<< ", uuid=" << service_uuid.c_str();
// 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 != sockets_.end() ? item->second : nullptr;
if (server_socket == nullptr) {
NEARBY_LOGS(ERROR) << "Failed to find BT Server socket: uuid="
<< service_uuid;
return {};
}
}
if (cancellation_flag->Cancelled()) {
NEARBY_LOGS(ERROR) << "G3 Bluetooth Connect: Has been cancelled: "
"service_uuid="
<< service_uuid;
return {};
}
CancellationFlagListener listener(cancellation_flag, [&server_socket]() {
NEARBY_LOGS(INFO) << "G3 Bluetooth Cancel Connect.";
if (server_socket != nullptr) server_socket->Close();
});
auto socket = std::make_unique<BluetoothSocket>(&GetAdapter());
// Finally, Request to connect to this socket.
if (!server_socket->Connect(*socket)) {
NEARBY_LOGS(ERROR)
<< "Failed to connect to existing BT Server socket: uuid="
<< service_uuid;
return {};
}
NEARBY_LOGS(INFO) << "G3 ConnectToService: connected: socket="
<< socket.get();
return socket;
}
std::unique_ptr<api::BluetoothServerSocket>
BluetoothClassicMedium::ListenForService(const std::string& service_name,
const std::string& service_uuid) {
auto socket = std::make_unique<BluetoothServerSocket>(GetAdapter());
socket->SetCloseNotifier([this, uuid = service_uuid]() {
absl::MutexLock lock(&mutex_);
sockets_.erase(uuid);
});
NEARBY_LOGS(INFO) << "Adding service: medium=" << this
<< ", uuid=" << service_uuid;
absl::MutexLock lock(&mutex_);
sockets_.emplace(service_uuid, socket.get());
return socket;
}
api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice(
const std::string& mac_address) {
auto& env = MediumEnvironment::Instance();
return env.FindBluetoothDevice(mac_address);
}
} // namespace g3
} // namespace nearby
} // namespace location
@@ -0,0 +1,238 @@
// 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_G3_BLUETOOTH_CLASSIC_H_
#define PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_
#include <memory>
#include <string>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/listeners.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/implementation/g3/bluetooth_adapter.h"
#include "internal/platform/implementation/g3/pipe.h"
namespace location {
namespace nearby {
namespace g3 {
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html.
class BluetoothSocket : public api::BluetoothSocket {
public:
BluetoothSocket() = default;
explicit BluetoothSocket(BluetoothAdapter* adapter) : adapter_(adapter) {}
~BluetoothSocket() override;
// Connects to another BluetoothSocket, to form a functional low-level
// channel. From this point on, and until Close is called, connection exists.
void Connect(BluetoothSocket& other);
// NOTE:
// It is an undefined behavior if GetInputStream() or GetOutputStream() is
// called for a not-connected BluetoothSocket, i.e. any object that is not
// returned by BluetoothClassicMedium::ConnectToService() for client side or
// BluetoothServerSocket::Accept() for server side of connection.
// Returns the InputStream of this connected BluetoothSocket.
InputStream& GetInputStream() override;
// Returns the OutputStream of this connected BluetoothSocket.
// This stream is for local side to write.
OutputStream& GetOutputStream() override;
// Returns address of a remote BluetoothSocket or nullptr.
BluetoothSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if socket is closed.
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
// 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 ABSL_LOCKS_EXCLUDED(mutex_);
// 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 ABSL_LOCKS_EXCLUDED(mutex_);
private:
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns InputStream of our side of a connection.
// This is what the remote side is supposed to read from.
// This is a helper for GetInputStream() method.
InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns OutputStream of our side of a connection.
// This is what the local size is supposed to write to.
// This is a helper for GetOutputStream() method.
OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Output pipe is initialized by constructor, it remains always valid, until
// it is closed. it represents output part of a local socket. Input part of a
// local socket comes from the peer socket, after connection.
std::shared_ptr<Pipe> output_{new Pipe};
std::shared_ptr<Pipe> input_;
mutable absl::Mutex mutex_;
BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only.
BluetoothSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
// 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<api::BluetoothSocket> 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(std::function<void()> 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<BluetoothSocket*> pending_sockets_
ABSL_GUARDED_BY(mutex_);
std::function<void()> close_notifier_ ABSL_GUARDED_BY(mutex_);
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
// 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<api::BluetoothSocket> 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<api::BluetoothServerSocket> ListenForService(
const std::string& service_name, const std::string& service_uuid) override
ABSL_LOCKS_EXCLUDED(mutex_);
api::BluetoothDevice* GetRemoteDevice(
const std::string& mac_address) override;
private:
absl::Mutex mutex_;
BluetoothAdapter* adapter_; // Our device adapter; read-only.
absl::flat_hash_map<std::string, BluetoothServerSocket*> sockets_
ABSL_GUARDED_BY(mutex_);
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_
@@ -0,0 +1,51 @@
// 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_G3_CONDITION_VARIABLE_H_
#define PLATFORM_IMPL_G3_CONDITION_VARIABLE_H_
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/condition_variable.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/g3/mutex.h"
namespace location {
namespace nearby {
namespace g3 {
class ConditionVariable : public api::ConditionVariable {
public:
explicit ConditionVariable(g3::Mutex* mutex) : mutex_(&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 g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_CONDITION_VARIABLE_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.
#include "internal/platform/implementation/crypto.h"
#include <cstdint>
#include <string>
#include "absl/strings/string_view.h"
#include "internal/platform/byte_array.h"
#include "src/include/openssl/digest.h"
namespace location {
namespace nearby {
// Initialize global crypto state.
void Crypto::Init() {}
static ByteArray Hash(absl::string_view input, const EVP_MD* algo) {
unsigned int md_out_size = EVP_MAX_MD_SIZE;
uint8_t digest_buffer[EVP_MAX_MD_SIZE];
if (input.empty()) return {};
if (!EVP_Digest(input.data(), input.size(), digest_buffer, &md_out_size, algo,
nullptr))
return {};
return ByteArray{reinterpret_cast<char*>(digest_buffer), md_out_size};
}
// Return MD5 hash of input.
ByteArray Crypto::Md5(absl::string_view input) {
return Hash(input, EVP_md5());
}
// Return SHA256 hash of input.
ByteArray Crypto::Sha256(absl::string_view input) {
return Hash(input, EVP_sha256());
}
} // namespace nearby
} // namespace location
@@ -0,0 +1,74 @@
// 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/g3/log_message.h"
#include <algorithm>
#include "base/stringprintf.h"
namespace location {
namespace nearby {
namespace g3 {
api::LogMessage::Severity g_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;
StringAppendV(&result, format, ap);
log_streamer_.stream() << result;
va_end(ap);
}
std::ostream& LogMessage::Stream() { return log_streamer_.stream(); }
} // namespace g3
namespace api {
void LogMessage::SetMinLogSeverity(Severity severity) {
g3::g_min_log_severity = severity;
}
bool LogMessage::ShouldCreateLogMessage(Severity severity) {
return severity >= g3::g_min_log_severity;
}
} // namespace api
} // namespace nearby
} // namespace location
@@ -0,0 +1,44 @@
// 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_G3_LOG_MESSAGE_H_
#define PLATFORM_IMPL_G3_LOG_MESSAGE_H_
#include "glog/logging.h"
#include "internal/platform/implementation/log_message.h"
namespace location {
namespace nearby {
namespace g3 {
// 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_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_LOG_MESSAGE_H_
@@ -0,0 +1,66 @@
// 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_G3_MULTI_THREAD_EXECUTOR_H_
#define PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
#include <atomic>
#include "absl/time/clock.h"
#include "internal/platform/implementation/submittable_executor.h"
#include "internal/platform/implementation/shared/count_down_latch.h"
#include "nisaba/port/thread_pool.h"
namespace location {
namespace nearby {
namespace g3 {
// An Executor that reuses a fixed number of threads operating off a shared
// unbounded queue.
class MultiThreadExecutor : public api::SubmittableExecutor {
public:
explicit MultiThreadExecutor(int max_parallelism)
: thread_pool_(max_parallelism) {
thread_pool_.StartWorkers();
}
void Execute(Runnable&& runnable) override {
if (!shutdown_) {
thread_pool_.Schedule(std::move(runnable));
}
}
bool DoSubmit(Runnable&& runnable) override {
if (shutdown_) return false;
thread_pool_.Schedule(std::move(runnable));
return true;
}
void Shutdown() override { DoShutdown(); }
~MultiThreadExecutor() override { DoShutdown(); }
void ScheduleAfter(absl::Duration delay, Runnable&& runnable) {
if (shutdown_) return;
thread_pool_.ScheduleAt(absl::Now() + delay, std::move(runnable));
}
bool InShutdown() const { return shutdown_; }
private:
void DoShutdown() { shutdown_ = true; }
std::atomic_bool shutdown_ = false;
ThreadPool thread_pool_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
@@ -0,0 +1,61 @@
// 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_G3_MUTEX_H_
#define PLATFORM_IMPL_G3_MUTEX_H_
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/mutex.h"
#include "internal/platform/implementation/shared/posix_mutex.h"
namespace location {
namespace nearby {
namespace g3 {
class ABSL_LOCKABLE Mutex : public api::Mutex {
public:
explicit Mutex(bool check) : check_(check) {}
~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 {
mutex_.Lock();
if (!check_) mutex_.ForgetDeadlockInfo();
}
void Unlock() ABSL_UNLOCK_FUNCTION() override { mutex_.Unlock(); }
private:
friend class ConditionVariable;
absl::Mutex mutex_;
bool check_;
};
class ABSL_LOCKABLE RecursiveMutex : public posix::Mutex {
public:
~RecursiveMutex() override = default;
RecursiveMutex() = default;
RecursiveMutex(RecursiveMutex&&) = delete;
RecursiveMutex& operator=(RecursiveMutex&&) = delete;
RecursiveMutex(const RecursiveMutex&) = delete;
RecursiveMutex& operator=(const RecursiveMutex&) = delete;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_MUTEX_H_
@@ -0,0 +1,44 @@
// 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_G3_PIPE_H_
#define PLATFORM_IMPL_G3_PIPE_H_
#include <memory>
#include "internal/platform/base_pipe.h"
#include "internal/platform/implementation/g3/condition_variable.h"
#include "internal/platform/implementation/g3/mutex.h"
namespace location {
namespace nearby {
namespace g3 {
class Pipe : public BasePipe {
public:
Pipe() {
auto mutex = std::make_unique<g3::Mutex>(/*check=*/true);
auto cond = std::make_unique<g3::ConditionVariable>(mutex.get());
Setup(std::move(mutex), std::move(cond));
}
~Pipe() override = default;
Pipe(Pipe&&) = delete;
Pipe& operator=(Pipe&&) = delete;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_PIPE_H_
@@ -0,0 +1,172 @@
// 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/platform.h"
#include <atomic>
#include <cstdint>
#include <memory>
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/time/time.h"
#include "internal/platform/implementation/atomic_boolean.h"
#include "internal/platform/implementation/atomic_reference.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/condition_variable.h"
#include "internal/platform/implementation/shared/count_down_latch.h"
#include "internal/platform/implementation/log_message.h"
#include "internal/platform/implementation/mutex.h"
#include "internal/platform/implementation/scheduled_executor.h"
#include "internal/platform/implementation/server_sync.h"
#include "internal/platform/implementation/submittable_executor.h"
#include "internal/platform/implementation/webrtc.h"
#include "internal/platform/implementation/wifi.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/implementation/g3/atomic_boolean.h"
#include "internal/platform/implementation/g3/atomic_reference.h"
#include "internal/platform/implementation/g3/ble.h"
#include "internal/platform/implementation/g3/bluetooth_adapter.h"
#include "internal/platform/implementation/g3/bluetooth_classic.h"
#include "internal/platform/implementation/g3/condition_variable.h"
#include "internal/platform/implementation/g3/log_message.h"
#include "internal/platform/implementation/g3/multi_thread_executor.h"
#include "internal/platform/implementation/g3/mutex.h"
#include "internal/platform/implementation/g3/scheduled_executor.h"
#include "internal/platform/implementation/g3/single_thread_executor.h"
#include "internal/platform/implementation/g3/webrtc.h"
#include "internal/platform/implementation/g3/wifi_lan.h"
#include "internal/platform/implementation/shared/file.h"
namespace location {
namespace nearby {
namespace api {
namespace {
std::string GetPayloadPath(PayloadId payload_id) {
return absl::StrCat("/tmp/", payload_id);
}
} // namespace
int GetCurrentTid() {
const LiveThread* my = Thread_GetMyLiveThread();
return LiveThread_Pthread_TID(my);
}
std::unique_ptr<SubmittableExecutor>
ImplementationPlatform::CreateSingleThreadExecutor() {
return absl::make_unique<g3::SingleThreadExecutor>();
}
std::unique_ptr<SubmittableExecutor>
ImplementationPlatform::CreateMultiThreadExecutor(int max_concurrency) {
return absl::make_unique<g3::MultiThreadExecutor>(max_concurrency);
}
std::unique_ptr<ScheduledExecutor>
ImplementationPlatform::CreateScheduledExecutor() {
return absl::make_unique<g3::ScheduledExecutor>();
}
std::unique_ptr<AtomicUint32> ImplementationPlatform::CreateAtomicUint32(
std::uint32_t value) {
return absl::make_unique<g3::AtomicUint32>(value);
}
std::unique_ptr<BluetoothAdapter>
ImplementationPlatform::CreateBluetoothAdapter() {
return absl::make_unique<g3::BluetoothAdapter>();
}
std::unique_ptr<CountDownLatch> ImplementationPlatform::CreateCountDownLatch(
std::int32_t count) {
return absl::make_unique<shared::CountDownLatch>(count);
}
std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
bool initial_value) {
return absl::make_unique<g3::AtomicBoolean>(initial_value);
}
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
PayloadId payload_id, std::int64_t total_size) {
return absl::make_unique<shared::InputFile>(GetPayloadPath(payload_id),
total_size);
}
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
PayloadId payload_id) {
return absl::make_unique<shared::OutputFile>(GetPayloadPath(payload_id));
}
std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
const char* file, int line, LogMessage::Severity severity) {
return absl::make_unique<g3::LogMessage>(file, line, severity);
}
std::unique_ptr<BluetoothClassicMedium>
ImplementationPlatform::CreateBluetoothClassicMedium(
api::BluetoothAdapter& adapter) {
return absl::make_unique<g3::BluetoothClassicMedium>(adapter);
}
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(
api::BluetoothAdapter& adapter) {
return absl::make_unique<g3::BleMedium>(adapter);
}
std::unique_ptr<ble_v2::BleMedium> ImplementationPlatform::CreateBleV2Medium(
api::BluetoothAdapter& adapter) {
return std::unique_ptr<ble_v2::BleMedium>();
}
std::unique_ptr<ServerSyncMedium>
ImplementationPlatform::CreateServerSyncMedium() {
return std::unique_ptr<ServerSyncMedium>(/*new ServerSyncMediumImpl()*/);
}
std::unique_ptr<WifiMedium> ImplementationPlatform::CreateWifiMedium() {
return std::unique_ptr<WifiMedium>();
}
std::unique_ptr<WifiLanMedium> ImplementationPlatform::CreateWifiLanMedium() {
return absl::make_unique<g3::WifiLanMedium>();
}
std::unique_ptr<WebRtcMedium> ImplementationPlatform::CreateWebRtcMedium() {
if (MediumEnvironment::Instance().GetEnvironmentConfig().webrtc_enabled) {
return absl::make_unique<g3::WebRtcMedium>();
} else {
return nullptr;
}
}
std::unique_ptr<Mutex> ImplementationPlatform::CreateMutex(Mutex::Mode mode) {
if (mode == Mutex::Mode::kRecursive)
return absl::make_unique<g3::RecursiveMutex>();
else
return absl::make_unique<g3::Mutex>(mode == Mutex::Mode::kRegular);
}
std::unique_ptr<ConditionVariable>
ImplementationPlatform::CreateConditionVariable(Mutex* mutex) {
return std::unique_ptr<ConditionVariable>(
new g3::ConditionVariable(static_cast<g3::Mutex*>(mutex)));
}
} // namespace api
} // namespace nearby
} // namespace location
@@ -0,0 +1,79 @@
// 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/g3/scheduled_executor.h"
#include <atomic>
#include <memory>
#include "absl/time/clock.h"
#include "internal/platform/implementation/cancelable.h"
#include "internal/platform/runnable.h"
namespace location {
namespace nearby {
namespace g3 {
namespace {
class ScheduledCancelable : public api::Cancelable {
public:
bool Cancel() override {
Status expected = kNotRun;
while (expected == kNotRun) {
if (status_.compare_exchange_strong(expected, kCanceled)) {
return true;
}
}
return false;
}
bool MarkExecuted() {
Status expected = kNotRun;
while (expected == kNotRun) {
if (status_.compare_exchange_strong(expected, kExecuted)) {
return true;
}
}
return false;
}
private:
enum Status {
kNotRun,
kExecuted,
kCanceled,
};
std::atomic<Status> status_ = kNotRun;
};
} // namespace
std::shared_ptr<api::Cancelable> ScheduledExecutor::Schedule(
Runnable&& runnable, absl::Duration delay) {
auto scheduled_cancelable = std::make_shared<ScheduledCancelable>();
if (executor_.InShutdown()) {
return scheduled_cancelable;
}
executor_.ScheduleAfter(
delay, [this, scheduled_cancelable, runnable(std::move(runnable))]() {
if (!executor_.InShutdown() && scheduled_cancelable->MarkExecuted()) {
runnable();
}
});
return scheduled_cancelable;
}
} // namespace g3
} // namespace nearby
} // namespace location
@@ -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.
#ifndef PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_
#define PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_
#include <atomic>
#include <memory>
#include "absl/time/clock.h"
#include "internal/platform/implementation/cancelable.h"
#include "internal/platform/implementation/scheduled_executor.h"
#include "internal/platform/runnable.h"
#include "internal/platform/implementation/g3/single_thread_executor.h"
#include "nisaba/port/thread_pool.h"
namespace location {
namespace nearby {
namespace g3 {
// An Executor that reuses a fixed number of threads operating off a shared
// unbounded queue.
class ScheduledExecutor final : public api::ScheduledExecutor {
public:
ScheduledExecutor() = default;
~ScheduledExecutor() override { executor_.Shutdown(); }
void Execute(Runnable&& runnable) override {
executor_.Execute(std::move(runnable));
}
std::shared_ptr<api::Cancelable> Schedule(Runnable&& runnable,
absl::Duration delay) override;
void Shutdown() override { executor_.Shutdown(); }
private:
SingleThreadExecutor executor_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_
@@ -0,0 +1,36 @@
// 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_G3_SINGLE_THREAD_EXECUTOR_H_
#define PLATFORM_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_
#include "internal/platform/implementation/g3/multi_thread_executor.h"
namespace location {
namespace nearby {
namespace g3 {
// An Executor that uses a single worker thread operating off an unbounded
// queue.
class SingleThreadExecutor final : public MultiThreadExecutor {
public:
SingleThreadExecutor() : MultiThreadExecutor(1) {}
~SingleThreadExecutor() override = default;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_
@@ -0,0 +1,30 @@
// 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 "absl/time/clock.h"
#include "internal/platform/exception.h"
namespace location {
namespace nearby {
absl::Time SystemClock::ElapsedRealtime() { return absl::Now(); }
Exception SystemClock::Sleep(absl::Duration duration) {
absl::SleepFor(duration);
return {Exception::kSuccess};
}
} // namespace nearby
} // namespace location
@@ -0,0 +1,97 @@
// 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/g3/webrtc.h"
#include <memory>
#include "internal/platform/medium_environment.h"
#include "webrtc/api/task_queue/default_task_queue_factory.h"
namespace location {
namespace nearby {
namespace g3 {
WebRtcSignalingMessenger::WebRtcSignalingMessenger(
absl::string_view self_id, const connections::LocationHint& location_hint)
: self_id_(self_id), location_hint_(location_hint) {}
bool WebRtcSignalingMessenger::SendMessage(absl::string_view peer_id,
const ByteArray& message) {
auto& env = MediumEnvironment::Instance();
env.SendWebRtcSignalingMessage(peer_id, message);
return true;
}
bool WebRtcSignalingMessenger::StartReceivingMessages(
OnSignalingMessageCallback on_message_callback,
OnSignalingCompleteCallback on_complete_callback) {
auto& env = MediumEnvironment::Instance();
env.RegisterWebRtcSignalingMessenger(self_id_, on_message_callback,
on_complete_callback);
return true;
}
void WebRtcSignalingMessenger::StopReceivingMessages() {
auto& env = MediumEnvironment::Instance();
env.UnregisterWebRtcSignalingMessenger(self_id_);
}
WebRtcMedium::~WebRtcMedium() { single_thread_executor_.Shutdown(); }
const std::string WebRtcMedium::GetDefaultCountryCode() { return "US"; }
void WebRtcMedium::CreatePeerConnection(
webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) {
auto& env = MediumEnvironment::Instance();
if (!env.GetUseValidPeerConnection()) {
callback(nullptr);
return;
}
webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
rtc_config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
webrtc::PeerConnectionDependencies dependencies(observer);
std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();
signaling_thread->SetName("signaling_thread", nullptr);
RTC_CHECK(signaling_thread->Start()) << "Failed to start thread";
webrtc::PeerConnectionFactoryDependencies factory_dependencies;
factory_dependencies.task_queue_factory =
webrtc::CreateDefaultTaskQueueFactory();
factory_dependencies.signaling_thread = signaling_thread.release();
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection =
webrtc::CreateModularPeerConnectionFactory(
std::move(factory_dependencies))
->CreatePeerConnection(rtc_config, std::move(dependencies));
single_thread_executor_.Execute(
[&env, callback = std::move(callback),
peer_connection = std::move(peer_connection)]() {
absl::SleepFor(env.GetPeerConnectionLatency());
callback(peer_connection);
});
}
std::unique_ptr<api::WebRtcSignalingMessenger>
WebRtcMedium::GetSignalingMessenger(
absl::string_view self_id, const connections::LocationHint& location_hint) {
return std::make_unique<WebRtcSignalingMessenger>(self_id, location_hint);
}
} // namespace g3
} // namespace nearby
} // namespace location
@@ -0,0 +1,81 @@
// 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_G3_WEBRTC_H_
#define PLATFORM_IMPL_G3_WEBRTC_H_
#include <memory>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/webrtc.h"
#include "internal/platform/implementation/g3/single_thread_executor.h"
#include "webrtc/api/peer_connection_interface.h"
namespace location {
namespace nearby {
namespace g3 {
class WebRtcSignalingMessenger : public api::WebRtcSignalingMessenger {
public:
using OnSignalingMessageCallback =
api::WebRtcSignalingMessenger::OnSignalingMessageCallback;
using OnSignalingCompleteCallback =
api::WebRtcSignalingMessenger::OnSignalingCompleteCallback;
explicit WebRtcSignalingMessenger(
absl::string_view self_id,
const connections::LocationHint& location_hint);
~WebRtcSignalingMessenger() override = default;
bool SendMessage(absl::string_view peer_id,
const ByteArray& message) override;
bool StartReceivingMessages(
OnSignalingMessageCallback on_message_callback,
OnSignalingCompleteCallback on_complete_callback) override;
void StopReceivingMessages() override;
private:
std::string self_id_;
connections::LocationHint location_hint_;
};
class WebRtcMedium : public api::WebRtcMedium {
public:
using PeerConnectionCallback = api::WebRtcMedium::PeerConnectionCallback;
WebRtcMedium() = default;
~WebRtcMedium() override;
const std::string GetDefaultCountryCode() override;
// Creates and returns a new webrtc::PeerConnectionInterface object via
// |callback|.
void CreatePeerConnection(webrtc::PeerConnectionObserver* observer,
PeerConnectionCallback callback) override;
// Returns a signaling messenger for sending WebRTC signaling messages.
std::unique_ptr<api::WebRtcSignalingMessenger> GetSignalingMessenger(
absl::string_view self_id,
const connections::LocationHint& location_hint) override;
private:
// Executor for handling calls to create a peer connection.
SingleThreadExecutor single_thread_executor_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_WEBRTC_H_
@@ -0,0 +1,371 @@
// 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/g3/wifi_lan.h"
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include "absl/strings/escaping.h"
#include "absl/strings/str_format.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/wifi_lan.h"
#include "internal/platform/cancellation_flag_listener.h"
#include "internal/platform/logging.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/nsd_service_info.h"
namespace location {
namespace nearby {
namespace g3 {
WifiLanSocket::~WifiLanSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
void WifiLanSocket::Connect(WifiLanSocket& other) {
absl::MutexLock lock(&mutex_);
remote_socket_ = &other;
input_ = other.output_;
}
InputStream& WifiLanSocket::GetInputStream() {
auto* remote_socket = GetRemoteSocket();
CHECK(remote_socket != nullptr);
return remote_socket->GetLocalInputStream();
}
OutputStream& WifiLanSocket::GetOutputStream() {
return GetLocalOutputStream();
}
WifiLanSocket* WifiLanSocket::GetRemoteSocket() {
absl::MutexLock lock(&mutex_);
return remote_socket_;
}
bool WifiLanSocket::IsConnected() const {
absl::MutexLock lock(&mutex_);
return IsConnectedLocked();
}
bool WifiLanSocket::IsClosed() const {
absl::MutexLock lock(&mutex_);
return closed_;
}
Exception WifiLanSocket::Close() {
absl::MutexLock lock(&mutex_);
DoClose();
return {Exception::kSuccess};
}
void WifiLanSocket::DoClose() {
if (!closed_) {
remote_socket_ = nullptr;
output_->GetOutputStream().Close();
output_->GetInputStream().Close();
input_->GetOutputStream().Close();
input_->GetInputStream().Close();
closed_ = true;
}
}
bool WifiLanSocket::IsConnectedLocked() const { return input_ != nullptr; }
InputStream& WifiLanSocket::GetLocalInputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetInputStream();
}
OutputStream& WifiLanSocket::GetLocalOutputStream() {
absl::MutexLock lock(&mutex_);
return output_->GetOutputStream();
}
std::string WifiLanServerSocket::GetName(const std::string& ip_address,
int port) {
std::string dot_delimited_string;
if (!ip_address.empty()) {
for (auto byte : ip_address) {
if (!dot_delimited_string.empty())
absl::StrAppend(&dot_delimited_string, ".");
absl::StrAppend(&dot_delimited_string, absl::StrFormat("%d", byte));
}
}
std::string out = absl::StrCat(dot_delimited_string, ":", port);
return out;
}
std::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::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<WifiLanSocket>();
local_socket->Connect(*remote_socket);
remote_socket->Connect(*local_socket);
cond_.SignalAll();
return local_socket;
}
bool WifiLanServerSocket::Connect(WifiLanSocket& socket) {
absl::MutexLock lock(&mutex_);
if (closed_) return false;
if (socket.IsConnected()) {
NEARBY_LOGS(ERROR)
<< "Failed to connect to WifiLan server socket: already connected";
return true; // already connected.
}
// add client socket to the pending list
pending_sockets_.insert(&socket);
cond_.SignalAll();
while (!socket.IsConnected()) {
cond_.Wait(&mutex_);
if (closed_) return false;
}
return true;
}
void WifiLanServerSocket::SetCloseNotifier(std::function<void()> notifier) {
absl::MutexLock lock(&mutex_);
close_notifier_ = std::move(notifier);
}
WifiLanServerSocket::~WifiLanServerSocket() {
absl::MutexLock lock(&mutex_);
DoClose();
}
Exception WifiLanServerSocket::Close() {
absl::MutexLock lock(&mutex_);
return DoClose();
}
Exception WifiLanServerSocket::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};
}
WifiLanMedium::WifiLanMedium() {
auto& env = MediumEnvironment::Instance();
env.RegisterWifiLanMedium(*this);
}
WifiLanMedium::~WifiLanMedium() {
auto& env = MediumEnvironment::Instance();
env.UnregisterWifiLanMedium(*this);
}
bool WifiLanMedium::StartAdvertising(const NsdServiceInfo& nsd_service_info) {
std::string service_type = nsd_service_info.GetServiceType();
NEARBY_LOGS(INFO) << "G3 WifiLan StartAdvertising: nsd_service_info="
<< &nsd_service_info
<< ", service_name=" << nsd_service_info.GetServiceName()
<< ", service_type=" << service_type;
{
absl::MutexLock lock(&mutex_);
if (advertising_info_.Existed(service_type)) {
NEARBY_LOGS(INFO)
<< "G3 WifiLan StartAdvertising: Can't start advertising because "
"service_type="
<< service_type << ", has started already.";
return false;
}
}
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForAdvertising(*this, nsd_service_info,
/*enabled=*/true);
{
absl::MutexLock lock(&mutex_);
advertising_info_.Add(service_type);
}
return true;
}
bool WifiLanMedium::StopAdvertising(const NsdServiceInfo& nsd_service_info) {
std::string service_type = nsd_service_info.GetServiceType();
NEARBY_LOGS(INFO) << "G3 WifiLan StopAdvertising: nsd_service_info="
<< &nsd_service_info
<< ", service_name=" << nsd_service_info.GetServiceName()
<< ", service_type=" << service_type;
{
absl::MutexLock lock(&mutex_);
if (!advertising_info_.Existed(service_type)) {
NEARBY_LOGS(INFO)
<< "G3 WifiLan StopAdvertising: Can't stop advertising because "
"we never started advertising for service_type="
<< service_type;
return false;
}
advertising_info_.Remove(service_type);
}
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForAdvertising(*this, nsd_service_info,
/*enabled=*/false);
return true;
}
bool WifiLanMedium::StartDiscovery(const std::string& service_type,
DiscoveredServiceCallback callback) {
NEARBY_LOGS(INFO) << "G3 WifiLan StartDiscovery: service_type="
<< service_type;
{
absl::MutexLock lock(&mutex_);
if (discovering_info_.Existed(service_type)) {
NEARBY_LOGS(INFO)
<< "G3 WifiLan StartDiscovery: Can't start discovery because "
"service_type="
<< service_type << " has started already.";
return false;
}
}
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForDiscovery(*this, std::move(callback), service_type,
true);
{
absl::MutexLock lock(&mutex_);
discovering_info_.Add(service_type);
}
return true;
}
bool WifiLanMedium::StopDiscovery(const std::string& service_type) {
NEARBY_LOGS(INFO) << "G3 WifiLan StopDiscovery: service_type="
<< service_type;
{
absl::MutexLock lock(&mutex_);
if (!discovering_info_.Existed(service_type)) {
NEARBY_LOGS(INFO)
<< "G3 WifiLan StopDiscovery: Can't stop discovering because we "
"never started discovering.";
return false;
}
discovering_info_.Remove(service_type);
}
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForDiscovery(*this, {}, service_type, false);
return true;
}
std::unique_ptr<api::WifiLanSocket> WifiLanMedium::ConnectToService(
const NsdServiceInfo& remote_service_info,
CancellationFlag* cancellation_flag) {
std::string service_type = remote_service_info.GetServiceType();
NEARBY_LOGS(INFO) << "G3 WifiLan ConnectToService [self]: medium=" << this
<< ", service_type=" << service_type;
return ConnectToService(remote_service_info.GetIPAddress(),
remote_service_info.GetPort(), cancellation_flag);
}
std::unique_ptr<api::WifiLanSocket> WifiLanMedium::ConnectToService(
const std::string& ip_address, int port,
CancellationFlag* cancellation_flag) {
std::string socket_name = WifiLanServerSocket::GetName(ip_address, port);
NEARBY_LOGS(INFO) << "G3 WifiLan ConnectToService [self]: medium=" << this
<< ", ip address + port=" << socket_name;
// First, find an instance of remote medium, that exposed this service.
auto& env = MediumEnvironment::Instance();
auto* remote_medium =
static_cast<WifiLanMedium*>(env.GetWifiLanMedium(ip_address, port));
if (!remote_medium) {
return {};
}
WifiLanServerSocket* server_socket = nullptr;
NEARBY_LOGS(INFO) << "G3 WifiLan ConnectToService [peer]: medium="
<< remote_medium
<< ", remote ip address + port=" << socket_name;
// Then, find our server socket context in this medium.
{
absl::MutexLock medium_lock(&remote_medium->mutex_);
auto item = remote_medium->server_sockets_.find(socket_name);
server_socket = item != server_sockets_.end() ? item->second : nullptr;
if (server_socket == nullptr) {
NEARBY_LOGS(ERROR)
<< "G3 WifiLan Failed to find WifiLan Server socket: socket_name="
<< socket_name;
return {};
}
}
if (cancellation_flag->Cancelled()) {
NEARBY_LOGS(ERROR) << "G3 WifiLan Connect: Has been cancelled: socket_name="
<< socket_name;
return {};
}
CancellationFlagListener listener(cancellation_flag, [&server_socket]() {
NEARBY_LOGS(INFO) << "G3 WifiLan Cancel Connect.";
if (server_socket != nullptr) {
server_socket->Close();
}
});
auto socket = std::make_unique<WifiLanSocket>();
// Finally, Request to connect to this socket.
if (!server_socket->Connect(*socket)) {
NEARBY_LOGS(ERROR) << "G3 WifiLan Failed to connect to existing WifiLan "
"Server socket: name="
<< socket_name;
return {};
}
NEARBY_LOGS(INFO) << "G3 WifiLan ConnectToService: connected: socket="
<< socket.get();
return socket;
}
std::unique_ptr<api::WifiLanServerSocket> WifiLanMedium::ListenForService(
int port) {
auto& env = MediumEnvironment::Instance();
auto server_socket = std::make_unique<WifiLanServerSocket>();
server_socket->SetIPAddress(env.GetFakeIPAddress());
server_socket->SetPort(port == 0 ? env.GetFakePort() : port);
std::string socket_name = WifiLanServerSocket::GetName(
server_socket->GetIPAddress(), server_socket->GetPort());
server_socket->SetCloseNotifier([this, socket_name]() {
absl::MutexLock lock(&mutex_);
server_sockets_.erase(socket_name);
});
NEARBY_LOGS(INFO) << "G3 WifiLan Adding server socket: medium=" << this
<< ", socket_name=" << socket_name;
absl::MutexLock lock(&mutex_);
server_sockets_.insert({socket_name, server_socket.get()});
return server_socket;
}
} // namespace g3
} // namespace nearby
} // namespace location
@@ -0,0 +1,285 @@
// 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_G3_WIFI_LAN_H_
#define PLATFORM_IMPL_G3_WIFI_LAN_H_
#include <memory>
#include <string>
#include <utility>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/wifi_lan.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/nsd_service_info.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/implementation/g3/multi_thread_executor.h"
#include "internal/platform/implementation/g3/pipe.h"
namespace location {
namespace nearby {
namespace g3 {
class WifiLanMedium;
class WifiLanSocket : public api::WifiLanSocket {
public:
WifiLanSocket() = default;
~WifiLanSocket() override;
// Connect to another WifiLanSocket, to form a functional low-level channel.
// from this point on, and until Close is called, connection exists.
void Connect(WifiLanSocket& other) ABSL_LOCKS_EXCLUDED(mutex_);
// Returns the InputStream of this connected WifiLanSocket.
InputStream& GetInputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns the OutputStream of this connected WifiLanSocket.
// This stream is for local side to write.
OutputStream& GetOutputStream() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns address of a remote WifiLanSocket or nullptr.
WifiLanSocket* GetRemoteSocket() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnected() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true if socket is closed.
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
private:
void DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns true if connection exists to the (possibly closed) remote socket.
bool IsConnectedLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns InputStream of our side of a connection.
// This is what the remote side is supposed to read from.
// This is a helper for GetInputStream() method.
InputStream& GetLocalInputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Returns OutputStream of our side of a connection.
// This is what the local size is supposed to write to.
// This is a helper for GetOutputStream() method.
OutputStream& GetLocalOutputStream() ABSL_LOCKS_EXCLUDED(mutex_);
// Output pipe is initialized by constructor, it remains always valid, until
// it is closed. it represents output part of a local socket. Input part of a
// local socket comes from the peer socket, after connection.
std::shared_ptr<Pipe> output_{new Pipe};
std::shared_ptr<Pipe> input_;
mutable absl::Mutex mutex_;
WifiLanSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
class WifiLanServerSocket : public api::WifiLanServerSocket {
public:
static std::string GetName(const std::string& ip_address, int port);
~WifiLanServerSocket() override;
// Gets ip address.
std::string GetIPAddress() const override ABSL_LOCKS_EXCLUDED(mutex_) {
absl::MutexLock lock(&mutex_);
return ip_address_;
}
// Sets the ip address.
void SetIPAddress(const std::string& ip_address) ABSL_LOCKS_EXCLUDED(mutex_) {
absl::MutexLock lock(&mutex_);
ip_address_ = ip_address;
}
// Gets the port.
int GetPort() const override ABSL_LOCKS_EXCLUDED(mutex_) {
absl::MutexLock lock(&mutex_);
return port_;
}
// Sets the port.
void SetPort(int port) ABSL_LOCKS_EXCLUDED(mutex_) {
absl::MutexLock lock(&mutex_);
port_ = port;
}
// 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 WifiLanSocket to the server side.
// If not null, returned socket is connected to its remote (client-side) peer.
std::unique_ptr<api::WifiLanSocket> 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.
// Returns true, if socket is successfully connected.
bool Connect(WifiLanSocket& socket) ABSL_LOCKS_EXCLUDED(mutex_);
// Called by the server side of a connection before passing ownership of
// WifiLanServerSocker to user, to track validity of a pointer to this
// server socket.
void SetCloseNotifier(std::function<void()> 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_);
mutable absl::Mutex mutex_;
std::string ip_address_ ABSL_GUARDED_BY(mutex_);
int port_ ABSL_GUARDED_BY(mutex_);
absl::CondVar cond_;
absl::flat_hash_set<WifiLanSocket*> pending_sockets_ ABSL_GUARDED_BY(mutex_);
std::function<void()> close_notifier_ ABSL_GUARDED_BY(mutex_);
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
// Container of operations that can be performed over the WifiLan medium.
class WifiLanMedium : public api::WifiLanMedium {
public:
WifiLanMedium();
~WifiLanMedium() override;
// Starts WifiLan advertising.
//
// nsd_service_info - NsdServiceInfo data that's advertised through mDNS
// service.
// On success if the service is now advertising.
// On error if the service cannot start to advertise or the service type in
// NsdServiceInfo has been passed previously which StopAdvertising is not
// been called.
bool StartAdvertising(const NsdServiceInfo& nsd_service_info) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Stops WifiLan advertising.
//
// nsd_service_info - NsdServiceInfo data that's advertised through mDNS
// service.
// On success if the service stops advertising.
// On error if the service cannot stop advertising or the service type in
// NsdServiceInfo cannot be found.
bool StopAdvertising(const NsdServiceInfo& nsd_service_info) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Starts the discovery of nearby WifiLan services.
//
// Returns true once the WifiLan discovery has been initiated. The
// service_type is associated with callback.
bool StartDiscovery(const std::string& service_type,
DiscoveredServiceCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Stops the discovery of nearby WifiLan services.
//
// service_type - The one assigend in StartDiscovery.
// On success if service_type is matched to the callback and will be removed
// from the list. If list is empty then stops the WifiLan discovery
// service.
// On error if the service_type is not existed, then return immediately.
bool StopDiscovery(const std::string& service_type) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Connects to a WifiLan service.
// On success, returns a new WifiLanSocket.
// On error, returns nullptr.
std::unique_ptr<api::WifiLanSocket> ConnectToService(
const NsdServiceInfo& remote_service_info,
CancellationFlag* cancellation_flag) override ABSL_LOCKS_EXCLUDED(mutex_);
// Connects to a WifiLan service by ip address and port.
// On success, returns a new WifiLanSocket.
// On error, returns nullptr.
std::unique_ptr<api::WifiLanSocket> ConnectToService(
const std::string& ip_address, int port,
CancellationFlag* cancellation_flag) override ABSL_LOCKS_EXCLUDED(mutex_);
// Listens for incoming connection.
//
// port - A port number.
// 0 : use a random port.
// 1~65536 : open a server socket on that exact port.
// On success, returns a new WifiLanServerSocket.
// On error, returns nullptr.
std::unique_ptr<api::WifiLanServerSocket> ListenForService(int port) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns the port range as a pair of min and max port.
absl::optional<std::pair<std::int32_t, std::int32_t>> GetDynamicPortRange()
override {
return std::make_pair(49152, 65535);
}
private:
struct AdvertisingInfo {
bool Empty() const { return service_types.empty(); }
void Clear() { service_types.clear(); }
void Add(const std::string& service_type) {
service_types.insert(service_type);
}
void Remove(const std::string& service_type) {
service_types.erase(service_type);
}
bool Existed(const std::string& service_type) const {
return service_types.contains(service_type);
}
absl::flat_hash_set<std::string> service_types;
};
struct DiscoveringInfo {
bool Empty() const { return service_types.empty(); }
void Clear() { service_types.clear(); }
void Add(const std::string& service_type) {
service_types.insert(service_type);
}
void Remove(const std::string& service_type) {
service_types.erase(service_type);
}
bool Existed(const std::string& service_type) const {
return service_types.contains(service_type);
}
absl::flat_hash_set<std::string> service_types;
};
absl::Mutex mutex_;
AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_);
DiscoveringInfo discovering_info_ ABSL_GUARDED_BY(mutex_);
absl::flat_hash_map<std::string, WifiLanServerSocket*> server_sockets_
ABSL_GUARDED_BY(mutex_);
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_WIFI_LAN_H_