Roll forward to cl/338482889

Signed-off-by: Alexey Polyudov <apolyudov@google.com>
Change-Id: I9850950db8bd84f0904ea1a413151887f52098cf
This commit is contained in:
Alexey Polyudov
2020-10-22 10:47:34 -07:00
parent d68e53cf03
commit 2155b3ddeb
542 changed files with 15219 additions and 42295 deletions
+95 -11
View File
@@ -1,26 +1,110 @@
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",
"count_down_latch.h",
"log_message.h",
"multi_thread_executor.h",
"mutex.h",
"pipe.h",
"scheduled_executor.h",
"single_thread_executor.h",
],
visibility = ["//visibility:private"],
deps = [
"//base",
"//platform/api:platform",
"//platform/api:types",
"//platform/base",
"//platform/base:util",
"//platform/impl/shared:posix_mutex",
"//absl/base:core_headers",
"//absl/synchronization",
"//absl/time",
"//thread",
],
)
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",
"//platform/api:comm",
"//platform/base",
"//platform/base:logging",
"//platform/base:test_util",
"//absl/base:core_headers",
"//absl/container:flat_hash_map",
"//absl/container:flat_hash_set",
"//absl/strings",
"//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 = [
"//platform/api:types",
"//platform/base",
"//absl/strings",
"//openssl:crypto",
],
)
cc_library(
name = "g3",
testonly = True,
srcs = [
"atomic_reference_impl.h",
"platform.cc",
"settable_future_impl.h",
"system_clock_impl.h",
],
visibility = [
"//core:__subpackages__",
"//platform:__subpackages__",
],
deps = [
"//platform:types",
"//platform/api",
"//platform/impl/shared:atomic_boolean",
":comm",
":crypto", # build_cleaner: keep
":types",
"//platform/api:comm",
"//platform/api:platform",
"//platform/api:types",
"//platform/base:test_util",
"//platform/impl/shared:file",
"//platform/impl/shared:posix_condition_variable",
"//platform/impl/shared:posix_lock",
"//platform/port:string",
"//absl/base:core_headers",
"//absl/synchronization",
"//absl/memory",
"//absl/strings",
"//absl/time",
"//absl/types:any",
],
)
+30
View File
@@ -0,0 +1,30 @@
#ifndef PLATFORM_IMPL_G3_ATOMIC_BOOLEAN_H_
#define PLATFORM_IMPL_G3_ATOMIC_BOOLEAN_H_
#include <atomic>
#include "platform/api/atomic_boolean.h"
namespace location {
namespace nearby {
namespace g3 {
// See documentation in
// https://source.corp.google.com/piper///depot/google3/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_
+33
View File
@@ -0,0 +1,33 @@
#ifndef PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_
#define PLATFORM_IMPL_G3_ATOMIC_REFERENCE_H_
#include <atomic>
#include <cstdint>
#include "platform/api/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_
@@ -1,39 +0,0 @@
#ifndef PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_
#define PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_
#include "platform/api/atomic_reference.h"
#include "platform/ptr.h"
#include "absl/base/integral_types.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/any.h"
namespace location {
namespace nearby {
namespace platform {
// Provide implementation for absl::any.
class AtomicReferenceImpl : public AtomicReference<absl::any> {
public:
explicit AtomicReferenceImpl(absl::any initial_value)
: value_(std::move(initial_value)) {}
~AtomicReferenceImpl() override = default;
absl::any get() override {
absl::MutexLock lock(&mutex_);
return value_;
}
void set(absl::any value) override {
absl::MutexLock lock(&mutex_);
value_ = std::move(value);
}
private:
absl::Mutex mutex_;
absl::any value_;
};
} // namespace platform
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_ATOMIC_REFERENCE_IMPL_H_
+351
View File
@@ -0,0 +1,351 @@
#include "platform/impl/g3/ble.h"
#include <iostream>
#include <memory>
#include <string>
#include "platform/api/ble.h"
#include "platform/base/logging.h"
#include "platform/base/medium_environment.h"
#include "absl/synchronization/mutex.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_) {
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) {
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 {};
}
}
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
+215
View File
@@ -0,0 +1,215 @@
#ifndef PLATFORM_IMPL_G3_BLE_H_
#define PLATFORM_IMPL_G3_BLE_H_
#include <memory>
#include <string>
#include "platform/api/ble.h"
#include "platform/base/byte_array.h"
#include "platform/base/input_stream.h"
#include "platform/base/output_stream.h"
#include "platform/impl/g3/bluetooth_adapter.h"
#include "platform/impl/g3/bluetooth_classic.h"
#include "platform/impl/g3/multi_thread_executor.h"
#include "platform/impl/g3/pipe.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.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) 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_
+121
View File
@@ -0,0 +1,121 @@
#include "platform/impl/g3/bluetooth_adapter.h"
#include <string>
#include "platform/base/medium_environment.h"
#include "platform/base/prng.h"
#include "platform/impl/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
+128
View File
@@ -0,0 +1,128 @@
#ifndef PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_
#define PLATFORM_IMPL_G3_BLUETOOTH_ADAPTER_H_
#include <string>
#include "platform/api/ble.h"
#include "platform/api/bluetooth_adapter.h"
#include "platform/api/bluetooth_classic.h"
#include "platform/impl/g3/single_thread_executor.h"
#include "absl/base/thread_annotations.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.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_
+251
View File
@@ -0,0 +1,251 @@
#include "platform/impl/g3/bluetooth_classic.h"
#include <memory>
#include <string>
#include "platform/api/bluetooth_classic.h"
#include "platform/base/logging.h"
#include "platform/base/medium_environment.h"
#include "platform/impl/g3/bluetooth_adapter.h"
#include "absl/synchronization/mutex.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 (pending_sockets_.empty()) {
cond_.Wait(&mutex_);
if (closed_) break;
}
// 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_LOG(ERROR,
"Failed to connect to BT server socket: already connected");
return true; // already connected.
}
// add client socket to the pending list
pending_sockets_.emplace(&socket);
cond_.SignalAll();
while (!socket.IsConnected()) {
cond_.Wait(&mutex_);
if (closed_) return false;
}
return true;
}
void BluetoothServerSocket::SetCloseNotifier(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) {
NEARBY_LOG(INFO,
"G3 ConnectToService [self]: medium=%p, adapter=%p, device=%p",
this, &GetAdapter(), &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_LOG(
INFO,
"G3 ConnectToService [peer]: medium=%p, adapter=%p, device=%p, uuid=%s",
medium, &adapter, &remote_device, 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_LOG(ERROR, "Failed to find BT Server socket: uuid=%s",
service_uuid.c_str());
return {};
}
}
auto socket = std::make_unique<BluetoothSocket>(&GetAdapter());
// Finally, Request to connect to this socket.
if (!server_socket->Connect(*socket)) {
NEARBY_LOG(ERROR, "Failed to connect to existing BT Server socket: uuid=%s",
service_uuid.c_str());
return {};
}
NEARBY_LOG(INFO, "G3 ConnectToService: connected: socket=%p", 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_LOG(INFO, "Adding service: medium=%p, uuid=%s", this,
service_uuid.c_str());
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
+224
View File
@@ -0,0 +1,224 @@
#ifndef PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_
#define PLATFORM_IMPL_G3_BLUETOOTH_CLASSIC_H_
#include <memory>
#include <string>
#include "platform/api/bluetooth_classic.h"
#include "platform/base/byte_array.h"
#include "platform/base/exception.h"
#include "platform/base/input_stream.h"
#include "platform/base/listeners.h"
#include "platform/base/output_stream.h"
#include "platform/impl/g3/bluetooth_adapter.h"
#include "platform/impl/g3/pipe.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/synchronization/mutex.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) 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_
+37
View File
@@ -0,0 +1,37 @@
#ifndef PLATFORM_IMPL_G3_CONDITION_VARIABLE_H_
#define PLATFORM_IMPL_G3_CONDITION_VARIABLE_H_
#include "platform/api/condition_variable.h"
#include "platform/base/exception.h"
#include "platform/impl/g3/mutex.h"
#include "absl/synchronization/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_
+59
View File
@@ -0,0 +1,59 @@
#ifndef PLATFORM_IMPL_G3_COUNT_DOWN_LATCH_H_
#define PLATFORM_IMPL_G3_COUNT_DOWN_LATCH_H_
#include "platform/api/count_down_latch.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
namespace location {
namespace nearby {
namespace g3 {
// A synchronization aid that allows one or more threads to wait until a set of
// operations being performed in other threads completes.
//
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html
class CountDownLatch final : public api::CountDownLatch {
public:
explicit CountDownLatch(int count) : count_(count) {}
CountDownLatch(const CountDownLatch&) = delete;
CountDownLatch& operator=(const CountDownLatch&) = delete;
CountDownLatch(CountDownLatch&&) = delete;
CountDownLatch& operator=(CountDownLatch&&) = delete;
ExceptionOr<bool> Await(absl::Duration timeout) override {
absl::MutexLock lock(&mutex_);
absl::Time deadline = absl::Now() + timeout;
while (count_ > 0) {
if (cond_.WaitWithDeadline(&mutex_, deadline)) {
return ExceptionOr<bool>(false);
}
}
return ExceptionOr<bool>(true);
}
Exception Await() override {
absl::MutexLock lock(&mutex_);
while (count_ > 0) {
cond_.Wait(&mutex_);
}
return {Exception::kSuccess};
}
void CountDown() override {
absl::MutexLock lock(&mutex_);
if (count_ > 0 && --count_ == 0) {
cond_.SignalAll();
}
}
private:
absl::Mutex mutex_; // Mutex to be used with cond_.Wait...() method family.
absl::CondVar cond_; // Condition to synchronize up to N waiting threads.
int count_
ABSL_GUARDED_BY(mutex_); // When zero, latch should release all waiters.
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_COUNT_DOWN_LATCH_H_
+39
View File
@@ -0,0 +1,39 @@
#include "platform/api/crypto.h"
#include <cstdint>
#include <string>
#include "platform/base/byte_array.h"
#include "absl/strings/string_view.h"
#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
+56
View File
@@ -0,0 +1,56 @@
#include "platform/impl/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) {
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
+30
View File
@@ -0,0 +1,30 @@
#ifndef PLATFORM_IMPL_G3_LOG_MESSAGE_H_
#define PLATFORM_IMPL_G3_LOG_MESSAGE_H_
#include "base/logging.h"
#include "platform/api/log_message.h"
namespace location {
namespace nearby {
namespace g3 {
// See documentation in
// https://source.corp.google.com/piper///depot/google3/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:
absl::LogStreamer log_streamer_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_LOG_MESSAGE_H_
@@ -0,0 +1,59 @@
#ifndef PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
#define PLATFORM_IMPL_G3_MULTI_THREAD_EXECUTOR_H_
#include <atomic>
#include "platform/api/submittable_executor.h"
#include "platform/impl/g3/count_down_latch.h"
#include "absl/time/clock.h"
#include "thread/threadpool.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(); }
int GetTid(int index) const override {
const auto* thread = thread_pool_.thread(index);
return thread ? thread->tid() : 0;
}
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_
+47
View File
@@ -0,0 +1,47 @@
#ifndef PLATFORM_IMPL_G3_MUTEX_H_
#define PLATFORM_IMPL_G3_MUTEX_H_
#include "platform/api/mutex.h"
#include "platform/impl/shared/posix_mutex.h"
#include "absl/synchronization/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_
+30
View File
@@ -0,0 +1,30 @@
#ifndef PLATFORM_IMPL_G3_PIPE_H_
#define PLATFORM_IMPL_G3_PIPE_H_
#include <memory>
#include "platform/base/base_pipe.h"
#include "platform/impl/g3/condition_variable.h"
#include "platform/impl/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_
+90 -81
View File
@@ -5,146 +5,155 @@
#include "platform/api/atomic_boolean.h"
#include "platform/api/atomic_reference.h"
#include "platform/api/ble.h"
#include "platform/api/ble_v2.h"
#include "platform/api/bluetooth_adapter.h"
#include "platform/api/bluetooth_classic.h"
#include "platform/api/condition_variable.h"
#include "platform/api/count_down_latch.h"
#include "platform/api/hash_utils.h"
#include "platform/api/lock.h"
#include "platform/api/log_message.h"
#include "platform/api/mutex.h"
#include "platform/api/scheduled_executor.h"
#include "platform/api/server_sync.h"
#include "platform/api/settable_future.h"
#include "platform/api/submittable_executor.h"
#include "platform/api/system_clock.h"
#include "platform/api/thread_utils.h"
#include "platform/api/webrtc.h"
#include "platform/api/wifi.h"
#include "platform/impl/g3/atomic_reference_impl.h"
#include "platform/impl/g3/settable_future_impl.h"
#include "platform/impl/g3/system_clock_impl.h"
#include "platform/impl/shared/atomic_boolean_impl.h"
#include "platform/impl/shared/file_impl.h"
#include "platform/impl/shared/posix_condition_variable.h"
#include "platform/impl/shared/posix_lock.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
#include "platform/base/medium_environment.h"
#include "platform/impl/g3/atomic_boolean.h"
#include "platform/impl/g3/atomic_reference.h"
#include "platform/impl/g3/ble.h"
#include "platform/impl/g3/bluetooth_adapter.h"
#include "platform/impl/g3/bluetooth_classic.h"
#include "platform/impl/g3/condition_variable.h"
#include "platform/impl/g3/count_down_latch.h"
#include "platform/impl/g3/log_message.h"
#include "platform/impl/g3/multi_thread_executor.h"
#include "platform/impl/g3/mutex.h"
#include "platform/impl/g3/scheduled_executor.h"
#include "platform/impl/g3/single_thread_executor.h"
#include "platform/impl/g3/webrtc.h"
#include "platform/impl/g3/wifi_lan.h"
#include "platform/impl/shared/file.h"
#include "absl/base/integral_types.h"
#include "absl/synchronization/mutex.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/time/time.h"
namespace location {
namespace nearby {
namespace platform {
namespace api {
namespace {
std::string getPayloadPath(std::int64_t payload_id) {
return "/tmp/" + std::to_string(payload_id);
std::string GetPayloadPath(PayloadId payload_id) {
return absl::StrCat("/tmp/", payload_id);
}
} // namespace
Ptr<SubmittableExecutor> ImplementationPlatform::createSingleThreadExecutor() {
return Ptr<SubmittableExecutor>(/*new SingleThreadExecutorImpl()*/);
int GetCurrentTid() {
const LiveThread* my = Thread_GetMyLiveThread();
return LiveThread_Pthread_TID(my);
}
Ptr<SubmittableExecutor> ImplementationPlatform::createMultiThreadExecutor(
int max_concurrency) {
return Ptr<SubmittableExecutor>(/*new MultiThreadExecutorImpl()*/);
std::unique_ptr<SubmittableExecutor>
ImplementationPlatform::CreateSingleThreadExecutor() {
return absl::make_unique<g3::SingleThreadExecutor>();
}
Ptr<ScheduledExecutor> ImplementationPlatform::createScheduledExecutor() {
return Ptr<ScheduledExecutor>(/*new ScheduledExecutorImpl()*/);
std::unique_ptr<SubmittableExecutor>
ImplementationPlatform::CreateMultiThreadExecutor(int max_concurrency) {
return absl::make_unique<g3::MultiThreadExecutor>(max_concurrency);
}
Ptr<AtomicReference<absl::any>>
ImplementationPlatform::createAtomicReferenceAny(absl::any initial_value) {
return Ptr<AtomicReference<absl::any>>(
new AtomicReferenceImpl(initial_value));
std::unique_ptr<ScheduledExecutor>
ImplementationPlatform::CreateScheduledExecutor() {
return absl::make_unique<g3::ScheduledExecutor>();
}
Ptr<SettableFuture<absl::any>>
ImplementationPlatform::createSettableFutureAny() {
return Ptr<SettableFuture<std::any>>(new SettableFutureImpl{});
std::unique_ptr<AtomicUint32>
ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) {
return absl::make_unique<g3::AtomicUint32>(value);
}
Ptr<BluetoothAdapter> ImplementationPlatform::createBluetoothAdapter() {
return Ptr<BluetoothAdapter>{};
std::unique_ptr<BluetoothAdapter>
ImplementationPlatform::CreateBluetoothAdapter() {
return absl::make_unique<g3::BluetoothAdapter>();
}
Ptr<WifiMedium> ImplementationPlatform::createWifiMedium() {
return Ptr<WifiMedium>();
}
Ptr<CountDownLatch> ImplementationPlatform::createCountDownLatch(
std::unique_ptr<CountDownLatch> ImplementationPlatform::CreateCountDownLatch(
std::int32_t count) {
return Ptr<CountDownLatch>(/*new CountDownLatchImpl(count)*/);
return absl::make_unique<g3::CountDownLatch>(count);
}
Ptr<ThreadUtils> ImplementationPlatform::createThreadUtils() {
return Ptr<ThreadUtils>(/*new ThreadUtilsImpl()*/);
}
Ptr<SystemClock> ImplementationPlatform::createSystemClock() {
return Ptr<SystemClock>(new SystemClockImpl());
}
Ptr<AtomicBoolean> ImplementationPlatform::createAtomicBoolean(
std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
bool initial_value) {
return Ptr<AtomicBoolean>(new AtomicBooleanImpl(initial_value));
return absl::make_unique<g3::AtomicBoolean>(initial_value);
}
Ptr<InputFile> ImplementationPlatform::createInputFile(
std::int64_t payload_id, std::int64_t total_size) {
return MakePtr(new InputFileImpl(getPayloadPath(payload_id), total_size));
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);
}
Ptr<OutputFile> ImplementationPlatform::createOutputFile(
std::int64_t payload_id) {
return MakePtr(new OutputFileImpl(getPayloadPath(payload_id)));
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
PayloadId payload_id) {
return absl::make_unique<shared::OutputFile>(GetPayloadPath(payload_id));
}
Ptr<BluetoothClassicMedium>
ImplementationPlatform::createBluetoothClassicMedium() {
return Ptr<BluetoothClassicMedium>();
std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
const char* file, int line, LogMessage::Severity severity) {
return absl::make_unique<g3::LogMessage>(file, line, severity);
}
Ptr<BLEMedium> ImplementationPlatform::createBLEMedium() {
return Ptr<BLEMedium>();
std::unique_ptr<BluetoothClassicMedium>
ImplementationPlatform::CreateBluetoothClassicMedium(
api::BluetoothAdapter& adapter) {
return absl::make_unique<g3::BluetoothClassicMedium>(adapter);
}
Ptr<BLEMediumV2> ImplementationPlatform::createBLEMediumV2() {
return Ptr<BLEMediumV2>();
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(
api::BluetoothAdapter& adapter) {
return absl::make_unique<g3::BleMedium>(adapter);
}
Ptr<ServerSyncMedium> ImplementationPlatform::createServerSyncMedium() {
return Ptr<ServerSyncMedium>(/*new ServerSyncMediumImpl()*/);
std::unique_ptr<ble_v2::BleMedium> ImplementationPlatform::CreateBleV2Medium(
api::BluetoothAdapter& adapter) {
return std::unique_ptr<ble_v2::BleMedium>();
}
Ptr<WebRtcSignalingMessenger>
ImplementationPlatform::createWebRtcSignalingMessenger(
const std::string& self_id) {
return Ptr<WebRtcSignalingMessenger>(/*new FCMSignalingMessenger()*/);
std::unique_ptr<ServerSyncMedium>
ImplementationPlatform::CreateServerSyncMedium() {
return std::unique_ptr<ServerSyncMedium>(/*new ServerSyncMediumImpl()*/);
}
Ptr<Lock> ImplementationPlatform::createLock() {
return Ptr<Lock>(new PosixLock());
std::unique_ptr<WifiMedium> ImplementationPlatform::CreateWifiMedium() {
return std::unique_ptr<WifiMedium>();
}
Ptr<ConditionVariable> ImplementationPlatform::createConditionVariable(
Ptr<Lock> lock) {
return Ptr<ConditionVariable>(new PosixConditionVariable(lock));
std::unique_ptr<WifiLanMedium> ImplementationPlatform::CreateWifiLanMedium() {
return absl::make_unique<g3::WifiLanMedium>();
}
Ptr<HashUtils> ImplementationPlatform::createHashUtils() {
return Ptr<HashUtils>(/*new HashUtilsImpl()*/);
std::unique_ptr<WebRtcMedium> ImplementationPlatform::CreateWebRtcMedium() {
if (MediumEnvironment::Instance().GetEnvironmentConfig().webrtc_enabled) {
return absl::make_unique<g3::WebRtcMedium>();
} else {
return nullptr;
}
}
std::string ImplementationPlatform::getDeviceId() {
// TODO(alexchau): Get deviceId from base
return "google3";
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);
}
} // namespace platform
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,65 @@
#include "platform/impl/g3/scheduled_executor.h"
#include <atomic>
#include <memory>
#include "platform/api/cancelable.h"
#include "platform/base/runnable.h"
#include "absl/time/clock.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
+45
View File
@@ -0,0 +1,45 @@
#ifndef PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_
#define PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_
#include <atomic>
#include <memory>
#include "platform/api/cancelable.h"
#include "platform/api/scheduled_executor.h"
#include "platform/base/runnable.h"
#include "platform/impl/g3/single_thread_executor.h"
#include "absl/time/clock.h"
#include "thread/threadpool.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(); }
int GetTid(int index) const override {
return executor_.GetTid(index);
}
private:
SingleThreadExecutor executor_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_SCHEDULED_EXECUTOR_H_
@@ -1,94 +0,0 @@
#ifndef PLATFORM_IMPL_G3_SETTABLE_FUTURE_IMPL_H_
#define PLATFORM_IMPL_G3_SETTABLE_FUTURE_IMPL_H_
#include <utility>
#include "platform/api/platform.h"
#include "platform/api/settable_future.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
#include "absl/types/any.h"
namespace location {
namespace nearby {
namespace platform {
class SettableFutureImpl : public SettableFuture<absl::any> {
public:
explicit SettableFutureImpl() = default;
~SettableFutureImpl() override = default;
bool set(absl::any value) override {
absl::MutexLock lock(&mutex_);
if (!done_) {
value_ = std::move(value);
done_ = true;
exception_ = {Exception::kSuccess};
completed_.SignalAll();
}
return true;
}
bool setException(Exception exception) override {
absl::MutexLock lock(&mutex_);
return SetExceptionLocked(exception);
}
void addListener(Ptr<Runnable> runnable, Executor* executor) override {}
ExceptionOr<std::any> get() override {
absl::MutexLock lock(&mutex_);
while (!done_) {
completed_.Wait(&mutex_);
}
return exception_.value != Exception::kSuccess
? ExceptionOr<std::any>{exception_.value}
: ExceptionOr<std::any>{value_};
}
ExceptionOr<std::any> get(std::int64_t timeout_ms) override {
absl::MutexLock lock(&mutex_);
absl::Duration timeout = absl::Milliseconds(timeout_ms);
while (!done_) {
absl::Time start_time = absl::Now();
if (completed_.WaitWithTimeout(&mutex_, timeout)) {
SetExceptionLocked({Exception::kTimeout});
break;
}
absl::Duration spent = absl::Now() - start_time;
if (spent < timeout) {
timeout -= spent;
} else if (!done_) {
SetExceptionLocked({Exception::kTimeout});
break;
}
}
return exception_.value != Exception::kSuccess
? ExceptionOr<std::any>{exception_.value}
: ExceptionOr<std::any>{value_};
}
private:
bool SetExceptionLocked(Exception exception) {
if (!done_) {
exception_ = exception.value != Exception::kSuccess
? exception
: Exception{Exception::kFailed};
done_ = true;
completed_.SignalAll();
}
return true;
}
absl::Mutex mutex_;
absl::CondVar completed_;
bool done_{false};
absl::any value_;
Exception exception_{Exception::kFailed};
};
} // namespace platform
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_SETTABLE_FUTURE_IMPL_H_
@@ -0,0 +1,22 @@
#ifndef PLATFORM_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_
#define PLATFORM_IMPL_G3_SINGLE_THREAD_EXECUTOR_H_
#include "platform/impl/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_
+16
View File
@@ -0,0 +1,16 @@
#include "platform/api/system_clock.h"
#include "platform/base/exception.h"
#include "absl/time/clock.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
-23
View File
@@ -1,23 +0,0 @@
#ifndef PLATFORM_IMPL_G3_SYSTEM_CLOCK_IMPL_H_
#define PLATFORM_IMPL_G3_SYSTEM_CLOCK_IMPL_H_
#include <cstdint>
#include "platform/api/system_clock.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
namespace location {
namespace nearby {
class SystemClockImpl : public SystemClock {
public:
std::int64_t elapsedRealtime() override {
return absl::ToUnixMillis(absl::Now());
}
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_SYSTEM_CLOCK_IMPL_H_
+68
View File
@@ -0,0 +1,68 @@
#include "platform/impl/g3/webrtc.h"
#include <memory>
#include "platform/base/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 listener) {
auto& env = MediumEnvironment::Instance();
env.RegisterWebRtcSignalingMessenger(self_id_, listener);
return true;
}
void WebRtcSignalingMessenger::StopReceivingMessages() {
auto& env = MediumEnvironment::Instance();
env.UnregisterWebRtcSignalingMessenger(self_id_);
}
void WebRtcMedium::CreatePeerConnection(
webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) {
auto& env = MediumEnvironment::Instance();
if (!env.GetUseValidPeerConnection()) {
callback(nullptr);
return;
}
webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
webrtc::PeerConnectionDependencies dependencies(observer);
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_.get();
callback(webrtc::CreateModularPeerConnectionFactory(
std::move(factory_dependencies))
->CreatePeerConnection(rtc_config, std::move(dependencies)));
}
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
+59
View File
@@ -0,0 +1,59 @@
#ifndef PLATFORM_IMPL_G3_WEBRTC_H_
#define PLATFORM_IMPL_G3_WEBRTC_H_
#include <memory>
#include "platform/api/webrtc.h"
#include "absl/strings/string_view.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;
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 listener) override;
void StopReceivingMessages() override;
private:
absl::string_view self_id_;
connections::LocationHint location_hint_;
};
class WebRtcMedium : public api::WebRtcMedium {
public:
using PeerConnectionCallback = api::WebRtcMedium::PeerConnectionCallback;
WebRtcMedium() = default;
~WebRtcMedium() override = default;
// 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:
std::unique_ptr<rtc::Thread> signaling_thread_;
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_WEBRTC_H_
+365
View File
@@ -0,0 +1,365 @@
#include "platform/impl/g3/wifi_lan.h"
#include <iostream>
#include <memory>
#include <string>
#include "platform/api/wifi_lan.h"
#include "platform/base/logging.h"
#include "platform/base/medium_environment.h"
#include "platform/base/prng.h"
#include "absl/synchronization/mutex.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};
}
WifiLanService* WifiLanSocket::GetRemoteWifiLanService() {
absl::MutexLock lock(&mutex_);
return service_;
}
void WifiLanSocket::DoClose() {
if (!closed_) {
remote_socket_ = nullptr;
output_->GetOutputStream().Close();
output_->GetInputStream().Close();
if (IsConnectedLocked()) {
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::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::Accept(
WifiLanService* service) {
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<WifiLanSocket>(service);
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_LOG(ERROR,
"Failed to connect to WifiLan 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 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() {
service_.SetMedium(this);
std::string ip_address;
ip_address.resize(4);
uint32_t raw_ip_addr = Prng().NextUint32();
uint16_t port = Prng().NextUint32();
ip_address[0] = static_cast<char>(raw_ip_addr >> 24);
ip_address[1] = static_cast<char>(raw_ip_addr >> 16);
ip_address[2] = static_cast<char>(raw_ip_addr >> 8);
ip_address[3] = static_cast<char>(raw_ip_addr >> 0);
service_.SetServiceAddress(ip_address, port);
auto& env = MediumEnvironment::Instance();
env.RegisterWifiLanMedium(*this);
}
WifiLanMedium::~WifiLanMedium() {
service_.SetMedium(nullptr);
auto& env = MediumEnvironment::Instance();
env.UnregisterWifiLanMedium(*this);
StopAdvertising(advertising_info_.service_id);
StopDiscovery(discovering_info_.service_id);
NEARBY_LOG(INFO, "WifiLanMedium 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_) {
CountDownLatch latch(1);
close_accept_loops_runner_.Execute([&latch]() { latch.CountDown(); });
latch.Await();
}
}
}
bool WifiLanMedium::StartAdvertising(const std::string& service_id,
const std::string& service_info_name,
const std::string& endpoint_info_name) {
NEARBY_LOG(INFO,
"G3 WifiLan StartAdvertising: service_id=%s, service_info_name=%s",
service_id.c_str(), service_info_name.c_str());
auto& env = MediumEnvironment::Instance();
service_.SetServiceName(service_info_name);
service_.SetTxtRecord("n", endpoint_info_name);
env.UpdateWifiLanMediumForAdvertising(*this, service_, service_id, true);
absl::MutexLock lock(&mutex_);
if (server_socket_ != nullptr) server_socket_.release();
server_socket_ = std::make_unique<WifiLanServerSocket>();
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(&service_);
if (client_socket == nullptr) break;
env.CallWifiLanAcceptedConnectionCallback(
*this, *(client_socket.release()), service_id);
}
}
acceptance_thread_running_.exchange(false);
});
advertising_info_.service_id = service_id;
return true;
}
bool WifiLanMedium::StopAdvertising(const std::string& service_id) {
NEARBY_LOG(INFO, "G3 WifiLan StopAdvertising: service_id=%s",
service_id.c_str());
{
absl::MutexLock lock(&mutex_);
if (advertising_info_.Empty()) {
NEARBY_LOG(INFO,
"G3 WifiLan StopAdvertising: Can't stop advertising because "
"we never started advertising.");
return false;
}
advertising_info_.Clear();
}
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForAdvertising(*this, service_, service_id, false);
accept_loops_runner_.Shutdown();
if (server_socket_ == nullptr) {
NEARBY_LOGS(ERROR) << "G3 WifiLan StopAdvertising: failed to find WifiLan "
"Server socket: service_id="
<< service_id;
// Fall through for server socket not found.
return true;
}
if (!server_socket_->Close().Ok()) {
NEARBY_LOG(INFO,
"G3 WifiLan StopAdvertising: Failed to close WifiLan server "
"socket for %s.",
service_id.c_str());
return false;
}
return true;
}
bool WifiLanMedium::StartDiscovery(const std::string& service_id,
DiscoveredServiceCallback callback) {
NEARBY_LOG(INFO, "G3 WifiLan StartDiscovery: service_id=%s",
service_id.c_str());
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForDiscovery(*this, service_id, std::move(callback),
true);
{
absl::MutexLock lock(&mutex_);
discovering_info_.service_id = service_id;
}
return true;
}
bool WifiLanMedium::StopDiscovery(const std::string& service_id) {
NEARBY_LOG(INFO, "G3 WifiLan StopDiscovery: service_id=%s",
service_id.c_str());
{
absl::MutexLock lock(&mutex_);
if (discovering_info_.Empty()) {
NEARBY_LOG(INFO,
"G3 WifiLan StopDiscovery: Can't stop discovering because we "
"never started discovering.");
return false;
}
discovering_info_.Clear();
}
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForDiscovery(*this, service_id, {}, false);
return true;
}
bool WifiLanMedium::StartAcceptingConnections(
const std::string& service_id, AcceptedConnectionCallback callback) {
NEARBY_LOG(INFO, "G3 WifiLan StartAcceptingConnections: service_id=%s",
service_id.c_str());
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForAcceptedConnection(*this, service_id, callback);
return true;
}
bool WifiLanMedium::StopAcceptingConnections(const std::string& service_id) {
NEARBY_LOG(INFO, "G3 WifiLan StopAcceptingConnections: service_id=%s",
service_id.c_str());
auto& env = MediumEnvironment::Instance();
env.UpdateWifiLanMediumForAcceptedConnection(*this, service_id, {});
return true;
}
std::unique_ptr<api::WifiLanSocket> WifiLanMedium::Connect(
api::WifiLanService& remote_service, const std::string& service_id) {
NEARBY_LOG(INFO,
"G3 WifiLan Connect: medium=%p, service=%p, service_info_name=%s, "
"service_id=%s",
this, &service_, remote_service.GetServiceName().c_str(),
service_id.c_str());
// First, find an instance of remote medium, that exposed this service.
auto* medium = static_cast<WifiLanService&>(remote_service).GetMedium();
if (!medium) return {}; // Can't find medium. Bail out.
WifiLanServerSocket* remote_server_socket = nullptr;
NEARBY_LOG(INFO,
"G3 WifiLan Connect [peer]: medium=%p, service=%p, "
"service_info_name=%s, service_id=%s",
medium, &remote_service, remote_service.GetServiceName().c_str(),
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_LOG(ERROR,
"G3 WifiLan Connect: Failed to find WifiLan Server socket: "
"service_id=%s",
service_id.c_str());
// Fall through for server socket not found.
return {};
}
}
WifiLanService service = static_cast<WifiLanService&>(remote_service);
auto socket = std::make_unique<WifiLanSocket>(&service);
// Finally, Request to connect to this socket.
if (!remote_server_socket->Connect(*socket)) {
NEARBY_LOG(ERROR,
"G3 WifiLan Connect: Failed to connect to existing WifiLan "
"Server socket: service_id=%s",
service_id.c_str());
return {};
}
NEARBY_LOG(INFO, "G3 WifiLan Connect: connected: socket=%p", socket.get());
return socket;
}
api::WifiLanService* WifiLanMedium::FindRemoteService(
const std::string& ip_address, int port) {
auto& env = MediumEnvironment::Instance();
return env.FindWifiLanService(ip_address, port);
}
} // namespace g3
} // namespace nearby
} // namespace location
+259
View File
@@ -0,0 +1,259 @@
#ifndef PLATFORM_IMPL_G3_WIFI_LAN_H_
#define PLATFORM_IMPL_G3_WIFI_LAN_H_
#include <memory>
#include <string>
#include <utility>
#include "platform/api/wifi_lan.h"
#include "platform/base/byte_array.h"
#include "platform/base/input_stream.h"
#include "platform/base/output_stream.h"
#include "platform/impl/g3/multi_thread_executor.h"
#include "platform/impl/g3/pipe.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/synchronization/mutex.h"
namespace location {
namespace nearby {
namespace g3 {
class WifiLanMedium;
// Opaque wrapper over a WifiLan service which contains packed
// |WifiLanServiceInfo| string name.
class WifiLanService : public api::WifiLanService {
public:
explicit WifiLanService(std::string service_info_name)
: service_info_name_(std::move(service_info_name)) {}
~WifiLanService() override = default;
std::string GetServiceName() const override { return service_info_name_; }
void SetServiceName(std::string service_info_name) {
service_info_name_ = std::move(service_info_name);
}
std::string GetTxtRecord(const std::string& txt_record_key) const override {
if (txt_records_.empty()) return {};
auto record = txt_records_.find(txt_record_key);
if (record == txt_records_.end()) return {};
return record->second;
}
void SetTxtRecord(const std::string& txt_record_key,
const std::string& txt_record_value) {
txt_records_.emplace(txt_record_key, txt_record_value);
}
std::pair<std::string, int> GetServiceAddress() const override {
return std::make_pair(ip_address_, port_);
}
void SetServiceAddress(const std::string& ip_address, int port) {
ip_address_ = ip_address;
port_ = port;
}
WifiLanMedium* GetMedium() { return medium_; }
void SetMedium(WifiLanMedium* medium) { medium_ = medium; }
private:
std::string service_info_name_;
absl::flat_hash_map<std::string, std::string> txt_records_;
WifiLanMedium* medium_ = nullptr;
std::string ip_address_;
int port_;
};
class WifiLanSocket : public api::WifiLanSocket {
public:
WifiLanSocket() = default;
explicit WifiLanSocket(WifiLanService* service) : service_(service) {}
~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_);
// Returns valid WifiLanService pointer if there is a connection, and
// nullptr otherwise.
WifiLanService* GetRemoteWifiLanService() 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_;
WifiLanService* service_;
WifiLanSocket* remote_socket_ ABSL_GUARDED_BY(mutex_) = nullptr;
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
};
class WifiLanServerSocket {
public:
~WifiLanServerSocket();
// 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(WifiLanService* service)
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() ABSL_LOCKS_EXCLUDED(mutex_);
private:
Exception DoClose() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
absl::Mutex 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;
bool StartAdvertising(const std::string& service_id,
const std::string& service_info_name,
const std::string& endpoint_info_name) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAdvertising(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once the WifiLan discovery has been initiated.
bool StartDiscovery(const std::string& service_id,
DiscoveredServiceCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once WifiLan discovery for service_id is well and truly
// stopped; after this returns, there must be no more invocations of the
// DiscoveredServiceCallback passed in to StartDiscovery() for service_id.
bool StopDiscovery(const std::string& service_id) override
ABSL_LOCKS_EXCLUDED(mutex_);
// Returns true once WifiLan 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 WifiLan service.
//
// On success, returns a new WifiLanSocket.
// On error, returns nullptr.
std::unique_ptr<api::WifiLanSocket> Connect(
api::WifiLanService& remote_service,
const std::string& service_id) override ABSL_LOCKS_EXCLUDED(mutex_);
api::WifiLanService* FindRemoteService(const std::string& ip_address,
int port) override;
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 DiscoveringInfo {
bool Empty() const { return service_id.empty(); }
void Clear() { service_id.clear(); }
std::string service_id;
};
absl::Mutex mutex_;
WifiLanService service_{"unknown G3 WifiLan service"};
// 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<WifiLanServerSocket> server_socket_;
AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_);
DiscoveringInfo discovering_info_ ABSL_GUARDED_BY(mutex_);
};
} // namespace g3
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_G3_WIFI_LAN_H_
+50 -3
View File
@@ -1,9 +1,56 @@
objc_library(
name = "ios",
name = "types",
srcs = [
"log_message.mm",
"scheduled_executor.mm",
],
hdrs = [
"atomic_boolean.h",
"atomic_reference.h",
"condition_variable.h",
"count_down_latch.h",
"log_message.h",
"multi_thread_executor.h",
"mutex.h",
"scheduled_executor.h",
"single_thread_executor.h",
],
visibility = [
"//googlemac/iPhone/Nearby/HelloSetup:__subpackages__",
"//platform/impl/ios:__pkg__",
],
deps = [
"//googlemac/iPhone/Shared/Nearby/Connections:Platform",
"//base",
"//platform/api:platform",
"//platform/api:types",
"//platform/base",
"//platform/base:util",
"//platform/impl/shared:posix_mutex",
"//absl/base:core_headers",
"//absl/synchronization",
"//absl/time",
"//thread",
],
)
objc_library(
name = "ios",
srcs = [
"platform.mm",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//core:__subpackages__",
"//platform:__subpackages__",
],
deps = [
":types",
"//platform/api:comm",
"//platform/api:platform",
"//platform/api:types",
"//platform/impl/shared:file",
"//absl/base:core_headers",
"//absl/memory",
"//absl/strings",
"//absl/time",
],
)
+28
View File
@@ -0,0 +1,28 @@
#ifndef PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_
#define PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_
#include <atomic>
#include "platform/api/atomic_boolean.h"
namespace location {
namespace nearby {
namespace ios {
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 ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_ATOMIC_BOOLEAN_H_
+33
View File
@@ -0,0 +1,33 @@
#ifndef PLATFORM_IMPL_IOS_ATOMIC_REFERENCE_H_
#define PLATFORM_IMPL_IOS_ATOMIC_REFERENCE_H_
#include <atomic>
#include <cstdint>
#include "platform/api/atomic_reference.h"
namespace location {
namespace nearby {
namespace ios {
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 ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_ATOMIC_REFERENCE_H_
@@ -0,0 +1,37 @@
#ifndef PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_
#define PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_
#include "platform/api/condition_variable.h"
#include "platform/base/exception.h"
#include "platform/impl/ios/mutex.h"
#include "absl/synchronization/mutex.h"
namespace location {
namespace nearby {
namespace ios {
class ConditionVariable : public api::ConditionVariable {
public:
explicit ConditionVariable(ios::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 ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_CONDITION_VARIABLE_H_
+55
View File
@@ -0,0 +1,55 @@
#ifndef PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_
#define PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_
#include "platform/api/count_down_latch.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
namespace location {
namespace nearby {
namespace ios {
class CountDownLatch final : public api::CountDownLatch {
public:
explicit CountDownLatch(int count) : count_(count) {}
CountDownLatch(const CountDownLatch&) = delete;
CountDownLatch& operator=(const CountDownLatch&) = delete;
CountDownLatch(CountDownLatch&&) = delete;
CountDownLatch& operator=(CountDownLatch&&) = delete;
ExceptionOr<bool> Await(absl::Duration timeout) override {
absl::MutexLock lock(&mutex_);
absl::Time deadline = absl::Now() + timeout;
while (count_ > 0) {
if (cond_.WaitWithDeadline(&mutex_, deadline)) {
return ExceptionOr<bool>(false);
}
}
return ExceptionOr<bool>(true);
}
Exception Await() override {
absl::MutexLock lock(&mutex_);
while (count_ > 0) {
cond_.Wait(&mutex_);
}
return {Exception::kSuccess};
}
void CountDown() override {
absl::MutexLock lock(&mutex_);
if (count_ > 0 && --count_ == 0) {
cond_.SignalAll();
}
}
private:
absl::Mutex mutex_; // Mutex to be used with cond_.Wait...() method family.
absl::CondVar cond_; // Condition to synchronize up to N waiting threads.
int count_
ABSL_GUARDED_BY(mutex_); // When zero, latch should release all waiters.
};
} // namespace ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_COUNT_DOWN_LATCH_H_
+28
View File
@@ -0,0 +1,28 @@
#ifndef PLATFORM_IMPL_IOS_LOG_MESSAGE_H_
#define PLATFORM_IMPL_IOS_LOG_MESSAGE_H_
#include "base/logging.h"
#include "platform/api/log_message.h"
namespace location {
namespace nearby {
namespace ios {
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:
absl::LogStreamer log_streamer_;
};
} // namespace ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_LOG_MESSAGE_H_
+56
View File
@@ -0,0 +1,56 @@
#include "platform/impl/ios/log_message.h"
#include <algorithm>
#include "base/stringprintf.h"
namespace location {
namespace nearby {
namespace ios {
api::LogMessage::Severity kMinLogSeverity = api::LogMessage::Severity::kInfo;
inline absl::LogSeverity ConvertSeverity(api::LogMessage::Severity severity) {
switch (severity) {
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 ios
namespace api {
void LogMessage::SetMinLogSeverity(Severity severity) {
ios::kMinLogSeverity = severity;
}
bool LogMessage::ShouldCreateLogMessage(Severity severity) {
return severity >= ios::kMinLogSeverity;
}
} // namespace api
} // namespace nearby
} // namespace location
@@ -0,0 +1,57 @@
#ifndef PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_
#define PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_
#include <atomic>
#include "platform/api/submittable_executor.h"
#include "platform/impl/ios/count_down_latch.h"
#include "absl/time/clock.h"
#include "thread/threadpool.h"
namespace location {
namespace nearby {
namespace ios {
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(); }
int GetTid(int index) const override {
const auto* thread = thread_pool_.thread(index);
return thread ? *(int*)(thread->tid()) : 0;
}
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 ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_MULTI_THREAD_EXECUTOR_H_
+47
View File
@@ -0,0 +1,47 @@
#ifndef PLATFORM_IMPL_IOS_MUTEX_H_
#define PLATFORM_IMPL_IOS_MUTEX_H_
#include "platform/api/mutex.h"
#include "platform/impl/shared/posix_mutex.h"
#include "absl/synchronization/mutex.h"
namespace location {
namespace nearby {
namespace ios {
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 ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_MUTEX_H_
+124
View File
@@ -0,0 +1,124 @@
#include "platform/api/platform.h"
#include <atomic>
#include <memory>
#include "platform/api/atomic_boolean.h"
#include "platform/api/atomic_reference.h"
#include "platform/api/condition_variable.h"
#include "platform/api/count_down_latch.h"
#include "platform/api/log_message.h"
#include "platform/api/mutex.h"
#include "platform/api/scheduled_executor.h"
#include "platform/api/submittable_executor.h"
#include "platform/impl/ios/atomic_boolean.h"
#include "platform/impl/ios/atomic_reference.h"
#include "platform/impl/ios/condition_variable.h"
#include "platform/impl/ios/count_down_latch.h"
#include "platform/impl/ios/log_message.h"
#include "platform/impl/ios/multi_thread_executor.h"
#include "platform/impl/ios/mutex.h"
#include "platform/impl/ios/scheduled_executor.h"
#include "platform/impl/ios/single_thread_executor.h"
#include "platform/impl/shared/file.h"
#include "absl/memory/memory.h"
namespace location {
namespace nearby {
namespace api {
namespace {
std::string GetPayloadPath(PayloadId payload_id) {
return absl::StrCat("/tmp/", payload_id);
}
} // namespace
std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(bool initial_value) {
return absl::make_unique<ios::AtomicBoolean>(initial_value);
}
std::unique_ptr<AtomicUint32> ImplementationPlatform::CreateAtomicUint32(std::uint32_t value) {
return absl::make_unique<ios::AtomicUint32>(value);
}
std::unique_ptr<CountDownLatch> ImplementationPlatform::CreateCountDownLatch(
std::int32_t count) {
return absl::make_unique<ios::CountDownLatch>(count);
}
std::unique_ptr<Mutex> ImplementationPlatform::CreateMutex(Mutex::Mode mode) {
if (mode == Mutex::Mode::kRecursive)
return absl::make_unique<ios::RecursiveMutex>();
else
return absl::make_unique<ios::Mutex>(mode == Mutex::Mode::kRegular);
}
std::unique_ptr<ConditionVariable> ImplementationPlatform::CreateConditionVariable(Mutex* mutex) {
return std::unique_ptr<ConditionVariable>(
new ios::ConditionVariable(static_cast<ios::Mutex*>(mutex)));
}
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<ios::LogMessage>(file, line, severity);
}
std::unique_ptr<SubmittableExecutor> ImplementationPlatform::CreateSingleThreadExecutor() {
return absl::make_unique<ios::SingleThreadExecutor>();
}
std::unique_ptr<SubmittableExecutor> ImplementationPlatform::CreateMultiThreadExecutor(
int max_concurrency) {
return absl::make_unique<ios::MultiThreadExecutor>(max_concurrency);
}
std::unique_ptr<ScheduledExecutor> ImplementationPlatform::CreateScheduledExecutor() {
return absl::make_unique<ios::ScheduledExecutor>();
}
std::unique_ptr<BluetoothAdapter> ImplementationPlatform::CreateBluetoothAdapter() {
return std::unique_ptr<BluetoothAdapter>();
}
std::unique_ptr<BluetoothClassicMedium> ImplementationPlatform::CreateBluetoothClassicMedium(
api::BluetoothAdapter& adapter) {
return std::unique_ptr<BluetoothClassicMedium>();
}
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(api::BluetoothAdapter& adapter) {
return std::unique_ptr<BleMedium>();
}
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>();
}
std::unique_ptr<WifiMedium> ImplementationPlatform::CreateWifiMedium() {
return std::unique_ptr<WifiMedium>();
}
std::unique_ptr<WifiLanMedium> ImplementationPlatform::CreateWifiLanMedium() {
return std::unique_ptr<WifiLanMedium>();
}
std::unique_ptr<WebRtcMedium> ImplementationPlatform::CreateWebRtcMedium() {
return std::unique_ptr<WebRtcMedium>();
}
} // namespace api
} // namespace nearby
} // namespace location
@@ -0,0 +1,43 @@
#ifndef PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_
#define PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_
#include <atomic>
#include <memory>
#include "platform/api/cancelable.h"
#include "platform/api/scheduled_executor.h"
#include "platform/base/runnable.h"
#include "platform/impl/ios/single_thread_executor.h"
#include "absl/time/clock.h"
#include "thread/threadpool.h"
namespace location {
namespace nearby {
namespace ios {
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(); }
int GetTid(int index) const override {
return executor_.GetTid(index);
}
private:
SingleThreadExecutor executor_;
};
} // namespace ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_SCHEDULED_EXECUTOR_H_
@@ -0,0 +1,65 @@
#include "platform/impl/ios/scheduled_executor.h"
#include <atomic>
#include <memory>
#include "platform/api/cancelable.h"
#include "platform/base/runnable.h"
#include "absl/time/clock.h"
namespace location {
namespace nearby {
namespace ios {
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 ios
} // namespace nearby
} // namespace location
@@ -0,0 +1,20 @@
#ifndef PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_
#define PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_
#include "platform/impl/ios/multi_thread_executor.h"
namespace location {
namespace nearby {
namespace ios {
class SingleThreadExecutor final : public MultiThreadExecutor {
public:
SingleThreadExecutor() : MultiThreadExecutor(1) {}
~SingleThreadExecutor() override = default;
};
} // namespace ios
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_IOS_SINGLE_THREAD_EXECUTOR_H_
-19
View File
@@ -1,19 +0,0 @@
cc_library(
name = "sample_platform",
srcs = [
"atomic_reference_impl.h",
"sample_platform.cc",
"settable_future_impl.h",
],
visibility = ["//visibility:private"],
deps = [
"//platform:types",
"//platform:utils",
"//platform/api",
"//platform/impl/shared:file",
"//platform/impl/shared/sample:sample_wifi_medium",
"//platform/port:string",
"//absl/time",
"//absl/types:any",
],
)
@@ -1,25 +0,0 @@
#ifndef PLATFORM_IMPL_SAMPLE_ATOMIC_REFERENCE_IMPL_H_
#define PLATFORM_IMPL_SAMPLE_ATOMIC_REFERENCE_IMPL_H_
#include "platform/api/atomic_reference_def.h"
#include "absl/types/any.h"
namespace location {
namespace nearby {
namespace platform {
// Provide implementation for absl::any.
class AtomicReferenceImpl : public AtomicReference<absl::any> {
public:
explicit AtomicReferenceImpl(absl::any initial_value) {}
~AtomicReferenceImpl() override = default;
absl::any get() override { return {}; }
void set(absl::any value) override {}
};
} // namespace platform
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_SAMPLE_ATOMIC_REFERENCE_IMPL_H_
-138
View File
@@ -1,138 +0,0 @@
#include <cstdint>
#include "platform/api/atomic_boolean.h"
#include "platform/api/atomic_reference_def.h"
#include "platform/api/ble.h"
#include "platform/api/ble_v2.h"
#include "platform/api/bluetooth_adapter.h"
#include "platform/api/bluetooth_classic.h"
#include "platform/api/condition_variable.h"
#include "platform/api/count_down_latch.h"
#include "platform/api/hash_utils.h"
#include "platform/api/lock.h"
#include "platform/api/platform.h"
#include "platform/api/server_sync.h"
#include "platform/api/settable_future_def.h"
#include "platform/api/submittable_executor_def.h"
#include "platform/api/system_clock.h"
#include "platform/api/thread_utils.h"
#include "platform/api/wifi.h"
#include "platform/cancelable.h"
#include "platform/impl/sample/atomic_reference_impl.h"
#include "platform/impl/sample/settable_future_impl.h"
#include "platform/impl/shared/file_impl.h"
#include "platform/impl/shared/sample/sample_wifi_medium.h"
#include "platform/port/string.h"
#include "platform/ptr.h"
#include "platform/runnable.h"
#include "absl/types/any.h"
namespace location {
namespace nearby {
namespace platform {
namespace {
std::string getPayloadPath(std::int64_t payload_id) {
return "/tmp/sample-" + std::to_string(payload_id);
}
} // namespace
Ptr<ScheduledExecutor> ImplementationPlatform::createScheduledExecutor() {
return Ptr<ScheduledExecutor>{};
}
Ptr<SubmittableExecutor> ImplementationPlatform::createSingleThreadExecutor() {
return Ptr<SubmittableExecutor>{};
}
Ptr<SubmittableExecutor> ImplementationPlatform::createMultiThreadExecutor(
int max_concurrency) {
return Ptr<SubmittableExecutor>{};
}
Ptr<AtomicReference<absl::any>>
ImplementationPlatform::createAtomicReferenceAny(absl::any initial_value) {
return Ptr<AtomicReference<absl::any>>(
new AtomicReferenceImpl(initial_value));
}
Ptr<SettableFuture<absl::any>>
ImplementationPlatform::createSettableFutureAny() {
return Ptr<SettableFuture<absl::any>>(new SettableFutureImpl{});
}
Ptr<BluetoothAdapter> ImplementationPlatform::createBluetoothAdapter() {
return Ptr<BluetoothAdapter>{};
}
Ptr<WifiMedium> ImplementationPlatform::createWifiMedium() {
return Ptr<WifiMedium>();
}
Ptr<CountDownLatch> ImplementationPlatform::createCountDownLatch(
std::int32_t count) {
return Ptr<CountDownLatch>{};
}
Ptr<ThreadUtils> ImplementationPlatform::createThreadUtils() {
return Ptr<ThreadUtils>{};
}
Ptr<SystemClock> ImplementationPlatform::createSystemClock() {
return Ptr<SystemClock>{};
}
Ptr<AtomicBoolean> ImplementationPlatform::createAtomicBoolean(
bool initial_value) {
return Ptr<AtomicBoolean>{};
}
Ptr<InputFile> ImplementationPlatform::createInputFile(
std::int64_t payload_id, std::int64_t total_size) {
return MakePtr(new InputFileImpl(getPayloadPath(payload_id), total_size));
}
Ptr<OutputFile> ImplementationPlatform::createOutputFile(
std::int64_t payload_id) {
return MakePtr(new OutputFileImpl(getPayloadPath(payload_id)));
}
Ptr<BluetoothClassicMedium>
ImplementationPlatform::createBluetoothClassicMedium() {
return Ptr<BluetoothClassicMedium>();
}
Ptr<BLEMedium> ImplementationPlatform::createBLEMedium() {
return Ptr<BLEMedium>();
}
Ptr<BLEMediumV2> ImplementationPlatform::createBLEMediumV2() {
return Ptr<BLEMediumV2>();
}
Ptr<ServerSyncMedium> ImplementationPlatform::createServerSyncMedium() {
return Ptr<ServerSyncMedium>{};
}
Ptr<WebRtcSignalingMessenger>
ImplementationPlatform::createWebRtcSignalingMessenger(
const std::string& self_id) {
return Ptr<WebRtcSignalingMessenger>{};
}
Ptr<Lock> ImplementationPlatform::createLock() { return Ptr<Lock>{}; }
Ptr<ConditionVariable> ImplementationPlatform::createConditionVariable(
Ptr<Lock> lock) {
return Ptr<ConditionVariable>{};
}
Ptr<HashUtils> ImplementationPlatform::createHashUtils() {
return Ptr<HashUtils>{};
}
std::string ImplementationPlatform::getDeviceId() { return "sample"; }
} // namespace platform
} // namespace nearby
} // namespace location
@@ -1,35 +0,0 @@
#ifndef PLATFORM_IMPL_SAMPLE_SETTABLE_FUTURE_IMPL_H_
#define PLATFORM_IMPL_SAMPLE_SETTABLE_FUTURE_IMPL_H_
#include "platform/api/settable_future_def.h"
#include "absl/types/any.h"
namespace location {
namespace nearby {
namespace platform {
class SettableFutureImpl : public SettableFuture<absl::any> {
public:
explicit SettableFutureImpl() = default;
~SettableFutureImpl() override = default;
bool set(absl::any value) override { return true; }
bool setException(Exception exception) override { return true; }
void addListener(Ptr<Runnable> runnable, Executor* executor) override {}
ExceptionOr<std::any> get() override {
return ExceptionOr<std::any>{Exception{Exception::kFailed}};
}
ExceptionOr<std::any> get(std::int64_t timeout_ms) override {
return ExceptionOr<std::any>{Exception{Exception::kFailed}};
}
};
} // namespace platform
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_SAMPLE_SETTABLE_FUTURE_IMPL_H_
+13 -29
View File
@@ -1,18 +1,16 @@
cc_library(
name = "posix_lock",
name = "posix_mutex",
srcs = [
"posix_lock.cc",
"posix_mutex.cc",
],
hdrs = [
"posix_lock.h",
"posix_mutex.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//platform/impl:__subpackages__",
],
deps = [
"//platform/api",
],
deps = ["//platform/api:types"],
)
cc_library(
@@ -25,49 +23,35 @@ cc_library(
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//platform/impl:__subpackages__",
],
deps = [
":posix_lock",
"//platform:types",
"//platform/api:condition_variable",
":posix_mutex",
"//platform/api:types",
],
)
cc_library(
name = "atomic_boolean",
hdrs = ["atomic_boolean_impl.h"],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//platform/impl:__subpackages__",
],
deps = ["//platform/api"],
)
cc_library(
name = "file",
srcs = ["file_impl.cc"],
hdrs = ["file_impl.h"],
srcs = ["file.cc"],
hdrs = ["file.h"],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//core:__subpackages__",
"//platform/impl:__subpackages__",
],
deps = [
"//platform:types",
"//platform/api",
"//platform/api:types",
"//platform/base",
"//absl/strings",
],
)
cc_test(
name = "file_test",
timeout = "short",
srcs = [
"file_impl_test.cc",
],
srcs = ["file_test.cc"],
deps = [
":file",
"//file/util:temp_path",
"//platform/base",
"//testing/base/public:gunit_main",
"//absl/strings",
],
+71
View File
@@ -0,0 +1,71 @@
cc_library(
name = "posix_lock",
srcs = [
"posix_lock.cc",
],
hdrs = [
"posix_lock.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//platform/impl:__subpackages__",
],
deps = [
"//platform/api",
],
)
cc_library(
name = "posix_condition_variable",
srcs = [
"posix_condition_variable.cc",
],
hdrs = [
"posix_condition_variable.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//platform/impl:__subpackages__",
],
deps = [
":posix_lock",
"//platform:types",
"//platform/api:condition_variable",
],
)
cc_library(
name = "atomic_boolean",
hdrs = ["atomic_boolean_impl.h"],
visibility = ["//platform/impl:__subpackages__"],
deps = ["//platform/api"],
)
cc_library(
name = "file",
srcs = ["file_impl.cc"],
hdrs = ["file_impl.h"],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//core:__subpackages__",
"//platform/impl:__subpackages__",
],
deps = [
"//platform:types",
"//platform/api",
],
)
cc_test(
name = "file_test",
timeout = "short",
srcs = [
"file_impl_test.cc",
],
deps = [
":file",
"//file/util:temp_path",
"//testing/base/public:gunit_main",
"//absl/strings",
],
)
@@ -1,33 +0,0 @@
#ifndef PLATFORM_IMPL_SHARED_ATOMIC_BOOLEAN_IMPL_H_
#define PLATFORM_IMPL_SHARED_ATOMIC_BOOLEAN_IMPL_H_
#include <atomic>
#include "platform/api/atomic_boolean.h"
namespace location {
namespace nearby {
class AtomicBooleanImpl : public AtomicBoolean {
public:
explicit AtomicBooleanImpl(bool initial_value) : value_(initial_value) {}
~AtomicBooleanImpl() override = default;
// AtomicBoolean:
bool get() override {
return value_.load();
}
// AtomicBoolean:
void set(bool value) override {
value_.store(value);
}
private:
std::atomic_bool value_;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_SHARED_ATOMIC_BOOLEAN_IMPL_H_
+81
View File
@@ -0,0 +1,81 @@
#include "platform/impl/shared/file.h"
#include <cstddef>
#include <memory>
#include "platform/base/exception.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace shared {
// InputFile
InputFile::InputFile(const std::string& path, std::int64_t size)
: file_(path), path_(path), total_size_(size) {}
ExceptionOr<ByteArray> InputFile::Read(std::int64_t size) {
if (!file_.is_open()) {
return ExceptionOr<ByteArray>{Exception::kIo};
}
if (file_.peek() == EOF) {
return ExceptionOr<ByteArray>{ByteArray{}};
}
if (!file_.good()) {
return ExceptionOr<ByteArray>{Exception::kIo};
}
ByteArray bytes(size);
std::unique_ptr<char[]> read_bytes{new char[size]};
file_.read(read_bytes.get(), static_cast<ptrdiff_t>(size));
auto num_bytes_read = file_.gcount();
if (num_bytes_read == 0) {
return ExceptionOr<ByteArray>{Exception::kIo};
}
return ExceptionOr<ByteArray>(ByteArray(read_bytes.get(), num_bytes_read));
}
Exception InputFile::Close() {
if (file_.is_open()) {
file_.close();
}
return {Exception::kSuccess};
}
// OutputFile
OutputFile::OutputFile(absl::string_view path) : file_(std::string(path)) {}
Exception OutputFile::Write(const ByteArray& data) {
if (!file_.is_open()) {
return {Exception::kIo};
}
if (!file_.good()) {
return {Exception::kIo};
}
file_.write(data.data(), data.size());
file_.flush();
return {file_.good() ? Exception::kSuccess : Exception::kIo};
}
Exception OutputFile::Flush() {
file_.flush();
return {file_.good() ? Exception::kSuccess : Exception::kIo};
}
Exception OutputFile::Close() {
if (file_.is_open()) {
file_.close();
}
return {Exception::kSuccess};
}
} // namespace shared
} // namespace nearby
} // namespace location
+53
View File
@@ -0,0 +1,53 @@
#ifndef PLATFORM_IMPL_SHARED_FILE_H_
#define PLATFORM_IMPL_SHARED_FILE_H_
#include <cstdint>
#include <fstream>
#include "platform/api/input_file.h"
#include "platform/api/output_file.h"
#include "platform/base/exception.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace shared {
class InputFile final : public api::InputFile {
public:
explicit InputFile(const std::string& path, std::int64_t size);
~InputFile() override = default;
InputFile(InputFile&&) = default;
InputFile& operator=(InputFile&&) = default;
ExceptionOr<ByteArray> Read(std::int64_t size) override;
std::string GetFilePath() const override { return path_; }
std::int64_t GetTotalSize() const override { return total_size_; }
Exception Close() override;
private:
std::ifstream file_;
std::string path_;
std::int64_t total_size_;
};
class OutputFile final : public api::OutputFile {
public:
explicit OutputFile(absl::string_view path);
~OutputFile() override = default;
OutputFile(OutputFile&&) = default;
OutputFile& operator=(OutputFile&&) = default;
Exception Write(const ByteArray& data) override;
Exception Flush() override;
Exception Close() override;
private:
std::ofstream file_;
};
} // namespace shared
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_SHARED_FILE_H_
-75
View File
@@ -1,75 +0,0 @@
#include "platform/impl/shared/file_impl.h"
#include <cstddef>
#include <memory>
namespace location {
namespace nearby {
// InputFile
InputFileImpl::InputFileImpl(const std::string& path, std::int64_t size)
: file_(path), path_(path), total_size_(size) {}
ExceptionOr<ConstPtr<ByteArray>> InputFileImpl::read(int64_t size) {
if (!file_.is_open()) {
return ExceptionOr<ConstPtr<ByteArray>>(Exception::IO);
}
if (file_.peek() == EOF) {
return ExceptionOr<ConstPtr<ByteArray>>(ConstPtr<ByteArray>());
}
if (!file_.good()) {
return ExceptionOr<ConstPtr<ByteArray>>(Exception::IO);
}
std::unique_ptr<char[]> read_bytes {new char [size]};
file_.read(read_bytes.get(), static_cast<ptrdiff_t>(size));
auto num_bytes_read = file_.gcount();
if (num_bytes_read == 0) {
return ExceptionOr<ConstPtr<ByteArray>>(Exception::IO);
}
return ExceptionOr<ConstPtr<ByteArray>>(
MakeConstPtr(new ByteArray(read_bytes.get(), num_bytes_read)));
}
std::string InputFileImpl::getFilePath() const { return path_; }
std::int64_t InputFileImpl::getTotalSize() const { return total_size_; }
void InputFileImpl::close() {
if (file_.is_open()) {
file_.close();
}
}
// OutputFile
OutputFileImpl::OutputFileImpl(const std::string& path) : file_(path) {}
Exception::Value OutputFileImpl::write(ConstPtr<ByteArray> data) {
ScopedPtr<ConstPtr<ByteArray>> scoped_data(data);
if (!file_.is_open()) {
return Exception::IO;
}
if (!file_.good()) {
return Exception::IO;
}
file_.write(data->getData(), data->size());
file_.flush();
return file_.good() ? Exception::NONE : Exception::IO;
}
void OutputFileImpl::close() {
if (file_.is_open()) {
file_.close();
}
}
} // namespace nearby
} // namespace location
-46
View File
@@ -1,46 +0,0 @@
#ifndef PLATFORM_IMPL_SHARED_FILE_IMPL_H_
#define PLATFORM_IMPL_SHARED_FILE_IMPL_H_
#include <cstdint>
#include <fstream>
#include "platform/api/input_file.h"
#include "platform/api/output_file.h"
#include "platform/exception.h"
#include "platform/ptr.h"
namespace location {
namespace nearby {
class InputFileImpl final : public InputFile {
public:
InputFileImpl(const std::string& path, std::int64_t size);
~InputFileImpl() override {}
ExceptionOr<ConstPtr<ByteArray>> read(std::int64_t size) override;
std::string getFilePath() const override;
std::int64_t getTotalSize() const override;
void close() override;
private:
std::ifstream file_;
const std::string path_;
const std::int64_t total_size_;
};
class OutputFileImpl final : public OutputFile {
public:
explicit OutputFileImpl(const std::string& path);
~OutputFileImpl() override {}
Exception::Value write(ConstPtr<ByteArray> data) override;
void close() override;
private:
std::ofstream file_;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_SHARED_FILE_IMPL_H_
-134
View File
@@ -1,134 +0,0 @@
#include "platform/impl/shared/file_impl.h"
#include <cstring>
#include <fstream>
#include <memory>
#include <ostream>
#include "file/util/temp_path.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
class FileImplTest : public ::testing::Test {
protected:
void SetUp() override {
temp_path_ = std::make_unique<TempPath>(TempPath::Local);
path_ = temp_path_->path() + "/file.txt";
std::ofstream output_file(path_);
file_ = std::fstream(path_, std::fstream::in | std::fstream::out);
}
void WriteToFile(absl::string_view text) {
file_ << text;
file_.flush();
size_ += text.size();
}
size_t GetSize() const { return size_; }
void AssertEquals(const ExceptionOr<ConstPtr<ByteArray>>& bytes,
const std::string& expected) {
ASSERT_TRUE(bytes.ok());
ScopedPtr<ConstPtr<ByteArray>> byte_array(bytes.result());
ASSERT_STREQ(byte_array->getData(), expected.c_str());
ASSERT_EQ(byte_array->size(), expected.length());
}
void AssertNull(const ExceptionOr<ConstPtr<ByteArray>>& bytes) {
ASSERT_TRUE(bytes.ok());
ASSERT_TRUE(bytes.result().isNull());
}
static constexpr int64_t kMaxSize = 3;
std::unique_ptr<TempPath> temp_path_;
std::string path_;
std::fstream file_;
size_t size_ = 0;
};
TEST_F(FileImplTest, InputFile_NonExistentPath) {
InputFileImpl input_file("/not/a/valid/path.txt", GetSize());
ExceptionOr<ConstPtr<ByteArray>> read_result = input_file.read(kMaxSize);
ASSERT_FALSE(read_result.ok());
ASSERT_EQ(read_result.exception(), Exception::IO);
}
TEST_F(FileImplTest, InputFile_GetFilePath) {
InputFileImpl input_file(path_, GetSize());
ASSERT_EQ(input_file.getFilePath(), path_);
}
TEST_F(FileImplTest, InputFile_EmptyFileEOF) {
InputFileImpl input_file(path_, GetSize());
AssertNull(input_file.read(kMaxSize));
}
TEST_F(FileImplTest, InputFile_ReadWorks) {
WriteToFile("abc");
InputFileImpl input_file(path_, GetSize());
auto read_data = input_file.read(kMaxSize);
read_data.result().destroy();
SUCCEED();
}
TEST_F(FileImplTest, InputFile_ReadUntilEOF) {
WriteToFile("abc");
InputFileImpl input_file(path_, GetSize());
AssertEquals(input_file.read(kMaxSize), "abc");
AssertNull(input_file.read(kMaxSize));
}
TEST_F(FileImplTest, InputFile_ReadWithSize) {
WriteToFile("abc");
InputFileImpl input_file(path_, GetSize());
AssertEquals(input_file.read(2), "ab");
AssertEquals(input_file.read(1), "c");
AssertNull(input_file.read(kMaxSize));
}
TEST_F(FileImplTest, InputFile_GetTotalSize) {
WriteToFile("abc");
InputFileImpl input_file(path_, GetSize());
EXPECT_EQ(input_file.getTotalSize(), 3);
AssertEquals(input_file.read(1), "a");
EXPECT_EQ(input_file.getTotalSize(), 3);
}
TEST_F(FileImplTest, InputFile_Close) {
WriteToFile("abc");
InputFileImpl input_file(path_, GetSize());
input_file.close();
ExceptionOr<ConstPtr<ByteArray>> read_result = input_file.read(kMaxSize);
ASSERT_FALSE(read_result.ok());
ASSERT_EQ(read_result.exception(), Exception::IO);
}
TEST_F(FileImplTest, OutputFile_NonExistentPath) {
OutputFileImpl output_file("/not/a/valid/path.txt");
ConstPtr<ByteArray> bytes = MakeConstPtr(new ByteArray("a", 1));
Exception::Value write_result = output_file.write(bytes);
ASSERT_EQ(write_result, Exception::IO);
}
TEST_F(FileImplTest, OutputFile_Write) {
OutputFileImpl output_file(path_);
ConstPtr<ByteArray> bytes1 = MakeConstPtr(new ByteArray("a", 1));
ConstPtr<ByteArray> bytes2 = MakeConstPtr(new ByteArray("bc", 2));
ASSERT_EQ(output_file.write(bytes1), Exception::NONE);
ASSERT_EQ(output_file.write(bytes2), Exception::NONE);
InputFileImpl input_file(path_, GetSize());
AssertEquals(input_file.read(kMaxSize), "abc");
}
TEST_F(FileImplTest, OutputFile_Close) {
OutputFileImpl output_file(path_);
output_file.close();
ConstPtr<ByteArray> bytes = MakeConstPtr(new ByteArray("a", 1));
ASSERT_EQ(output_file.write(bytes), Exception::IO);
}
} // namespace nearby
} // namespace location
+134
View File
@@ -0,0 +1,134 @@
#include "platform/impl/shared/file.h"
#include <cstring>
#include <fstream>
#include <memory>
#include <ostream>
#include "file/util/temp_path.h"
#include "platform/base/byte_array.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace shared {
class FileTest : public ::testing::Test {
protected:
void SetUp() override {
temp_path_ = std::make_unique<TempPath>(TempPath::Local);
path_ = temp_path_->path() + "/file.txt";
std::ofstream output_file(path_);
file_ = std::fstream(path_, std::fstream::in | std::fstream::out);
}
void WriteToFile(absl::string_view text) {
file_ << text;
file_.flush();
size_ += text.size();
}
size_t GetSize() const { return size_; }
void AssertEquals(const ExceptionOr<ByteArray>& bytes,
const std::string& expected) {
EXPECT_TRUE(bytes.ok());
EXPECT_EQ(std::string(bytes.result()), expected);
}
void AssertEmpty(const ExceptionOr<ByteArray>& bytes) {
EXPECT_TRUE(bytes.ok());
EXPECT_TRUE(bytes.result().Empty());
}
static constexpr int64_t kMaxSize = 3;
std::unique_ptr<TempPath> temp_path_;
std::string path_;
std::fstream file_;
size_t size_ = 0;
};
TEST_F(FileTest, InputFile_NonExistentPath) {
InputFile input_file("/not/a/valid/path.txt", GetSize());
ExceptionOr<ByteArray> read_result = input_file.Read(kMaxSize);
EXPECT_FALSE(read_result.ok());
EXPECT_TRUE(read_result.GetException().Raised(Exception::kIo));
}
TEST_F(FileTest, InputFile_GetFilePath) {
InputFile input_file(path_, GetSize());
EXPECT_EQ(input_file.GetFilePath(), path_);
}
TEST_F(FileTest, InputFile_EmptyFileEOF) {
InputFile input_file(path_, GetSize());
AssertEmpty(input_file.Read(kMaxSize));
}
TEST_F(FileTest, InputFile_ReadWorks) {
WriteToFile("abc");
InputFile input_file(path_, GetSize());
input_file.Read(kMaxSize);
SUCCEED();
}
TEST_F(FileTest, InputFile_ReadUntilEOF) {
WriteToFile("abc");
InputFile input_file(path_, GetSize());
AssertEquals(input_file.Read(kMaxSize), "abc");
AssertEmpty(input_file.Read(kMaxSize));
}
TEST_F(FileTest, InputFile_ReadWithSize) {
WriteToFile("abc");
InputFile input_file(path_, GetSize());
AssertEquals(input_file.Read(2), "ab");
AssertEquals(input_file.Read(1), "c");
AssertEmpty(input_file.Read(kMaxSize));
}
TEST_F(FileTest, InputFile_GetTotalSize) {
WriteToFile("abc");
InputFile input_file(path_, GetSize());
EXPECT_EQ(input_file.GetTotalSize(), 3);
AssertEquals(input_file.Read(1), "a");
EXPECT_EQ(input_file.GetTotalSize(), 3);
}
TEST_F(FileTest, InputFile_Close) {
WriteToFile("abc");
InputFile input_file(path_, GetSize());
input_file.Close();
ExceptionOr<ByteArray> read_result = input_file.Read(kMaxSize);
EXPECT_FALSE(read_result.ok());
EXPECT_TRUE(read_result.GetException().Raised(Exception::kIo));
}
TEST_F(FileTest, OutputFile_NonExistentPath) {
OutputFile output_file("/not/a/valid/path.txt");
ByteArray bytes("a", 1);
EXPECT_TRUE(output_file.Write(bytes).Raised(Exception::kIo));
}
TEST_F(FileTest, OutputFile_Write) {
OutputFile output_file(path_);
ByteArray bytes1("a");
ByteArray bytes2("bc");
EXPECT_EQ(output_file.Write(bytes1), Exception{Exception::kSuccess});
EXPECT_EQ(output_file.Write(bytes2), Exception{Exception::kSuccess});
InputFile input_file(path_, GetSize());
AssertEquals(input_file.Read(kMaxSize), "abc");
}
TEST_F(FileTest, OutputFile_Close) {
OutputFile output_file(path_);
output_file.Close();
ByteArray bytes("a");
EXPECT_EQ(output_file.Write(bytes), Exception{Exception::kIo});
}
} // namespace shared
} // namespace nearby
} // namespace location
@@ -2,27 +2,29 @@
namespace location {
namespace nearby {
namespace posix {
PosixConditionVariable::PosixConditionVariable(Ptr<PosixLock> lock)
: lock_(lock), attr_(), cond_() {
ConditionVariable::ConditionVariable(Mutex* mutex)
: mutex_(mutex), attr_(), cond_() {
pthread_condattr_init(&attr_);
pthread_cond_init(&cond_, &attr_);
}
PosixConditionVariable::~PosixConditionVariable() {
ConditionVariable::~ConditionVariable() {
pthread_cond_destroy(&cond_);
pthread_condattr_destroy(&attr_);
}
void PosixConditionVariable::notify() { pthread_cond_broadcast(&cond_); }
void ConditionVariable::Notify() { pthread_cond_broadcast(&cond_); }
Exception::Value PosixConditionVariable::wait() {
pthread_cond_wait(&cond_, &(lock_->mutex_));
Exception ConditionVariable::Wait() {
pthread_cond_wait(&cond_, &(mutex_->mutex_));
return Exception::kSuccess;
return {Exception::kSuccess};
}
} // namespace posix
} // namespace nearby
} // namespace location
@@ -4,26 +4,27 @@
#include <pthread.h>
#include "platform/api/condition_variable.h"
#include "platform/impl/shared/posix_lock.h"
#include "platform/ptr.h"
#include "platform/impl/shared/posix_mutex.h"
namespace location {
namespace nearby {
namespace posix {
class PosixConditionVariable : public ConditionVariable {
class ConditionVariable : public api::ConditionVariable {
public:
explicit PosixConditionVariable(Ptr<PosixLock> lock);
~PosixConditionVariable() override;
explicit ConditionVariable(Mutex* mutex);
~ConditionVariable() override;
void notify() override;
Exception::Value wait() override;
void Notify() override;
Exception Wait() override;
private:
Ptr<PosixLock> lock_;
Mutex* mutex_;
pthread_condattr_t attr_;
pthread_cond_t cond_;
};
} // namespace posix
} // namespace nearby
} // namespace location
-29
View File
@@ -1,29 +0,0 @@
#ifndef PLATFORM_IMPL_SHARED_POSIX_LOCK_H_
#define PLATFORM_IMPL_SHARED_POSIX_LOCK_H_
#include <pthread.h>
#include "platform/api/lock.h"
namespace location {
namespace nearby {
class PosixLock : public Lock {
public:
PosixLock();
~PosixLock() override;
void lock() override;
void unlock() override;
private:
friend class PosixConditionVariable;
pthread_mutexattr_t attr_;
pthread_mutex_t mutex_;
};
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_SHARED_POSIX_LOCK_H_
@@ -1,24 +1,26 @@
#include "platform/impl/shared/posix_lock.h"
#include "platform/impl/shared/posix_mutex.h"
namespace location {
namespace nearby {
namespace posix {
PosixLock::PosixLock() : attr_(), mutex_() {
Mutex::Mutex() : attr_(), mutex_() {
pthread_mutexattr_init(&attr_);
pthread_mutexattr_settype(&attr_, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex_, &attr_);
}
PosixLock::~PosixLock() {
Mutex::~Mutex() {
pthread_mutex_destroy(&mutex_);
pthread_mutexattr_destroy(&attr_);
}
void PosixLock::lock() { pthread_mutex_lock(&mutex_); }
void Mutex::Lock() { pthread_mutex_lock(&mutex_); }
void PosixLock::unlock() { pthread_mutex_unlock(&mutex_); }
void Mutex::Unlock() { pthread_mutex_unlock(&mutex_); }
} // namespace posix
} // namespace nearby
} // namespace location
+31
View File
@@ -0,0 +1,31 @@
#ifndef PLATFORM_IMPL_SHARED_POSIX_MUTEX_H_
#define PLATFORM_IMPL_SHARED_POSIX_MUTEX_H_
#include <pthread.h>
#include "platform/api/mutex.h"
namespace location {
namespace nearby {
namespace posix {
class ABSL_LOCKABLE Mutex : public api::Mutex {
public:
Mutex();
~Mutex() override;
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() override;
void Unlock() ABSL_UNLOCK_FUNCTION() override;
private:
friend class ConditionVariable;
pthread_mutexattr_t attr_;
pthread_mutex_t mutex_;
};
} // namespace posix
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_SHARED_POSIX_MUTEX_H_
-21
View File
@@ -1,21 +0,0 @@
cc_library(
name = "sample_wifi_medium",
srcs = [
"sample_wifi_medium.cc",
],
hdrs = [
"sample_wifi_medium.h",
],
visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
"//core:__subpackages__",
"//platform/impl:__subpackages__",
],
deps = [
"//platform:types",
"//platform:utils",
"//platform/api",
"//platform/port:string",
"//absl/time",
],
)
@@ -1,110 +0,0 @@
#include "platform/impl/shared/sample/sample_wifi_medium.h"
#include <cstdint>
#include "platform/prng.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
namespace location {
namespace nearby {
namespace sample {
namespace {
const char* kOpenSSID = "__OPEN__";
const char* kWpaPskSSID = "__WPA_PSK__";
const char* kWepSSID = "__WEP__";
const char* kNoInternetConnectivitySSID = "__NO_INTERNET_CONNECTIVITY__";
const char* kConnectionFailureSSID = "__CONNECTION_FAILURE__";
const char* kAuthFailureSSID = "__AUTH_FAILURE__";
std::uint32_t boundedUInt32(std::uint32_t upper_limit) {
return Prng().nextUInt32() % (upper_limit + 1);
}
void randomSleep(std::uint32_t upper_limit_millis) {
absl::SleepFor(absl::Milliseconds(boundedUInt32(upper_limit_millis)));
}
} // namespace
std::vector<SampleWifiScanResult> SampleWifiMedium::canned_scan_results_;
SampleWifiMedium::SampleWifiMedium() : current_ssid_() {
// One-time initialization of our static canned_scan_results_.
if (canned_scan_results_.empty()) {
canned_scan_results_.push_back(
SampleWifiScanResult(kOpenSSID, 1, 2401, WifiAuthType::OPEN));
canned_scan_results_.push_back(
SampleWifiScanResult(kWpaPskSSID, 2, 5002, WifiAuthType::WPA_PSK));
canned_scan_results_.push_back(
SampleWifiScanResult(kWepSSID, 3, 2403, WifiAuthType::WEP));
canned_scan_results_.push_back(SampleWifiScanResult(
kNoInternetConnectivitySSID, 4, 5004, WifiAuthType::OPEN));
canned_scan_results_.push_back(SampleWifiScanResult(
kConnectionFailureSSID, 5, 2405, WifiAuthType::OPEN));
canned_scan_results_.push_back(
SampleWifiScanResult(kAuthFailureSSID, 6, 5006, WifiAuthType::OPEN));
}
}
SampleWifiMedium::~SampleWifiMedium() {}
bool SampleWifiMedium::scan(
Ptr<WifiMedium::ScanResultCallback> scan_result_callback) {
// Sleep for up to 10 seconds, to simulate performing an actual Wifi scan.
randomSleep(10 * 1000);
// Construct the response.
std::vector<ConstPtr<WifiScanResult> > scan_results;
for (std::vector<SampleWifiScanResult>::const_iterator it =
canned_scan_results_.begin();
it != canned_scan_results_.end(); it++) {
scan_results.push_back(ConstPtr<WifiScanResult>(
new SampleWifiScanResult(it->getSSID(), it->getSignalStrengthDbm(),
it->getFrequencyMhz(), it->getAuthType())));
}
// And report it back.
scan_result_callback->onScanResults(scan_results);
return false;
}
WifiConnectionStatus::Value SampleWifiMedium::connectToNetwork(
const std::string& ssid, const std::string& password,
WifiAuthType::Value auth_type) {
// Sleep for up to 10 seconds, to simulate actually connecting to the SSID.
randomSleep(10 * 1000);
if (kConnectionFailureSSID == ssid) {
return WifiConnectionStatus::CONNECTION_FAILURE;
}
if (kAuthFailureSSID == ssid) {
return WifiConnectionStatus::AUTH_FAILURE;
}
return WifiConnectionStatus::CONNECTED;
}
bool SampleWifiMedium::verifyInternetConnectivity() {
if (current_ssid_.empty()) {
return false;
}
// Sleep for up to 5 seconds, to simulate actually verifying internet
// connectivity.
randomSleep(5 * 1000);
return current_ssid_ != kNoInternetConnectivitySSID;
}
std::string SampleWifiMedium::getIPAddress() {
return current_ssid_.empty() ? "" : "1.2.3.4";
}
} // namespace sample
} // namespace nearby
} // namespace location
@@ -1,59 +0,0 @@
#ifndef PLATFORM_IMPL_SHARED_SAMPLE_SAMPLE_WIFI_MEDIUM_H_
#define PLATFORM_IMPL_SHARED_SAMPLE_SAMPLE_WIFI_MEDIUM_H_
#include "platform/api/wifi.h"
namespace location {
namespace nearby {
namespace sample {
class SampleWifiScanResult : public WifiScanResult {
public:
SampleWifiScanResult(const std::string& ssid,
std::int32_t signal_strength_dbm,
std::int32_t frequency_mhz,
WifiAuthType::Value auth_type)
: ssid_(ssid),
signal_strength_dbm_(signal_strength_dbm),
frequency_mhz_(frequency_mhz),
auth_type_(auth_type) {}
~SampleWifiScanResult() override {}
std::string getSSID() const override { return ssid_; }
std::int32_t getSignalStrengthDbm() const override {
return signal_strength_dbm_;
}
std::int32_t getFrequencyMhz() const override { return frequency_mhz_; }
WifiAuthType::Value getAuthType() const override { return auth_type_; }
private:
const std::string ssid_;
const std::int32_t signal_strength_dbm_;
const std::int32_t frequency_mhz_;
const WifiAuthType::Value auth_type_;
};
class SampleWifiMedium : public WifiMedium {
public:
SampleWifiMedium();
~SampleWifiMedium() override;
bool scan(Ptr<ScanResultCallback> scan_result_callback) override;
WifiConnectionStatus::Value connectToNetwork(
const std::string& ssid, const std::string& password,
WifiAuthType::Value auth_type) override;
bool verifyInternetConnectivity() override;
std::string getIPAddress() override;
private:
static std::vector<SampleWifiScanResult> canned_scan_results_;
// The SSID this Wifi stack is currently connected to; empty string if none.
std::string current_ssid_;
};
} // namespace sample
} // namespace nearby
} // namespace location
#endif // PLATFORM_IMPL_SHARED_SAMPLE_SAMPLE_WIFI_MEDIUM_H_