mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Merge branch 'master' into release
Change-Id: I1301beacba87281b5818eb5e3f54525919158918
This commit is contained in:
+2
-3
@@ -20,9 +20,7 @@ cc_library(
|
||||
hdrs = [
|
||||
"core.h",
|
||||
],
|
||||
visibility = [
|
||||
"//core_v2:__subpackages__",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":core_types",
|
||||
"//core_v2/internal",
|
||||
@@ -56,6 +54,7 @@ cc_library(
|
||||
"//platform_v2/public:comm",
|
||||
"//platform_v2/public:logging",
|
||||
"//platform_v2/public:types",
|
||||
"//proto:connections_enums_portable_proto",
|
||||
"//absl/strings",
|
||||
"//absl/types:variant",
|
||||
],
|
||||
|
||||
+2
-1
@@ -68,10 +68,11 @@ void Core::StopDiscovery(ResultCallback callback) {
|
||||
|
||||
void Core::RequestConnection(absl::string_view endpoint_id,
|
||||
ConnectionRequestInfo info,
|
||||
ConnectionOptions options,
|
||||
ResultCallback callback) {
|
||||
assert(!endpoint_id.empty());
|
||||
|
||||
router_.RequestConnection(&client_, endpoint_id, info, callback);
|
||||
router_.RequestConnection(&client_, endpoint_id, info, options, callback);
|
||||
}
|
||||
|
||||
void Core::AcceptConnection(absl::string_view endpoint_id,
|
||||
|
||||
+2
-1
@@ -118,7 +118,8 @@ class Core {
|
||||
// issue with Bluetooth/WiFi.
|
||||
// Status::STATUS_ERROR if we failed to connect for any other reason.
|
||||
void RequestConnection(absl::string_view endpoint_id,
|
||||
ConnectionRequestInfo info, ResultCallback callback);
|
||||
ConnectionRequestInfo info, ConnectionOptions options,
|
||||
ResultCallback callback);
|
||||
|
||||
// Accepts a connection to a remote endpoint. This method must be called
|
||||
// before Payloads can be exchanged with the remote endpoint.
|
||||
|
||||
@@ -18,6 +18,7 @@ cc_library(
|
||||
"base_endpoint_channel.cc",
|
||||
"base_pcp_handler.cc",
|
||||
"ble_advertisement.cc",
|
||||
"ble_endpoint_channel.cc",
|
||||
"bluetooth_device_name.cc",
|
||||
"bluetooth_endpoint_channel.cc",
|
||||
"client_proxy.cc",
|
||||
@@ -42,6 +43,7 @@ cc_library(
|
||||
"base_endpoint_channel.h",
|
||||
"base_pcp_handler.h",
|
||||
"ble_advertisement.h",
|
||||
"ble_endpoint_channel.h",
|
||||
"bluetooth_device_name.h",
|
||||
"bluetooth_endpoint_channel.h",
|
||||
"client_proxy.h",
|
||||
@@ -83,8 +85,10 @@ cc_library(
|
||||
"//proto:connections_enums_portable_proto",
|
||||
"//securegcm:ukey2",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/container:btree",
|
||||
"//absl/container:flat_hash_map",
|
||||
"//absl/container:flat_hash_set",
|
||||
"//absl/functional:bind_front",
|
||||
"//absl/memory",
|
||||
"//absl/strings",
|
||||
"//absl/time",
|
||||
@@ -110,6 +114,7 @@ cc_library(
|
||||
deps = [
|
||||
":internal",
|
||||
"//core_v2:core_types",
|
||||
"//platform_v2/base",
|
||||
"//platform_v2/base:test_util",
|
||||
"//platform_v2/public:types",
|
||||
"//testing/base/public:gunit",
|
||||
@@ -121,6 +126,7 @@ cc_library(
|
||||
cc_test(
|
||||
name = "core_v2_internal_test",
|
||||
size = "small",
|
||||
timeout = "moderate",
|
||||
srcs = [
|
||||
"base_endpoint_channel_test.cc",
|
||||
"base_pcp_handler_test.cc",
|
||||
|
||||
@@ -122,8 +122,7 @@ ExceptionOr<ByteArray> BaseEndpointChannel::Read() {
|
||||
// If encryption is enabled, decode the message.
|
||||
std::string input(std::move(result));
|
||||
std::unique_ptr<std::string> decrypted_data =
|
||||
crypto_context_->DecodeMessageFromPeer(
|
||||
std::string(std::move(result)));
|
||||
crypto_context_->DecodeMessageFromPeer(input);
|
||||
if (decrypted_data) {
|
||||
result = ByteArray(std::move(*decrypted_data));
|
||||
} else {
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
|
||||
#include "core_v2/internal/offline_frames.h"
|
||||
#include "core_v2/internal/pcp_handler.h"
|
||||
#include "core_v2/options.h"
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "platform_v2/public/system_clock.h"
|
||||
#include "securegcm/d2d_connection_context_v1.h"
|
||||
#include "securegcm/ukey2_handshake.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
namespace location {
|
||||
@@ -39,9 +41,11 @@ using ::securegcm::UKey2Handshake;
|
||||
constexpr absl::Duration BasePcpHandler::kConnectionRequestReadTimeout;
|
||||
constexpr absl::Duration BasePcpHandler::kRejectedConnectionCloseDelay;
|
||||
|
||||
BasePcpHandler::BasePcpHandler(EndpointManager* endpoint_manager,
|
||||
BasePcpHandler::BasePcpHandler(Mediums* mediums,
|
||||
EndpointManager* endpoint_manager,
|
||||
EndpointChannelManager* channel_manager, Pcp pcp)
|
||||
: endpoint_manager_(endpoint_manager),
|
||||
: mediums_(mediums),
|
||||
endpoint_manager_(endpoint_manager),
|
||||
channel_manager_(channel_manager),
|
||||
pcp_(pcp) {}
|
||||
|
||||
@@ -72,25 +76,27 @@ Status BasePcpHandler::StartAdvertising(ClientProxy* client,
|
||||
const ConnectionOptions& options,
|
||||
const ConnectionRequestInfo& info) {
|
||||
Future<Status> response;
|
||||
ConnectionOptions advertising_options = options.CompatibleOptions();
|
||||
RunOnPcpHandlerThread(
|
||||
[this, client, &service_id, &info, &options, &response]() {
|
||||
auto result = StartAdvertisingImpl(client, service_id,
|
||||
client->GenerateLocalEndpointId(),
|
||||
info.name, options);
|
||||
[this, client, &service_id, &info, &advertising_options, &response]() {
|
||||
auto result = StartAdvertisingImpl(
|
||||
client, service_id, client->GetLocalEndpointId(),
|
||||
info.endpoint_info, advertising_options);
|
||||
if (!result.status.Ok()) {
|
||||
response.Set(result.status);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now that we've succeeded, mark the client as advertising.
|
||||
advertising_options_ = options;
|
||||
advertising_options_ = advertising_options;
|
||||
advertising_listener_ = info.listener;
|
||||
client->StartedAdvertising(service_id, GetStrategy(), info.listener,
|
||||
absl::MakeSpan(result.mediums));
|
||||
response.Set({Status::kSuccess});
|
||||
});
|
||||
return WaitForResult(absl::StrCat("StartAdvertising(", info.name, ")"),
|
||||
client->GetClientId(), &response);
|
||||
return WaitForResult(
|
||||
absl::StrCat("StartAdvertising(", std::string(info.endpoint_info), ")"),
|
||||
client->GetClientId(), &response);
|
||||
}
|
||||
|
||||
void BasePcpHandler::StopAdvertising(ClientProxy* client) {
|
||||
@@ -109,10 +115,11 @@ Status BasePcpHandler::StartDiscovery(ClientProxy* client,
|
||||
const ConnectionOptions& options,
|
||||
const DiscoveryListener& listener) {
|
||||
Future<Status> response;
|
||||
ConnectionOptions discovery_options = options.CompatibleOptions();
|
||||
RunOnPcpHandlerThread(
|
||||
[this, client, service_id, options, &listener, &response]() {
|
||||
[this, client, service_id, discovery_options, &listener, &response]() {
|
||||
// Ask the implementation to attempt to start discovery.
|
||||
auto result = StartDiscoveryImpl(client, service_id, options);
|
||||
auto result = StartDiscoveryImpl(client, service_id, discovery_options);
|
||||
if (!result.status.Ok()) {
|
||||
response.Set(result.status);
|
||||
return;
|
||||
@@ -120,7 +127,7 @@ Status BasePcpHandler::StartDiscovery(ClientProxy* client,
|
||||
|
||||
// Now that we've succeeded, mark the client as discovering and clear
|
||||
// out any old endpoints we had discovered.
|
||||
discovery_options_ = options;
|
||||
discovery_options_ = discovery_options;
|
||||
discovered_endpoints_.clear();
|
||||
client->StartedDiscovery(service_id, GetStrategy(), listener,
|
||||
absl::MakeSpan(result.mediums));
|
||||
@@ -139,7 +146,7 @@ void BasePcpHandler::StopDiscovery(ClientProxy* client) {
|
||||
latch.CountDown();
|
||||
});
|
||||
|
||||
WaitForLatch("stopDiscovery", &latch);
|
||||
WaitForLatch("StopDiscovery", &latch);
|
||||
}
|
||||
|
||||
void BasePcpHandler::WaitForLatch(const std::string& method_name,
|
||||
@@ -162,10 +169,12 @@ Status BasePcpHandler::WaitForResult(const std::string& method_name,
|
||||
NEARBY_LOG(INFO, "waiting for future to complete");
|
||||
ExceptionOr<Status> result = future->Get();
|
||||
if (!result.ok()) {
|
||||
NEARBY_LOG(INFO, "Future completed with exception: %d", result.exception());
|
||||
NEARBY_LOG(INFO, "Future:[%s] completed with exception: %d",
|
||||
method_name.c_str(), result.exception());
|
||||
return {Status::kError};
|
||||
}
|
||||
NEARBY_LOG(INFO, "Future completed with status: %d", result.result().value);
|
||||
NEARBY_LOG(INFO, "Future:[%s] completed with status: %d", method_name.c_str(),
|
||||
result.result().value);
|
||||
return result.result();
|
||||
}
|
||||
|
||||
@@ -232,11 +241,12 @@ void BasePcpHandler::OnEncryptionSuccessRunnable(
|
||||
endpoint_manager_->RegisterEndpoint(
|
||||
connection_info.client, endpoint_id,
|
||||
{
|
||||
.remote_endpoint_name = connection_info.remote_endpoint_name,
|
||||
.remote_endpoint_info = connection_info.remote_endpoint_info,
|
||||
.authentication_token = auth_token,
|
||||
.raw_authentication_token = raw_auth_token,
|
||||
.is_incoming_connection = connection_info.is_incoming,
|
||||
},
|
||||
connection_info.options,
|
||||
std::move(connection_info.channel), connection_info.listener);
|
||||
|
||||
if (connection_info.result != nullptr) {
|
||||
@@ -279,9 +289,10 @@ void BasePcpHandler::OnEncryptionFailureRunnable(
|
||||
|
||||
Status BasePcpHandler::RequestConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const ConnectionRequestInfo& info) {
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options) {
|
||||
Future<Status> result;
|
||||
RunOnPcpHandlerThread([this, client, &info, endpoint_id, &result]() {
|
||||
RunOnPcpHandlerThread([this, client, &info, options, endpoint_id, &result]() {
|
||||
absl::Time start_time = SystemClock::ElapsedRealtime();
|
||||
|
||||
// If we already have a pending connection, then we shouldn't allow any more
|
||||
@@ -302,8 +313,7 @@ Status BasePcpHandler::RequestConnection(ClientProxy* client,
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<DiscoveredEndpoint*> endpoints;
|
||||
auto endpoint = GetDiscoveredEndpoint(endpoint_id);
|
||||
DiscoveredEndpoint* endpoint = GetDiscoveredEndpoint(endpoint_id);
|
||||
if (endpoint == nullptr) {
|
||||
NEARBY_LOG(INFO, "Discovered endpoint not found: id=%s",
|
||||
endpoint_id.c_str());
|
||||
@@ -311,24 +321,24 @@ Status BasePcpHandler::RequestConnection(ClientProxy* client,
|
||||
return;
|
||||
}
|
||||
|
||||
auto webrtc_endpoint = absl::make_unique<WebRtcEndpoint>(
|
||||
DiscoveredEndpoint{endpoint->endpoint_id, endpoint->endpoint_name,
|
||||
endpoint->service_id,
|
||||
proto::connections::Medium::WEB_RTC},
|
||||
CreatePeerIdFromAdvertisement(endpoint->service_id,
|
||||
endpoint->endpoint_id,
|
||||
endpoint->endpoint_name));
|
||||
endpoints.push_back(endpoint);
|
||||
endpoints.push_back(webrtc_endpoint.get());
|
||||
|
||||
std::sort(endpoints.begin(), endpoints.end(),
|
||||
[this](DiscoveredEndpoint* a, DiscoveredEndpoint* b) -> bool {
|
||||
return IsPreferred(*a, *b);
|
||||
});
|
||||
if (discovery_options_.allowed.web_rtc) {
|
||||
auto webrtc_endpoint = std::make_shared<WebRtcEndpoint>(
|
||||
DiscoveredEndpoint{endpoint->endpoint_id, endpoint->endpoint_info,
|
||||
endpoint->service_id,
|
||||
proto::connections::Medium::WEB_RTC},
|
||||
CreatePeerIdFromAdvertisement(endpoint->service_id,
|
||||
endpoint->endpoint_id,
|
||||
endpoint->endpoint_info));
|
||||
OnEndpointFound(client, webrtc_endpoint);
|
||||
}
|
||||
|
||||
auto endpoints = GetDiscoveredEndpoints(endpoint_id);
|
||||
std::unique_ptr<EndpointChannel> channel;
|
||||
ConnectImplResult connect_impl_result;
|
||||
|
||||
// TODO(b/156634369): add GetRemoteBluetoothMacAddressEndpoint here for
|
||||
// valid remote mac address.
|
||||
|
||||
for (auto connect_endpoint : endpoints) {
|
||||
connect_impl_result = ConnectImpl(client, connect_endpoint);
|
||||
if (connect_impl_result.status.Ok()) {
|
||||
@@ -352,7 +362,7 @@ Status BasePcpHandler::RequestConnection(ClientProxy* client,
|
||||
// The first message we have to send, after connecting, is to tell the
|
||||
// endpoint about ourselves.
|
||||
Exception write_exception = WriteConnectionRequestFrame(
|
||||
channel.get(), client->GenerateLocalEndpointId(), info.name, nonce,
|
||||
channel.get(), client->GetLocalEndpointId(), info.endpoint_info, nonce,
|
||||
GetConnectionMediumsByPriority());
|
||||
if (!write_exception.Ok()) {
|
||||
NEARBY_LOG(INFO, "Failed to send connection request: id=%s",
|
||||
@@ -368,18 +378,19 @@ Status BasePcpHandler::RequestConnection(ClientProxy* client,
|
||||
// We've successfully connected to the device, and are now about to jump on
|
||||
// to the EncryptionRunner thread to start running our encryption protocol.
|
||||
// We'll mark ourselves as pending in case we get another call to
|
||||
// requestConnection or OnIncomingConnection, so that we can cancel the
|
||||
// RequestConnection or OnIncomingConnection, so that we can cancel the
|
||||
// connection if needed.
|
||||
EndpointChannel* endpoint_channel =
|
||||
pending_connections_
|
||||
.emplace(endpoint_id,
|
||||
PendingConnectionInfo{
|
||||
.client = client,
|
||||
.remote_endpoint_name = endpoint->endpoint_name,
|
||||
.remote_endpoint_info = endpoint->endpoint_info,
|
||||
.nonce = nonce,
|
||||
.is_incoming = false,
|
||||
.start_time = start_time,
|
||||
.listener = info.listener,
|
||||
.options = options,
|
||||
.result = MakeSwapper(&result),
|
||||
.channel = std::move(channel),
|
||||
})
|
||||
@@ -388,20 +399,21 @@ Status BasePcpHandler::RequestConnection(ClientProxy* client,
|
||||
NEARBY_LOG(INFO, "Initiating secure connection: id=%s",
|
||||
endpoint_id.c_str());
|
||||
// Next, we'll set up encryption. When it's done, our future will return and
|
||||
// requestConnection() will finish.
|
||||
// RequestConnection() will finish.
|
||||
encryption_runner_.StartClient(client, endpoint_id, endpoint_channel,
|
||||
GetResultListener());
|
||||
});
|
||||
NEARBY_LOG(INFO, "Waiting for connection to complete: id=%s",
|
||||
endpoint_id.c_str());
|
||||
auto status =
|
||||
WaitForResult(absl::StrCat("requestConnection(", endpoint_id, ")"),
|
||||
WaitForResult(absl::StrCat("RequestConnection(", endpoint_id, ")"),
|
||||
client->GetClientId(), &result);
|
||||
NEARBY_LOG(INFO, "Wait is complete: id=%s; status=%d", endpoint_id.c_str(),
|
||||
status.value);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Get any single discovered endpoint for a given endpoint_id.
|
||||
BasePcpHandler::DiscoveredEndpoint* BasePcpHandler::GetDiscoveredEndpoint(
|
||||
const std::string& endpoint_id) {
|
||||
auto it = discovered_endpoints_.find(endpoint_id);
|
||||
@@ -411,6 +423,20 @@ BasePcpHandler::DiscoveredEndpoint* BasePcpHandler::GetDiscoveredEndpoint(
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
std::vector<BasePcpHandler::DiscoveredEndpoint*>
|
||||
BasePcpHandler::GetDiscoveredEndpoints(const std::string& endpoint_id) {
|
||||
std::vector<BasePcpHandler::DiscoveredEndpoint*> result;
|
||||
auto it = discovered_endpoints_.equal_range(endpoint_id);
|
||||
for (auto item = it.first; item != it.second; item++) {
|
||||
result.push_back(item->second.get());
|
||||
}
|
||||
std::sort(result.begin(), result.end(),
|
||||
[this](DiscoveredEndpoint* a, DiscoveredEndpoint* b) -> bool {
|
||||
return IsPreferred(*a, *b);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void BasePcpHandler::PendingConnectionInfo::SetCryptoContext(
|
||||
std::unique_ptr<UKey2Handshake> ukey2) {
|
||||
this->ukey2 = std::move(ukey2);
|
||||
@@ -446,10 +472,10 @@ bool BasePcpHandler::CanReceiveIncomingConnection(ClientProxy* client) const {
|
||||
|
||||
Exception BasePcpHandler::WriteConnectionRequestFrame(
|
||||
EndpointChannel* endpoint_channel, const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name, std::int32_t nonce,
|
||||
const ByteArray& local_endpoint_info, std::int32_t nonce,
|
||||
const std::vector<proto::connections::Medium>& supported_mediums) {
|
||||
return endpoint_channel->Write(parser::ForConnectionRequest(
|
||||
local_endpoint_id, local_endpoint_name, nonce, supported_mediums));
|
||||
local_endpoint_id, local_endpoint_info, nonce, supported_mediums));
|
||||
}
|
||||
|
||||
void BasePcpHandler::ProcessPreConnectionInitiationFailure(
|
||||
@@ -543,7 +569,7 @@ Status BasePcpHandler::AcceptConnection(
|
||||
response.Set({Status::kSuccess});
|
||||
});
|
||||
|
||||
return WaitForResult(absl::StrCat("acceptConnection(", endpoint_id, ")"),
|
||||
return WaitForResult(absl::StrCat("AcceptConnection(", endpoint_id, ")"),
|
||||
client->GetClientId(), &response);
|
||||
}
|
||||
|
||||
@@ -595,7 +621,7 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client,
|
||||
response.Set({Status::kSuccess});
|
||||
});
|
||||
|
||||
return WaitForResult(absl::StrCat("rejectConnection(", endpoint_id, ")"),
|
||||
return WaitForResult(absl::StrCat("RejectConnection(", endpoint_id, ")"),
|
||||
client->GetClientId(), &response);
|
||||
}
|
||||
|
||||
@@ -662,44 +688,52 @@ ConnectionOptions BasePcpHandler::GetConnectionOptions() const {
|
||||
return advertising_options_;
|
||||
}
|
||||
|
||||
ConnectionOptions BasePcpHandler::GetDiscoveryOptions() const {
|
||||
return discovery_options_;
|
||||
}
|
||||
|
||||
void BasePcpHandler::OnEndpointFound(
|
||||
ClientProxy* client,
|
||||
std::shared_ptr<BasePcpHandler::DiscoveredEndpoint> endpoint) {
|
||||
ClientProxy* client, std::shared_ptr<DiscoveredEndpoint> endpoint) {
|
||||
// Check if we've seen this endpoint ID before.
|
||||
std::string& endpoint_id = endpoint->endpoint_id;
|
||||
BasePcpHandler::DiscoveredEndpoint* previously_discovered_endpoint =
|
||||
GetDiscoveredEndpoint(endpoint_id);
|
||||
|
||||
NEARBY_LOG(INFO, "OnEndpointFound: id='%s' [enter]", endpoint_id.c_str());
|
||||
if (previously_discovered_endpoint == nullptr) {
|
||||
// If this is the first medium we've discovered this endpoint over, then add
|
||||
// it to the map.
|
||||
const auto& owned_endpoint =
|
||||
discovered_endpoints_.emplace(endpoint_id, std::move(endpoint))
|
||||
.first->second;
|
||||
|
||||
auto range = discovered_endpoints_.equal_range(endpoint->endpoint_id);
|
||||
|
||||
DiscoveredEndpoint* owned_endpoint = nullptr;
|
||||
for (auto& item = range.first; item != range.second; ++item) {
|
||||
auto& discovered_endpoint = item->second;
|
||||
if (discovered_endpoint->medium != endpoint->medium) continue;
|
||||
// Check if there was a info change. If there was, report the previous
|
||||
// endpoint as lost.
|
||||
if (discovered_endpoint->endpoint_info != endpoint->endpoint_info) {
|
||||
OnEndpointLost(client, *discovered_endpoint);
|
||||
discovered_endpoint = endpoint; // Replace endpoint.
|
||||
OnEndpointFound(client, std::move(endpoint));
|
||||
return;
|
||||
} else {
|
||||
owned_endpoint = endpoint.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!owned_endpoint) {
|
||||
owned_endpoint =
|
||||
discovered_endpoints_.emplace(endpoint_id, std::move(endpoint))
|
||||
->second.get();
|
||||
}
|
||||
|
||||
// Range is empty: this is the first endpoint we discovered so far.
|
||||
// Report this endpoint_id to client.
|
||||
if (range.first == range.second) {
|
||||
NEARBY_LOG(INFO, "Adding new endpoint: id=%s", endpoint_id.c_str());
|
||||
// And, as it's the first time, report it to the client.
|
||||
client->OnEndpointFound(
|
||||
owned_endpoint->service_id, owned_endpoint->endpoint_id,
|
||||
owned_endpoint->endpoint_name, owned_endpoint->medium);
|
||||
} else if (previously_discovered_endpoint->endpoint_name !=
|
||||
endpoint->endpoint_name) {
|
||||
// If we've already seen this endpoint before, check if there was a name
|
||||
// change. If there was, report the previous endpoint as lost.
|
||||
NEARBY_LOG(INFO, "Switch to new endpoint: id=%s", endpoint_id.c_str());
|
||||
|
||||
OnEndpointLost(client, *previously_discovered_endpoint);
|
||||
OnEndpointFound(client, std::move(endpoint));
|
||||
owned_endpoint->endpoint_info, owned_endpoint->medium);
|
||||
} else {
|
||||
// Otherwise, we need to see if the medium we discovered the endpoint over
|
||||
// this time is better than the medium we originally discovered the endpoint
|
||||
// over.
|
||||
NEARBY_LOG(INFO, "Rediscovered endpoint on new media: id=%s",
|
||||
endpoint_id.c_str());
|
||||
if (IsPreferred(*endpoint, *previously_discovered_endpoint)) {
|
||||
discovered_endpoints_.insert_or_assign(endpoint_id, std::move(endpoint));
|
||||
}
|
||||
NEARBY_LOGS(INFO) << "Adding new medium for endpoint: id=" << endpoint_id
|
||||
<< "; medium=" << owned_endpoint->medium;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,19 +747,22 @@ void BasePcpHandler::OnEndpointLost(
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate that the cached endpoint has the same name as the one reported as
|
||||
// onLost. If the name differs, then no-op. This likely means that the remote
|
||||
// device changed their name. We reported onFound for the new name and are
|
||||
// just now figuring out that we lost the old name.
|
||||
if (discovered_endpoint->endpoint_name != endpoint.endpoint_name) {
|
||||
// Validate that the cached endpoint has the same info as the one reported as
|
||||
// onLost. If the info differs, then no-op. This likely means that the remote
|
||||
// device changed their info. We reported onFound for the new info and are
|
||||
// just now figuring out that we lost the old info.
|
||||
if (discovered_endpoint->endpoint_info != endpoint.endpoint_info) {
|
||||
NEARBY_LOG(INFO, "Previous endpoint name mismatch; passed=%s; expected=%s",
|
||||
endpoint.endpoint_name.c_str(),
|
||||
discovered_endpoint->endpoint_name.c_str());
|
||||
absl::BytesToHexString(endpoint.endpoint_info.data()).c_str(),
|
||||
absl::BytesToHexString(discovered_endpoint->endpoint_info.data())
|
||||
.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
auto item = discovered_endpoints_.extract(endpoint.endpoint_id);
|
||||
client->OnEndpointLost(endpoint.service_id, endpoint.endpoint_id);
|
||||
if (!discovered_endpoints_.count(endpoint.endpoint_id)) {
|
||||
client->OnEndpointLost(endpoint.service_id, endpoint.endpoint_id);
|
||||
}
|
||||
}
|
||||
|
||||
bool BasePcpHandler::IsPreferred(
|
||||
@@ -746,17 +783,24 @@ bool BasePcpHandler::IsPreferred(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
NEARBY_LOG(FATAL, "Failed to determine preferred medium; bailing out");
|
||||
std::string medium_string;
|
||||
for (const auto& medium : mediums) {
|
||||
absl::StrAppend(&medium_string, medium, "; ");
|
||||
}
|
||||
NEARBY_LOG(FATAL,
|
||||
"Failed to determine preferred medium; bailing out; mediums=%s; "
|
||||
"new=%d; old=%d",
|
||||
medium_string.c_str(), new_endpoint.medium, old_endpoint.medium);
|
||||
return false;
|
||||
}
|
||||
|
||||
Exception BasePcpHandler::OnIncomingConnection(
|
||||
ClientProxy* client, const std::string& remote_device_name,
|
||||
ClientProxy* client, const ByteArray& remote_endpoint_info,
|
||||
std::unique_ptr<EndpointChannel> channel,
|
||||
proto::connections::Medium medium) {
|
||||
absl::Time start_time = SystemClock::ElapsedRealtime();
|
||||
|
||||
// Fixes an NPE in ClientProxy.OnConnectionResult. The crash happened when
|
||||
// Fixes an NPE in ClientProxy.OnConnectionAccepted. The crash happened when
|
||||
// the client stopped advertising and we nulled out state, followed by an
|
||||
// incoming connection where we attempted to check that state.
|
||||
if (!client->IsAdvertising()) {
|
||||
@@ -777,7 +821,8 @@ Exception BasePcpHandler::OnIncomingConnection(
|
||||
ERROR,
|
||||
"Failed to parse incoming connection request; client_id=0x%" PRIX64
|
||||
"; device=%s",
|
||||
client->GetClientId(), remote_device_name.c_str());
|
||||
client->GetClientId(),
|
||||
absl::BytesToHexString(remote_endpoint_info.data()).c_str());
|
||||
ProcessPreConnectionInitiationFailure("", channel.get(), {Status::kError},
|
||||
nullptr);
|
||||
return {Exception::kSuccess};
|
||||
@@ -791,7 +836,8 @@ Exception BasePcpHandler::OnIncomingConnection(
|
||||
NEARBY_LOG(INFO,
|
||||
"Incoming connection request; client_id=0x%" PRIX64
|
||||
"; device=%s; id=%s",
|
||||
client->GetClientId(), remote_device_name.c_str(),
|
||||
client->GetClientId(),
|
||||
absl::BytesToHexString(remote_endpoint_info.data()).c_str(),
|
||||
connection_request.endpoint_id().c_str());
|
||||
if (client->IsConnectedToEndpoint(connection_request.endpoint_id())) {
|
||||
return {Exception::kIo};
|
||||
@@ -815,20 +861,20 @@ Exception BasePcpHandler::OnIncomingConnection(
|
||||
// EndpointInfo. The legacy field stores it as a string while the newer field
|
||||
// stores it as a byte array. We'll attempt to grab from the newer field, but
|
||||
// will accept the older string if it's all that exists.
|
||||
const std::string endpoint_name = connection_request.has_endpoint_info()
|
||||
? connection_request.endpoint_info()
|
||||
: connection_request.endpoint_name();
|
||||
const ByteArray endpoint_info{connection_request.has_endpoint_info()
|
||||
? connection_request.endpoint_info()
|
||||
: connection_request.endpoint_name()};
|
||||
|
||||
// We've successfully connected to the device, and are now about to jump on to
|
||||
// the EncryptionRunner thread to start running our encryption protocol. We'll
|
||||
// mark ourselves as pending in case we get another call to requestConnection
|
||||
// mark ourselves as pending in case we get another call to RequestConnection
|
||||
// or OnIncomingConnection, so that we can cancel the connection if needed.
|
||||
auto* owned_channel =
|
||||
pending_connections_
|
||||
.emplace(connection_request.endpoint_id(),
|
||||
PendingConnectionInfo{
|
||||
.client = client,
|
||||
.remote_endpoint_name = endpoint_name,
|
||||
.remote_endpoint_info = endpoint_info,
|
||||
.nonce = connection_request.nonce(),
|
||||
.is_incoming = true,
|
||||
.start_time = start_time,
|
||||
@@ -1093,8 +1139,9 @@ void BasePcpHandler::PendingConnectionInfo::LocalEndpointRejectedConnection(
|
||||
|
||||
mediums::PeerId BasePcpHandler::CreatePeerIdFromAdvertisement(
|
||||
const std::string& service_id, const std::string& endpoint_id,
|
||||
const std::string& endpoint_name) {
|
||||
std::string seed = absl::StrCat(service_id, endpoint_id, endpoint_name);
|
||||
const ByteArray& endpoint_info) {
|
||||
std::string seed =
|
||||
absl::StrCat(service_id, endpoint_id, std::string(endpoint_info));
|
||||
return mediums::PeerId::FromSeed(ByteArray(std::move(seed)));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "core_v2/internal/encryption_runner.h"
|
||||
#include "core_v2/internal/endpoint_channel_manager.h"
|
||||
#include "core_v2/internal/endpoint_manager.h"
|
||||
#include "core_v2/internal/mediums/mediums.h"
|
||||
#include "core_v2/internal/mediums/webrtc.h"
|
||||
#include "core_v2/internal/pcp.h"
|
||||
#include "core_v2/internal/pcp_handler.h"
|
||||
@@ -31,6 +32,7 @@
|
||||
#include "core_v2/options.h"
|
||||
#include "core_v2/status.h"
|
||||
#include "proto/connections/offline_wire_formats.pb.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/prng.h"
|
||||
#include "platform_v2/public/atomic_boolean.h"
|
||||
#include "platform_v2/public/atomic_reference.h"
|
||||
@@ -43,6 +45,7 @@
|
||||
#include "proto/connections_enums.pb.h"
|
||||
#include "securegcm/d2d_connection_context_v1.h"
|
||||
#include "securegcm/ukey2_handshake.h"
|
||||
#include "absl/container/btree_map.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
@@ -91,7 +94,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
using FrameProcessor = EndpointManager::FrameProcessor;
|
||||
|
||||
// TODO(apolyudov): Add SecureRandom.
|
||||
BasePcpHandler(EndpointManager* endpoint_manager,
|
||||
BasePcpHandler(Mediums* mediums, EndpointManager* endpoint_manager,
|
||||
EndpointChannelManager* channel_manager, Pcp pcp);
|
||||
~BasePcpHandler() override;
|
||||
BasePcpHandler(BasePcpHandler&&) = delete;
|
||||
@@ -101,44 +104,45 @@ class BasePcpHandler : public PcpHandler,
|
||||
// Notifies ConnectionListener (info.listener) in case of any event.
|
||||
// See
|
||||
// cpp/core_v2/listeners.h;l=78
|
||||
Status StartAdvertising(ClientProxy* client_proxy,
|
||||
Status StartAdvertising(ClientProxy* client,
|
||||
const std::string& service_id,
|
||||
const ConnectionOptions& options,
|
||||
const ConnectionRequestInfo& info) override;
|
||||
|
||||
// Stops Advertising is active, and changes CLientProxy state,
|
||||
// otherwise does nothing.
|
||||
void StopAdvertising(ClientProxy* client_proxy) override;
|
||||
void StopAdvertising(ClientProxy* client) override;
|
||||
|
||||
// Starts discovery of endpoints that may be advertising.
|
||||
// Updates ClientProxy state once discovery started.
|
||||
// DiscoveryListener will get called in case of any event.
|
||||
Status StartDiscovery(ClientProxy* client_proxy,
|
||||
Status StartDiscovery(ClientProxy* client,
|
||||
const std::string& service_id,
|
||||
const ConnectionOptions& options,
|
||||
const DiscoveryListener& listener) override;
|
||||
|
||||
// Stops Discovery if it is active, and changes CLientProxy state,
|
||||
// otherwise does nothing.
|
||||
void StopDiscovery(ClientProxy* client_proxy) override;
|
||||
void StopDiscovery(ClientProxy* client) override;
|
||||
|
||||
// Requests a newly discovered remote endpoint it to form a connection.
|
||||
// Updates state on ClientProxy.
|
||||
Status RequestConnection(ClientProxy* client_proxy,
|
||||
Status RequestConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const ConnectionRequestInfo& info) override;
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options) override;
|
||||
|
||||
// Called by either party to accept connection on their part.
|
||||
// Until both parties call it, connection will not reach a data phase.
|
||||
// Updates state in ClientProxy.
|
||||
Status AcceptConnection(ClientProxy* client_proxy,
|
||||
Status AcceptConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const PayloadListener& payload_listener) override;
|
||||
|
||||
// Called by either party to reject connection on their part.
|
||||
// If either party does call it, connection will terminate.
|
||||
// Updates state in ClientProxy.
|
||||
Status RejectConnection(ClientProxy* client_proxy,
|
||||
Status RejectConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id) override;
|
||||
|
||||
// @EndpointManagerReaderThread
|
||||
@@ -149,7 +153,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
// Called when an endpoint disconnects while we're waiting for both sides to
|
||||
// approve/reject the connection.
|
||||
// @EndpointManagerThread
|
||||
void OnEndpointDisconnect(ClientProxy* client_proxy,
|
||||
void OnEndpointDisconnect(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
CountDownLatch* barrier) override;
|
||||
|
||||
@@ -181,21 +185,37 @@ class BasePcpHandler : public PcpHandler,
|
||||
// instance (but it can if implementation desires to do so).
|
||||
// BasePcpHandler will hold on to the shared_ptr<DiscoveredEndpoint>.
|
||||
struct DiscoveredEndpoint {
|
||||
DiscoveredEndpoint(std::string endpoint_id, std::string endpoint_name,
|
||||
DiscoveredEndpoint(std::string endpoint_id, ByteArray endpoint_info,
|
||||
std::string service_id,
|
||||
proto::connections::Medium medium)
|
||||
: endpoint_id(std::move(endpoint_id)),
|
||||
endpoint_name(std::move(endpoint_name)),
|
||||
endpoint_info(std::move(endpoint_info)),
|
||||
service_id(std::move(service_id)),
|
||||
medium(medium) {}
|
||||
virtual ~DiscoveredEndpoint() = default;
|
||||
|
||||
std::string endpoint_id;
|
||||
std::string endpoint_name;
|
||||
ByteArray endpoint_info;
|
||||
std::string service_id;
|
||||
proto::connections::Medium medium;
|
||||
};
|
||||
|
||||
struct BluetoothEndpoint : public DiscoveredEndpoint {
|
||||
BluetoothEndpoint(DiscoveredEndpoint endpoint, BluetoothDevice device)
|
||||
: DiscoveredEndpoint(std::move(endpoint)),
|
||||
bluetooth_device(std::move(device)) {}
|
||||
|
||||
BluetoothDevice bluetooth_device;
|
||||
};
|
||||
|
||||
struct WifiLanEndpoint : public DiscoveredEndpoint {
|
||||
WifiLanEndpoint(DiscoveredEndpoint endpoint, WifiLanService service)
|
||||
: DiscoveredEndpoint(std::move(endpoint)),
|
||||
wifi_lan_service(std::move(service)) {}
|
||||
|
||||
WifiLanService wifi_lan_service;
|
||||
};
|
||||
|
||||
struct WebRtcEndpoint : public DiscoveredEndpoint {
|
||||
WebRtcEndpoint(DiscoveredEndpoint endpoint, mediums::PeerId peer_id)
|
||||
: DiscoveredEndpoint(std::move(endpoint)),
|
||||
@@ -214,54 +234,64 @@ class BasePcpHandler : public PcpHandler,
|
||||
void RunOnPcpHandlerThread(Runnable runnable);
|
||||
|
||||
ConnectionOptions GetConnectionOptions() const;
|
||||
ConnectionOptions GetDiscoveryOptions() const;
|
||||
|
||||
// @PcpHandlerThread
|
||||
void OnEndpointFound(ClientProxy* client_proxy,
|
||||
void OnEndpointFound(ClientProxy* client,
|
||||
std::shared_ptr<DiscoveredEndpoint> endpoint);
|
||||
|
||||
// @PcpHandlerThread
|
||||
void OnEndpointLost(ClientProxy* client_proxy,
|
||||
void OnEndpointLost(ClientProxy* client,
|
||||
const DiscoveredEndpoint& endpoint);
|
||||
|
||||
Exception OnIncomingConnection(
|
||||
ClientProxy* client_proxy, const std::string& remote_device_name,
|
||||
ClientProxy* client, const ByteArray& remote_endpoint_info,
|
||||
std::unique_ptr<EndpointChannel> endpoint_channel,
|
||||
proto::connections::Medium medium); // throws Exception::IO
|
||||
|
||||
virtual bool HasOutgoingConnections(ClientProxy* client_proxy) const;
|
||||
virtual bool HasIncomingConnections(ClientProxy* client_proxy) const;
|
||||
virtual bool HasOutgoingConnections(ClientProxy* client) const;
|
||||
virtual bool HasIncomingConnections(ClientProxy* client) const;
|
||||
|
||||
virtual bool CanSendOutgoingConnection(ClientProxy* client_proxy) const;
|
||||
virtual bool CanReceiveIncomingConnection(ClientProxy* client_proxy) const;
|
||||
virtual bool CanSendOutgoingConnection(ClientProxy* client) const;
|
||||
virtual bool CanReceiveIncomingConnection(ClientProxy* client) const;
|
||||
|
||||
// @PcpHandlerThread
|
||||
virtual StartOperationResult StartAdvertisingImpl(
|
||||
ClientProxy* client_proxy, const std::string& service_id,
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name,
|
||||
const ByteArray& local_endpoint_info,
|
||||
const ConnectionOptions& options) = 0;
|
||||
// @PcpHandlerThread
|
||||
virtual Status StopAdvertisingImpl(ClientProxy* client_proxy) = 0;
|
||||
virtual Status StopAdvertisingImpl(ClientProxy* client) = 0;
|
||||
|
||||
// @PcpHandlerThread
|
||||
virtual StartOperationResult StartDiscoveryImpl(
|
||||
ClientProxy* client_proxy, const std::string& service_id,
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const ConnectionOptions& options) = 0;
|
||||
// @PcpHandlerThread
|
||||
virtual Status StopDiscoveryImpl(ClientProxy* client_proxy) = 0;
|
||||
virtual Status StopDiscoveryImpl(ClientProxy* client) = 0;
|
||||
|
||||
// @PcpHandlerThread
|
||||
virtual ConnectImplResult ConnectImpl(ClientProxy* client_proxy,
|
||||
virtual ConnectImplResult ConnectImpl(ClientProxy* client,
|
||||
DiscoveredEndpoint* endpoint) = 0;
|
||||
|
||||
virtual std::vector<proto::connections::Medium>
|
||||
GetConnectionMediumsByPriority() = 0;
|
||||
virtual proto::connections::Medium GetDefaultUpgradeMedium() = 0;
|
||||
|
||||
// Returns the first discovered endpoint for the given endpoint_id.
|
||||
DiscoveredEndpoint* GetDiscoveredEndpoint(const std::string& endpoint_id);
|
||||
|
||||
// Returns a vector of discovered endpoints, sorted in order of decreasing
|
||||
// preference.
|
||||
std::vector<BasePcpHandler::DiscoveredEndpoint*>
|
||||
GetDiscoveredEndpoints(const std::string& endpoint_id);
|
||||
|
||||
mediums::PeerId CreatePeerIdFromAdvertisement(const string& service_id,
|
||||
const string& endpoint_id,
|
||||
const string& endpoint_name);
|
||||
const ByteArray& endpoint_info);
|
||||
|
||||
Mediums* mediums_;
|
||||
EndpointManager* endpoint_manager_;
|
||||
EndpointChannelManager* channel_manager_;
|
||||
|
||||
@@ -286,13 +316,14 @@ class BasePcpHandler : public PcpHandler,
|
||||
|
||||
// Client state tracker to report events to. Never changes. Always valid.
|
||||
ClientProxy* client = nullptr;
|
||||
// Peer endpoint name, or empty, if not discovered yet. May change.
|
||||
std::string remote_endpoint_name;
|
||||
// Peer endpoint info, or empty, if not discovered yet. May change.
|
||||
ByteArray remote_endpoint_info;
|
||||
std::int32_t nonce = 0;
|
||||
bool is_incoming = false;
|
||||
absl::Time start_time{absl::InfinitePast()};
|
||||
// Client callbacks. Always valid.
|
||||
ConnectionListener listener;
|
||||
ConnectionOptions options;
|
||||
|
||||
// Only set for outgoing connections. If set, we must call
|
||||
// result->Set() when connection is established, or rejected.
|
||||
@@ -336,7 +367,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
|
||||
static Exception WriteConnectionRequestFrame(
|
||||
EndpointChannel* endpoint_channel, const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name, std::int32_t nonce,
|
||||
const ByteArray& local_endpoint_info, std::int32_t nonce,
|
||||
const std::vector<proto::connections::Medium>& supported_mediums);
|
||||
|
||||
static constexpr absl::Duration kConnectionRequestReadTimeout =
|
||||
@@ -344,8 +375,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
static constexpr absl::Duration kRejectedConnectionCloseDelay =
|
||||
absl::Seconds(2);
|
||||
|
||||
void OnConnectionResponse(ClientProxy* client_proxy,
|
||||
const std::string& endpoint_id,
|
||||
void OnConnectionResponse(ClientProxy* client, const std::string& endpoint_id,
|
||||
const OfflineFrame& frame);
|
||||
|
||||
// Returns true if the new endpoint is preferred over the old endpoint.
|
||||
@@ -367,8 +397,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
// We're not sure how far our outgoing connection has gotten. We may (or may
|
||||
// not) have called ClientProxy::OnConnectionInitiated. Therefore, we'll
|
||||
// call both preInit and preResult failures.
|
||||
void ProcessTieBreakLoss(ClientProxy* client_proxy,
|
||||
const std::string& endpoint_id,
|
||||
void ProcessTieBreakLoss(ClientProxy* client, const std::string& endpoint_id,
|
||||
PendingConnectionInfo* info);
|
||||
|
||||
// Called when an incoming connection has been accepted by both sides.
|
||||
@@ -380,7 +409,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
// for outgoing connections and older devices that don't report their
|
||||
// supported mediums.
|
||||
void InitiateBandwidthUpgrade(
|
||||
ClientProxy* client_proxy, const std::string& endpoint_id,
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
const std::vector<proto::connections::Medium>& supported_mediums);
|
||||
|
||||
// Returns the optimal medium supported by both devices.
|
||||
@@ -391,9 +420,8 @@ class BasePcpHandler : public PcpHandler,
|
||||
EndpointChannel* channel,
|
||||
Status status,
|
||||
Future<Status>* result);
|
||||
void ProcessPreConnectionResultFailure(ClientProxy* client_proxy,
|
||||
void ProcessPreConnectionResultFailure(ClientProxy* client,
|
||||
const std::string& endpoint_id);
|
||||
DiscoveredEndpoint* GetDiscoveredEndpoint(const std::string& endpoint_id);
|
||||
|
||||
// Called when either side accepts/rejects the connection, but only takes
|
||||
// effect after both have accepted or one side has rejected.
|
||||
@@ -404,7 +432,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
// onResult(DISCONNECTED) instead of onResult(REJECTED)), we delay our
|
||||
// close. If the other side behaves properly, we shouldn't even see the
|
||||
// delay (because they will also close the connection).
|
||||
void EvaluateConnectionResult(ClientProxy* client_proxy,
|
||||
void EvaluateConnectionResult(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
bool can_close_immediately);
|
||||
|
||||
@@ -427,7 +455,7 @@ class BasePcpHandler : public PcpHandler,
|
||||
// removed from this map.
|
||||
absl::flat_hash_map<std::string, PendingConnectionInfo> pending_connections_;
|
||||
// A map of endpoint id -> DiscoveredEndpoint.
|
||||
absl::flat_hash_map<std::string, std::shared_ptr<DiscoveredEndpoint>>
|
||||
absl::btree_multimap<std::string, std::shared_ptr<DiscoveredEndpoint>>
|
||||
discovered_endpoints_;
|
||||
// A map of endpoint id -> alarm. These alarms delay closing the
|
||||
// EndpointChannel to give the other side enough time to read the rejection
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
#include "core_v2/internal/encryption_runner.h"
|
||||
#include "core_v2/internal/offline_frames.h"
|
||||
#include "core_v2/listeners.h"
|
||||
#include "core_v2/options.h"
|
||||
#include "core_v2/params.h"
|
||||
#include "proto/connections/offline_wire_formats.pb.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
#include "platform_v2/public/pipe.h"
|
||||
#include "proto/connections_enums.pb.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/time/time.h"
|
||||
@@ -44,6 +46,20 @@ using ::testing::MockFunction;
|
||||
using ::testing::Return;
|
||||
using ::testing::StrictMock;
|
||||
|
||||
constexpr BooleanMediumSelector kTestCases[] = {
|
||||
BooleanMediumSelector{},
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.wifi_lan = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
.wifi_lan = true,
|
||||
},
|
||||
};
|
||||
|
||||
class MockEndpointChannel : public BaseEndpointChannel {
|
||||
public:
|
||||
explicit MockEndpointChannel(Pipe* reader, Pipe* writer)
|
||||
@@ -72,8 +88,10 @@ class MockEndpointChannel : public BaseEndpointChannel {
|
||||
|
||||
class MockPcpHandler : public BasePcpHandler {
|
||||
public:
|
||||
MockPcpHandler(EndpointManager* em, EndpointChannelManager* ecm)
|
||||
: BasePcpHandler(em, ecm, Pcp::kP2pCluster) {}
|
||||
using DiscoveredEndpoint = BasePcpHandler::DiscoveredEndpoint;
|
||||
|
||||
MockPcpHandler(Mediums* m, EndpointManager* em, EndpointChannelManager* ecm)
|
||||
: BasePcpHandler(m, em, ecm, Pcp::kP2pCluster) {}
|
||||
|
||||
// Expose protected inner types of a base type for mocking.
|
||||
using BasePcpHandler::ConnectImplResult;
|
||||
@@ -94,9 +112,9 @@ class MockPcpHandler : public BasePcpHandler {
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(StartOperationResult, StartAdvertisingImpl,
|
||||
(ClientProxy * client, const string& service_id,
|
||||
const string& local_endpoint_id,
|
||||
const string& local_endpoint_name,
|
||||
(ClientProxy * client, const std::string& service_id,
|
||||
const std::string& local_endpoint_id,
|
||||
const ByteArray& local_endpoint_info,
|
||||
const ConnectionOptions& options),
|
||||
(override));
|
||||
MOCK_METHOD(Status, StopAdvertisingImpl, (ClientProxy * client), (override));
|
||||
@@ -112,8 +130,7 @@ class MockPcpHandler : public BasePcpHandler {
|
||||
|
||||
std::vector<proto::connections::Medium> GetConnectionMediumsByPriority()
|
||||
override {
|
||||
return {proto::connections::Medium::BLE,
|
||||
proto::connections::Medium::WEB_RTC};
|
||||
return GetDiscoveryMediums();
|
||||
}
|
||||
|
||||
// Mock adapters for protected non-virtual methods of a base class.
|
||||
@@ -124,22 +141,37 @@ class MockPcpHandler : public BasePcpHandler {
|
||||
void OnEndpointLost(ClientProxy* client, const DiscoveredEndpoint& endpoint) {
|
||||
BasePcpHandler::OnEndpointLost(client, endpoint);
|
||||
}
|
||||
std::vector<BasePcpHandler::DiscoveredEndpoint*> GetDiscoveredEndpoints(
|
||||
const std::string& endpoint_id) {
|
||||
return BasePcpHandler::GetDiscoveredEndpoints(endpoint_id);
|
||||
}
|
||||
|
||||
std::vector<proto::connections::Medium> GetDiscoveryMediums() {
|
||||
auto allowed =
|
||||
BasePcpHandler::GetDiscoveryOptions().CompatibleOptions().allowed;
|
||||
return GetMediumsFromSelector(allowed);
|
||||
}
|
||||
|
||||
std::vector<proto::connections::Medium> GetMediumsFromSelector(
|
||||
BooleanMediumSelector allowed) {
|
||||
return allowed.GetMediums(true);
|
||||
}
|
||||
};
|
||||
|
||||
class MockContext {
|
||||
public:
|
||||
explicit MockContext(std::atomic_bool* destroyed = nullptr) {
|
||||
explicit MockContext(std::atomic_int* destroyed = nullptr) {
|
||||
destroyed_ = destroyed;
|
||||
}
|
||||
MockContext(MockContext&&) = default;
|
||||
MockContext& operator=(MockContext&&) = default;
|
||||
|
||||
~MockContext() {
|
||||
if (destroyed_) *destroyed_ = true;
|
||||
if (destroyed_) (*destroyed_)++;
|
||||
}
|
||||
|
||||
private:
|
||||
Swapper<std::atomic_bool> destroyed_{nullptr};
|
||||
Swapper<std::atomic_int> destroyed_{nullptr};
|
||||
};
|
||||
|
||||
struct MockDiscoveredEndpoint : public MockPcpHandler::DiscoveredEndpoint {
|
||||
@@ -149,7 +181,8 @@ struct MockDiscoveredEndpoint : public MockPcpHandler::DiscoveredEndpoint {
|
||||
MockContext context;
|
||||
};
|
||||
|
||||
class BasePcpHandlerTest : public ::testing::Test {
|
||||
class BasePcpHandlerTest
|
||||
: public ::testing::TestWithParam<BooleanMediumSelector> {
|
||||
protected:
|
||||
struct MockConnectionListener {
|
||||
StrictMock<MockFunction<void(const std::string& endpoint_id,
|
||||
@@ -167,7 +200,7 @@ class BasePcpHandlerTest : public ::testing::Test {
|
||||
};
|
||||
struct MockDiscoveryListener {
|
||||
StrictMock<MockFunction<void(const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id)>>
|
||||
endpoint_found_cb;
|
||||
StrictMock<MockFunction<void(const std::string& endpoint_id)>>
|
||||
@@ -177,39 +210,43 @@ class BasePcpHandlerTest : public ::testing::Test {
|
||||
endpoint_distance_changed_cb;
|
||||
};
|
||||
|
||||
void StartAdvertising(ClientProxy* client, MockPcpHandler* pcp_handler) {
|
||||
void StartAdvertising(ClientProxy* client, MockPcpHandler* pcp_handler,
|
||||
BooleanMediumSelector allowed = GetParam()) {
|
||||
std::string service_id{"service"};
|
||||
ConnectionOptions options{
|
||||
.strategy = Strategy::kP2pCluster,
|
||||
.allowed = allowed,
|
||||
.auto_upgrade_bandwidth = true,
|
||||
.enforce_topology_constraints = true,
|
||||
};
|
||||
ConnectionRequestInfo info{
|
||||
.name = "remote_endpoint_name",
|
||||
.endpoint_info = ByteArray{"remote_endpoint_name"},
|
||||
.listener = connection_listener_,
|
||||
};
|
||||
EXPECT_CALL(*pcp_handler,
|
||||
StartAdvertisingImpl(client, service_id, _, info.name, _))
|
||||
EXPECT_CALL(*pcp_handler, StartAdvertisingImpl(client, service_id, _,
|
||||
info.endpoint_info, _))
|
||||
.WillOnce(Return(MockPcpHandler::StartOperationResult{
|
||||
.status = {Status::kSuccess},
|
||||
.mediums = {Medium::BLE},
|
||||
.mediums = pcp_handler->GetMediumsFromSelector(allowed),
|
||||
}));
|
||||
EXPECT_EQ(pcp_handler->StartAdvertising(client, service_id, options, info),
|
||||
Status{Status::kSuccess});
|
||||
EXPECT_TRUE(client->IsAdvertising());
|
||||
}
|
||||
|
||||
void StartDiscovery(ClientProxy* client, MockPcpHandler* pcp_handler) {
|
||||
void StartDiscovery(ClientProxy* client, MockPcpHandler* pcp_handler,
|
||||
BooleanMediumSelector allowed = GetParam()) {
|
||||
std::string service_id{"service"};
|
||||
ConnectionOptions options{
|
||||
.strategy = Strategy::kP2pCluster,
|
||||
.allowed = allowed,
|
||||
.auto_upgrade_bandwidth = true,
|
||||
.enforce_topology_constraints = true,
|
||||
};
|
||||
EXPECT_CALL(*pcp_handler, StartDiscoveryImpl(client, service_id, _))
|
||||
.WillOnce(Return(MockPcpHandler::StartOperationResult{
|
||||
.status = {Status::kSuccess},
|
||||
.mediums = {Medium::BLE},
|
||||
.mediums = pcp_handler->GetMediumsFromSelector(allowed),
|
||||
}));
|
||||
EXPECT_EQ(pcp_handler->StartDiscovery(client, service_id, options,
|
||||
discovery_listener_),
|
||||
@@ -219,7 +256,8 @@ class BasePcpHandlerTest : public ::testing::Test {
|
||||
|
||||
std::pair<std::unique_ptr<MockEndpointChannel>,
|
||||
std::unique_ptr<MockEndpointChannel>>
|
||||
SetupConnection(Pipe& pipe_a, Pipe& pipe_b) { // NOLINT
|
||||
SetupConnection(Pipe& pipe_a, Pipe& pipe_b,
|
||||
proto::connections::Medium medium) { // NOLINT
|
||||
auto channel_a = std::make_unique<MockEndpointChannel>(&pipe_b, &pipe_a);
|
||||
auto channel_b = std::make_unique<MockEndpointChannel>(&pipe_a, &pipe_b);
|
||||
// On initiator (A) side, we drop the first write, since this is a
|
||||
@@ -235,7 +273,7 @@ class BasePcpHandlerTest : public ::testing::Test {
|
||||
Invoke([channel = channel_a.get()](const ByteArray& data) {
|
||||
return channel->DoWrite(data);
|
||||
}));
|
||||
EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(Medium::BLE));
|
||||
EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium));
|
||||
EXPECT_CALL(*channel_a, GetLastReadTimestamp)
|
||||
.WillRepeatedly(Return(absl::Now()));
|
||||
EXPECT_CALL(*channel_a, IsPaused).WillRepeatedly(Return(false));
|
||||
@@ -247,7 +285,7 @@ class BasePcpHandlerTest : public ::testing::Test {
|
||||
Invoke([channel = channel_b.get()](const ByteArray& data) {
|
||||
return channel->DoWrite(data);
|
||||
}));
|
||||
EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(Medium::BLE));
|
||||
EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium));
|
||||
EXPECT_CALL(*channel_b, GetLastReadTimestamp)
|
||||
.WillRepeatedly(Return(absl::Now()));
|
||||
EXPECT_CALL(*channel_b, IsPaused).WillRepeatedly(Return(false));
|
||||
@@ -258,39 +296,50 @@ class BasePcpHandlerTest : public ::testing::Test {
|
||||
std::unique_ptr<MockEndpointChannel> channel_a,
|
||||
MockEndpointChannel* channel_b, ClientProxy* client,
|
||||
MockPcpHandler* pcp_handler,
|
||||
std::atomic_bool* flag = nullptr) {
|
||||
proto::connections::Medium connect_medium,
|
||||
std::atomic_int* flag = nullptr) {
|
||||
ConnectionRequestInfo info{
|
||||
.name = "ABCD",
|
||||
.endpoint_info = ByteArray{"ABCD"},
|
||||
.listener = connection_listener_,
|
||||
};
|
||||
ConnectionOptions options{
|
||||
.remote_bluetooth_mac_address =
|
||||
ByteArray{std::string("\x12\x34\x56\x78\x9a\xbc")},
|
||||
};
|
||||
EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call);
|
||||
EXPECT_CALL(*pcp_handler, CanSendOutgoingConnection)
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(*pcp_handler, GetStrategy)
|
||||
.WillRepeatedly(Return(Strategy::kP2pCluster));
|
||||
EXPECT_CALL(mock_connection_listener_.initiated_cb, Call).Times(1);
|
||||
EXPECT_CALL(*pcp_handler, ConnectImpl)
|
||||
.WillOnce(
|
||||
Invoke([&channel_a](ClientProxy* client,
|
||||
MockPcpHandler::DiscoveredEndpoint* endpoint) {
|
||||
return MockPcpHandler::ConnectImplResult{
|
||||
.medium = Medium::BLE,
|
||||
.status = {Status::kSuccess},
|
||||
.endpoint_channel = std::move(channel_a),
|
||||
};
|
||||
}));
|
||||
// Simulate successful discovery.
|
||||
auto encryption_runner = std::make_unique<EncryptionRunner>();
|
||||
pcp_handler->OnEndpointFound(
|
||||
client, std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
|
||||
{
|
||||
endpoint_id,
|
||||
info.name,
|
||||
"service",
|
||||
Medium::BLE,
|
||||
},
|
||||
MockContext{flag},
|
||||
}));
|
||||
auto allowed_mediums = pcp_handler->GetDiscoveryMediums();
|
||||
|
||||
EXPECT_CALL(*pcp_handler, ConnectImpl)
|
||||
.WillOnce(Invoke([&channel_a, connect_medium](
|
||||
ClientProxy* client,
|
||||
MockPcpHandler::DiscoveredEndpoint* endpoint) {
|
||||
return MockPcpHandler::ConnectImplResult{
|
||||
.medium = connect_medium,
|
||||
.status = {Status::kSuccess},
|
||||
.endpoint_channel = std::move(channel_a),
|
||||
};
|
||||
}));
|
||||
|
||||
for (const auto& discovered_medium : allowed_mediums) {
|
||||
pcp_handler->OnEndpointFound(
|
||||
client,
|
||||
std::make_shared<MockDiscoveredEndpoint>(MockDiscoveredEndpoint{
|
||||
{
|
||||
endpoint_id,
|
||||
info.endpoint_info,
|
||||
"service",
|
||||
discovered_medium,
|
||||
},
|
||||
MockContext{flag},
|
||||
}));
|
||||
}
|
||||
auto other_client = std::make_unique<ClientProxy>();
|
||||
|
||||
// Run peer crypto in advance, if channel_b is provided.
|
||||
@@ -299,8 +348,9 @@ class BasePcpHandlerTest : public ::testing::Test {
|
||||
encryption_runner->StartServer(other_client.get(), endpoint_id, channel_b,
|
||||
{});
|
||||
}
|
||||
EXPECT_EQ(pcp_handler->RequestConnection(client, endpoint_id, info),
|
||||
Status{Status::kSuccess});
|
||||
EXPECT_EQ(
|
||||
pcp_handler->RequestConnection(client, endpoint_id, info, options),
|
||||
Status{Status::kSuccess});
|
||||
NEARBY_LOG(INFO, "Stopping Encryption Runner");
|
||||
}
|
||||
|
||||
@@ -327,26 +377,29 @@ class BasePcpHandlerTest : public ::testing::Test {
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(BasePcpHandlerTest, ConstructorDestructorWorks) {
|
||||
TEST_P(BasePcpHandlerTest, ConstructorDestructorWorks) {
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, StartAdvertisingChangesState) {
|
||||
TEST_P(BasePcpHandlerTest, StartAdvertisingChangesState) {
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartAdvertising(&client, &pcp_handler);
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, StopAdvertisingChangesState) {
|
||||
TEST_P(BasePcpHandlerTest, StopAdvertisingChangesState) {
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartAdvertising(&client, &pcp_handler);
|
||||
EXPECT_CALL(pcp_handler, StopAdvertisingImpl(&client)).Times(1);
|
||||
EXPECT_TRUE(client.IsAdvertising());
|
||||
@@ -354,19 +407,21 @@ TEST_F(BasePcpHandlerTest, StopAdvertisingChangesState) {
|
||||
EXPECT_FALSE(client.IsAdvertising());
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, StartDiscoveryChangesState) {
|
||||
TEST_P(BasePcpHandlerTest, StartDiscoveryChangesState) {
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartDiscovery(&client, &pcp_handler);
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, StopDiscoveryChangesState) {
|
||||
TEST_P(BasePcpHandlerTest, StopDiscoveryChangesState) {
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartDiscovery(&client, &pcp_handler);
|
||||
EXPECT_CALL(pcp_handler, StopDiscoveryImpl(&client)).Times(1);
|
||||
EXPECT_TRUE(client.IsDiscovering());
|
||||
@@ -374,40 +429,46 @@ TEST_F(BasePcpHandlerTest, StopDiscoveryChangesState) {
|
||||
EXPECT_FALSE(client.IsDiscovering());
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, RequestConnectionChangesState) {
|
||||
TEST_P(BasePcpHandlerTest, RequestConnectionChangesState) {
|
||||
std::string endpoint_id{"1234"};
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartDiscovery(&client, &pcp_handler);
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_);
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums();
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
EXPECT_CALL(*channel_a, CloseImpl).Times(1);
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
|
||||
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(), &client,
|
||||
&pcp_handler);
|
||||
&pcp_handler, connect_medium);
|
||||
NEARBY_LOG(INFO, "RequestConnection complete");
|
||||
channel_b->Close();
|
||||
pcp_handler.DisconnectFromEndpointManager();
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, AcceptConnectionChangesState) {
|
||||
TEST_P(BasePcpHandlerTest, AcceptConnectionChangesState) {
|
||||
std::string endpoint_id{"1234"};
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartDiscovery(&client, &pcp_handler);
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_);
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums();
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
EXPECT_CALL(*channel_a, CloseImpl).Times(1);
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(), &client,
|
||||
&pcp_handler);
|
||||
&pcp_handler, connect_medium);
|
||||
NEARBY_LOG(INFO, "Attempting to accept connection: id=%s",
|
||||
endpoint_id.c_str());
|
||||
EXPECT_EQ(pcp_handler.AcceptConnection(&client, endpoint_id, {}),
|
||||
@@ -418,18 +479,21 @@ TEST_F(BasePcpHandlerTest, AcceptConnectionChangesState) {
|
||||
pcp_handler.DisconnectFromEndpointManager();
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, RejectConnectionChangesState) {
|
||||
TEST_P(BasePcpHandlerTest, RejectConnectionChangesState) {
|
||||
std::string endpoint_id{"1234"};
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartDiscovery(&client, &pcp_handler);
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_);
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums();
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium);
|
||||
auto& channel_b = channel_pair.second;
|
||||
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(1);
|
||||
RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b.get(),
|
||||
&client, &pcp_handler);
|
||||
&client, &pcp_handler, connect_medium);
|
||||
NEARBY_LOGS(INFO) << "Attempting to reject connection: id=" << endpoint_id;
|
||||
EXPECT_EQ(pcp_handler.RejectConnection(&client, endpoint_id),
|
||||
Status{Status::kSuccess});
|
||||
@@ -438,20 +502,23 @@ TEST_F(BasePcpHandlerTest, RejectConnectionChangesState) {
|
||||
pcp_handler.DisconnectFromEndpointManager();
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, OnIncomingFrameChangesState) {
|
||||
TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) {
|
||||
std::string endpoint_id{"1234"};
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartDiscovery(&client, &pcp_handler);
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_);
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums();
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
EXPECT_CALL(*channel_a, CloseImpl).Times(1);
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(), &client,
|
||||
&pcp_handler);
|
||||
&pcp_handler, connect_medium);
|
||||
NEARBY_LOGS(INFO) << "Attempting to accept connection: id=" << endpoint_id;
|
||||
EXPECT_CALL(mock_connection_listener_.accepted_cb, Call).Times(1);
|
||||
EXPECT_CALL(mock_connection_listener_.disconnected_cb, Call)
|
||||
@@ -462,28 +529,33 @@ TEST_F(BasePcpHandlerTest, OnIncomingFrameChangesState) {
|
||||
auto frame =
|
||||
parser::FromBytes(parser::ForConnectionResponse(Status::kSuccess));
|
||||
pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, &client,
|
||||
Medium::BLE);
|
||||
connect_medium);
|
||||
NEARBY_LOGS(INFO) << "Closing connection: id=" << endpoint_id;
|
||||
channel_b->Close();
|
||||
pcp_handler.DisconnectFromEndpointManager();
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) {
|
||||
std::atomic_bool destroyed_flag = false;
|
||||
TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) {
|
||||
std::atomic_int destroyed_flag = 0;
|
||||
int mediums_count = 0;
|
||||
{
|
||||
std::string endpoint_id{"1234"};
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&em, &ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartDiscovery(&client, &pcp_handler);
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_);
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums();
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
EXPECT_CALL(*channel_a, CloseImpl).Times(1);
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(),
|
||||
&client, &pcp_handler, &destroyed_flag);
|
||||
&client, &pcp_handler, connect_medium, &destroyed_flag);
|
||||
mediums_count = mediums.size();
|
||||
NEARBY_LOG(INFO, "Attempting to accept connection: id=%s",
|
||||
endpoint_id.c_str());
|
||||
EXPECT_EQ(pcp_handler.AcceptConnection(&client, endpoint_id, {}),
|
||||
@@ -493,9 +565,57 @@ TEST_F(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) {
|
||||
channel_b->Close();
|
||||
pcp_handler.DisconnectFromEndpointManager();
|
||||
}
|
||||
EXPECT_TRUE(destroyed_flag.load());
|
||||
EXPECT_EQ(destroyed_flag.load(), mediums_count);
|
||||
}
|
||||
|
||||
TEST_P(BasePcpHandlerTest, MultipleMediumsProduceSingleEndpointLostEvent) {
|
||||
BooleanMediumSelector allowed = GetParam();
|
||||
if (allowed.Count(true) < 2) {
|
||||
// Ignore single-medium test cases, and implicit "all mediums" case.
|
||||
SUCCEED();
|
||||
return;
|
||||
}
|
||||
std::atomic_int destroyed_flag = 0;
|
||||
int mediums_count = 0;
|
||||
{
|
||||
std::string endpoint_id{"1234"};
|
||||
ClientProxy client;
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
MockPcpHandler pcp_handler(&m, &em, &ecm);
|
||||
StartDiscovery(&client, &pcp_handler);
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums();
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(pipe_a_, pipe_b_, connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
EXPECT_CALL(*channel_a, CloseImpl).Times(1);
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
|
||||
EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call).Times(1);
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(),
|
||||
&client, &pcp_handler, connect_medium, &destroyed_flag);
|
||||
auto allowed_mediums = pcp_handler.GetDiscoveryMediums();
|
||||
mediums_count = allowed_mediums.size();
|
||||
NEARBY_LOG(INFO, "Attempting to accept connection: id=%s",
|
||||
endpoint_id.c_str());
|
||||
EXPECT_EQ(pcp_handler.AcceptConnection(&client, endpoint_id, {}),
|
||||
Status{Status::kSuccess});
|
||||
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
|
||||
for (const auto* endpoint :
|
||||
pcp_handler.GetDiscoveredEndpoints(endpoint_id)) {
|
||||
pcp_handler.OnEndpointLost(&client, *endpoint);
|
||||
}
|
||||
NEARBY_LOG(INFO, "Closing connection: id=%s", endpoint_id.c_str());
|
||||
channel_b->Close();
|
||||
pcp_handler.DisconnectFromEndpointManager();
|
||||
}
|
||||
EXPECT_EQ(destroyed_flag.load(), mediums_count);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ParameterizedBasePcpHandlerTest, BasePcpHandlerTest,
|
||||
::testing::ValuesIn(kTestCases));
|
||||
|
||||
} // namespace
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@@ -27,12 +27,33 @@ namespace connections {
|
||||
BleAdvertisement::BleAdvertisement(Version version, Pcp pcp,
|
||||
const ByteArray& service_id_hash,
|
||||
const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& bluetooth_mac_address) {
|
||||
if (version != Version::kV1 ||
|
||||
service_id_hash.size() != kServiceIdHashLength || endpoint_id.empty() ||
|
||||
DoInitialize(/*fast_advertisement=*/false, version, pcp, service_id_hash,
|
||||
endpoint_id, endpoint_info, bluetooth_mac_address);
|
||||
}
|
||||
|
||||
BleAdvertisement::BleAdvertisement(Version version, Pcp pcp,
|
||||
const std::string& endpoint_id,
|
||||
const ByteArray& endpoint_info) {
|
||||
DoInitialize(/*fast_advertisement=*/true, version, pcp, {}, endpoint_id,
|
||||
endpoint_info, {});
|
||||
}
|
||||
|
||||
void BleAdvertisement::DoInitialize(bool fast_advertisement, Version version,
|
||||
Pcp pcp, const ByteArray& service_id_hash,
|
||||
const std::string& endpoint_id,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& bluetooth_mac_address) {
|
||||
fast_advertisement_ = fast_advertisement;
|
||||
if (!fast_advertisement_) {
|
||||
if (service_id_hash.size() != kServiceIdHashLength) return;
|
||||
}
|
||||
int max_endpoint_info_length =
|
||||
fast_advertisement_ ? kMaxFastEndpointInfoLength : kMaxEndpointInfoLength;
|
||||
if (version != Version::kV1 || endpoint_id.empty() ||
|
||||
endpoint_id.length() != kEndpointIdLength ||
|
||||
endpoint_name.length() > kMaxEndpointNameLength) {
|
||||
endpoint_info.size() > max_endpoint_info_length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,20 +70,29 @@ BleAdvertisement::BleAdvertisement(Version version, Pcp pcp,
|
||||
pcp_ = pcp;
|
||||
service_id_hash_ = service_id_hash;
|
||||
endpoint_id_ = endpoint_id;
|
||||
endpoint_name_ = endpoint_name;
|
||||
if (!BluetoothMacAddressHexStringToBytes(bluetooth_mac_address).Empty()) {
|
||||
bluetooth_mac_address_ = bluetooth_mac_address;
|
||||
endpoint_info_ = endpoint_info;
|
||||
if (!fast_advertisement_) {
|
||||
if (!BluetoothUtils::FromString(bluetooth_mac_address).Empty()) {
|
||||
bluetooth_mac_address_ = bluetooth_mac_address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BleAdvertisement::BleAdvertisement(const ByteArray& ble_advertisement_bytes) {
|
||||
BleAdvertisement::BleAdvertisement(bool fast_advertisement,
|
||||
const ByteArray& ble_advertisement_bytes) {
|
||||
fast_advertisement_ = fast_advertisement;
|
||||
|
||||
if (ble_advertisement_bytes.Empty()) {
|
||||
NEARBY_LOG(ERROR,
|
||||
"Cannot deserialize BleAdvertisement: null bytes passed in.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ble_advertisement_bytes.size() < kMinAdvertisementLength) {
|
||||
int min_advertisement_length = fast_advertisement_
|
||||
? kMinFastAdvertisementLength
|
||||
: kMinAdvertisementLength;
|
||||
|
||||
if (ble_advertisement_bytes.size() < min_advertisement_length) {
|
||||
NEARBY_LOG(ERROR,
|
||||
"Cannot deserialize BleAdvertisement: expecting min %d raw "
|
||||
"bytes, got %" PRIu64,
|
||||
@@ -96,43 +126,44 @@ BleAdvertisement::BleAdvertisement(const ByteArray& ble_advertisement_bytes) {
|
||||
pcp_);
|
||||
}
|
||||
|
||||
// The next 3 bytes are supposed to be the service_id_hash.
|
||||
service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength);
|
||||
// The next 3 bytes are supposed to be the service_id_hash if not fast
|
||||
// advertisment.
|
||||
if (!fast_advertisement_)
|
||||
service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength);
|
||||
|
||||
// The next 4 bytes are supposed to be the endpoint_id.
|
||||
endpoint_id_ = std::string{base_input_stream.ReadBytes(kEndpointIdLength)};
|
||||
|
||||
// The next 1 byte are supposed to be the length of the endpoint_name.
|
||||
std::uint32_t expected_endpoint_name_length = base_input_stream.ReadUint8();
|
||||
// The next 1 byte are supposed to be the length of the endpoint_info.
|
||||
std::uint32_t expected_endpoint_info_length = base_input_stream.ReadUint8();
|
||||
|
||||
// The next x bytes are the endpoint name. (Max length is 131 bytes).
|
||||
// Check that the stated endpoint_name_length is the same as what we
|
||||
// received.
|
||||
auto endpoint_name_bytes =
|
||||
base_input_stream.ReadBytes(expected_endpoint_name_length);
|
||||
if (endpoint_name_bytes.Empty() ||
|
||||
endpoint_name_bytes.size() != expected_endpoint_name_length) {
|
||||
// The next x bytes are the endpoint info. (Max length is 131 bytes or 17
|
||||
// bytes as fast_advertisement being true).
|
||||
endpoint_info_ = base_input_stream.ReadBytes(expected_endpoint_info_length);
|
||||
const int max_endpoint_info_length =
|
||||
fast_advertisement_ ? kMaxFastEndpointInfoLength : kMaxEndpointInfoLength;
|
||||
if (endpoint_info_.Empty() ||
|
||||
endpoint_info_.size() != expected_endpoint_info_length ||
|
||||
endpoint_info_.size() > max_endpoint_info_length) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Cannot deserialize BleAdvertisement: expected "
|
||||
"endpointName to be %d bytes, got %" PRIu64,
|
||||
expected_endpoint_name_length, endpoint_name_bytes.size());
|
||||
"Cannot deserialize BleAdvertisement(fast advertisement=%d): "
|
||||
"expected endpointInfo to be %d bytes, got %" PRIu64,
|
||||
fast_advertisement_, expected_endpoint_info_length,
|
||||
endpoint_info_.size());
|
||||
|
||||
// Clear enpoint_id for validadity.
|
||||
endpoint_id_.clear();
|
||||
return;
|
||||
}
|
||||
endpoint_name_ = std::string{endpoint_name_bytes};
|
||||
|
||||
// The next 6 bytes are the bluetooth mac address.
|
||||
auto bluetooth_mac_address_bytes =
|
||||
base_input_stream.ReadBytes(kBluetoothMacAddressLength);
|
||||
// If the Bluetooth MAC Address bytes are unset or invalid, leave the
|
||||
// string empty. Otherwise, convert it to the proper colon delimited
|
||||
// format.
|
||||
if (!IsBluetoothMacAddressUnset(bluetooth_mac_address_bytes)) {
|
||||
// The next 6 bytes are the bluetooth mac address if not fast advertisment.
|
||||
if (!fast_advertisement_) {
|
||||
auto bluetooth_mac_address_bytes =
|
||||
base_input_stream.ReadBytes(BluetoothUtils::kBluetoothMacAddressLength);
|
||||
bluetooth_mac_address_ =
|
||||
HexBytesToColonDelimitedString(bluetooth_mac_address_bytes);
|
||||
BluetoothUtils::ToString(bluetooth_mac_address_bytes);
|
||||
}
|
||||
|
||||
base_input_stream.Close();
|
||||
}
|
||||
|
||||
@@ -147,74 +178,35 @@ BleAdvertisement::operator ByteArray() const {
|
||||
// The next 5 bits are the Pcp.
|
||||
version_and_pcp_byte |= static_cast<char>(pcp_) & kPcpBitmask;
|
||||
|
||||
// clang-format off
|
||||
std::string out = absl::StrCat(std::string(1, version_and_pcp_byte),
|
||||
std::string(service_id_hash_),
|
||||
endpoint_id_,
|
||||
std::string(1, endpoint_name_.size()),
|
||||
endpoint_name_);
|
||||
// clang-format on
|
||||
std::string out;
|
||||
if (fast_advertisement_) {
|
||||
// clang-format off
|
||||
out = absl::StrCat(std::string(1, version_and_pcp_byte),
|
||||
endpoint_id_,
|
||||
std::string(1, endpoint_info_.size()),
|
||||
std::string(endpoint_info_));
|
||||
// clang-format on
|
||||
} else {
|
||||
// clang-format off
|
||||
out = absl::StrCat(std::string(1, version_and_pcp_byte),
|
||||
std::string(service_id_hash_),
|
||||
endpoint_id_,
|
||||
std::string(1, endpoint_info_.size()),
|
||||
std::string(endpoint_info_));
|
||||
// clang-format on
|
||||
|
||||
// The next 6 bytes are the bluetooth mac address. If bluetooth_mac_address is
|
||||
// invalid or empty, we get back a null byte array.
|
||||
auto bluetooth_mac_address_bytes(
|
||||
BluetoothMacAddressHexStringToBytes(bluetooth_mac_address_));
|
||||
if (!bluetooth_mac_address_bytes.Empty()) {
|
||||
absl::StrAppend(&out, std::string(bluetooth_mac_address_bytes));
|
||||
// The next 6 bytes are the bluetooth mac address. If bluetooth_mac_address
|
||||
// is invalid or empty, we get back a null byte array.
|
||||
auto bluetooth_mac_address_bytes{
|
||||
BluetoothUtils::FromString(bluetooth_mac_address_)};
|
||||
if (!bluetooth_mac_address_bytes.Empty()) {
|
||||
absl::StrAppend(&out, std::string(bluetooth_mac_address_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
return ByteArray(std::move(out));
|
||||
}
|
||||
|
||||
ByteArray BleAdvertisement::BluetoothMacAddressHexStringToBytes(
|
||||
const std::string& bluetooth_mac_address) const {
|
||||
std::string bt_mac_address(bluetooth_mac_address);
|
||||
|
||||
// Remove the colon delimiters.
|
||||
bt_mac_address.erase(
|
||||
std::remove(bt_mac_address.begin(), bt_mac_address.end(), ':'),
|
||||
bt_mac_address.end());
|
||||
|
||||
// If the bluetooth mac address is invalid (wrong size), return a null byte
|
||||
// array.
|
||||
if (bt_mac_address.length() != kBluetoothMacAddressLength * 2) {
|
||||
return ByteArray();
|
||||
}
|
||||
|
||||
// Convert to bytes. If MAC Address bytes are unset, return a null byte array.
|
||||
auto bt_mac_address_string(absl::HexStringToBytes(bt_mac_address));
|
||||
auto bt_mac_address_bytes =
|
||||
ByteArray(bt_mac_address_string.data(), bt_mac_address_string.size());
|
||||
if (IsBluetoothMacAddressUnset(bt_mac_address_bytes)) {
|
||||
return ByteArray();
|
||||
}
|
||||
return bt_mac_address_bytes;
|
||||
}
|
||||
|
||||
std::string BleAdvertisement::HexBytesToColonDelimitedString(
|
||||
const ByteArray& hex_bytes) const {
|
||||
// Convert the hex bytes to a string.
|
||||
std::string colon_delimited_string(
|
||||
absl::BytesToHexString(std::string(hex_bytes.data(), hex_bytes.size())));
|
||||
absl::AsciiStrToUpper(&colon_delimited_string);
|
||||
|
||||
// Insert the colons.
|
||||
for (int i = colon_delimited_string.length() - 2; i > 0; i -= 2) {
|
||||
colon_delimited_string.insert(i, ":");
|
||||
}
|
||||
return colon_delimited_string;
|
||||
}
|
||||
|
||||
bool BleAdvertisement::IsBluetoothMacAddressUnset(
|
||||
const ByteArray& bluetooth_mac_address_bytes) const {
|
||||
for (int i = 0; i < bluetooth_mac_address_bytes.size(); i++) {
|
||||
if (bluetooth_mac_address_bytes.data()[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define CORE_V2_INTERNAL_BLE_ADVERTISEMENT_H_
|
||||
|
||||
#include "core_v2/internal/pcp.h"
|
||||
#include "platform_v2/base/bluetooth_utils.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
|
||||
namespace location {
|
||||
@@ -25,8 +26,11 @@ namespace connections {
|
||||
// Represents the format of the Connections Ble Advertisement used in
|
||||
// Advertising + Discovery.
|
||||
//
|
||||
// <p>[VERSION][PCP][SERVICE_ID_HASH][ENDPOINT_ID][ENDPOINT_NAME_SIZE]
|
||||
// [ENDPOINT_NAME][BLUETOOTH_MAC]
|
||||
// <p>[VERSION][PCP][SERVICE_ID_HASH][ENDPOINT_ID][ENDPOINT_INFO_SIZE]
|
||||
// [ENDPOINT_INFO][BLUETOOTH_MAC]
|
||||
//
|
||||
// <p>The fast version of this advertisement simply omits SERVICE_ID_HASH and
|
||||
// the Bluetooth MAC address.
|
||||
//
|
||||
// <p>See go/connections-ble-advertisement for more information.
|
||||
class BleAdvertisement {
|
||||
@@ -39,28 +43,35 @@ class BleAdvertisement {
|
||||
// can never go beyond V7.
|
||||
};
|
||||
|
||||
static constexpr int kServiceIdHashLength = 3;
|
||||
static constexpr int kVersionAndPcpLength = 1;
|
||||
// Should be defined as EndpointManager<Platform>::kEndpointIdLength, but that
|
||||
// involves making BleAdvertisement templatized on Platform just for
|
||||
// that one little thing, so forget it (at least for now).
|
||||
static constexpr int kEndpointIdLength = 4;
|
||||
static constexpr int kEndpointNameSizeLength = 1;
|
||||
static constexpr int kBluetoothMacAddressLength = 6;
|
||||
static constexpr int kMinAdvertisementLength =
|
||||
kVersionAndPcpLength + kServiceIdHashLength + kEndpointIdLength +
|
||||
kEndpointNameSizeLength + kBluetoothMacAddressLength;
|
||||
static constexpr int kMaxEndpointNameLength = 131;
|
||||
static constexpr int kVersionBitmask = 0x0E0;
|
||||
static constexpr int kPcpBitmask = 0x01F;
|
||||
static constexpr int kEndpointNameLengthBitmask = 0x0FF;
|
||||
static constexpr int kServiceIdHashLength = 3;
|
||||
static constexpr int kEndpointIdLength = 4;
|
||||
static constexpr int kEndpointInfoSizeLength = 1;
|
||||
static constexpr int kEndpointInfoLengthBitmask = 0x0FF;
|
||||
static constexpr int kMinAdvertisementLength =
|
||||
kVersionAndPcpLength + kServiceIdHashLength + kEndpointIdLength +
|
||||
kEndpointInfoSizeLength + BluetoothUtils::kBluetoothMacAddressLength;
|
||||
|
||||
// The difference between normal and fast advertisements is that the fast one
|
||||
// omits the SERVICE_ID_HASH and Bluetooth MAC address. This is done to save
|
||||
// space.
|
||||
static constexpr int kMinFastAdvertisementLength =
|
||||
kMinAdvertisementLength - kServiceIdHashLength -
|
||||
BluetoothUtils::kBluetoothMacAddressLength;
|
||||
static constexpr int kMaxEndpointInfoLength = 131;
|
||||
static constexpr int kMaxFastEndpointInfoLength = 17;
|
||||
|
||||
BleAdvertisement() = default;
|
||||
BleAdvertisement(Version version, Pcp pcp, const std::string& endpoint_id,
|
||||
const ByteArray& endpoint_info);
|
||||
BleAdvertisement(Version version, Pcp pcp, const ByteArray& service_id_hash,
|
||||
const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& bluetooth_mac_address);
|
||||
explicit BleAdvertisement(const ByteArray& ble_advertisement_bytes);
|
||||
BleAdvertisement(bool fast_advertisement,
|
||||
const ByteArray& ble_advertisement_bytes);
|
||||
BleAdvertisement(const BleAdvertisement&) = default;
|
||||
BleAdvertisement& operator=(const BleAdvertisement&) = default;
|
||||
BleAdvertisement(BleAdvertisement&&) = default;
|
||||
@@ -70,25 +81,27 @@ class BleAdvertisement {
|
||||
explicit operator ByteArray() const;
|
||||
|
||||
bool IsValid() const { return !endpoint_id_.empty(); }
|
||||
bool IsFastAdvertisement() const { return fast_advertisement_; }
|
||||
Version GetVersion() const { return version_; }
|
||||
Pcp GetPcp() const { return pcp_; }
|
||||
ByteArray GetServiceIdHash() const { return service_id_hash_; }
|
||||
std::string GetEndpointId() const { return endpoint_id_; }
|
||||
std::string GetEndpointName() const { return endpoint_name_; }
|
||||
ByteArray GetEndpointInfo() const { return endpoint_info_; }
|
||||
std::string GetBluetoothMacAddress() const { return bluetooth_mac_address_; }
|
||||
|
||||
private:
|
||||
ByteArray BluetoothMacAddressHexStringToBytes(
|
||||
const std::string& bluetooth_mac_address) const;
|
||||
std::string HexBytesToColonDelimitedString(const ByteArray& hex_bytes) const;
|
||||
bool IsBluetoothMacAddressUnset(
|
||||
const ByteArray& bluetooth_mac_address_bytes) const;
|
||||
void DoInitialize(bool fast_advertisement, Version version, Pcp pcp,
|
||||
const ByteArray& service_id_hash,
|
||||
const std::string& endpoint_id,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& bluetooth_mac_address);
|
||||
|
||||
bool fast_advertisement_ = false;
|
||||
Version version_ = Version::kUndefined;
|
||||
Pcp pcp_ = Pcp::kUnknown;
|
||||
ByteArray service_id_hash_;
|
||||
std::string endpoint_id_;
|
||||
std::string endpoint_name_;
|
||||
ByteArray endpoint_info_;
|
||||
std::string bluetooth_mac_address_;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,81 +23,138 @@ namespace {
|
||||
|
||||
constexpr BleAdvertisement::Version kVersion = BleAdvertisement::Version::kV1;
|
||||
constexpr Pcp kPcp = Pcp::kP2pCluster;
|
||||
constexpr absl::string_view kServiceIDHashBytes{"\x0a\x0b\x0c"};
|
||||
constexpr absl::string_view kEndPointID{"AB12"};
|
||||
constexpr absl::string_view kServiceIdHashBytes{"\x0a\x0b\x0c"};
|
||||
constexpr absl::string_view kEndpointId{"AB12"};
|
||||
constexpr absl::string_view kEndpointName{
|
||||
"How much wood can a woodchuck chuck if a wood chuck would chuck wood?"};
|
||||
constexpr absl::string_view kFastAdvertisementEndpointName{"Fast Advertise"};
|
||||
constexpr absl::string_view kBluetoothMacAddress{"00:00:E6:88:64:13"};
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionWorks) {
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
std::string(kBluetoothMacAddress)};
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, std::string(kBluetoothMacAddress)};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_FALSE(ble_advertisement.IsFastAdvertisement());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointID, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(kEndpointName, ble_advertisement.GetEndpointName());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionWorksWithEmptyEndpointName) {
|
||||
std::string empty_endpoint_name;
|
||||
TEST(BleAdvertisementTest, ConstructionWorksForFastAdvertisement) {
|
||||
ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)};
|
||||
BleAdvertisement ble_advertisement{kVersion, kPcp, std::string(kEndpointId),
|
||||
fast_endpoint_info};
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_TRUE(ble_advertisement.IsFastAdvertisement());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(fast_endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionWorksWithEmptyEndpointInfo) {
|
||||
ByteArray empty_endpoint_info;
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
empty_endpoint_name,
|
||||
std::string(kEndpointId),
|
||||
empty_endpoint_info,
|
||||
std::string(kBluetoothMacAddress)};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_FALSE(ble_advertisement.IsFastAdvertisement());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointID, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(empty_endpoint_name, ble_advertisement.GetEndpointName());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(empty_endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionWorksWithEmojiEndpointName) {
|
||||
std::string emoji_endpoint_name{"\u0001F450 \u0001F450"};
|
||||
TEST(BleAdvertisementTest,
|
||||
ConstructionWorksWithEmptyEndpointInfoForFastAdvertisement) {
|
||||
ByteArray empty_endpoint_info;
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion, kPcp, std::string(kEndpointId),
|
||||
empty_endpoint_info};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_TRUE(ble_advertisement.IsFastAdvertisement());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(empty_endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionWorksWithEmojiEndpointInfo) {
|
||||
ByteArray emoji_endpoint_info{std::string("\u0001F450 \u0001F450")};
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
emoji_endpoint_name,
|
||||
std::string(kEndpointId),
|
||||
emoji_endpoint_info,
|
||||
std::string(kBluetoothMacAddress)};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_FALSE(ble_advertisement.IsFastAdvertisement());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointID, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(emoji_endpoint_name, ble_advertisement.GetEndpointName());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(emoji_endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionFailsWithLongEndpointName) {
|
||||
std::string long_endpoint_name(BleAdvertisement::kMaxEndpointNameLength + 1,
|
||||
TEST(BleAdvertisementTest,
|
||||
ConstructionWorksWithEmojiEndpointInfoForFastAdvertisement) {
|
||||
ByteArray emoji_endpoint_info{std::string("\u0001F450 \u0001F450")};
|
||||
|
||||
BleAdvertisement ble_advertisement{kVersion, kPcp, std::string(kEndpointId),
|
||||
emoji_endpoint_info};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_TRUE(ble_advertisement.IsFastAdvertisement());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(emoji_endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionFailsWithLongEndpointInfo) {
|
||||
std::string long_endpoint_name(BleAdvertisement::kMaxEndpointInfoLength + 1,
|
||||
'x');
|
||||
ByteArray long_endpoint_info{long_endpoint_name};
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
long_endpoint_name,
|
||||
std::string(kBluetoothMacAddress)};
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
long_endpoint_info, std::string(kBluetoothMacAddress)};
|
||||
|
||||
EXPECT_FALSE(ble_advertisement.IsValid());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest,
|
||||
ConstructionFailsWithLongEndpointInfoForFastAdvertisement) {
|
||||
std::string long_endpoint_name(
|
||||
BleAdvertisement::kMaxFastEndpointInfoLength + 1, 'x');
|
||||
ByteArray long_endpoint_info{long_endpoint_name};
|
||||
|
||||
BleAdvertisement ble_advertisement{kVersion, kPcp, std::string(kEndpointId),
|
||||
long_endpoint_info};
|
||||
|
||||
EXPECT_FALSE(ble_advertisement.IsValid());
|
||||
}
|
||||
@@ -105,13 +162,23 @@ TEST(BleAdvertisementTest, ConstructionFailsWithLongEndpointName) {
|
||||
TEST(BleAdvertisementTest, ConstructionFailsWithBadVersion) {
|
||||
auto bad_version = static_cast<BleAdvertisement::Version>(666);
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{bad_version,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
std::string(kBluetoothMacAddress)};
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
bad_version, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, std::string(kBluetoothMacAddress)};
|
||||
|
||||
EXPECT_FALSE(ble_advertisement.IsValid());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest,
|
||||
ConstructionFailsWithBadVersionForFastAdvertisement) {
|
||||
auto bad_version = static_cast<BleAdvertisement::Version>(666);
|
||||
|
||||
ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
bad_version, kPcp, std::string(kEndpointId), fast_endpoint_info};
|
||||
|
||||
EXPECT_FALSE(ble_advertisement.IsValid());
|
||||
}
|
||||
@@ -119,13 +186,22 @@ TEST(BleAdvertisementTest, ConstructionFailsWithBadVersion) {
|
||||
TEST(BleAdvertisementTest, ConstructionFailsWithBadPCP) {
|
||||
auto bad_pcp = static_cast<Pcp>(666);
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
bad_pcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
std::string(kBluetoothMacAddress)};
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, bad_pcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, std::string(kBluetoothMacAddress)};
|
||||
|
||||
EXPECT_FALSE(ble_advertisement.IsValid());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionFailsWithBadPCPForFastAdvertisement) {
|
||||
auto bad_pcp = static_cast<Pcp>(666);
|
||||
|
||||
ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, bad_pcp, std::string(kEndpointId), fast_endpoint_info};
|
||||
|
||||
EXPECT_FALSE(ble_advertisement.IsValid());
|
||||
}
|
||||
@@ -133,13 +209,12 @@ TEST(BleAdvertisementTest, ConstructionFailsWithBadPCP) {
|
||||
TEST(BleAdvertisementTest, ConstructionSucceedsWithEmptyBluetoothMacAddress) {
|
||||
std::string empty_bluetooth_mac_address = "";
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
empty_bluetooth_mac_address};
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, empty_bluetooth_mac_address};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
}
|
||||
@@ -147,125 +222,180 @@ TEST(BleAdvertisementTest, ConstructionSucceedsWithEmptyBluetoothMacAddress) {
|
||||
TEST(BleAdvertisementTest, ConstructionSucceedsWithInvalidBluetoothMacAddress) {
|
||||
std::string bad_bluetooth_mac_address = "022:00";
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
bad_bluetooth_mac_address};
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, bad_bluetooth_mac_address};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointID, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(kEndpointName, ble_advertisement.GetEndpointName());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
EXPECT_TRUE(ble_advertisement.GetBluetoothMacAddress().empty());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionFromBytesWorks) {
|
||||
// Serialize good data into a good Ble Advertisement.
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement org_ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
std::string(kBluetoothMacAddress)};
|
||||
auto ble_advertisement_bytes = ByteArray(org_ble_advertisement);
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement org_ble_advertisement{
|
||||
kVersion, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, std::string(kBluetoothMacAddress)};
|
||||
ByteArray ble_advertisement_bytes(org_ble_advertisement);
|
||||
|
||||
BleAdvertisement ble_advertisement{ble_advertisement_bytes};
|
||||
BleAdvertisement ble_advertisement{false, ble_advertisement_bytes};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_FALSE(ble_advertisement.IsFastAdvertisement());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(service_id_hash, ble_advertisement.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointID, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(kEndpointName, ble_advertisement.GetEndpointName());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
EXPECT_EQ(kBluetoothMacAddress, ble_advertisement.GetBluetoothMacAddress());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionFromBytesWorksForFastAdvertisement) {
|
||||
// Serialize good data into a good Ble Advertisement.
|
||||
ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)};
|
||||
BleAdvertisement org_ble_advertisement{
|
||||
kVersion, kPcp, std::string(kEndpointId), fast_endpoint_info};
|
||||
ByteArray ble_advertisement_bytes(org_ble_advertisement);
|
||||
|
||||
BleAdvertisement ble_advertisement{true, ble_advertisement_bytes};
|
||||
|
||||
EXPECT_TRUE(ble_advertisement.IsValid());
|
||||
EXPECT_TRUE(ble_advertisement.IsFastAdvertisement());
|
||||
EXPECT_EQ(kVersion, ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(kEndpointId, ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(fast_endpoint_info, ble_advertisement.GetEndpointInfo());
|
||||
}
|
||||
|
||||
// Bytes at the end should be ignored so that they can be used as reserve bytes
|
||||
// in the future.
|
||||
TEST(BleAdvertisementTest, ConstructionFromLongLengthBytesWorks) {
|
||||
// Serialize good data into a good Ble Advertisement.
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
std::string(kBluetoothMacAddress)};
|
||||
auto ble_advertisement_bytes = ByteArray(ble_advertisement);
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, std::string(kBluetoothMacAddress)};
|
||||
ByteArray ble_advertisement_bytes(ble_advertisement);
|
||||
|
||||
// Add bytes to the end of the valid Ble advertisement.
|
||||
auto long_ble_advertisement_bytes =
|
||||
ByteArray(BleAdvertisement::kMinAdvertisementLength + 1000);
|
||||
ByteArray long_ble_advertisement_bytes(
|
||||
BleAdvertisement::kMinAdvertisementLength + 1000);
|
||||
ASSERT_LE(ble_advertisement_bytes.size(),
|
||||
long_ble_advertisement_bytes.size());
|
||||
memcpy(long_ble_advertisement_bytes.data(),
|
||||
ble_advertisement_bytes.data(),
|
||||
memcpy(long_ble_advertisement_bytes.data(), ble_advertisement_bytes.data(),
|
||||
ble_advertisement_bytes.size());
|
||||
|
||||
BleAdvertisement long_ble_advertisement{long_ble_advertisement_bytes};
|
||||
BleAdvertisement long_ble_advertisement{false, long_ble_advertisement_bytes};
|
||||
|
||||
EXPECT_TRUE(long_ble_advertisement.IsValid());
|
||||
EXPECT_EQ(kVersion, long_ble_advertisement.GetVersion());
|
||||
EXPECT_EQ(kPcp, long_ble_advertisement.GetPcp());
|
||||
EXPECT_EQ(service_id_hash, long_ble_advertisement.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointID, long_ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(kEndpointName, long_ble_advertisement.GetEndpointName());
|
||||
EXPECT_EQ(kEndpointId, long_ble_advertisement.GetEndpointId());
|
||||
EXPECT_EQ(endpoint_info, long_ble_advertisement.GetEndpointInfo());
|
||||
EXPECT_EQ(kBluetoothMacAddress,
|
||||
long_ble_advertisement.GetBluetoothMacAddress());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionFromNullBytesFails) {
|
||||
BleAdvertisement ble_advertisement{ByteArray{}};
|
||||
BleAdvertisement ble_advertisement{false, ByteArray{}};
|
||||
|
||||
EXPECT_FALSE(ble_advertisement.IsValid());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionFromNullBytesFailsForFastAdvertisement) {
|
||||
BleAdvertisement ble_advertisement{true, ByteArray{}};
|
||||
|
||||
EXPECT_FALSE(ble_advertisement.IsValid());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest, ConstructionFromShortLengthBytesFails) {
|
||||
// Serialize good data into a good Ble Advertisement.
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
std::string(kBluetoothMacAddress)};
|
||||
auto ble_advertisement_bytes = ByteArray(ble_advertisement);
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, std::string(kBluetoothMacAddress)};
|
||||
ByteArray ble_advertisement_bytes(ble_advertisement);
|
||||
|
||||
// Shorten the valid Ble Advertisement.
|
||||
ByteArray short_ble_advertisement_bytes{
|
||||
ble_advertisement_bytes.data(),
|
||||
BleAdvertisement::kMinAdvertisementLength - 1};
|
||||
|
||||
BleAdvertisement short_ble_advertisement{short_ble_advertisement_bytes};
|
||||
BleAdvertisement short_ble_advertisement{false,
|
||||
short_ble_advertisement_bytes};
|
||||
|
||||
EXPECT_FALSE(short_ble_advertisement.IsValid());
|
||||
}
|
||||
TEST(BleAdvertisementTest,
|
||||
ConstructionFromShortLengthBytesFailsForFastAdvertisement) {
|
||||
// Serialize good data into a good Ble Advertisement.
|
||||
ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)};
|
||||
BleAdvertisement ble_advertisement{kVersion, kPcp, std::string(kEndpointId),
|
||||
fast_endpoint_info};
|
||||
ByteArray ble_advertisement_bytes(ble_advertisement);
|
||||
|
||||
// Shorten the valid Ble Advertisement.
|
||||
ByteArray short_ble_advertisement_bytes{
|
||||
ble_advertisement_bytes.data(),
|
||||
BleAdvertisement::kMinAdvertisementLength - 1};
|
||||
|
||||
BleAdvertisement short_ble_advertisement{true, short_ble_advertisement_bytes};
|
||||
|
||||
EXPECT_FALSE(short_ble_advertisement.IsValid());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest,
|
||||
ConstructionFromByesWithWrongEndpointNameLengthFails) {
|
||||
ConstructionFromByesWithWrongEndpointInfoLengthFails) {
|
||||
// Serialize good data into a good Ble Advertisement.
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BleAdvertisement ble_advertisement{kVersion,
|
||||
kPcp,
|
||||
service_id_hash,
|
||||
std::string(kEndPointID),
|
||||
std::string(kEndpointName),
|
||||
std::string(kBluetoothMacAddress)};
|
||||
auto ble_advertisement_bytes = ByteArray(ble_advertisement);
|
||||
ByteArray service_id_hash{std::string(kServiceIdHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndpointName)};
|
||||
BleAdvertisement ble_advertisement{
|
||||
kVersion, kPcp,
|
||||
service_id_hash, std::string(kEndpointId),
|
||||
endpoint_info, std::string(kBluetoothMacAddress)};
|
||||
ByteArray ble_advertisement_bytes(ble_advertisement);
|
||||
|
||||
// Corrupt the EndpointNameLength bits.
|
||||
auto corrupt_ble_advertisement_string = std::string(ble_advertisement_bytes);
|
||||
std::string corrupt_ble_advertisement_string(ble_advertisement_bytes);
|
||||
corrupt_ble_advertisement_string[8] ^= 0x0FF;
|
||||
auto corrupt_ble_advertisement_bytes =
|
||||
ByteArray(corrupt_ble_advertisement_string);
|
||||
ByteArray corrupt_ble_advertisement_bytes(corrupt_ble_advertisement_string);
|
||||
|
||||
BleAdvertisement corrupt_ble_advertisement{corrupt_ble_advertisement_bytes};
|
||||
BleAdvertisement corrupt_ble_advertisement{false,
|
||||
corrupt_ble_advertisement_bytes};
|
||||
|
||||
EXPECT_FALSE(corrupt_ble_advertisement.IsValid());
|
||||
}
|
||||
|
||||
TEST(BleAdvertisementTest,
|
||||
ConstructionFromByesWithWrongEndpointInfoLengthFailsForFastAdvertisement) {
|
||||
// Serialize good data into a good Ble Advertisement.
|
||||
ByteArray fast_endpoint_info{std::string(kFastAdvertisementEndpointName)};
|
||||
BleAdvertisement ble_advertisement{kVersion, kPcp, std::string(kEndpointId),
|
||||
fast_endpoint_info};
|
||||
ByteArray ble_advertisement_bytes = ByteArray(ble_advertisement);
|
||||
|
||||
// Corrupt the EndpointInfoLength bits.
|
||||
std::string corrupt_ble_advertisement_string(ble_advertisement_bytes);
|
||||
corrupt_ble_advertisement_string[5] ^= 0x0FF;
|
||||
ByteArray corrupt_ble_advertisement_bytes(corrupt_ble_advertisement_string);
|
||||
|
||||
BleAdvertisement corrupt_ble_advertisement{true,
|
||||
corrupt_ble_advertisement_bytes};
|
||||
|
||||
EXPECT_FALSE(corrupt_ble_advertisement.IsValid());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "core_v2/internal/ble_endpoint_channel.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/public/ble.h"
|
||||
#include "platform_v2/public/logging.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
namespace {
|
||||
|
||||
OutputStream* GetOutputStreamOrNull(BleSocket& socket) {
|
||||
if (socket.GetRemotePeripheral().IsValid()) return &socket.GetOutputStream();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InputStream* GetInputStreamOrNull(BleSocket& socket) {
|
||||
if (socket.GetRemotePeripheral().IsValid()) return &socket.GetInputStream();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BleEndpointChannel::BleEndpointChannel(const std::string& channel_name,
|
||||
BleSocket socket)
|
||||
: BaseEndpointChannel(channel_name, GetInputStreamOrNull(socket),
|
||||
GetOutputStreamOrNull(socket)),
|
||||
ble_socket_(std::move(socket)) {}
|
||||
|
||||
proto::connections::Medium BleEndpointChannel::GetMedium() const {
|
||||
return proto::connections::Medium::BLE;
|
||||
}
|
||||
|
||||
void BleEndpointChannel::CloseImpl() {
|
||||
auto status = ble_socket_.Close();
|
||||
if (!status.Ok()) {
|
||||
NEARBY_LOG(INFO, "Failed to close Ble socket: exception=%d", status.value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef CORE_V2_INTERNAL_BLE_ENDPOINT_CHANNEL_H_
|
||||
#define CORE_V2_INTERNAL_BLE_ENDPOINT_CHANNEL_H_
|
||||
|
||||
#include "core_v2/internal/base_endpoint_channel.h"
|
||||
#include "platform_v2/public/ble.h"
|
||||
#include "proto/connections_enums.pb.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
class BleEndpointChannel final : public BaseEndpointChannel {
|
||||
public:
|
||||
// Creates both outgoing and incoming Ble channels.
|
||||
BleEndpointChannel(const std::string& channel_name, BleSocket socket);
|
||||
|
||||
proto::connections::Medium GetMedium() const override;
|
||||
|
||||
private:
|
||||
void CloseImpl() override;
|
||||
|
||||
BleSocket ble_socket_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // CORE_V2_INTERNAL_BLE_ENDPOINT_CHANNEL_H_
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "platform_v2/base/base64_utils.h"
|
||||
#include "platform_v2/base/base_input_stream.h"
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
namespace location {
|
||||
@@ -31,7 +32,7 @@ namespace connections {
|
||||
BluetoothDeviceName::BluetoothDeviceName(Version version, Pcp pcp,
|
||||
absl::string_view endpoint_id,
|
||||
const ByteArray& service_id_hash,
|
||||
absl::string_view endpoint_name) {
|
||||
const ByteArray& endpoint_info) {
|
||||
if (version != Version::kV1 || endpoint_id.empty() ||
|
||||
endpoint_id.length() != kEndpointIdLength ||
|
||||
service_id_hash.size() != kServiceIdHashLength) {
|
||||
@@ -50,7 +51,7 @@ BluetoothDeviceName::BluetoothDeviceName(Version version, Pcp pcp,
|
||||
pcp_ = pcp;
|
||||
endpoint_id_ = std::string(endpoint_id);
|
||||
service_id_hash_ = service_id_hash;
|
||||
endpoint_name_ = std::string(endpoint_name);
|
||||
endpoint_info_ = endpoint_info;
|
||||
}
|
||||
|
||||
BluetoothDeviceName::BluetoothDeviceName(
|
||||
@@ -120,24 +121,22 @@ BluetoothDeviceName::BluetoothDeviceName(
|
||||
// untouched.
|
||||
base_input_stream.ReadBytes(kReservedLength);
|
||||
|
||||
// The next 1 byte are supposed to be the length of the endpoint_name.
|
||||
std::uint32_t expected_endpoint_name_length = base_input_stream.ReadUint8();
|
||||
// The next 1 byte are supposed to be the length of the endpoint_info.
|
||||
std::uint32_t expected_endpoint_info_length = base_input_stream.ReadUint8();
|
||||
|
||||
// The rest bytes are supposed to be the endpoint_name
|
||||
auto endpoint_name_bytes =
|
||||
base_input_stream.ReadBytes(expected_endpoint_name_length);
|
||||
if (endpoint_name_bytes.Empty() ||
|
||||
endpoint_name_bytes.size() != expected_endpoint_name_length) {
|
||||
// The rest bytes are supposed to be the endpoint_info
|
||||
endpoint_info_ = base_input_stream.ReadBytes(expected_endpoint_info_length);
|
||||
if (endpoint_info_.Empty() ||
|
||||
endpoint_info_.size() != expected_endpoint_info_length) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Cannot deserialize BluetoothDeviceName: expected "
|
||||
"endpointName to be %d bytes, got %" PRIu64,
|
||||
expected_endpoint_name_length, endpoint_name_bytes.size());
|
||||
"endpoint info to be %d bytes, got %" PRIu64,
|
||||
expected_endpoint_info_length, endpoint_info_.size());
|
||||
|
||||
// Clear enpoint_id for validadity.
|
||||
endpoint_id_.clear();
|
||||
return;
|
||||
}
|
||||
endpoint_name_ = std::string{endpoint_name_bytes};
|
||||
}
|
||||
|
||||
BluetoothDeviceName::operator std::string() const {
|
||||
@@ -154,14 +153,14 @@ BluetoothDeviceName::operator std::string() const {
|
||||
|
||||
ByteArray reserved_bytes{kReservedLength};
|
||||
|
||||
std::string usable_endpoint_name(endpoint_name_);
|
||||
if (endpoint_name_.size() > kMaxEndpointNameLength) {
|
||||
ByteArray usable_endpoint_info(endpoint_info_);
|
||||
if (endpoint_info_.size() > kMaxEndpointInfoLength) {
|
||||
NEARBY_LOG(INFO,
|
||||
"While serializing Advertisement, truncating Endpoint Name %s "
|
||||
"(%lu bytes) down to %d bytes",
|
||||
endpoint_name_.c_str(), endpoint_name_.size(),
|
||||
kMaxEndpointNameLength);
|
||||
usable_endpoint_name.erase(kMaxEndpointNameLength);
|
||||
absl::BytesToHexString(endpoint_info_.data()).c_str(),
|
||||
endpoint_info_.size(), kMaxEndpointInfoLength);
|
||||
usable_endpoint_info.SetData(endpoint_info_.data(), kMaxEndpointInfoLength);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@@ -169,8 +168,8 @@ BluetoothDeviceName::operator std::string() const {
|
||||
endpoint_id_,
|
||||
std::string(service_id_hash_),
|
||||
std::string(reserved_bytes),
|
||||
std::string(1, usable_endpoint_name.size()),
|
||||
usable_endpoint_name);
|
||||
std::string(1, usable_endpoint_info.size()),
|
||||
std::string(usable_endpoint_info));
|
||||
// clang-format on
|
||||
|
||||
return Base64Utils::Encode(ByteArray{std::move(out)});
|
||||
|
||||
@@ -44,7 +44,7 @@ class BluetoothDeviceName {
|
||||
BluetoothDeviceName() = default;
|
||||
BluetoothDeviceName(Version version, Pcp pcp, absl::string_view endpoint_id,
|
||||
const ByteArray& service_id_hash,
|
||||
absl::string_view endpoint_name);
|
||||
const ByteArray& endpoint_info);
|
||||
explicit BluetoothDeviceName(absl::string_view bluetooth_device_name_string);
|
||||
BluetoothDeviceName(const BluetoothDeviceName&) = default;
|
||||
BluetoothDeviceName& operator=(const BluetoothDeviceName&) = default;
|
||||
@@ -59,15 +59,15 @@ class BluetoothDeviceName {
|
||||
Pcp GetPcp() const { return pcp_; }
|
||||
std::string GetEndpointId() const { return endpoint_id_; }
|
||||
ByteArray GetServiceIdHash() const { return service_id_hash_; }
|
||||
std::string GetEndpointName() const { return endpoint_name_; }
|
||||
ByteArray GetEndpointInfo() const { return endpoint_info_; }
|
||||
|
||||
private:
|
||||
static constexpr int kMaxBluetoothDeviceNameLength = 147;
|
||||
static constexpr int kEndpointIdLength = 4;
|
||||
static constexpr int kReservedLength = 7;
|
||||
static constexpr int kMaxEndpointNameLength = 131;
|
||||
static constexpr int kMaxEndpointInfoLength = 131;
|
||||
static constexpr int kMinBluetoothDeviceNameLength =
|
||||
kMaxBluetoothDeviceNameLength - kMaxEndpointNameLength;
|
||||
kMaxBluetoothDeviceNameLength - kMaxEndpointInfoLength;
|
||||
|
||||
static constexpr int kVersionBitmask = 0x0E0;
|
||||
static constexpr int kPcpBitmask = 0x01F;
|
||||
@@ -77,7 +77,7 @@ class BluetoothDeviceName {
|
||||
Pcp pcp_{Pcp::kUnknown};
|
||||
std::string endpoint_id_;
|
||||
ByteArray service_id_hash_;
|
||||
std::string endpoint_name_;
|
||||
ByteArray endpoint_info_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
|
||||
@@ -34,38 +34,40 @@ constexpr absl::string_view kEndPointName{"RAWK + ROWL!"};
|
||||
|
||||
TEST(BluetoothDeviceNameTest, ConstructionWorks) {
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
BluetoothDeviceName bluetooth_device_name{kVersion, kPcp, kEndPointID,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_TRUE(bluetooth_device_name.IsValid());
|
||||
EXPECT_EQ(kVersion, bluetooth_device_name.GetVersion());
|
||||
EXPECT_EQ(kPcp, bluetooth_device_name.GetPcp());
|
||||
EXPECT_EQ(kEndPointID, bluetooth_device_name.GetEndpointId());
|
||||
EXPECT_EQ(service_id_hash, bluetooth_device_name.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointName, bluetooth_device_name.GetEndpointName());
|
||||
EXPECT_EQ(endpoint_info, bluetooth_device_name.GetEndpointInfo());
|
||||
}
|
||||
|
||||
TEST(BluetoothDeviceNameTest, ConstructionWorksWithEmptyEndpointName) {
|
||||
std::string empty_endpoint_name;
|
||||
ByteArray empty_endpoint_info;
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
BluetoothDeviceName bluetooth_device_name{
|
||||
kVersion, kPcp, kEndPointID, service_id_hash, empty_endpoint_name};
|
||||
kVersion, kPcp, kEndPointID, service_id_hash, empty_endpoint_info};
|
||||
|
||||
EXPECT_TRUE(bluetooth_device_name.IsValid());
|
||||
EXPECT_EQ(kVersion, bluetooth_device_name.GetVersion());
|
||||
EXPECT_EQ(kPcp, bluetooth_device_name.GetPcp());
|
||||
EXPECT_EQ(kEndPointID, bluetooth_device_name.GetEndpointId());
|
||||
EXPECT_EQ(service_id_hash, bluetooth_device_name.GetServiceIdHash());
|
||||
EXPECT_EQ(empty_endpoint_name, bluetooth_device_name.GetEndpointName());
|
||||
EXPECT_EQ(empty_endpoint_info, bluetooth_device_name.GetEndpointInfo());
|
||||
}
|
||||
|
||||
TEST(BluetoothDeviceNameTest, ConstructionFailsWithBadVersion) {
|
||||
auto bad_version = static_cast<BluetoothDeviceName::Version>(666);
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
BluetoothDeviceName bluetooth_device_name{bad_version, kPcp, kEndPointID,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(bluetooth_device_name.IsValid());
|
||||
}
|
||||
@@ -74,8 +76,9 @@ TEST(BluetoothDeviceNameTest, ConstructionFailsWithBadPcp) {
|
||||
auto bad_pcp = static_cast<Pcp>(666);
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
BluetoothDeviceName bluetooth_device_name{kVersion, bad_pcp, kEndPointID,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(bluetooth_device_name.IsValid());
|
||||
}
|
||||
@@ -84,8 +87,9 @@ TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortEndpointId) {
|
||||
std::string short_endpoint_id("AB1");
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
BluetoothDeviceName bluetooth_device_name{kVersion, kPcp, short_endpoint_id,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(bluetooth_device_name.IsValid());
|
||||
}
|
||||
@@ -94,8 +98,9 @@ TEST(BluetoothDeviceNameTest, ConstructionFailsWithLongEndpointId) {
|
||||
std::string long_endpoint_id("AB12X");
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
BluetoothDeviceName bluetooth_device_name{kVersion, kPcp, long_endpoint_id,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(bluetooth_device_name.IsValid());
|
||||
}
|
||||
@@ -104,8 +109,9 @@ TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortServiceIdHash) {
|
||||
char short_service_id_hash_bytes[] = "\x0a\x0b";
|
||||
|
||||
ByteArray short_service_id_hash{short_service_id_hash_bytes};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
BluetoothDeviceName bluetooth_device_name{
|
||||
kVersion, kPcp, kEndPointID, short_service_id_hash, kEndPointName};
|
||||
kVersion, kPcp, kEndPointID, short_service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(bluetooth_device_name.IsValid());
|
||||
}
|
||||
@@ -114,8 +120,9 @@ TEST(BluetoothDeviceNameTest, ConstructionFailsWithLongServiceIdHash) {
|
||||
char long_service_id_hash_bytes[] = "\x0a\x0b\x0c\x0d";
|
||||
|
||||
ByteArray long_service_id_hash{long_service_id_hash_bytes};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
BluetoothDeviceName bluetooth_device_name{
|
||||
kVersion, kPcp, kEndPointID, long_service_id_hash, kEndPointName};
|
||||
kVersion, kPcp, kEndPointID, long_service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(bluetooth_device_name.IsValid());
|
||||
}
|
||||
@@ -133,8 +140,9 @@ TEST(BluetoothDeviceNameTest, ConstructionFailsWithShortStringLength) {
|
||||
TEST(BluetoothDeviceNameTest, ConstructionFailsWithWrongEndpointNameLength) {
|
||||
// Serialize good data into a good Bluetooth Device Name.
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
BluetoothDeviceName bluetooth_device_name{kVersion, kPcp, kEndPointID,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
auto bluetooth_device_name_string = std::string(bluetooth_device_name);
|
||||
|
||||
// Base64-decode the good Bluetooth Device Name.
|
||||
@@ -159,9 +167,10 @@ TEST(BluetoothDeviceNameTest, ConstructionFailsWithWrongEndpointNameLength) {
|
||||
|
||||
TEST(BluetoothDeviceNameTest, CanParseGeneratedName) {
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
// Build name1 from scratch.
|
||||
BluetoothDeviceName name1{kVersion, kPcp, kEndPointID, service_id_hash,
|
||||
kEndPointName};
|
||||
endpoint_info};
|
||||
// Build name2 from string composed from name1.
|
||||
BluetoothDeviceName name2{std::string(name1)};
|
||||
EXPECT_TRUE(name1.IsValid());
|
||||
@@ -170,7 +179,7 @@ TEST(BluetoothDeviceNameTest, CanParseGeneratedName) {
|
||||
EXPECT_EQ(name1.GetPcp(), name2.GetPcp());
|
||||
EXPECT_EQ(name1.GetEndpointId(), name2.GetEndpointId());
|
||||
EXPECT_EQ(name1.GetServiceIdHash(), name2.GetServiceIdHash());
|
||||
EXPECT_EQ(name1.GetEndpointName(), name2.GetEndpointName());
|
||||
EXPECT_EQ(name1.GetEndpointInfo(), name2.GetEndpointInfo());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "proto/connections_enums.pb.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
namespace location {
|
||||
@@ -38,21 +39,22 @@ ClientProxy::~ClientProxy() { Reset(); }
|
||||
|
||||
std::int64_t ClientProxy::GetClientId() const { return client_id_; }
|
||||
|
||||
std::string ClientProxy::GenerateLocalEndpointId() {
|
||||
// 1) Concatenate the Random 64-bit value with "client" string.
|
||||
// 2) Compute a hash of that concatenation.
|
||||
// 3) Base64-encode that hash, to make it human-readable.
|
||||
// 4) Use only the first kEndpointIdLength bytes to make ID.
|
||||
ByteArray id_hash = Crypto::Sha256(
|
||||
absl::StrCat("client", prng_.NextInt64()));
|
||||
|
||||
std::string id = Base64Utils::Encode(id_hash).substr(0, kEndpointIdLength);
|
||||
|
||||
NEARBY_LOG(
|
||||
INFO, "ClientProxy [Local Endpoint Generated]: client=%p; endpoint_id=%s",
|
||||
this, id.c_str());
|
||||
|
||||
return id;
|
||||
std::string ClientProxy::GetLocalEndpointId() {
|
||||
if (local_endpoint_id_.empty()) {
|
||||
// 1) Concatenate the Random 64-bit value with "client" string.
|
||||
// 2) Compute a hash of that concatenation.
|
||||
// 3) Base64-encode that hash, to make it human-readable.
|
||||
// 4) Use only the first kEndpointIdLength bytes to make ID.
|
||||
ByteArray id_hash =
|
||||
Crypto::Sha256(absl::StrCat("client", prng_.NextInt64()));
|
||||
std::string id = Base64Utils::Encode(id_hash).substr(0, kEndpointIdLength);
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"ClientProxy [Local Endpoint Generated]: client=%p; endpoint_id=%s",
|
||||
this, id.c_str());
|
||||
local_endpoint_id_ = id;
|
||||
}
|
||||
return local_endpoint_id_;
|
||||
}
|
||||
|
||||
void ClientProxy::Reset() {
|
||||
@@ -69,6 +71,7 @@ void ClientProxy::StartedAdvertising(
|
||||
absl::Span<proto::connections::Medium> mediums) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (connections_.empty()) local_endpoint_id_.clear();
|
||||
advertising_info_ = {service_id, listener};
|
||||
}
|
||||
|
||||
@@ -78,6 +81,7 @@ void ClientProxy::StoppedAdvertising() {
|
||||
if (IsAdvertising()) {
|
||||
advertising_info_.Clear();
|
||||
}
|
||||
if (connections_.empty()) local_endpoint_id_.clear();
|
||||
}
|
||||
|
||||
bool ClientProxy::IsAdvertising() const {
|
||||
@@ -97,6 +101,7 @@ void ClientProxy::StartedDiscovery(
|
||||
absl::Span<proto::connections::Medium> mediums) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (connections_.empty()) local_endpoint_id_.clear();
|
||||
discovery_info_ = DiscoveryInfo{service_id, listener};
|
||||
}
|
||||
|
||||
@@ -107,6 +112,7 @@ void ClientProxy::StoppedDiscovery() {
|
||||
discovered_endpoint_ids_.clear();
|
||||
discovery_info_.Clear();
|
||||
}
|
||||
if (connections_.empty()) local_endpoint_id_.clear();
|
||||
}
|
||||
|
||||
bool ClientProxy::IsDiscoveringServiceId(const std::string& service_id) const {
|
||||
@@ -129,13 +135,14 @@ std::string ClientProxy::GetDiscoveryServiceId() const {
|
||||
|
||||
void ClientProxy::OnEndpointFound(const std::string& service_id,
|
||||
const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
proto::connections::Medium medium) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
NEARBY_LOG(INFO,
|
||||
"ClientProxy [Endpoint Found]: [enter] id=%s; service=%s; name=%s",
|
||||
endpoint_id.c_str(), service_id.c_str(), endpoint_name.c_str());
|
||||
"ClientProxy [Endpoint Found]: [enter] id=%s; service=%s; info=%s",
|
||||
endpoint_id.c_str(), service_id.c_str(),
|
||||
absl::BytesToHexString(endpoint_info.data()).c_str());
|
||||
if (!IsDiscoveringServiceId(service_id)) {
|
||||
NEARBY_LOG(INFO, "ClientProxy [Endpoint Found]: [no discovery] id=%s",
|
||||
endpoint_id.c_str());
|
||||
@@ -147,7 +154,7 @@ void ClientProxy::OnEndpointFound(const std::string& service_id,
|
||||
return;
|
||||
}
|
||||
discovered_endpoint_ids_.insert(endpoint_id);
|
||||
discovery_info_.listener.endpoint_found_cb(endpoint_id, endpoint_name,
|
||||
discovery_info_.listener.endpoint_found_cb(endpoint_id, endpoint_info,
|
||||
service_id);
|
||||
}
|
||||
|
||||
@@ -164,6 +171,7 @@ void ClientProxy::OnEndpointLost(const std::string& service_id,
|
||||
|
||||
void ClientProxy::OnConnectionInitiated(const std::string& endpoint_id,
|
||||
const ConnectionResponseInfo& info,
|
||||
const ConnectionOptions& options,
|
||||
const ConnectionListener& listener) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
@@ -174,6 +182,7 @@ void ClientProxy::OnConnectionInitiated(const std::string& endpoint_id,
|
||||
endpoint_id, Connection{
|
||||
.is_incoming = info.is_incoming_connection,
|
||||
.connection_listener = listener,
|
||||
.connection_options = options,
|
||||
});
|
||||
// Instead of using structured binding which is nice, but banned
|
||||
// (can not use c++17 features, until chromium does) we unpack manually.
|
||||
@@ -248,6 +257,7 @@ void ClientProxy::OnDisconnected(const std::string& endpoint_id, bool notify) {
|
||||
item->connection_listener.disconnected_cb({endpoint_id});
|
||||
}
|
||||
connections_.erase(endpoint_id);
|
||||
if (connections_.empty()) local_endpoint_id_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +272,17 @@ bool ClientProxy::ConnectionStatusMatches(const std::string& endpoint_id,
|
||||
return false;
|
||||
}
|
||||
|
||||
BooleanMediumSelector ClientProxy::GetUpgradeMediums(
|
||||
const std::string& endpoint_id) const {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
const Connection* item = LookupConnection(endpoint_id);
|
||||
if (item != nullptr) {
|
||||
return item->connection_options.allowed;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ClientProxy::IsConnectedToEndpoint(const std::string& endpoint_id) const {
|
||||
return ConnectionStatusMatches(endpoint_id, Connection::kConnected);
|
||||
}
|
||||
@@ -483,6 +504,7 @@ void ClientProxy::RemoveAllEndpoints() {
|
||||
// endpoint, in the case when this is called from stopAllEndpoints(). For now,
|
||||
// just remove without notifying.
|
||||
connections_.clear();
|
||||
local_endpoint_id_.clear();
|
||||
}
|
||||
|
||||
bool ClientProxy::ConnectionStatusesContains(
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "core_v2/listeners.h"
|
||||
#include "core_v2/options.h"
|
||||
#include "core_v2/status.h"
|
||||
#include "core_v2/strategy.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
@@ -49,7 +50,7 @@ class ClientProxy final {
|
||||
|
||||
std::int64_t GetClientId() const;
|
||||
|
||||
std::string GenerateLocalEndpointId();
|
||||
std::string GetLocalEndpointId();
|
||||
|
||||
// Clears all the runtime state of this client.
|
||||
void Reset();
|
||||
@@ -78,7 +79,7 @@ class ClientProxy final {
|
||||
// Proxies to the client's DiscoveryListener::OnEndpointFound() callback.
|
||||
void OnEndpointFound(const std::string& service_id,
|
||||
const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
proto::connections::Medium medium);
|
||||
// Proxies to the client's DiscoveryListener::OnEndpointLost() callback.
|
||||
void OnEndpointLost(const std::string& service_id,
|
||||
@@ -87,6 +88,7 @@ class ClientProxy final {
|
||||
// Proxies to the client's ConnectionListener::OnInitiated() callback.
|
||||
void OnConnectionInitiated(const std::string& endpoint_id,
|
||||
const ConnectionResponseInfo& info,
|
||||
const ConnectionOptions& options,
|
||||
const ConnectionListener& listener);
|
||||
|
||||
// Proxies to the client's ConnectionListener::OnAccepted() callback.
|
||||
@@ -102,6 +104,8 @@ class ClientProxy final {
|
||||
// ConnectionListener.disconnected_cb() callback.
|
||||
void OnDisconnected(const std::string& endpoint_id, bool notify);
|
||||
|
||||
// Returns all mediums eligible for upgrade.
|
||||
BooleanMediumSelector GetUpgradeMediums(const std::string& endpoint_id) const;
|
||||
// Returns true if it's safe to send payloads to this endpoint.
|
||||
bool IsConnectedToEndpoint(const std::string& endpoint_id) const;
|
||||
// Returns all endpoints that can safely be sent payloads.
|
||||
@@ -171,6 +175,7 @@ class ClientProxy final {
|
||||
Status status{kPending};
|
||||
ConnectionListener connection_listener;
|
||||
PayloadListener payload_listener;
|
||||
ConnectionOptions connection_options;
|
||||
};
|
||||
|
||||
struct AdvertisingInfo {
|
||||
@@ -202,6 +207,7 @@ class ClientProxy final {
|
||||
|
||||
mutable RecursiveMutex mutex_;
|
||||
std::int64_t client_id_;
|
||||
std::string local_endpoint_id_;
|
||||
Prng prng_;
|
||||
|
||||
// If not empty, we are currently advertising and accepting connection
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "core_v2/listeners.h"
|
||||
#include "core_v2/options.h"
|
||||
#include "core_v2/strategy.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "gmock/gmock.h"
|
||||
@@ -36,7 +37,7 @@ class ClientProxyTest : public testing::Test {
|
||||
protected:
|
||||
struct MockDiscoveryListener {
|
||||
StrictMock<MockFunction<void(const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id)>>
|
||||
endpoint_found_cb;
|
||||
StrictMock<MockFunction<void(const std::string& endpoint_id)>>
|
||||
@@ -66,14 +67,14 @@ class ClientProxyTest : public testing::Test {
|
||||
};
|
||||
|
||||
struct Endpoint {
|
||||
std::string name;
|
||||
ByteArray info;
|
||||
std::string id;
|
||||
};
|
||||
|
||||
Endpoint StartAdvertising(ClientProxy* client, ConnectionListener listener) {
|
||||
Endpoint endpoint{
|
||||
.name = "advertising endpoint name",
|
||||
.id = client->GenerateLocalEndpointId(),
|
||||
.info = ByteArray{"advertising endpoint name"},
|
||||
.id = client->GetLocalEndpointId(),
|
||||
};
|
||||
client->StartedAdvertising(service_id_, strategy_, listener,
|
||||
absl::MakeSpan(mediums_));
|
||||
@@ -82,8 +83,8 @@ class ClientProxyTest : public testing::Test {
|
||||
|
||||
Endpoint StartDiscovery(ClientProxy* client, DiscoveryListener listener) {
|
||||
Endpoint endpoint{
|
||||
.name = "discovery endpoint name",
|
||||
.id = client->GenerateLocalEndpointId(),
|
||||
.info = ByteArray{"discovery endpoint name"},
|
||||
.id = client->GetLocalEndpointId(),
|
||||
};
|
||||
client->StartedDiscovery(service_id_, strategy_, listener,
|
||||
absl::MakeSpan(mediums_));
|
||||
@@ -92,7 +93,8 @@ class ClientProxyTest : public testing::Test {
|
||||
|
||||
void OnDiscoveryEndpointFound(ClientProxy* client, const Endpoint& endpoint) {
|
||||
EXPECT_CALL(mock_discovery_.endpoint_found_cb, Call).Times(1);
|
||||
client->OnEndpointFound(service_id_, endpoint.id, endpoint.name, medium_);
|
||||
client->OnEndpointFound(service_id_, endpoint.id, endpoint.info,
|
||||
medium_);
|
||||
}
|
||||
|
||||
void OnDiscoveryEndpointLost(ClientProxy* client, const Endpoint& endpoint) {
|
||||
@@ -105,8 +107,9 @@ class ClientProxyTest : public testing::Test {
|
||||
EXPECT_CALL(mock_discovery_connection_.initiated_cb, Call).Times(1);
|
||||
const std::string auth_token{"auth_token"};
|
||||
const ByteArray raw_auth_token{auth_token};
|
||||
advertising_connection_info_.remote_endpoint_name = endpoint.name;
|
||||
advertising_connection_info_.remote_endpoint_info = endpoint.info;
|
||||
client->OnConnectionInitiated(endpoint.id, advertising_connection_info_,
|
||||
connection_options_,
|
||||
discovery_connection_listener_);
|
||||
EXPECT_TRUE(client->HasPendingConnectionToEndpoint(endpoint.id));
|
||||
}
|
||||
@@ -222,6 +225,7 @@ class ClientProxyTest : public testing::Test {
|
||||
.payload_progress_cb =
|
||||
mock_discovery_payload_.payload_progress_cb.AsStdFunction(),
|
||||
};
|
||||
ConnectionOptions connection_options_;
|
||||
};
|
||||
|
||||
TEST_F(ClientProxyTest, ConstructorDestructorWorks) { SUCCEED(); }
|
||||
@@ -231,8 +235,8 @@ TEST_F(ClientProxyTest, ClientIdIsUnique) {
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, GeneratedEndpointIdIsUnique) {
|
||||
EXPECT_NE(client1_.GenerateLocalEndpointId(),
|
||||
client2_.GenerateLocalEndpointId());
|
||||
EXPECT_NE(client1_.GetLocalEndpointId(),
|
||||
client2_.GetLocalEndpointId());
|
||||
}
|
||||
|
||||
TEST_F(ClientProxyTest, ResetClearsState) {
|
||||
|
||||
@@ -66,13 +66,13 @@ bool HandleEncryptionSuccess(const std::string& endpoint_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
void CancelableAlarmRunnable(ClientProxy* client_proxy,
|
||||
void CancelableAlarmRunnable(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Timing out encryption for client %" PRId64
|
||||
" to endpoint %s after %" PRId64 " ms",
|
||||
client_proxy->GetClientId(), endpoint_id.c_str(),
|
||||
client->GetClientId(), endpoint_id.c_str(),
|
||||
static_cast<std::int64_t>(absl::ToInt64Milliseconds(kTimeout)));
|
||||
endpoint_channel->Close();
|
||||
}
|
||||
@@ -90,7 +90,7 @@ class ServerRunnable final {
|
||||
|
||||
void operator()() const {
|
||||
CancelableAlarm timeout_alarm(
|
||||
"EncryptionRunner.startServer() timeout",
|
||||
"EncryptionRunner.StartServer() timeout",
|
||||
[this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); },
|
||||
kTimeout, alarm_executor_);
|
||||
|
||||
@@ -123,7 +123,7 @@ class ServerRunnable final {
|
||||
return;
|
||||
}
|
||||
|
||||
NEARBY_LOG(INFO, "In startServer(), read UKEY2 Message 1 from endpoint %s",
|
||||
NEARBY_LOG(INFO, "In StartServer(), read UKEY2 Message 1 from endpoint %s",
|
||||
endpoint_id_.c_str());
|
||||
|
||||
// Message 2 (Server Init)
|
||||
@@ -145,7 +145,7 @@ class ServerRunnable final {
|
||||
return;
|
||||
}
|
||||
|
||||
NEARBY_LOG(INFO, "In startServer(), wrote UKEY2 Message 2 to endpoint %s",
|
||||
NEARBY_LOG(INFO, "In StartServer(), wrote UKEY2 Message 2 to endpoint %s",
|
||||
endpoint_id_.c_str());
|
||||
|
||||
// Message 3 (Client Finish)
|
||||
@@ -170,7 +170,7 @@ class ServerRunnable final {
|
||||
return;
|
||||
}
|
||||
|
||||
NEARBY_LOG(INFO, "In startServer(), read UKEY2 Message 3 from endpoint %s",
|
||||
NEARBY_LOG(INFO, "In StartServer(), read UKEY2 Message 3 from endpoint %s",
|
||||
endpoint_id_.c_str());
|
||||
|
||||
timeout_alarm.Cancel();
|
||||
@@ -184,7 +184,7 @@ class ServerRunnable final {
|
||||
|
||||
private:
|
||||
void LogException() const {
|
||||
NEARBY_LOG(ERROR, "In startServer(), UKEY2 failed with endpoint %s",
|
||||
NEARBY_LOG(ERROR, "In StartServer(), UKEY2 failed with endpoint %s",
|
||||
endpoint_id_.c_str());
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ class ServerRunnable final {
|
||||
channel_->Write(ByteArray(*parse_result.alert_to_send));
|
||||
if (!write_exception.Ok()) {
|
||||
NEARBY_LOG(WARNING,
|
||||
"In startServer(), client %" PRId64
|
||||
"In StartServer(), client %" PRId64
|
||||
" failed to pass the alert error message to endpoint %s",
|
||||
client_->GetClientId(), endpoint_id_.c_str());
|
||||
}
|
||||
@@ -356,22 +356,22 @@ EncryptionRunner::~EncryptionRunner() {
|
||||
}
|
||||
|
||||
void EncryptionRunner::StartServer(
|
||||
ClientProxy* client_proxy, const std::string& endpoint_id,
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
EncryptionRunner::ResultListener&& listener) {
|
||||
server_executor_.Execute(
|
||||
[runnable{ServerRunnable(client_proxy, &alarm_executor_, endpoint_id,
|
||||
[runnable{ServerRunnable(client, &alarm_executor_, endpoint_id,
|
||||
endpoint_channel, std::move(listener))}]() {
|
||||
runnable();
|
||||
});
|
||||
}
|
||||
|
||||
void EncryptionRunner::StartClient(
|
||||
ClientProxy* client_proxy, const std::string& endpoint_id,
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
EncryptionRunner::ResultListener&& listener) {
|
||||
client_executor_.Execute(
|
||||
[runnable{ClientRunnable(client_proxy, &alarm_executor_, endpoint_id,
|
||||
[runnable{ClientRunnable(client, &alarm_executor_, endpoint_id,
|
||||
endpoint_channel, std::move(listener))}]() {
|
||||
runnable();
|
||||
});
|
||||
|
||||
@@ -65,11 +65,11 @@ class EncryptionRunner {
|
||||
};
|
||||
|
||||
// @AnyThread
|
||||
void StartServer(ClientProxy* client_proxy, const std::string& endpoint_id,
|
||||
void StartServer(ClientProxy* client, const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
ResultListener&& result_listener);
|
||||
// @AnyThread
|
||||
void StartClient(ClientProxy* client_proxy, const std::string& endpoint_id,
|
||||
void StartClient(ClientProxy* client, const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
ResultListener&& result_listener);
|
||||
|
||||
|
||||
@@ -88,6 +88,11 @@ void EndpointChannelManager::SetActiveEndpointChannel(
|
||||
if (endpoint->IsEncrypted()) channel_state_.EncryptChannel(endpoint);
|
||||
}
|
||||
|
||||
int EndpointChannelManager::GetConnectedEndpointsCount() const {
|
||||
MutexLock lock(&mutex_);
|
||||
return channel_state_.GetConnectedEndpointsCount();
|
||||
}
|
||||
|
||||
///////////////////////////////// ChannelState /////////////////////////////////
|
||||
|
||||
// endpoint - channel endpoint to encrypt
|
||||
|
||||
@@ -94,6 +94,8 @@ class EndpointChannelManager final {
|
||||
bool UnregisterChannelForEndpoint(const std::string& endpoint_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
int GetConnectedEndpointsCount() const ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
// Tracks channel state for all endpoints. This includes what EndpointChannel
|
||||
// the endpoint is currently using and whether or not the EndpointChannel has
|
||||
@@ -111,9 +113,7 @@ class EndpointChannelManager final {
|
||||
}
|
||||
|
||||
// True if we have a 'context' for the endpoint.
|
||||
bool IsEncrypted() const {
|
||||
return context != nullptr;
|
||||
}
|
||||
bool IsEncrypted() const { return context != nullptr; }
|
||||
|
||||
std::shared_ptr<EndpointChannel> channel;
|
||||
std::shared_ptr<EncryptionContext> context;
|
||||
@@ -148,6 +148,7 @@ class EndpointChannelManager final {
|
||||
proto::connections::DisconnectionReason reason);
|
||||
|
||||
bool EncryptChannel(EndpointData* endpoint);
|
||||
int GetConnectedEndpointsCount() const { return endpoints_.size(); }
|
||||
|
||||
private:
|
||||
// Endpoint ID -> EndpointData. Contains everything we know about the
|
||||
@@ -160,7 +161,7 @@ class EndpointChannelManager final {
|
||||
std::unique_ptr<EndpointChannel> channel)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
Mutex mutex_;
|
||||
mutable Mutex mutex_;
|
||||
ChannelState channel_state_ ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
|
||||
@@ -241,8 +241,7 @@ EndpointManager::~EndpointManager() {
|
||||
NEARBY_LOG(INFO, "EndpointManager is down");
|
||||
}
|
||||
|
||||
EndpointManager::FrameProcessor::Handle
|
||||
EndpointManager::RegisterFrameProcessor(
|
||||
EndpointManager::FrameProcessor::Handle EndpointManager::RegisterFrameProcessor(
|
||||
V1Frame::FrameType frame_type, EndpointManager::FrameProcessor* processor) {
|
||||
const FrameProcessor::Handle handle = processor;
|
||||
CountDownLatch latch(1);
|
||||
@@ -332,6 +331,7 @@ void EndpointManager::EnsureWorkersTerminated(const std::string& endpoint_id) {
|
||||
void EndpointManager::RegisterEndpoint(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const ConnectionResponseInfo& info,
|
||||
const ConnectionOptions& options,
|
||||
std::unique_ptr<EndpointChannel> channel,
|
||||
const ConnectionListener& listener) {
|
||||
CountDownLatch latch(1);
|
||||
@@ -343,7 +343,8 @@ void EndpointManager::RegisterEndpoint(ClientProxy* client,
|
||||
// We ignore the risk of job not scheduled (and an associated risk of memory
|
||||
// leak), because this may only happen during service shutdown.
|
||||
RunOnEndpointManagerThread([this, client, channel = channel.release(),
|
||||
&endpoint_id, &info, &listener, &latch]() {
|
||||
&endpoint_id, &info, &options, &listener,
|
||||
&latch]() {
|
||||
// Pass ownership of channel to EndpointChannelManager
|
||||
NEARBY_LOG(INFO, "Registering endpoint with channel manager: id=%s",
|
||||
endpoint_id.c_str());
|
||||
@@ -396,7 +397,7 @@ void EndpointManager::RegisterEndpoint(ClientProxy* client,
|
||||
|
||||
// It's now time to let the client know of this new connection so that
|
||||
// they can accept or reject it.
|
||||
client->OnConnectionInitiated(endpoint_id, info, listener);
|
||||
client->OnConnectionInitiated(endpoint_id, info, options, listener);
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
|
||||
@@ -95,8 +95,8 @@ class EndpointManager {
|
||||
// FrameProcessor* instances are of dynamic duration and survive all sessions.
|
||||
// returns unique handle to be used for unregistering.
|
||||
// Blocks until registration is complete.
|
||||
FrameProcessor::Handle RegisterFrameProcessor(
|
||||
V1Frame::FrameType frame_type, FrameProcessor* processor);
|
||||
FrameProcessor::Handle RegisterFrameProcessor(V1Frame::FrameType frame_type,
|
||||
FrameProcessor* processor);
|
||||
void UnregisterFrameProcessor(V1Frame::FrameType frame_type,
|
||||
const void* handle, bool sync = false);
|
||||
|
||||
@@ -105,6 +105,7 @@ class EndpointManager {
|
||||
// Blocks until registration is complete.
|
||||
void RegisterEndpoint(ClientProxy* client, const std::string& endpoint_id,
|
||||
const ConnectionResponseInfo& info,
|
||||
const ConnectionOptions& options,
|
||||
std::unique_ptr<EndpointChannel> channel,
|
||||
const ConnectionListener& listener);
|
||||
// Called when a client explicitly asks to disconnect from this endpoint. In
|
||||
@@ -215,8 +216,7 @@ class EndpointManager {
|
||||
|
||||
EndpointChannelManager* channel_manager_;
|
||||
|
||||
absl::flat_hash_map<V1Frame::FrameType, FrameProcessor*>
|
||||
frame_processors_;
|
||||
absl::flat_hash_map<V1Frame::FrameType, FrameProcessor*> frame_processors_;
|
||||
|
||||
// We keep track of all registered channel endpoints here.
|
||||
absl::flat_hash_map<std::string, EndpointState> endpoints_;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "core_v2/internal/client_proxy.h"
|
||||
#include "core_v2/internal/endpoint_channel_manager.h"
|
||||
#include "core_v2/internal/offline_frames.h"
|
||||
#include "core_v2/options.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
@@ -54,8 +55,7 @@ class MockEndpointChannel : public EndpointChannel {
|
||||
MOCK_METHOD(std::string, GetName, (), (const override));
|
||||
MOCK_METHOD(Medium, GetMedium, (), (const override));
|
||||
MOCK_METHOD(void, EnableEncryption,
|
||||
(std::shared_ptr<EncryptionContext> context),
|
||||
(override));
|
||||
(std::shared_ptr<EncryptionContext> context), (override));
|
||||
MOCK_METHOD(bool, IsPaused, (), (const override));
|
||||
MOCK_METHOD(void, Pause, (), (override));
|
||||
MOCK_METHOD(void, Resume, (), (override));
|
||||
@@ -103,22 +103,23 @@ class EndpointManagerTest : public ::testing::Test {
|
||||
EXPECT_CALL(*channel, GetLastReadTimestamp())
|
||||
.WillRepeatedly(Return(start_time_));
|
||||
EXPECT_CALL(mock_listener_.initiated_cb, Call).Times(1);
|
||||
em_.RegisterEndpoint(&client_, endpoint_id_, info_, std::move(channel),
|
||||
listener_);
|
||||
em_.RegisterEndpoint(&client_, endpoint_id_, info_, options_,
|
||||
std::move(channel), listener_);
|
||||
if (should_close) {
|
||||
EXPECT_TRUE(done.Await(absl::Milliseconds(1000)).result());
|
||||
}
|
||||
}
|
||||
|
||||
ClientProxy client_;
|
||||
ConnectionOptions options_;
|
||||
std::vector<std::unique_ptr<EndpointManager::FrameProcessor>> processors_;
|
||||
EndpointChannelManager ecm_;
|
||||
EndpointManager em_{&ecm_};
|
||||
std::string endpoint_id_ = "endpoint_id";
|
||||
ConnectionResponseInfo info_ = {
|
||||
.remote_endpoint_name = "name",
|
||||
.remote_endpoint_info = ByteArray{"info"},
|
||||
.authentication_token = "auth_token",
|
||||
.raw_authentication_token = ByteArray("auth_token"),
|
||||
.raw_authentication_token = ByteArray{"auth_token"},
|
||||
.is_incoming_connection = true,
|
||||
};
|
||||
struct MockConnectionListener {
|
||||
@@ -172,8 +173,10 @@ TEST_F(EndpointManagerTest, UnregisterEndpointCallsOnDisconnected) {
|
||||
TEST_F(EndpointManagerTest, RegisterFrameProcessorWorks) {
|
||||
auto endpoint_channel = std::make_unique<MockEndpointChannel>();
|
||||
auto connect_request = std::make_unique<MockFrameProcessor>();
|
||||
auto read_data = parser::ForConnectionRequest("endpoint_id", "endpoint_name",
|
||||
1234, std::vector{Medium::BLE});
|
||||
ByteArray endpoint_info{"endpoint_name"};
|
||||
auto read_data =
|
||||
parser::ForConnectionRequest("endpoint_id", endpoint_info,
|
||||
1234, std::vector{Medium::BLE});
|
||||
EXPECT_CALL(*connect_request, OnIncomingFrame);
|
||||
EXPECT_CALL(*connect_request, OnEndpointDisconnect);
|
||||
EXPECT_CALL(*endpoint_channel, Read())
|
||||
|
||||
@@ -16,6 +16,7 @@ cc_library(
|
||||
name = "mediums",
|
||||
srcs = [
|
||||
"advertisement_read_result.cc",
|
||||
"ble.cc",
|
||||
"ble_advertisement.cc",
|
||||
"ble_advertisement_header.cc",
|
||||
"ble_packet.cc",
|
||||
@@ -29,6 +30,7 @@ cc_library(
|
||||
],
|
||||
hdrs = [
|
||||
"advertisement_read_result.h",
|
||||
"ble.h",
|
||||
"ble_advertisement.h",
|
||||
"ble_advertisement_header.h",
|
||||
"ble_packet.h",
|
||||
@@ -70,6 +72,7 @@ cc_library(
|
||||
srcs = ["utils.cc"],
|
||||
hdrs = ["utils.h"],
|
||||
visibility = [
|
||||
"//core_v2/internal:__pkg__",
|
||||
"//core_v2/internal/mediums/webrtc:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
@@ -88,6 +91,7 @@ cc_test(
|
||||
"ble_advertisement_test.cc",
|
||||
"ble_packet_test.cc",
|
||||
"ble_peripheral_test.cc",
|
||||
"ble_test.cc",
|
||||
"bloom_filter_test.cc",
|
||||
"bluetooth_classic_test.cc",
|
||||
"bluetooth_radio_test.cc",
|
||||
@@ -107,6 +111,7 @@ cc_test(
|
||||
"//platform_v2/public:logging",
|
||||
"//platform_v2/public:types",
|
||||
"//testing/base/public:gunit_main",
|
||||
"//absl/strings",
|
||||
"//absl/time",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
#include "core_v2/internal/mediums/ble.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "platform_v2/public/mutex_lock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
Ble::Ble(BluetoothRadio& radio) : radio_(radio) {}
|
||||
|
||||
bool Ble::IsAvailable() const {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
return IsAvailableLocked();
|
||||
}
|
||||
|
||||
bool Ble::IsAvailableLocked() const { return medium_.IsValid(); }
|
||||
|
||||
bool Ble::StartAdvertising(const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (advertisement_bytes.Empty()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Refusing to turn on BLE advertising. Empty advertisement data.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (advertisement_bytes.size() > kMaxAdvertisementLength) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Refusing to start BLE advertising because the advertisement "
|
||||
"was too long. Expected at most %d bytes but received %d.",
|
||||
kMaxAdvertisementLength, advertisement_bytes.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsAdvertisingLocked(service_id)) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Failed to BLE advertise because we're already advertising.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!radio_.IsEnabled()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Can't start BLE scanning because Bluetooth was never turned on";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsAvailableLocked()) {
|
||||
NEARBY_LOGS(INFO) << "Can't turn on BLE advertising. BLE is not available.";
|
||||
return false;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << "Turning on BLE advertising with advertisement bytes="
|
||||
<< advertisement_bytes.data() << "("
|
||||
<< advertisement_bytes.size() << ")"
|
||||
<< ", service id=" << service_id;
|
||||
if (!medium_.StartAdvertising(service_id, advertisement_bytes)) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Failed to turn on BLE advertising with advertisement bytes="
|
||||
<< advertisement_bytes.data() << "(" << advertisement_bytes.size()
|
||||
<< ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
advertising_info_.Add(service_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ble::StopAdvertising(const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (!IsAdvertisingLocked(service_id)) {
|
||||
NEARBY_LOGS(INFO) << "Can't turn off BLE advertising; it is already off";
|
||||
return false;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << "Turned off BLE advertising with service id="
|
||||
<< service_id;
|
||||
bool ret = medium_.StopAdvertising(service_id);
|
||||
// Reset our bundle of advertising state to mark that we're no longer
|
||||
// advertising.
|
||||
advertising_info_.Remove(service_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Ble::IsAdvertising(const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
return IsAdvertisingLocked(service_id);
|
||||
}
|
||||
|
||||
bool Ble::IsAdvertisingLocked(const std::string& service_id) {
|
||||
return advertising_info_.Existed(service_id);
|
||||
}
|
||||
|
||||
bool Ble::StartScanning(const std::string& service_id,
|
||||
DiscoveredPeripheralCallback callback) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (service_id.empty()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Refusing to start BLE scanning with empty service id.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsScanningLocked(service_id)) {
|
||||
NEARBY_LOGS(INFO) << "Refusing to start scan of BLE peripherals because "
|
||||
"another scanning is already in-progress.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!radio_.IsEnabled()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Can't start BLE scanning because Bluetooth was never turned on";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsAvailableLocked()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Can't scan BLE peripherals because BLE isn't available.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!medium_.StartScanning(service_id, callback)) {
|
||||
NEARBY_LOGS(INFO) << "Failed to start scan of BLE services.";
|
||||
return false;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << "Turned on BLE scanning with service id=" << service_id;
|
||||
// Mark the fact that we're currently performing a BLE discovering.
|
||||
scanning_info_.Add(service_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ble::StopScanning(const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (!IsScanningLocked(service_id)) {
|
||||
NEARBY_LOGS(INFO) << "Can't turn off BLE sacanning because we never "
|
||||
"started scanning.";
|
||||
return false;
|
||||
}
|
||||
|
||||
NEARBY_LOG(INFO, "Turned off BLE scanning with service id=%s",
|
||||
service_id.c_str());
|
||||
bool ret = medium_.StopScanning(service_id);
|
||||
scanning_info_.Clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Ble::IsScanning(const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
return IsScanningLocked(service_id);
|
||||
}
|
||||
|
||||
bool Ble::IsScanningLocked(const std::string& service_id) {
|
||||
return scanning_info_.Existed(service_id);
|
||||
}
|
||||
|
||||
bool Ble::StartAcceptingConnections(const std::string& service_id,
|
||||
AcceptedConnectionCallback callback) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (service_id.empty()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Refusing to start accepting BLE connections with empty service id.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsAcceptingConnectionsLocked(service_id)) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Refusing to start accepting BLE connections for "
|
||||
<< service_id
|
||||
<< " because another BLE peripheral socket is already in-progress.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!radio_.IsEnabled()) {
|
||||
NEARBY_LOGS(INFO) << "Can't start accepting BLE connections for "
|
||||
<< service_id
|
||||
<< " because Bluetooth isn't enabled.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsAvailableLocked()) {
|
||||
NEARBY_LOGS(INFO) << "Can't start accepting BLE connections for "
|
||||
<< service_id << " because BLE isn't available.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!medium_.StartAcceptingConnections(service_id, callback)) {
|
||||
NEARBY_LOGS(INFO) << "Failed to accept connections callback for "
|
||||
<< service_id << " .";
|
||||
return false;
|
||||
}
|
||||
|
||||
accepting_connections_info_.Add(service_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ble::StopAcceptingConnections(const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (!IsAcceptingConnectionsLocked(service_id)) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Can't stop accepting BLE connections because it was never started.";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = medium_.StopAcceptingConnections(service_id);
|
||||
// Reset our bundle of accepting connections state to mark that we're no
|
||||
// longer accepting connections.
|
||||
accepting_connections_info_.Remove(service_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Ble::IsAcceptingConnections(const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
return IsAcceptingConnectionsLocked(service_id);
|
||||
}
|
||||
|
||||
bool Ble::IsAcceptingConnectionsLocked(const std::string& service_id) {
|
||||
return accepting_connections_info_.Existed(service_id);
|
||||
}
|
||||
|
||||
BleSocket Ble::Connect(BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "BLE::Connect: service=" << &peripheral;
|
||||
// Socket to return. To allow for NRVO to work, it has to be a single object.
|
||||
BleSocket socket;
|
||||
|
||||
if (service_id.empty()) {
|
||||
NEARBY_LOGS(INFO) << "Refusing to create BLE socket with empty service_id.";
|
||||
return socket;
|
||||
}
|
||||
|
||||
if (!radio_.IsEnabled()) {
|
||||
NEARBY_LOGS(INFO) << "Can't create client BLE socket to "
|
||||
<< &peripheral << " because Bluetooth isn't enabled.";
|
||||
return socket;
|
||||
}
|
||||
|
||||
if (!IsAvailableLocked()) {
|
||||
NEARBY_LOGS(INFO) << "Can't create client BLE socket [service_id="
|
||||
<< service_id << "]; BLE isn't available.";
|
||||
return socket;
|
||||
}
|
||||
|
||||
socket = medium_.Connect(peripheral, service_id);
|
||||
if (!socket.IsValid()) {
|
||||
NEARBY_LOGS(INFO) << "Failed to Connect via BLE [service=" << service_id
|
||||
<< "]";
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,162 @@
|
||||
#ifndef CORE_V2_INTERNAL_MEDIUMS_BLE_H_
|
||||
#define CORE_V2_INTERNAL_MEDIUMS_BLE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "core_v2/internal/mediums/bluetooth_radio.h"
|
||||
#include "core_v2/listeners.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/public/ble.h"
|
||||
#include "platform_v2/public/multi_thread_executor.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
class Ble {
|
||||
public:
|
||||
using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback;
|
||||
using AcceptedConnectionCallback = BleMedium::AcceptedConnectionCallback;
|
||||
|
||||
explicit Ble(BluetoothRadio& bluetooth_radio);
|
||||
~Ble() = default;
|
||||
|
||||
// Returns true, if Ble communications are supported by a platform.
|
||||
bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Sets custom advertisement data, and then enables Ble advertising.
|
||||
// Returns true, if data is successfully set, and false otherwise.
|
||||
bool StartAdvertising(const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Disables Ble advertising.
|
||||
bool StopAdvertising(const std::string& service_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
bool IsAdvertising(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Enables Ble scanning mode. Will report any discoverable peripherals in
|
||||
// range through a callback. Returns true, if scanning mode was enabled,
|
||||
// false otherwise.
|
||||
bool StartScanning(const std::string& service_id,
|
||||
DiscoveredPeripheralCallback callback)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Disables Ble discovery mode.
|
||||
bool StopScanning(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
bool IsScanning(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Starts a worker thread, creates a Ble socket, associates it with a
|
||||
// service id.
|
||||
bool StartAcceptingConnections(const std::string& service_id,
|
||||
AcceptedConnectionCallback callback)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Closes socket corresponding to a service id.
|
||||
bool StopAcceptingConnections(const std::string& service_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
bool IsAcceptingConnections(const std::string& service_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Returns true if this object owns a valid platform implementation.
|
||||
bool IsMediumValid() const ABSL_LOCKS_EXCLUDED(mutex_) {
|
||||
MutexLock lock(&mutex_);
|
||||
return medium_.IsValid();
|
||||
}
|
||||
|
||||
// Returns true if this object has a valid BluetoothAdapter reference.
|
||||
bool IsAdapterValid() const ABSL_LOCKS_EXCLUDED(mutex_) {
|
||||
MutexLock lock(&mutex_);
|
||||
return adapter_.IsValid();
|
||||
}
|
||||
|
||||
// Establishes connection to Ble peripheral that was might be started on
|
||||
// another peripheral with StartAcceptingConnections() using the same
|
||||
// service_id. Blocks until connection is established, or server-side is
|
||||
// terminated. Returns socket instance. On success, BleSocket.IsValid() return
|
||||
// true.
|
||||
BleSocket Connect(BlePeripheral& peripheral, const std::string& service_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
static constexpr int kMaxAdvertisementLength = 512;
|
||||
|
||||
struct AdvertisingInfo {
|
||||
bool Empty() const { return service_ids.empty(); }
|
||||
void Clear() { service_ids.clear(); }
|
||||
void Add(const std::string& service_id) { service_ids.emplace(service_id); }
|
||||
void Remove(const std::string& service_id) {
|
||||
service_ids.erase(service_id);
|
||||
}
|
||||
bool Existed(const std::string& service_id) const {
|
||||
return service_ids.contains(service_id);
|
||||
}
|
||||
|
||||
absl::flat_hash_set<std::string> service_ids;
|
||||
};
|
||||
|
||||
struct ScanningInfo {
|
||||
bool Empty() const { return service_ids.empty(); }
|
||||
void Clear() { service_ids.clear(); }
|
||||
void Add(const std::string& service_id) { service_ids.emplace(service_id); }
|
||||
void Remove(const std::string& service_id) {
|
||||
service_ids.erase(service_id);
|
||||
}
|
||||
bool Existed(const std::string& service_id) const {
|
||||
return service_ids.contains(service_id);
|
||||
}
|
||||
|
||||
absl::flat_hash_set<std::string> service_ids;
|
||||
};
|
||||
|
||||
struct AcceptingConnectionsInfo {
|
||||
bool Empty() const { return service_ids.empty(); }
|
||||
void Clear() { service_ids.clear(); }
|
||||
void Add(const std::string& service_id) { service_ids.emplace(service_id); }
|
||||
void Remove(const std::string& service_id) {
|
||||
service_ids.erase(service_id);
|
||||
}
|
||||
bool Existed(const std::string& service_id) const {
|
||||
return service_ids.contains(service_id);
|
||||
}
|
||||
|
||||
absl::flat_hash_set<std::string> service_ids;
|
||||
};
|
||||
|
||||
// Same as IsAvailable(), but must be called with mutex_ held.
|
||||
bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// Same as IsAdvertising(), but must be called with mutex_ held.
|
||||
bool IsAdvertisingLocked(const std::string& service_id)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// Same as IsDiscovering(), but must be called with mutex_ held.
|
||||
bool IsScanningLocked(const std::string& service_id)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// Same as IsAcceptingConnections(), but must be called with mutex_ held.
|
||||
bool IsAcceptingConnectionsLocked(const std::string& service_id)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
mutable Mutex mutex_;
|
||||
BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_);
|
||||
BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){
|
||||
radio_.GetBluetoothAdapter()};
|
||||
BleMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_};
|
||||
AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_);
|
||||
ScanningInfo scanning_info_ ABSL_GUARDED_BY(mutex_);
|
||||
AcceptingConnectionsInfo accepting_connections_info_ ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // CORE_V2_INTERNAL_MEDIUMS_BLE_H_
|
||||
@@ -0,0 +1,162 @@
|
||||
#include "core_v2/internal/mediums/ble.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "core_v2/internal/mediums/bluetooth_radio.h"
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "platform_v2/public/ble.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace {
|
||||
|
||||
constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000);
|
||||
constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"};
|
||||
constexpr absl::string_view kAdvertisementString{"\x0a\x0b\x0c\x0d"};
|
||||
|
||||
class BleTest : public ::testing::Test {
|
||||
protected:
|
||||
using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback;
|
||||
|
||||
BleTest() { env_.Stop(); }
|
||||
|
||||
MediumEnvironment& env_{MediumEnvironment::Instance()};
|
||||
};
|
||||
|
||||
TEST_F(BleTest, CanConstructValidObject) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
Ble ble_a{radio_a};
|
||||
Ble ble_b{radio_b};
|
||||
|
||||
EXPECT_TRUE(ble_a.IsMediumValid());
|
||||
EXPECT_TRUE(ble_a.IsAdapterValid());
|
||||
EXPECT_TRUE(ble_a.IsAvailable());
|
||||
EXPECT_TRUE(ble_b.IsMediumValid());
|
||||
EXPECT_TRUE(ble_b.IsAdapterValid());
|
||||
EXPECT_TRUE(ble_b.IsAvailable());
|
||||
EXPECT_NE(&radio_a.GetBluetoothAdapter(), &radio_b.GetBluetoothAdapter());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleTest, CanStartAdvertising) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
Ble ble_a{radio_a};
|
||||
Ble ble_b{radio_b};
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
std::string service_id(kServiceID);
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
ble_b.StartScanning(service_id,
|
||||
DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch](BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
});
|
||||
|
||||
EXPECT_TRUE(ble_a.StartAdvertising(service_id, advertisement_bytes));
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopAdvertising(service_id));
|
||||
EXPECT_TRUE(ble_b.StopScanning(service_id));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleTest, CanStartDiscovery) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
Ble ble_a{radio_a};
|
||||
Ble ble_b{radio_b};
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
std::string service_id(kServiceID);
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
CountDownLatch accept_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
ble_b.StartAdvertising(service_id, advertisement_bytes);
|
||||
|
||||
EXPECT_TRUE(ble_a.StartScanning(
|
||||
service_id, DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&accept_latch](BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
accept_latch.CountDown();
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[&lost_latch](BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
lost_latch.CountDown();
|
||||
},
|
||||
}));
|
||||
EXPECT_TRUE(accept_latch.Await(kWaitDuration).result());
|
||||
ble_b.StopAdvertising(service_id);
|
||||
EXPECT_TRUE(lost_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopScanning(service_id));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleTest, CanStartAcceptingConnectionsAndConnect) {
|
||||
env_.Start();
|
||||
BluetoothRadio radio_a;
|
||||
BluetoothRadio radio_b;
|
||||
Ble ble_a{radio_a};
|
||||
Ble ble_b{radio_b};
|
||||
radio_a.Enable();
|
||||
radio_b.Enable();
|
||||
std::string service_id(kServiceID);
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch accept_latch(1);
|
||||
|
||||
ble_a.StartAdvertising(service_id, advertisement_bytes);
|
||||
ble_a.StartAcceptingConnections(
|
||||
service_id,
|
||||
{
|
||||
.accepted_cb = [&accept_latch](
|
||||
BleSocket socket,
|
||||
const std::string&) { accept_latch.CountDown(); },
|
||||
});
|
||||
BlePeripheral discovered_peripheral;
|
||||
ble_b.StartScanning(
|
||||
service_id,
|
||||
{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch, &discovered_peripheral](
|
||||
BlePeripheral& peripheral, const std::string& service_id) {
|
||||
discovered_peripheral = peripheral;
|
||||
NEARBY_LOG(INFO, "Discovered peripheral=%p [impl=%p]",
|
||||
&peripheral, &peripheral.GetImpl());
|
||||
found_latch.CountDown();
|
||||
},
|
||||
});
|
||||
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
ASSERT_TRUE(discovered_peripheral.IsValid());
|
||||
|
||||
BleSocket socket =
|
||||
ble_b.Connect(discovered_peripheral, service_id);
|
||||
|
||||
EXPECT_TRUE(accept_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(socket.IsValid());
|
||||
ble_b.StopScanning(service_id);
|
||||
ble_a.StopAdvertising(service_id);
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -382,6 +382,12 @@ BluetoothSocket BluetoothClassic::Connect(BluetoothDevice& bluetooth_device,
|
||||
return socket;
|
||||
}
|
||||
|
||||
BluetoothDevice BluetoothClassic::FindRemoteDevice(
|
||||
const std::string& mac_address) {
|
||||
MutexLock lock(&mutex_);
|
||||
return medium_.FindRemoteDevice(mac_address);
|
||||
}
|
||||
|
||||
std::string BluetoothClassic::GenerateUuidFromString(const std::string& data) {
|
||||
return std::string(Uuid(data));
|
||||
}
|
||||
|
||||
@@ -114,6 +114,9 @@ class BluetoothClassic {
|
||||
const std::string& service_name)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
BluetoothDevice FindRemoteDevice(const std::string& mac_address)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
struct ScanInfo {
|
||||
bool valid = false;
|
||||
|
||||
@@ -26,6 +26,8 @@ BluetoothClassic& Mediums::GetBluetoothClassic() {
|
||||
return bluetooth_classic_;
|
||||
}
|
||||
|
||||
Ble& Mediums::GetBle() { return ble_; }
|
||||
|
||||
WifiLan& Mediums::GetWifiLan() {
|
||||
return wifi_lan_;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef CORE_V2_INTERNAL_MEDIUMS_MEDIUMS_H_
|
||||
#define CORE_V2_INTERNAL_MEDIUMS_MEDIUMS_H_
|
||||
|
||||
#include "core_v2/internal/mediums/ble.h"
|
||||
#include "core_v2/internal/mediums/bluetooth_classic.h"
|
||||
#include "core_v2/internal/mediums/bluetooth_radio.h"
|
||||
#include "core_v2/internal/mediums/webrtc.h"
|
||||
@@ -36,6 +37,9 @@ class Mediums {
|
||||
// Returns a handle to the Bluetooth Classic medium.
|
||||
BluetoothClassic& GetBluetoothClassic();
|
||||
|
||||
// Returns a handle to the Ble medium.
|
||||
Ble& GetBle();
|
||||
|
||||
// Returns a handle to the Wifi-Lan medium.
|
||||
WifiLan& GetWifiLan();
|
||||
|
||||
@@ -53,6 +57,7 @@ class Mediums {
|
||||
// corresponding radio.
|
||||
BluetoothRadio bluetooth_radio_;
|
||||
BluetoothClassic bluetooth_classic_{bluetooth_radio_};
|
||||
Ble ble_{bluetooth_radio_};
|
||||
WifiLan wifi_lan_;
|
||||
mediums::WebRtc webrtc_;
|
||||
};
|
||||
|
||||
@@ -58,8 +58,7 @@ bool WifiLan::StartAdvertising(const std::string& service_id,
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << "Turned on WifiLan advertising with service info name="
|
||||
<< service_info_name
|
||||
<< ", service id=" << service_id;
|
||||
<< service_info_name << ", service id=" << service_id;
|
||||
advertising_info_.Add(service_id);
|
||||
return true;
|
||||
}
|
||||
@@ -222,7 +221,8 @@ bool WifiLan::IsAcceptingConnectionsLocked(const std::string& service_id) {
|
||||
WifiLanSocket WifiLan::Connect(WifiLanService& wifi_lan_service,
|
||||
const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
NEARBY_LOG(INFO, "WifiLan::Connect: service=%p", &wifi_lan_service);
|
||||
NEARBY_LOG(INFO, "WifiLan::Connect: service=%p, service_info_name=%s",
|
||||
&wifi_lan_service, wifi_lan_service.GetName().c_str());
|
||||
// Socket to return. To allow for NRVO to work, it has to be a single object.
|
||||
WifiLanSocket socket;
|
||||
|
||||
@@ -242,13 +242,19 @@ WifiLanSocket WifiLan::Connect(WifiLanService& wifi_lan_service,
|
||||
|
||||
socket = medium_.Connect(wifi_lan_service, service_id);
|
||||
if (!socket.IsValid()) {
|
||||
NEARBY_LOG(INFO, "Failed to Connect via WifiLan [service=%s]",
|
||||
NEARBY_LOG(INFO, "Failed to Connect via WifiLan [service_id=%s]",
|
||||
service_id.c_str());
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
WifiLanService WifiLan::GetRemoteWifiLanService(const std::string& ip_address,
|
||||
int port) {
|
||||
MutexLock lock(&mutex_);
|
||||
return medium_.FindRemoteService(ip_address, port);
|
||||
}
|
||||
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -83,6 +83,9 @@ class WifiLan {
|
||||
const std::string& service_id)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
WifiLanService GetRemoteWifiLanService(const std::string& ip_address,
|
||||
int port) ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
private:
|
||||
struct AdvertisingInfo {
|
||||
bool Empty() const { return service_ids.empty(); }
|
||||
@@ -129,7 +132,7 @@ class WifiLan {
|
||||
// Same as IsAvailable(), but must be called with mutex_ held.
|
||||
bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// Same as IsAdvertising(), but must be called with mutex_ held.
|
||||
// Same as IsAdvertising(), but must be called with mutex_ held.
|
||||
bool IsAdvertisingLocked(const std::string& service_id)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "platform_v2/public/wifi_lan.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -47,7 +48,6 @@ TEST_F(WifiLanTest, CanConstructValidObject) {
|
||||
WifiLan wifi_lan_a;
|
||||
WifiLan wifi_lan_b;
|
||||
std::string service_id(kServiceID);
|
||||
std::string service_name{kServiceInfoName};
|
||||
|
||||
EXPECT_TRUE(wifi_lan_a.IsAvailable());
|
||||
EXPECT_TRUE(wifi_lan_b.IsAvailable());
|
||||
@@ -59,19 +59,19 @@ TEST_F(WifiLanTest, CanStartAdvertising) {
|
||||
WifiLan wifi_lan_a;
|
||||
WifiLan wifi_lan_b;
|
||||
std::string service_id(kServiceID);
|
||||
std::string service_name{kServiceInfoName};
|
||||
std::string service_info_name{kServiceInfoName};
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
wifi_lan_b.StartDiscovery(
|
||||
service_id, DiscoveredServiceCallback{
|
||||
.service_discovered_cb =
|
||||
[&found_latch](WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
absl::string_view service_id) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
});
|
||||
|
||||
EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id, service_name));
|
||||
EXPECT_TRUE(wifi_lan_a.StartAdvertising(service_id, service_info_name));
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(wifi_lan_a.StopAdvertising(service_id));
|
||||
EXPECT_TRUE(wifi_lan_b.StopDiscovery(service_id));
|
||||
@@ -83,11 +83,11 @@ TEST_F(WifiLanTest, CanStartDiscovery) {
|
||||
WifiLan wifi_lan_a;
|
||||
WifiLan wifi_lan_b;
|
||||
std::string service_id(kServiceID);
|
||||
std::string service_name{kServiceInfoName};
|
||||
std::string service_info_name{kServiceInfoName};
|
||||
CountDownLatch accept_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
wifi_lan_b.StartAdvertising(service_id, service_name);
|
||||
wifi_lan_b.StartAdvertising(service_id, service_info_name);
|
||||
|
||||
EXPECT_TRUE(wifi_lan_a.StartDiscovery(
|
||||
service_id, {
|
||||
@@ -114,17 +114,17 @@ TEST_F(WifiLanTest, CanStartAcceptingConnectionsAndConnect) {
|
||||
WifiLan wifi_lan_a;
|
||||
WifiLan wifi_lan_b;
|
||||
std::string service_id(kServiceID);
|
||||
std::string service_name{kServiceInfoName};
|
||||
std::string service_info_name{kServiceInfoName};
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch accept_latch(1);
|
||||
|
||||
wifi_lan_a.StartAdvertising(service_id, service_name);
|
||||
wifi_lan_a.StartAdvertising(service_id, service_info_name);
|
||||
wifi_lan_a.StartAcceptingConnections(
|
||||
service_id,
|
||||
{
|
||||
.accepted_cb = [&accept_latch](
|
||||
WifiLanSocket socket,
|
||||
const std::string&) { accept_latch.CountDown(); },
|
||||
absl::string_view) { accept_latch.CountDown(); },
|
||||
});
|
||||
WifiLanService discovered_service;
|
||||
wifi_lan_b.StartDiscovery(
|
||||
@@ -132,7 +132,7 @@ TEST_F(WifiLanTest, CanStartAcceptingConnectionsAndConnect) {
|
||||
{
|
||||
.service_discovered_cb =
|
||||
[&found_latch, &discovered_service](
|
||||
WifiLanService& service, const std::string& service_id) {
|
||||
WifiLanService& service, absl::string_view service_id) {
|
||||
discovered_service = service;
|
||||
NEARBY_LOG(INFO, "Discovered service=%p [impl=%p]", &service,
|
||||
&service.GetImpl());
|
||||
@@ -149,6 +149,7 @@ TEST_F(WifiLanTest, CanStartAcceptingConnectionsAndConnect) {
|
||||
EXPECT_TRUE(accept_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(socket.IsValid());
|
||||
wifi_lan_b.StopDiscovery(service_id);
|
||||
wifi_lan_a.StopAcceptingConnections(service_id);
|
||||
wifi_lan_a.StopAdvertising(service_id);
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
@@ -49,7 +49,8 @@ class MockServiceController : public ServiceController {
|
||||
|
||||
MOCK_METHOD(Status, RequestConnection,
|
||||
(ClientProxy * client, const std::string& endpoint_id,
|
||||
const ConnectionRequestInfo& info),
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(Status, AcceptConnection,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "core/internal/message_lite.h"
|
||||
#include "proto/connections/offline_wire_formats.pb.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
|
||||
namespace location {
|
||||
@@ -27,7 +28,6 @@ namespace parser {
|
||||
namespace {
|
||||
|
||||
using ExceptionOrOfflineFrame = ExceptionOr<OfflineFrame>;
|
||||
using Medium = proto::connections::Medium;
|
||||
using MessageLite = ::google::protobuf::MessageLite;
|
||||
|
||||
ByteArray ToBytes(OfflineFrame&& frame) {
|
||||
@@ -58,7 +58,7 @@ V1Frame::FrameType GetFrameType(const OfflineFrame& frame) {
|
||||
}
|
||||
|
||||
ByteArray ForConnectionRequest(const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
std::int32_t nonce,
|
||||
const std::vector<Medium>& mediums) {
|
||||
OfflineFrame frame;
|
||||
@@ -68,8 +68,8 @@ ByteArray ForConnectionRequest(const std::string& endpoint_id,
|
||||
v1_frame->set_type(V1Frame::CONNECTION_REQUEST);
|
||||
auto* connection_request = v1_frame->mutable_connection_request();
|
||||
connection_request->set_endpoint_id(endpoint_id);
|
||||
connection_request->set_endpoint_name(endpoint_name);
|
||||
connection_request->set_endpoint_info(endpoint_name);
|
||||
connection_request->set_endpoint_name(std::string(endpoint_info));
|
||||
connection_request->set_endpoint_info(std::string(endpoint_info));
|
||||
connection_request->set_nonce(nonce);
|
||||
for (const auto& medium : mediums) {
|
||||
connection_request->add_mediums(MediumToConnectionRequestMedium(medium));
|
||||
@@ -122,7 +122,7 @@ ByteArray ForControlPayloadTransfer(
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ByteArray ForBandwidthUpgradeWifiHotspot(const std::string& ssid,
|
||||
ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid,
|
||||
const std::string& password,
|
||||
std::int32_t port) {
|
||||
OfflineFrame frame;
|
||||
@@ -134,8 +134,7 @@ ByteArray ForBandwidthUpgradeWifiHotspot(const std::string& ssid,
|
||||
sub_frame->set_event_type(
|
||||
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
|
||||
auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
|
||||
upgrade_path_info->set_medium(
|
||||
BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WIFI_HOTSPOT);
|
||||
upgrade_path_info->set_medium(UpgradePathInfo::WIFI_HOTSPOT);
|
||||
auto* wifi_hotspot_credentials =
|
||||
upgrade_path_info->mutable_wifi_hotspot_credentials();
|
||||
wifi_hotspot_credentials->set_ssid(ssid);
|
||||
@@ -145,7 +144,46 @@ ByteArray ForBandwidthUpgradeWifiHotspot(const std::string& ssid,
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ByteArray ForBandwidthUpgradeLastWrite() {
|
||||
ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address,
|
||||
std::int32_t port) {
|
||||
OfflineFrame frame;
|
||||
|
||||
frame.set_version(OfflineFrame::V1);
|
||||
auto* v1_frame = frame.mutable_v1();
|
||||
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
|
||||
auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation();
|
||||
sub_frame->set_event_type(
|
||||
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
|
||||
auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
|
||||
upgrade_path_info->set_medium(UpgradePathInfo::WIFI_LAN);
|
||||
auto* wifi_lan_socket = upgrade_path_info->mutable_wifi_lan_socket();
|
||||
wifi_lan_socket->set_ip_address(ip_address);
|
||||
wifi_lan_socket->set_wifi_port(port);
|
||||
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id,
|
||||
const std::string& mac_address) {
|
||||
OfflineFrame frame;
|
||||
|
||||
frame.set_version(OfflineFrame::V1);
|
||||
auto* v1_frame = frame.mutable_v1();
|
||||
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
|
||||
auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation();
|
||||
sub_frame->set_event_type(
|
||||
BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE);
|
||||
auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
|
||||
upgrade_path_info->set_medium(UpgradePathInfo::BLUETOOTH);
|
||||
auto* bluetooth_credentials =
|
||||
upgrade_path_info->mutable_bluetooth_credentials();
|
||||
bluetooth_credentials->set_mac_address(mac_address);
|
||||
bluetooth_credentials->set_service_name(service_id);
|
||||
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ByteArray ForBwuLastWrite() {
|
||||
OfflineFrame frame;
|
||||
|
||||
frame.set_version(OfflineFrame::V1);
|
||||
@@ -158,7 +196,7 @@ ByteArray ForBandwidthUpgradeLastWrite() {
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ByteArray ForBandwidthUpgradeSafeToClose() {
|
||||
ByteArray ForBwuSafeToClose() {
|
||||
OfflineFrame frame;
|
||||
|
||||
frame.set_version(OfflineFrame::V1);
|
||||
@@ -171,7 +209,7 @@ ByteArray ForBandwidthUpgradeSafeToClose() {
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ByteArray ForBandwidthUpgradeIntroduction(const std::string& endpoint_id) {
|
||||
ByteArray ForBwuIntroduction(const std::string& endpoint_id) {
|
||||
OfflineFrame frame;
|
||||
|
||||
frame.set_version(OfflineFrame::V1);
|
||||
@@ -186,6 +224,21 @@ ByteArray ForBandwidthUpgradeIntroduction(const std::string& endpoint_id) {
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ByteArray ForBwuFailure(const UpgradePathInfo& info) {
|
||||
OfflineFrame frame;
|
||||
|
||||
frame.set_version(OfflineFrame::V1);
|
||||
auto* v1_frame = frame.mutable_v1();
|
||||
v1_frame->set_type(V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION);
|
||||
auto* sub_frame = v1_frame->mutable_bandwidth_upgrade_negotiation();
|
||||
sub_frame->set_event_type(
|
||||
BandwidthUpgradeNegotiationFrame::UPGRADE_FAILURE);
|
||||
auto* upgrade_path_info = sub_frame->mutable_upgrade_path_info();
|
||||
*upgrade_path_info = info;
|
||||
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ByteArray ForKeepAlive() {
|
||||
OfflineFrame frame;
|
||||
|
||||
@@ -197,8 +250,57 @@ ByteArray ForKeepAlive() {
|
||||
return ToBytes(std::move(frame));
|
||||
}
|
||||
|
||||
ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(
|
||||
proto::connections::Medium medium) {
|
||||
UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium) {
|
||||
switch (medium) {
|
||||
case Medium::MDNS:
|
||||
return UpgradePathInfo::MDNS;
|
||||
case Medium::BLUETOOTH:
|
||||
return UpgradePathInfo::BLUETOOTH;
|
||||
case Medium::WIFI_HOTSPOT:
|
||||
return UpgradePathInfo::WIFI_HOTSPOT;
|
||||
case Medium::BLE:
|
||||
return UpgradePathInfo::BLE;
|
||||
case Medium::WIFI_LAN:
|
||||
return UpgradePathInfo::WIFI_LAN;
|
||||
case Medium::WIFI_AWARE:
|
||||
return UpgradePathInfo::WIFI_AWARE;
|
||||
case Medium::NFC:
|
||||
return UpgradePathInfo::NFC;
|
||||
case Medium::WIFI_DIRECT:
|
||||
return UpgradePathInfo::WIFI_DIRECT;
|
||||
case Medium::WEB_RTC:
|
||||
return UpgradePathInfo::WEB_RTC;
|
||||
default:
|
||||
return UpgradePathInfo::UNKNOWN_MEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium) {
|
||||
switch (medium) {
|
||||
case UpgradePathInfo::MDNS:
|
||||
return Medium::MDNS;
|
||||
case UpgradePathInfo::BLUETOOTH:
|
||||
return Medium::BLUETOOTH;
|
||||
case UpgradePathInfo::WIFI_HOTSPOT:
|
||||
return Medium::WIFI_HOTSPOT;
|
||||
case UpgradePathInfo::BLE:
|
||||
return Medium::BLE;
|
||||
case UpgradePathInfo::WIFI_LAN:
|
||||
return Medium::WIFI_LAN;
|
||||
case UpgradePathInfo::WIFI_AWARE:
|
||||
return Medium::WIFI_AWARE;
|
||||
case UpgradePathInfo::NFC:
|
||||
return Medium::NFC;
|
||||
case UpgradePathInfo::WIFI_DIRECT:
|
||||
return Medium::WIFI_DIRECT;
|
||||
case UpgradePathInfo::WEB_RTC:
|
||||
return Medium::WEB_RTC;
|
||||
default:
|
||||
return Medium::UNKNOWN_MEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(Medium medium) {
|
||||
switch (medium) {
|
||||
case Medium::MDNS:
|
||||
return ConnectionRequestFrame::MDNS;
|
||||
@@ -223,8 +325,7 @@ ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(
|
||||
}
|
||||
}
|
||||
|
||||
proto::connections::Medium ConnectionRequestMediumToMedium(
|
||||
ConnectionRequestFrame::Medium medium) {
|
||||
Medium ConnectionRequestMediumToMedium(ConnectionRequestFrame::Medium medium) {
|
||||
switch (medium) {
|
||||
case ConnectionRequestFrame::MDNS:
|
||||
return Medium::MDNS;
|
||||
@@ -249,9 +350,9 @@ proto::connections::Medium ConnectionRequestMediumToMedium(
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<proto::connections::Medium> ConnectionRequestMediumsToMediums(
|
||||
std::vector<Medium> ConnectionRequestMediumsToMediums(
|
||||
const ConnectionRequestFrame& frame) {
|
||||
std::vector<proto::connections::Medium> result;
|
||||
std::vector<Medium> result;
|
||||
for (const auto& int_medium : frame.mediums()) {
|
||||
result.push_back(ConnectionRequestMediumToMedium(
|
||||
static_cast<ConnectionRequestFrame::Medium>(int_medium)));
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "core_v2/options.h"
|
||||
#include "proto/connections/offline_wire_formats.pb.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/exception.h"
|
||||
@@ -28,6 +29,8 @@ namespace nearby {
|
||||
namespace connections {
|
||||
namespace parser {
|
||||
|
||||
using UpgradePathInfo = BandwidthUpgradeNegotiationFrame::UpgradePathInfo;
|
||||
|
||||
// Serialize/Deserialize Nearby Connections Protocol messages.
|
||||
|
||||
// Parses incoming message.
|
||||
@@ -39,12 +42,13 @@ ExceptionOr<OfflineFrame> FromBytes(const ByteArray& offline_frame_bytes);
|
||||
// V1Frame::UNKNOWN_FRAME_TYPE, if frame contents is not recognized.
|
||||
V1Frame::FrameType GetFrameType(const OfflineFrame& offline_frame);
|
||||
|
||||
// Build ConnectionRequest message.
|
||||
// Builds Connection Request / Response messages.
|
||||
ByteArray ForConnectionRequest(
|
||||
const std::string& endpoint_id, const std::string& endpoint_name,
|
||||
std::int32_t nonce, const std::vector<proto::connections::Medium>& mediums);
|
||||
const std::string& endpoint_id, const ByteArray& endpoint_info,
|
||||
std::int32_t nonce, const std::vector<Medium>& mediums);
|
||||
ByteArray ForConnectionResponse(std::int32_t status);
|
||||
|
||||
// Builds Payload transfer messages.
|
||||
ByteArray ForDataPayloadTransfer(
|
||||
const PayloadTransferFrame::PayloadHeader& header,
|
||||
const PayloadTransferFrame::PayloadChunk& chunk);
|
||||
@@ -52,19 +56,27 @@ ByteArray ForControlPayloadTransfer(
|
||||
const PayloadTransferFrame::PayloadHeader& header,
|
||||
const PayloadTransferFrame::ControlMessage& control);
|
||||
|
||||
ByteArray ForBandwidthUpgradeWifiHotspot(
|
||||
const std::string& ssid, const std::string& password, std::int32_t port);
|
||||
ByteArray ForBandwidthUpgradeLastWrite();
|
||||
ByteArray ForBandwidthUpgradeSafeToClose();
|
||||
ByteArray ForBandwidthUpgradeIntroduction(const std::string& endpoint_id);
|
||||
// Builds Bandwidth Upgrade [BWU] messages.
|
||||
ByteArray ForBwuIntroduction(const std::string& endpoint_id);
|
||||
ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid,
|
||||
const std::string& password,
|
||||
std::int32_t port);
|
||||
ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address,
|
||||
std::int32_t port);
|
||||
ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id,
|
||||
const std::string& mac_address);
|
||||
ByteArray ForBwuFailure(const UpgradePathInfo& info);
|
||||
ByteArray ForBwuLastWrite();
|
||||
ByteArray ForBwuSafeToClose();
|
||||
|
||||
ByteArray ForKeepAlive();
|
||||
|
||||
ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(
|
||||
proto::connections::Medium medium);
|
||||
proto::connections::Medium ConnectionRequestMediumToMedium(
|
||||
ConnectionRequestFrame::Medium medium);
|
||||
std::vector<proto::connections::Medium> ConnectionRequestMediumsToMediums(
|
||||
UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium);
|
||||
Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium);
|
||||
|
||||
ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(Medium medium);
|
||||
Medium ConnectionRequestMediumToMedium(ConnectionRequestFrame::Medium medium);
|
||||
std::vector<Medium> ConnectionRequestMediumsToMediums(
|
||||
const ConnectionRequestFrame& connection_request_frame);
|
||||
|
||||
} // namespace parser
|
||||
|
||||
@@ -93,7 +93,7 @@ TEST(OfflineFramesTest, CanGenerateConnectionRequest) {
|
||||
>
|
||||
>)pb";
|
||||
ByteArray bytes = ForConnectionRequest(
|
||||
std::string(kEndpointId), std::string(kEndpointName), kNonce,
|
||||
std::string(kEndpointId), ByteArray{std::string(kEndpointName)}, kNonce,
|
||||
std::vector(kMediums.begin(), kMediums.end()));
|
||||
auto response = FromBytes(bytes);
|
||||
ASSERT_TRUE(response.ok());
|
||||
@@ -171,7 +171,7 @@ TEST(OfflineFramesTest, CanGenerateDataPayloadTransfer) {
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
}
|
||||
|
||||
TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeWifiHotspot) {
|
||||
TEST(OfflineFramesTest, CanGenerateBwuWifiHotspotPathAvailable) {
|
||||
constexpr char kExpected[] =
|
||||
R"pb(
|
||||
version: V1
|
||||
@@ -189,14 +189,60 @@ TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeWifiHotspot) {
|
||||
>
|
||||
>
|
||||
>)pb";
|
||||
ByteArray bytes = ForBandwidthUpgradeWifiHotspot("ssid", "password", 1234);
|
||||
ByteArray bytes = ForBwuWifiHotspotPathAvailable("ssid", "password", 1234);
|
||||
auto response = FromBytes(bytes);
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = FromBytes(bytes).result();
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
}
|
||||
|
||||
TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeLastWrite) {
|
||||
TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) {
|
||||
constexpr char kExpected[] =
|
||||
R"pb(
|
||||
version: V1
|
||||
v1: <
|
||||
type: BANDWIDTH_UPGRADE_NEGOTIATION
|
||||
bandwidth_upgrade_negotiation: <
|
||||
event_type: UPGRADE_PATH_AVAILABLE
|
||||
upgrade_path_info: <
|
||||
medium: WIFI_LAN
|
||||
wifi_lan_socket: < ip_address: "\x01\x02\x03\x04" wifi_port: 1234 >
|
||||
>
|
||||
>
|
||||
>)pb";
|
||||
ByteArray bytes = ForBwuWifiLanPathAvailable("\x01\x02\x03\x04", 1234);
|
||||
auto response = FromBytes(bytes);
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = FromBytes(bytes).result();
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
}
|
||||
|
||||
TEST(OfflineFramesTest, CanGenerateBwuBluetoothPathAvailable) {
|
||||
constexpr char kExpected[] =
|
||||
R"pb(
|
||||
version: V1
|
||||
v1: <
|
||||
type: BANDWIDTH_UPGRADE_NEGOTIATION
|
||||
bandwidth_upgrade_negotiation: <
|
||||
event_type: UPGRADE_PATH_AVAILABLE
|
||||
upgrade_path_info: <
|
||||
medium: BLUETOOTH
|
||||
bluetooth_credentials: <
|
||||
service_name: "service"
|
||||
mac_address: "\x11\x22\x33\x44\x55\x66"
|
||||
>
|
||||
>
|
||||
>
|
||||
>)pb";
|
||||
ByteArray bytes =
|
||||
ForBwuBluetoothPathAvailable("service", "\x11\x22\x33\x44\x55\x66");
|
||||
auto response = FromBytes(bytes);
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = FromBytes(bytes).result();
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
}
|
||||
|
||||
TEST(OfflineFramesTest, CanGenerateBwuLastWrite) {
|
||||
constexpr char kExpected[] =
|
||||
R"pb(
|
||||
version: V1
|
||||
@@ -204,14 +250,14 @@ TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeLastWrite) {
|
||||
type: BANDWIDTH_UPGRADE_NEGOTIATION
|
||||
bandwidth_upgrade_negotiation: < event_type: LAST_WRITE_TO_PRIOR_CHANNEL >
|
||||
>)pb";
|
||||
ByteArray bytes = ForBandwidthUpgradeLastWrite();
|
||||
ByteArray bytes = ForBwuLastWrite();
|
||||
auto response = FromBytes(bytes);
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = FromBytes(bytes).result();
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
}
|
||||
|
||||
TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeSafeToClose) {
|
||||
TEST(OfflineFramesTest, CanGenerateBwuSafeToClose) {
|
||||
constexpr char kExpected[] =
|
||||
R"pb(
|
||||
version: V1
|
||||
@@ -219,14 +265,14 @@ TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeSafeToClose) {
|
||||
type: BANDWIDTH_UPGRADE_NEGOTIATION
|
||||
bandwidth_upgrade_negotiation: < event_type: SAFE_TO_CLOSE_PRIOR_CHANNEL >
|
||||
>)pb";
|
||||
ByteArray bytes = ForBandwidthUpgradeSafeToClose();
|
||||
ByteArray bytes = ForBwuSafeToClose();
|
||||
auto response = FromBytes(bytes);
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = FromBytes(bytes).result();
|
||||
EXPECT_THAT(message, EqualsProto(kExpected));
|
||||
}
|
||||
|
||||
TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeIntroduction) {
|
||||
TEST(OfflineFramesTest, CanGenerateBwuIntroduction) {
|
||||
constexpr char kExpected[] =
|
||||
R"pb(
|
||||
version: V1
|
||||
@@ -237,7 +283,7 @@ TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeIntroduction) {
|
||||
client_introduction: < endpoint_id: "ABC" >
|
||||
>
|
||||
>)pb";
|
||||
ByteArray bytes = ForBandwidthUpgradeIntroduction(std::string(kEndpointId));
|
||||
ByteArray bytes = ForBwuIntroduction(std::string(kEndpointId));
|
||||
auto response = FromBytes(bytes);
|
||||
ASSERT_TRUE(response.ok());
|
||||
OfflineFrame message = FromBytes(bytes).result();
|
||||
|
||||
@@ -20,9 +20,7 @@ namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
OfflineServiceController::~OfflineServiceController() {
|
||||
Stop();
|
||||
}
|
||||
OfflineServiceController::~OfflineServiceController() { Stop(); }
|
||||
|
||||
void OfflineServiceController::Stop() {
|
||||
if (stop_.Set(true)) return;
|
||||
@@ -52,8 +50,8 @@ void OfflineServiceController::StopDiscovery(ClientProxy* client) {
|
||||
|
||||
Status OfflineServiceController::RequestConnection(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
const ConnectionRequestInfo& info) {
|
||||
return pcp_manager_.RequestConnection(client, endpoint_id, info);
|
||||
const ConnectionRequestInfo& info, const ConnectionOptions& options) {
|
||||
return pcp_manager_.RequestConnection(client, endpoint_id, info, options);
|
||||
}
|
||||
|
||||
Status OfflineServiceController::AcceptConnection(
|
||||
|
||||
@@ -54,7 +54,8 @@ class OfflineServiceController : public ServiceController {
|
||||
|
||||
Status RequestConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const ConnectionRequestInfo& info) override;
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options) override;
|
||||
Status AcceptConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const PayloadListener& listener) override;
|
||||
@@ -65,8 +66,8 @@ class OfflineServiceController : public ServiceController {
|
||||
const std::string& endpoint_id) override;
|
||||
|
||||
void SendPayload(ClientProxy* client,
|
||||
const std::vector<std::string>& endpoint_ids,
|
||||
Payload payload) override;
|
||||
const std::vector<std::string>& endpoint_ids,
|
||||
Payload payload) override;
|
||||
Status CancelPayload(ClientProxy* client,
|
||||
Payload::Id payload_id) override;
|
||||
|
||||
|
||||
@@ -39,7 +39,21 @@ constexpr absl::Duration kProgressTimeout = absl::Milliseconds(1000);
|
||||
constexpr absl::Duration kDefaultTimeout = absl::Milliseconds(1000);
|
||||
constexpr absl::Duration kDisconnectTimeout = absl::Milliseconds(15000);
|
||||
|
||||
class OfflineServiceControllerTest : public ::testing::Test {
|
||||
constexpr BooleanMediumSelector kTestCases[] = {
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.wifi_lan = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
.wifi_lan = true,
|
||||
},
|
||||
};
|
||||
|
||||
class OfflineServiceControllerTest
|
||||
: public ::testing::TestWithParam<BooleanMediumSelector> {
|
||||
protected:
|
||||
OfflineServiceControllerTest() { env_.Stop(); }
|
||||
|
||||
@@ -49,7 +63,7 @@ class OfflineServiceControllerTest : public ::testing::Test {
|
||||
user_b.StartDiscovery(std::string(kServiceId), &discover_latch_);
|
||||
EXPECT_TRUE(discover_latch_.Await(kDefaultTimeout).result());
|
||||
EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId);
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_name, user_a.GetName());
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo());
|
||||
EXPECT_FALSE(user_b.GetDiscovered().endpoint_id.empty());
|
||||
NEARBY_LOG(INFO, "EP-B: [discovered] %s",
|
||||
user_b.GetDiscovered().endpoint_id.c_str());
|
||||
@@ -67,29 +81,30 @@ class OfflineServiceControllerTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
CountDownLatch discover_latch_{1};
|
||||
CountDownLatch lost_latch_{1};
|
||||
CountDownLatch connect_latch_{2};
|
||||
CountDownLatch accept_latch_{2};
|
||||
CountDownLatch payload_latch_{1};
|
||||
MediumEnvironment& env_ = MediumEnvironment::Instance();
|
||||
};
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanCreateOne) {
|
||||
TEST_P(OfflineServiceControllerTest, CanCreateOne) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanCreateMany) {
|
||||
TEST_P(OfflineServiceControllerTest, CanCreateMany) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanStartAdvertising) {
|
||||
TEST_P(OfflineServiceControllerTest, CanStartAdvertising) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
EXPECT_FALSE(user_a.IsAdvertising());
|
||||
EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), nullptr),
|
||||
Eq(Status{Status::kSuccess}));
|
||||
@@ -97,10 +112,10 @@ TEST_F(OfflineServiceControllerTest, CanStartAdvertising) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanStartDiscoveryBeforeAdvertising) {
|
||||
TEST_P(OfflineServiceControllerTest, CanStartDiscoveryBeforeAdvertising) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
EXPECT_FALSE(user_b.IsDiscovering());
|
||||
EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_),
|
||||
Eq(Status{Status::kSuccess}));
|
||||
@@ -113,10 +128,10 @@ TEST_F(OfflineServiceControllerTest, CanStartDiscoveryBeforeAdvertising) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanStartDiscoveryAfterAdvertising) {
|
||||
TEST_P(OfflineServiceControllerTest, CanStartDiscoveryAfterAdvertising) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
EXPECT_FALSE(user_b.IsDiscovering());
|
||||
EXPECT_FALSE(user_b.IsAdvertising());
|
||||
EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), nullptr),
|
||||
@@ -131,29 +146,39 @@ TEST_F(OfflineServiceControllerTest, CanStartDiscoveryAfterAdvertising) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanStopAdvertising) {
|
||||
TEST_P(OfflineServiceControllerTest, CanStopAdvertising) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
EXPECT_FALSE(user_a.IsAdvertising());
|
||||
EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), nullptr),
|
||||
Eq(Status{Status::kSuccess}));
|
||||
EXPECT_TRUE(user_a.IsAdvertising());
|
||||
user_a.StopAdvertising();
|
||||
EXPECT_FALSE(user_a.IsAdvertising());
|
||||
EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_),
|
||||
EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_,
|
||||
&lost_latch_),
|
||||
Eq(Status{Status::kSuccess}));
|
||||
EXPECT_TRUE(user_b.IsDiscovering());
|
||||
EXPECT_FALSE(discover_latch_.Await(kDefaultTimeout).result());
|
||||
auto discover_none = discover_latch_.Await(kDefaultTimeout).GetResult();
|
||||
if (!discover_none) {
|
||||
EXPECT_TRUE(true);
|
||||
} else {
|
||||
// There are rare cases (1/1000) that advertisment data has been captured by
|
||||
// discovery device before advertising is stopped. So we need to check if
|
||||
// lost_cb has grabbed the event in the end to prove the advertising service
|
||||
// is stopped.
|
||||
EXPECT_TRUE(lost_latch_.Await(kDefaultTimeout).result());
|
||||
}
|
||||
user_a.Stop();
|
||||
user_b.Stop();
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanStopDiscovery) {
|
||||
TEST_P(OfflineServiceControllerTest, CanStopDiscovery) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
EXPECT_FALSE(user_b.IsDiscovering());
|
||||
EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_),
|
||||
Eq(Status{Status::kSuccess}));
|
||||
@@ -168,10 +193,10 @@ TEST_F(OfflineServiceControllerTest, CanStopDiscovery) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanConnect) {
|
||||
TEST_P(OfflineServiceControllerTest, CanConnect) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), &connect_latch_),
|
||||
Eq(Status{Status::kSuccess}));
|
||||
EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_),
|
||||
@@ -185,10 +210,10 @@ TEST_F(OfflineServiceControllerTest, CanConnect) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanAcceptConnection) {
|
||||
TEST_P(OfflineServiceControllerTest, CanAcceptConnection) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), &connect_latch_),
|
||||
Eq(Status{Status::kSuccess}));
|
||||
EXPECT_THAT(user_b.StartDiscovery(std::string(kServiceId), &discover_latch_),
|
||||
@@ -209,10 +234,10 @@ TEST_F(OfflineServiceControllerTest, CanAcceptConnection) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanRejectConnection) {
|
||||
TEST_P(OfflineServiceControllerTest, CanRejectConnection) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
CountDownLatch reject_latch(1);
|
||||
EXPECT_THAT(user_a.StartAdvertising(std::string(kServiceId), &connect_latch_),
|
||||
Eq(Status{Status::kSuccess}));
|
||||
@@ -230,10 +255,10 @@ TEST_F(OfflineServiceControllerTest, CanRejectConnection) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanSendBytePayload) {
|
||||
TEST_P(OfflineServiceControllerTest, CanSendBytePayload) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
ASSERT_TRUE(SetupConnection(user_a, user_b));
|
||||
ByteArray message(std::string{kMessage});
|
||||
user_a.SendPayload(Payload(message));
|
||||
@@ -245,10 +270,10 @@ TEST_F(OfflineServiceControllerTest, CanSendBytePayload) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanSendStreamPayload) {
|
||||
TEST_P(OfflineServiceControllerTest, CanSendStreamPayload) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
ASSERT_TRUE(SetupConnection(user_a, user_b));
|
||||
ByteArray message(std::string{kMessage});
|
||||
auto pipe = std::make_shared<Pipe>();
|
||||
@@ -272,10 +297,10 @@ TEST_F(OfflineServiceControllerTest, CanSendStreamPayload) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanCancelStreamPayload) {
|
||||
TEST_P(OfflineServiceControllerTest, CanCancelStreamPayload) {
|
||||
env_.Start();
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
ASSERT_TRUE(SetupConnection(user_a, user_b));
|
||||
ByteArray message(std::string{kMessage});
|
||||
auto pipe = std::make_shared<Pipe>();
|
||||
@@ -312,11 +337,11 @@ TEST_F(OfflineServiceControllerTest, CanCancelStreamPayload) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(OfflineServiceControllerTest, CanDisconnect) {
|
||||
TEST_P(OfflineServiceControllerTest, CanDisconnect) {
|
||||
env_.Start();
|
||||
CountDownLatch disconnect_latch(1);
|
||||
OfflineSimulationUser user_a(kDeviceA);
|
||||
OfflineSimulationUser user_b(kDeviceB);
|
||||
OfflineSimulationUser user_a(kDeviceA, GetParam());
|
||||
OfflineSimulationUser user_b(kDeviceB, GetParam());
|
||||
ASSERT_TRUE(SetupConnection(user_a, user_b));
|
||||
NEARBY_LOGS(INFO) << "Disconnecting";
|
||||
user_b.ExpectDisconnect(disconnect_latch);
|
||||
@@ -329,6 +354,10 @@ TEST_F(OfflineServiceControllerTest, CanDisconnect) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ParametrisedOfflineServiceControllerTest,
|
||||
OfflineServiceControllerTest,
|
||||
::testing::ValuesIn(kTestCases));
|
||||
|
||||
} // namespace
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "core_v2/internal/offline_simulation_user.h"
|
||||
|
||||
#include "core_v2/listeners.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
#include "platform_v2/public/system_clock.h"
|
||||
#include "absl/functional/bind_front.h"
|
||||
@@ -32,7 +33,7 @@ void OfflineSimulationUser::OnConnectionInitiated(
|
||||
NEARBY_LOG(INFO, "StartAdvertising: initiated_cb called");
|
||||
discovered_ = DiscoveredInfo{
|
||||
.endpoint_id = endpoint_id,
|
||||
.endpoint_name = name_,
|
||||
.endpoint_info = GetInfo(),
|
||||
.service_id = service_id_,
|
||||
};
|
||||
}
|
||||
@@ -57,12 +58,12 @@ void OfflineSimulationUser::OnEndpointDisconnect(
|
||||
}
|
||||
|
||||
void OfflineSimulationUser::OnEndpointFound(const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Device discovered: id=%s", endpoint_id.c_str());
|
||||
discovered_ = DiscoveredInfo{
|
||||
.endpoint_id = endpoint_id,
|
||||
.endpoint_name = endpoint_name,
|
||||
.endpoint_info = endpoint_info,
|
||||
.service_id = service_id,
|
||||
};
|
||||
if (found_latch_) found_latch_->CountDown();
|
||||
@@ -121,7 +122,7 @@ Status OfflineSimulationUser::StartAdvertising(const std::string& service_id,
|
||||
};
|
||||
return ctrl_.StartAdvertising(&client_, service_id_, options_,
|
||||
{
|
||||
.name = name_,
|
||||
.endpoint_info = info_,
|
||||
.listener = std::move(listener),
|
||||
});
|
||||
}
|
||||
@@ -131,8 +132,10 @@ void OfflineSimulationUser::StopAdvertising() {
|
||||
}
|
||||
|
||||
Status OfflineSimulationUser::StartDiscovery(const std::string& service_id,
|
||||
CountDownLatch* latch) {
|
||||
found_latch_ = latch;
|
||||
CountDownLatch* found_latch,
|
||||
CountDownLatch* lost_latch) {
|
||||
found_latch_ = found_latch;
|
||||
lost_latch_ = lost_latch;
|
||||
DiscoveryListener listener = {
|
||||
.endpoint_found_cb =
|
||||
absl::bind_front(&OfflineSimulationUser::OnEndpointFound, this),
|
||||
@@ -158,11 +161,13 @@ Status OfflineSimulationUser::RequestConnection(CountDownLatch* latch) {
|
||||
.disconnected_cb =
|
||||
absl::bind_front(&OfflineSimulationUser::OnEndpointDisconnect, this),
|
||||
};
|
||||
return ctrl_.RequestConnection(&client_, discovered_.endpoint_id,
|
||||
{
|
||||
.name = discovered_.endpoint_name,
|
||||
.listener = std::move(listener),
|
||||
});
|
||||
return ctrl_.RequestConnection(
|
||||
&client_, discovered_.endpoint_id,
|
||||
{
|
||||
.endpoint_info = discovered_.endpoint_info,
|
||||
.listener = std::move(listener),
|
||||
},
|
||||
connection_options_);
|
||||
}
|
||||
|
||||
Status OfflineSimulationUser::AcceptConnection(CountDownLatch* latch) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "core_v2/internal/client_proxy.h"
|
||||
#include "core_v2/internal/offline_service_controller.h"
|
||||
#include "core_v2/options.h"
|
||||
#include "platform_v2/public/atomic_boolean.h"
|
||||
#include "platform_v2/public/condition_variable.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
@@ -39,15 +40,21 @@ class OfflineSimulationUser {
|
||||
public:
|
||||
struct DiscoveredInfo {
|
||||
std::string endpoint_id;
|
||||
std::string endpoint_name;
|
||||
ByteArray endpoint_info;
|
||||
std::string service_id;
|
||||
|
||||
bool Empty() const { return endpoint_id.empty(); }
|
||||
void Clear() { endpoint_id.clear(); }
|
||||
};
|
||||
|
||||
explicit OfflineSimulationUser(absl::string_view device_name)
|
||||
: name_(device_name) {}
|
||||
explicit OfflineSimulationUser(
|
||||
absl::string_view device_name,
|
||||
BooleanMediumSelector allowed = BooleanMediumSelector())
|
||||
: info_{ByteArray{std::string(device_name)}},
|
||||
options_{
|
||||
.strategy = Strategy::kP2pCluster,
|
||||
.allowed = allowed,
|
||||
} {}
|
||||
virtual ~OfflineSimulationUser() = default;
|
||||
|
||||
// Calls PcpManager::StartAdvertising().
|
||||
@@ -59,9 +66,13 @@ class OfflineSimulationUser {
|
||||
void StopAdvertising();
|
||||
|
||||
// Calls PcpManager::StartDiscovery().
|
||||
// If latch is provided, will call latch->CountDown() in the endpoint_found_cb
|
||||
// callback.
|
||||
Status StartDiscovery(const std::string& service_id, CountDownLatch* latch);
|
||||
// If found_latch is provided, will call found_latch->CountDown() in the
|
||||
// endpoint_found_cb callback.
|
||||
// If lost_latch is provided, will call lost_latch->CountDown() in the
|
||||
// endpoint_lost_cb callback.
|
||||
Status StartDiscovery(const std::string& service_id,
|
||||
CountDownLatch* found_latch,
|
||||
CountDownLatch* lost_latch = nullptr);
|
||||
|
||||
// Calls PcpManager::StopDiscovery().
|
||||
void StopDiscovery();
|
||||
@@ -93,7 +104,7 @@ class OfflineSimulationUser {
|
||||
void ExpectDisconnect(CountDownLatch& latch) { disconnect_latch_ = &latch; }
|
||||
|
||||
const DiscoveredInfo& GetDiscovered() const { return discovered_; }
|
||||
std::string GetName() const { return name_; }
|
||||
ByteArray GetInfo() const { return info_; }
|
||||
|
||||
bool WaitForProgress(std::function<bool(const PayloadProgressInfo&)> pred,
|
||||
absl::Duration timeout);
|
||||
@@ -123,6 +134,8 @@ class OfflineSimulationUser {
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
StopAdvertising();
|
||||
StopDiscovery();
|
||||
ctrl_.Stop();
|
||||
}
|
||||
|
||||
@@ -137,7 +150,7 @@ class OfflineSimulationUser {
|
||||
|
||||
// DiscoveryListener callbacks
|
||||
void OnEndpointFound(const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id);
|
||||
void OnEndpointLost(const std::string& endpoint_id);
|
||||
|
||||
@@ -148,6 +161,8 @@ class OfflineSimulationUser {
|
||||
|
||||
std::string service_id_;
|
||||
DiscoveredInfo discovered_;
|
||||
ConnectionOptions connection_options_;
|
||||
|
||||
Mutex progress_mutex_;
|
||||
ConditionVariable progress_sync_{&progress_mutex_};
|
||||
PayloadProgressInfo progress_info_;
|
||||
@@ -162,8 +177,8 @@ class OfflineSimulationUser {
|
||||
CountDownLatch* disconnect_latch_ = nullptr;
|
||||
Future<bool>* future_ = nullptr;
|
||||
std::function<bool(const PayloadProgressInfo&)> predicate_;
|
||||
std::string name_;
|
||||
ConnectionOptions options_{.strategy = Strategy::kP2pCluster};
|
||||
ByteArray info_;
|
||||
ConnectionOptions options_;
|
||||
ClientProxy client_;
|
||||
OfflineServiceController ctrl_;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "core_v2/internal/p2p_cluster_pcp_handler.h"
|
||||
|
||||
#include "core_v2/internal/base_pcp_handler.h"
|
||||
#include "core_v2/internal/ble_advertisement.h"
|
||||
#include "core_v2/internal/ble_endpoint_channel.h"
|
||||
#include "core_v2/internal/bluetooth_endpoint_channel.h"
|
||||
#include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h"
|
||||
#include "core_v2/internal/webrtc_endpoint_channel.h"
|
||||
@@ -22,6 +24,8 @@
|
||||
#include "platform_v2/base/types.h"
|
||||
#include "platform_v2/public/crypto.h"
|
||||
#include "proto/connections_enums.pb.h"
|
||||
#include "absl/functional/bind_front.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -36,13 +40,14 @@ ByteArray P2pClusterPcpHandler::GenerateHash(const std::string& source,
|
||||
}
|
||||
|
||||
P2pClusterPcpHandler::P2pClusterPcpHandler(
|
||||
Mediums& mediums, EndpointManager* endpoint_manager,
|
||||
Mediums* mediums, EndpointManager* endpoint_manager,
|
||||
EndpointChannelManager* endpoint_channel_manager, Pcp pcp)
|
||||
: BasePcpHandler(endpoint_manager, endpoint_channel_manager, pcp),
|
||||
bluetooth_radio_(mediums.GetBluetoothRadio()),
|
||||
bluetooth_medium_(mediums.GetBluetoothClassic()),
|
||||
wifi_lan_medium_(mediums.GetWifiLan()),
|
||||
webrtc_medium_(mediums.GetWebRtc()) {}
|
||||
: BasePcpHandler(mediums, endpoint_manager, endpoint_channel_manager, pcp),
|
||||
bluetooth_radio_(mediums->GetBluetoothRadio()),
|
||||
bluetooth_medium_(mediums->GetBluetoothClassic()),
|
||||
ble_medium_(mediums->GetBle()),
|
||||
wifi_lan_medium_(mediums->GetWifiLan()),
|
||||
webrtc_medium_(mediums->GetWebRtc()) {}
|
||||
|
||||
// Returns a vector or mediums sorted in order or decreasing priority for
|
||||
// all the supported mediums.
|
||||
@@ -59,6 +64,9 @@ P2pClusterPcpHandler::GetConnectionMediumsByPriority() {
|
||||
if (bluetooth_medium_.IsAvailable()) {
|
||||
mediums.push_back(proto::connections::BLUETOOTH);
|
||||
}
|
||||
if (ble_medium_.IsAvailable()) {
|
||||
mediums.push_back(proto::connections::BLE);
|
||||
}
|
||||
return mediums;
|
||||
}
|
||||
|
||||
@@ -68,35 +76,55 @@ proto::connections::Medium P2pClusterPcpHandler::GetDefaultUpgradeMedium() {
|
||||
|
||||
BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name, const ConnectionOptions& options) {
|
||||
const std::string& local_endpoint_id, const ByteArray& local_endpoint_info,
|
||||
const ConnectionOptions& options) {
|
||||
std::vector<proto::connections::Medium> mediums_started_successfully;
|
||||
|
||||
const ByteArray wifi_lan_hash =
|
||||
GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength);
|
||||
proto::connections::Medium wifi_lan_medium =
|
||||
StartWifiLanAdvertising(client, service_id, wifi_lan_hash,
|
||||
local_endpoint_id, local_endpoint_name);
|
||||
if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::StartAdvertisingImpl: WifiLan added");
|
||||
mediums_started_successfully.push_back(wifi_lan_medium);
|
||||
if (options.allowed.wifi_lan) {
|
||||
const ByteArray wifi_lan_hash =
|
||||
GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength);
|
||||
proto::connections::Medium wifi_lan_medium =
|
||||
StartWifiLanAdvertising(client, service_id, wifi_lan_hash,
|
||||
local_endpoint_id, local_endpoint_info);
|
||||
if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::StartAdvertisingImpl: WifiLan added");
|
||||
mediums_started_successfully.push_back(wifi_lan_medium);
|
||||
}
|
||||
}
|
||||
|
||||
proto::connections::Medium webrtc_medium = StartListeningForWebRtcConnections(
|
||||
client, service_id, local_endpoint_id, local_endpoint_name);
|
||||
if (webrtc_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
mediums_started_successfully.push_back(webrtc_medium);
|
||||
if (options.allowed.web_rtc) {
|
||||
proto::connections::Medium webrtc_medium =
|
||||
StartListeningForWebRtcConnections(
|
||||
client, service_id, local_endpoint_id, local_endpoint_info);
|
||||
if (webrtc_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::StartAdvertisingImpl: WebRtc added");
|
||||
mediums_started_successfully.push_back(webrtc_medium);
|
||||
}
|
||||
}
|
||||
|
||||
const ByteArray bluetooth_hash =
|
||||
GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength);
|
||||
proto::connections::Medium bluetooth_medium =
|
||||
StartBluetoothAdvertising(client, service_id, bluetooth_hash,
|
||||
local_endpoint_id, local_endpoint_name);
|
||||
if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: BT added");
|
||||
mediums_started_successfully.push_back(bluetooth_medium);
|
||||
if (options.allowed.bluetooth) {
|
||||
const ByteArray bluetooth_hash =
|
||||
GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength);
|
||||
proto::connections::Medium bluetooth_medium =
|
||||
StartBluetoothAdvertising(client, service_id, bluetooth_hash,
|
||||
local_endpoint_id, local_endpoint_info);
|
||||
if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: BT added");
|
||||
mediums_started_successfully.push_back(bluetooth_medium);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.allowed.ble) {
|
||||
const ByteArray ble_hash =
|
||||
GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength);
|
||||
proto::connections::Medium ble_medium = StartBleAdvertising(
|
||||
client, service_id, ble_hash, local_endpoint_id, local_endpoint_info);
|
||||
if (ble_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: Ble added");
|
||||
mediums_started_successfully.push_back(ble_medium);
|
||||
}
|
||||
}
|
||||
|
||||
if (mediums_started_successfully.empty()) {
|
||||
@@ -120,6 +148,8 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) {
|
||||
bluetooth_medium_.TurnOffDiscoverability();
|
||||
bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
||||
|
||||
ble_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
||||
|
||||
webrtc_medium_.StopAcceptingConnections();
|
||||
|
||||
wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
||||
@@ -160,90 +190,210 @@ bool P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint(
|
||||
return true;
|
||||
}
|
||||
|
||||
std::function<void(BluetoothDevice&)>
|
||||
P2pClusterPcpHandler::MakeBluetoothDeviceDiscoveredHandler(
|
||||
ClientProxy* client, const std::string& service_id) {
|
||||
return [this, client, service_id](BluetoothDevice& device) {
|
||||
RunOnPcpHandlerThread([this, client, service_id, &device]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"BT discovery handler (FOUND) [client=%p, service=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the Bluetooth device name.
|
||||
const std::string& device_name_string = device.GetName();
|
||||
BluetoothDeviceName device_name(device_name_string);
|
||||
|
||||
// Make sure the Bluetooth device name points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id,
|
||||
device_name))
|
||||
return;
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
void P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
BluetoothDevice& device) {
|
||||
RunOnPcpHandlerThread([this, client, service_id, &device]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Invoking BasePcpHandler::OnEndpointFound() for BT "
|
||||
"service=%s; id=%s; name=%s",
|
||||
service_id.c_str(), device_name.GetEndpointId().c_str(),
|
||||
device_name.GetEndpointName().c_str());
|
||||
OnEndpointFound(client,
|
||||
std::make_shared<BluetoothEndpoint>(BluetoothEndpoint{
|
||||
{
|
||||
device_name.GetEndpointId(),
|
||||
device_name.GetEndpointName(),
|
||||
service_id,
|
||||
proto::connections::Medium::BLUETOOTH,
|
||||
},
|
||||
device,
|
||||
}));
|
||||
});
|
||||
};
|
||||
"BT discovery handler (FOUND) [client=%p, service=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the Bluetooth device name.
|
||||
const std::string& device_name_string = device.GetName();
|
||||
BluetoothDeviceName device_name(device_name_string);
|
||||
|
||||
// Make sure the Bluetooth device name points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id,
|
||||
device_name))
|
||||
return;
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Invoking BasePcpHandler::OnEndpointFound() for BT service="
|
||||
<< service_id << "; id=" << device_name.GetEndpointId() << "; name="
|
||||
<< absl::BytesToHexString(device_name.GetEndpointInfo().data());
|
||||
OnEndpointFound(client,
|
||||
std::make_shared<BluetoothEndpoint>(BluetoothEndpoint{
|
||||
{
|
||||
device_name.GetEndpointId(),
|
||||
device_name.GetEndpointInfo(),
|
||||
service_id,
|
||||
proto::connections::Medium::BLUETOOTH,
|
||||
},
|
||||
device,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
std::function<void(BluetoothDevice&)>
|
||||
P2pClusterPcpHandler::MakeBluetoothDeviceLostHandler(
|
||||
ClientProxy* client, const std::string& service_id) {
|
||||
return [this, client, service_id](BluetoothDevice& device) {
|
||||
RunOnPcpHandlerThread([this, client, &service_id, &device]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"BT discovery handler (LOST) [client=%p, service=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
void P2pClusterPcpHandler::BluetoothDeviceLostHandler(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
BluetoothDevice& device) {
|
||||
const std::string& device_name_string = device.GetName();
|
||||
RunOnPcpHandlerThread([this, client, service_id, device_name_string]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"BT discovery handler (LOST) [client=%p, service=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the Bluetooth device name.
|
||||
const std::string& device_name_string = device.GetName();
|
||||
BluetoothDeviceName device_name(device_name_string);
|
||||
// Parse the Bluetooth device name.
|
||||
BluetoothDeviceName device_name(device_name_string);
|
||||
|
||||
// Make sure the Bluetooth device name points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id,
|
||||
device_name))
|
||||
return;
|
||||
// Make sure the Bluetooth device name points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id,
|
||||
device_name))
|
||||
return;
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
NEARBY_LOG(INFO,
|
||||
"BT discovery handler (LOST) [client=%p, service=%s]: report "
|
||||
"to client",
|
||||
client, service_id.c_str());
|
||||
OnEndpointLost(client, DiscoveredEndpoint{
|
||||
device_name.GetEndpointId(),
|
||||
device_name.GetEndpointInfo(),
|
||||
service_id,
|
||||
proto::connections::Medium::BLUETOOTH,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bool P2pClusterPcpHandler::IsRecognizedBleEndpoint(
|
||||
const std::string& service_id,
|
||||
const BleAdvertisement& advertisement) const {
|
||||
if (!advertisement.IsValid()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::IsRecognizedBleEndpoint: advertisement "
|
||||
"is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (advertisement.GetVersion() != BleAdvertisement::Version::kV1) {
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Version is "
|
||||
"not matched; advertisement.Version=%d, Version=%d",
|
||||
advertisement.GetVersion(), BleAdvertisement::Version::kV1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (advertisement.GetPcp() != GetPcp()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint: Pcp is "
|
||||
"not matched; advertisement.Pcp=%d, Pcp=%d",
|
||||
advertisement.GetPcp(), GetPcp());
|
||||
return false;
|
||||
}
|
||||
|
||||
ByteArray expected_service_id_hash =
|
||||
GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength);
|
||||
|
||||
if (advertisement.GetServiceIdHash() != expected_service_id_hash) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::IsRecognizedBleEndpoint: service "
|
||||
"id hash is "
|
||||
"not matched; advertisement.service_id_hash=%s, expected=%s",
|
||||
advertisement.GetServiceIdHash().data(),
|
||||
expected_service_id_hash.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler(
|
||||
ClientProxy* client, BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
RunOnPcpHandlerThread([this, client, service_id, &peripheral]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Ble scanning handler (FOUND) [client=%p, service_id=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the Ble advertisement bytes.
|
||||
BleAdvertisement advertisement(
|
||||
/*fast_advertisement=*/false,
|
||||
peripheral.GetAdvertisementBytes(service_id));
|
||||
|
||||
// Make sure the Ble advertisement points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedBleEndpoint(service_id, advertisement)) return;
|
||||
|
||||
// Store all the state we need to be able to re-create a BleEndpoint
|
||||
// in BlePeripheralLostHandler, since that isn't privy to
|
||||
// the bytes of the ble advertisement itself.
|
||||
found_ble_endpoints_.emplace(
|
||||
peripheral.GetName(),
|
||||
BleEndpointState(advertisement.GetEndpointId(),
|
||||
advertisement.GetEndpointInfo()));
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Invoking BasePcpHandler::OnEndpointFound() for Ble service="
|
||||
<< service_id << "; id=" << advertisement.GetEndpointId() << "; name="
|
||||
<< absl::BytesToHexString(advertisement.GetEndpointInfo().data());
|
||||
OnEndpointFound(client, std::make_shared<BleEndpoint>(BleEndpoint{
|
||||
{
|
||||
advertisement.GetEndpointId(),
|
||||
advertisement.GetEndpointInfo(),
|
||||
service_id,
|
||||
proto::connections::Medium::BLE,
|
||||
},
|
||||
peripheral,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::BlePeripheralLostHandler(
|
||||
ClientProxy* client, BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
std::string peripheral_name = peripheral.GetName();
|
||||
NEARBY_LOG(INFO, "Ble: [LOST, SCHED] peripheral_name=%s",
|
||||
peripheral_name.c_str());
|
||||
RunOnPcpHandlerThread([this, client, service_id, &peripheral]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Ble scanning handler (LOST) [client=%p, service_id=%s]: not "
|
||||
"in scanning mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove this BlePeripheral from found_ble_endpoints_, and
|
||||
// report the endpoint as lost to the client.
|
||||
auto item = found_ble_endpoints_.find(peripheral.GetName());
|
||||
if (item != found_ble_endpoints_.end()) {
|
||||
BleEndpointState ble_endpoint_state(item->second);
|
||||
found_ble_endpoints_.erase(item);
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
NEARBY_LOG(INFO,
|
||||
"BT discovery handler (LOST) [client=%p, service=%s]: report "
|
||||
"to client",
|
||||
"Ble scanning handler (LOST) [client=%p, "
|
||||
"service_id=%s]: report to client",
|
||||
client, service_id.c_str());
|
||||
OnEndpointLost(client, BluetoothEndpoint{
|
||||
{
|
||||
device_name.GetEndpointId(),
|
||||
device_name.GetEndpointName(),
|
||||
service_id,
|
||||
proto::connections::Medium::BLUETOOTH,
|
||||
},
|
||||
device,
|
||||
OnEndpointLost(client, DiscoveredEndpoint{
|
||||
ble_endpoint_state.endpoint_id,
|
||||
ble_endpoint_state.endpoint_info,
|
||||
service_id,
|
||||
proto::connections::Medium::BLE,
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint(
|
||||
@@ -280,90 +430,84 @@ bool P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint(
|
||||
return true;
|
||||
}
|
||||
|
||||
std::function<void(WifiLanService&, const std::string&)>
|
||||
P2pClusterPcpHandler::MakeWifiLanServiceDiscoveredHandler(
|
||||
ClientProxy* client, const std::string& service_id) {
|
||||
return [this, client](WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
RunOnPcpHandlerThread([this, client, service_id, &service]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"WifiLan discovery handler (FOUND) [client=%p, service=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the WifiLan service name.
|
||||
const std::string& service_info_name = service.GetName();
|
||||
WifiLanServiceInfo service_info(service_info_name);
|
||||
|
||||
// Make sure the WifiLan service name points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedWifiLanEndpoint(service_id, service_info)) return;
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
NEARBY_LOG(INFO,
|
||||
"Invoking BasePcpHandler::OnEndpointFound() for WifiLan "
|
||||
"service=%s; id=%s; name=%s",
|
||||
service_id.c_str(), service_info.GetEndpointId().c_str(),
|
||||
service_info.GetEndpointName().c_str());
|
||||
OnEndpointFound(client, std::make_shared<WifiLanEndpoint>(WifiLanEndpoint{
|
||||
{
|
||||
service_info.GetEndpointId(),
|
||||
service_info.GetEndpointName(),
|
||||
service_id,
|
||||
proto::connections::Medium::WIFI_LAN,
|
||||
},
|
||||
service,
|
||||
}));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
std::function<void(WifiLanService&, const std::string&)>
|
||||
P2pClusterPcpHandler::MakeWifiLanServiceLostHandler(
|
||||
ClientProxy* client, const std::string& service_id) {
|
||||
return [this, client](WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
RunOnPcpHandlerThread([this, client, &service_id, &service]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"WifiLan discovery handler (LOST) [client=%p, service=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the WifiLan service name.
|
||||
const std::string& service_info_name = service.GetName();
|
||||
WifiLanServiceInfo service_info(service_info_name);
|
||||
|
||||
// Make sure the WifiLan service name points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedWifiLanEndpoint(service_id, service_info)) return;
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
void P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler(
|
||||
ClientProxy* client, WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
RunOnPcpHandlerThread([this, client, service_id, &service]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"WifiLan discovery handler (LOST) [client=%p, service=%s]: report "
|
||||
"to client",
|
||||
"WifiLan discovery handler (FOUND) [client=%p, service=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
OnEndpointLost(client, WifiLanEndpoint{
|
||||
{
|
||||
service_info.GetEndpointId(),
|
||||
service_info.GetEndpointName(),
|
||||
service_id,
|
||||
proto::connections::Medium::WIFI_LAN,
|
||||
},
|
||||
service,
|
||||
});
|
||||
});
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the WifiLan service name.
|
||||
const std::string& service_info_name = service.GetName();
|
||||
WifiLanServiceInfo service_info(service_info_name);
|
||||
|
||||
// Make sure the WifiLan service name points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedWifiLanEndpoint(service_id, service_info)) return;
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"Invoking BasePcpHandler::OnEndpointFound() for WifiLan "
|
||||
"service=%s; id=%s; name=%s",
|
||||
service_id.c_str(), service_info.GetEndpointId().c_str(),
|
||||
absl::BytesToHexString(service_info.GetEndpointInfo().data()).c_str());
|
||||
OnEndpointFound(client, std::make_shared<WifiLanEndpoint>(WifiLanEndpoint{
|
||||
{
|
||||
service_info.GetEndpointId(),
|
||||
service_info.GetEndpointInfo(),
|
||||
service_id,
|
||||
proto::connections::Medium::WIFI_LAN,
|
||||
},
|
||||
service,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
void P2pClusterPcpHandler::WifiLanServiceLostHandler(
|
||||
ClientProxy* client, WifiLanService& service,
|
||||
const std::string& service_id) {
|
||||
std::string service_info_name = service.GetName();
|
||||
NEARBY_LOG(INFO, "WifiLAN: [LOST, SCHED] service_info_name=%s",
|
||||
service_info_name.c_str());
|
||||
RunOnPcpHandlerThread([this, client, service_id, service_info_name]() {
|
||||
// Make sure we are still discovering before proceeding.
|
||||
if (!client->IsDiscovering()) {
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"WifiLan discovery handler (LOST) [client=%p, service=%s]: not "
|
||||
"in discovery mode",
|
||||
client, service_id.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the WifiLan service name.
|
||||
WifiLanServiceInfo service_info(service_info_name);
|
||||
|
||||
// Make sure the WifiLan service name points to a valid
|
||||
// endpoint we're discovering.
|
||||
if (!IsRecognizedWifiLanEndpoint(service_id, service_info)) return;
|
||||
|
||||
// Report the discovered endpoint to the client.
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"WifiLan discovery handler (LOST) [client=%p, service_id=%s]: report "
|
||||
"to client",
|
||||
client, service_id.c_str());
|
||||
OnEndpointLost(client, DiscoveredEndpoint{
|
||||
service_info.GetEndpointId(),
|
||||
service_info.GetEndpointInfo(),
|
||||
service_id,
|
||||
proto::connections::Medium::WIFI_LAN,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl(
|
||||
@@ -371,28 +515,54 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl(
|
||||
const ConnectionOptions& options) {
|
||||
std::vector<proto::connections::Medium> mediums_started_successfully;
|
||||
|
||||
proto::connections::Medium wifi_lan_medium = StartWifiLanDiscovery(
|
||||
{
|
||||
.service_discovered_cb =
|
||||
MakeWifiLanServiceDiscoveredHandler(client, service_id),
|
||||
.service_lost_cb = MakeWifiLanServiceLostHandler(client, service_id),
|
||||
},
|
||||
client, service_id);
|
||||
if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: WifiLan added");
|
||||
mediums_started_successfully.push_back(wifi_lan_medium);
|
||||
if (options.allowed.wifi_lan) {
|
||||
proto::connections::Medium wifi_lan_medium = StartWifiLanDiscovery(
|
||||
{
|
||||
.service_discovered_cb = absl::bind_front(
|
||||
&P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler, this,
|
||||
client),
|
||||
.service_lost_cb = absl::bind_front(
|
||||
&P2pClusterPcpHandler::WifiLanServiceLostHandler, this, client),
|
||||
},
|
||||
client, service_id);
|
||||
if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::StartDiscoveryImpl: WifiLan added");
|
||||
mediums_started_successfully.push_back(wifi_lan_medium);
|
||||
}
|
||||
}
|
||||
|
||||
proto::connections::Medium bluetooth_medium = StartBluetoothDiscovery(
|
||||
{
|
||||
.device_discovered_cb =
|
||||
MakeBluetoothDeviceDiscoveredHandler(client, service_id),
|
||||
.device_lost_cb = MakeBluetoothDeviceLostHandler(client, service_id),
|
||||
},
|
||||
client, service_id);
|
||||
if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: BT added");
|
||||
mediums_started_successfully.push_back(bluetooth_medium);
|
||||
if (options.allowed.bluetooth) {
|
||||
proto::connections::Medium bluetooth_medium = StartBluetoothDiscovery(
|
||||
{
|
||||
.device_discovered_cb = absl::bind_front(
|
||||
&P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler, this,
|
||||
client, service_id),
|
||||
.device_lost_cb = absl::bind_front(
|
||||
&P2pClusterPcpHandler::BluetoothDeviceLostHandler, this, client,
|
||||
service_id),
|
||||
},
|
||||
client, service_id);
|
||||
if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: BT added");
|
||||
mediums_started_successfully.push_back(bluetooth_medium);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.allowed.ble) {
|
||||
proto::connections::Medium ble_medium = StartBleScanning(
|
||||
{
|
||||
.peripheral_discovered_cb = absl::bind_front(
|
||||
&P2pClusterPcpHandler::BlePeripheralDiscoveredHandler, this,
|
||||
client),
|
||||
.peripheral_lost_cb = absl::bind_front(
|
||||
&P2pClusterPcpHandler::BlePeripheralLostHandler, this, client),
|
||||
},
|
||||
client, service_id);
|
||||
if (ble_medium != proto::connections::UNKNOWN_MEDIUM) {
|
||||
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: Ble added");
|
||||
mediums_started_successfully.push_back(ble_medium);
|
||||
}
|
||||
}
|
||||
|
||||
if (mediums_started_successfully.empty()) {
|
||||
@@ -411,6 +581,7 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl(
|
||||
Status P2pClusterPcpHandler::StopDiscoveryImpl(ClientProxy* client) {
|
||||
wifi_lan_medium_.StopDiscovery(client->GetDiscoveryServiceId());
|
||||
bluetooth_medium_.StopDiscovery();
|
||||
ble_medium_.StopScanning(client->GetDiscoveryServiceId());
|
||||
return {Status::kSuccess};
|
||||
}
|
||||
|
||||
@@ -429,6 +600,13 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::ConnectImpl(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case proto::connections::Medium::BLE: {
|
||||
auto* ble_endpoint = down_cast<BleEndpoint*>(endpoint);
|
||||
if (ble_endpoint) {
|
||||
return BleConnectImpl(client, ble_endpoint);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case proto::connections::Medium::WIFI_LAN: {
|
||||
auto* wifi_lan_endpoint = down_cast<WifiLanEndpoint*>(endpoint);
|
||||
if (wifi_lan_endpoint) {
|
||||
@@ -455,7 +633,7 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::ConnectImpl(
|
||||
proto::connections::Medium P2pClusterPcpHandler::StartBluetoothAdvertising(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name) {
|
||||
const ByteArray& local_endpoint_info) {
|
||||
// Start listening for connections before advertising in case a connection
|
||||
// request comes in very quickly.
|
||||
NEARBY_LOG(
|
||||
@@ -474,20 +652,22 @@ proto::connections::Medium P2pClusterPcpHandler::StartBluetoothAdvertising(
|
||||
service_id.c_str());
|
||||
if (!bluetooth_radio_.Enable() ||
|
||||
!bluetooth_medium_.StartAcceptingConnections(
|
||||
service_id, {.accepted_cb = [this, client, local_endpoint_name](
|
||||
service_id, {.accepted_cb = [this, client, local_endpoint_info](
|
||||
BluetoothSocket socket) {
|
||||
if (!socket.IsValid()) {
|
||||
NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s",
|
||||
local_endpoint_name.c_str());
|
||||
std::string(local_endpoint_info).c_str());
|
||||
return;
|
||||
}
|
||||
RunOnPcpHandlerThread([this, client, local_endpoint_name,
|
||||
RunOnPcpHandlerThread([this, client, local_endpoint_info,
|
||||
socket = std::move(socket)]() mutable {
|
||||
std::string remote_device_name =
|
||||
socket.GetRemoteDevice().GetName();
|
||||
auto channel = absl::make_unique<BluetoothEndpointChannel>(
|
||||
remote_device_name, socket);
|
||||
OnIncomingConnection(client, remote_device_name,
|
||||
ByteArray remote_device_info{remote_device_name};
|
||||
|
||||
OnIncomingConnection(client, remote_device_info,
|
||||
std::move(channel),
|
||||
proto::connections::Medium::BLUETOOTH);
|
||||
});
|
||||
@@ -501,11 +681,12 @@ proto::connections::Medium P2pClusterPcpHandler::StartBluetoothAdvertising(
|
||||
"P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: "
|
||||
"make name; id=%s, hash=%s, name=%s",
|
||||
service_id.c_str(), local_endpoint_id.c_str(),
|
||||
std::string(service_id_hash).c_str(), local_endpoint_name.c_str());
|
||||
absl::BytesToHexString(service_id_hash.data()).c_str(),
|
||||
absl::BytesToHexString(local_endpoint_info.data()).c_str());
|
||||
// Generate a BluetoothDeviceName with which to become Bluetooth discoverable.
|
||||
std::string device_name(BluetoothDeviceName(
|
||||
BluetoothDeviceName::Version::kV1, GetPcp(), local_endpoint_id,
|
||||
service_id_hash, local_endpoint_name));
|
||||
service_id_hash, local_endpoint_info));
|
||||
if (device_name.empty()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::StartBluetoothAdvertising: generate "
|
||||
@@ -578,10 +759,132 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BluetoothConnectImpl(
|
||||
};
|
||||
}
|
||||
|
||||
proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
|
||||
const ByteArray& local_endpoint_info) {
|
||||
// Start listening for connections before advertising in case a connection
|
||||
// request comes in very quickly.
|
||||
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id="
|
||||
<< service_id << ": start";
|
||||
if (ble_medium_.IsAcceptingConnections(service_id)) {
|
||||
NEARBY_LOGS(ERROR) << "Ble is already accepting connections for service_id="
|
||||
<< service_id;
|
||||
return proto::connections::UNKNOWN_MEDIUM;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id="
|
||||
<< service_id << ": invoking";
|
||||
if (!bluetooth_radio_.Enable() ||
|
||||
!ble_medium_.StartAcceptingConnections(
|
||||
service_id,
|
||||
{.accepted_cb = [this, client, local_endpoint_info](
|
||||
BleSocket socket, const std::string& service_id) {
|
||||
if (!socket.IsValid()) {
|
||||
NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s",
|
||||
std::string(local_endpoint_info).c_str());
|
||||
return;
|
||||
}
|
||||
RunOnPcpHandlerThread([this, client, local_endpoint_info,
|
||||
service_id,
|
||||
socket = std::move(socket)]() mutable {
|
||||
std::string remote_peripheral_name =
|
||||
socket.GetRemotePeripheral().GetName();
|
||||
auto channel = absl::make_unique<BleEndpointChannel>(
|
||||
remote_peripheral_name, socket);
|
||||
ByteArray remote_peripheral_info =
|
||||
socket.GetRemotePeripheral().GetAdvertisementBytes(
|
||||
service_id);
|
||||
|
||||
OnIncomingConnection(client, remote_peripheral_info,
|
||||
std::move(channel),
|
||||
proto::connections::Medium::BLE);
|
||||
});
|
||||
}})) {
|
||||
NEARBY_LOGS(ERROR)
|
||||
<< "Ble failed to start accepting connections for service_id="
|
||||
<< service_id;
|
||||
return proto::connections::UNKNOWN_MEDIUM;
|
||||
}
|
||||
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::StartBleAdvertising: service=%s: "
|
||||
"make advertisement; id=%s, hash=%s, name=%s",
|
||||
service_id.c_str(), local_endpoint_id.c_str(),
|
||||
std::string(service_id_hash).c_str(),
|
||||
std::string(local_endpoint_info).c_str());
|
||||
// Generate a BleAdvertisement with which to become Ble discoverable.
|
||||
// TODO(edwinwu): Add a bluetooth_adapter method to get the mac address.
|
||||
std::string bluetooth_mac_address;
|
||||
ByteArray advertisement_bytes(BleAdvertisement(
|
||||
BleAdvertisement::Version::kV1, GetPcp(), service_id_hash,
|
||||
local_endpoint_id, local_endpoint_info, bluetooth_mac_address));
|
||||
if (advertisement_bytes.Empty()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::StartBleAdvertising: generate "
|
||||
"BleAdvertisement failed");
|
||||
ble_medium_.StopAcceptingConnections(service_id);
|
||||
return proto::connections::UNKNOWN_MEDIUM;
|
||||
} else {
|
||||
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: generate "
|
||||
"BleAdvertisement succeeded; advertisement_bytes="
|
||||
<< advertisement_bytes.data();
|
||||
}
|
||||
|
||||
NEARBY_LOG(
|
||||
INFO, "P2pClusterPcpHandler::StartBleAdvertising: service_id=%s: come up",
|
||||
service_id.c_str());
|
||||
|
||||
if (!ble_medium_.StartAdvertising(service_id, advertisement_bytes)) {
|
||||
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: failed to "
|
||||
"start advertising, advertisement_bytes=%p"
|
||||
<< advertisement_bytes.data();
|
||||
ble_medium_.StopAcceptingConnections(service_id);
|
||||
return proto::connections::UNKNOWN_MEDIUM;
|
||||
}
|
||||
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id="
|
||||
<< service_id << ": done";
|
||||
return proto::connections::BLE;
|
||||
}
|
||||
|
||||
proto::connections::Medium P2pClusterPcpHandler::StartBleScanning(
|
||||
BleDiscoveredPeripheralCallback callback, ClientProxy* client,
|
||||
const std::string& service_id) {
|
||||
if (bluetooth_radio_.Enable() &&
|
||||
ble_medium_.StartScanning(service_id, std::move(callback))) {
|
||||
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleScanning: ok";
|
||||
return proto::connections::BLE;
|
||||
} else {
|
||||
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleScanning: failed";
|
||||
return proto::connections::UNKNOWN_MEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl(
|
||||
ClientProxy* client, BleEndpoint* endpoint) {
|
||||
BlePeripheral& peripheral = endpoint->ble_peripheral;
|
||||
|
||||
BleSocket ble_socket = ble_medium_.Connect(peripheral, endpoint->service_id);
|
||||
if (!ble_socket.IsValid()) {
|
||||
return BasePcpHandler::ConnectImplResult{
|
||||
.status = {Status::kBleError},
|
||||
};
|
||||
}
|
||||
|
||||
auto channel =
|
||||
absl::make_unique<BleEndpointChannel>(endpoint->endpoint_id, ble_socket);
|
||||
|
||||
return BasePcpHandler::ConnectImplResult{
|
||||
.medium = proto::connections::Medium::BLE,
|
||||
.status = {Status::kSuccess},
|
||||
.endpoint_channel = std::move(channel),
|
||||
};
|
||||
}
|
||||
|
||||
proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name) {
|
||||
const ByteArray& local_endpoint_info) {
|
||||
// Start listening for connections before advertising in case a connection
|
||||
// request comes in very quickly.
|
||||
NEARBY_LOG(INFO,
|
||||
@@ -598,21 +901,23 @@ proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising(
|
||||
"P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: invoking",
|
||||
service_id.c_str());
|
||||
if (!wifi_lan_medium_.StartAcceptingConnections(
|
||||
service_id, {.accepted_cb = [this, client, local_endpoint_name](
|
||||
service_id, {.accepted_cb = [this, client, local_endpoint_info](
|
||||
WifiLanSocket socket,
|
||||
const std::string& service_id) {
|
||||
if (!socket.IsValid()) {
|
||||
NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s",
|
||||
local_endpoint_name.c_str());
|
||||
std::string(local_endpoint_info).c_str());
|
||||
return;
|
||||
}
|
||||
RunOnPcpHandlerThread([this, client, local_endpoint_name,
|
||||
RunOnPcpHandlerThread([this, client, local_endpoint_info,
|
||||
socket = std::move(socket)]() mutable {
|
||||
std::string remote_service_info_name =
|
||||
socket.GetRemoteWifiLanService().GetName();
|
||||
auto channel = absl::make_unique<WifiLanEndpointChannel>(
|
||||
remote_service_info_name, socket);
|
||||
OnIncomingConnection(client, remote_service_info_name,
|
||||
ByteArray remote_service_info{remote_service_info_name};
|
||||
|
||||
OnIncomingConnection(client, remote_service_info,
|
||||
std::move(channel),
|
||||
proto::connections::Medium::WIFI_LAN);
|
||||
});
|
||||
@@ -627,11 +932,12 @@ proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising(
|
||||
"P2pClusterPcpHandler::StartWifiLanAdvertising: service=%s: "
|
||||
"make name; id=%s, hash=%s, name=%s",
|
||||
service_id.c_str(), local_endpoint_id.c_str(),
|
||||
std::string(service_id_hash).c_str(), local_endpoint_name.c_str());
|
||||
absl::BytesToHexString(service_id_hash.data()).c_str(),
|
||||
absl::BytesToHexString(local_endpoint_info.data()).c_str());
|
||||
// Generate a WifiLanServiceInfo with which to become WifiLan discoverable.
|
||||
std::string service_info_name(WifiLanServiceInfo(
|
||||
WifiLanServiceInfo::Version::kV1, GetPcp(), local_endpoint_id,
|
||||
service_id_hash, local_endpoint_name));
|
||||
service_id_hash, local_endpoint_info));
|
||||
if (service_info_name.empty()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"P2pClusterPcpHandler::StartWifiLanAdvertising: generate "
|
||||
@@ -701,20 +1007,20 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl(
|
||||
proto::connections::Medium
|
||||
P2pClusterPcpHandler::StartListeningForWebRtcConnections(
|
||||
ClientProxy* client, const string& service_id,
|
||||
const string& local_endpoint_id, const string& local_endpoint_name) {
|
||||
const string& local_endpoint_id, const ByteArray& local_endpoint_info) {
|
||||
if (!webrtc_medium_.IsAvailable()) {
|
||||
return proto::connections::UNKNOWN_MEDIUM;
|
||||
}
|
||||
|
||||
if (!webrtc_medium_.IsAcceptingConnections()) {
|
||||
mediums::PeerId self_id = CreatePeerIdFromAdvertisement(
|
||||
service_id, local_endpoint_id, local_endpoint_name);
|
||||
service_id, local_endpoint_id, local_endpoint_info);
|
||||
if (!webrtc_medium_.StartAcceptingConnections(
|
||||
self_id, {[this, client, local_endpoint_name](
|
||||
self_id, {[this, client, local_endpoint_info](
|
||||
mediums::WebRtcSocketWrapper socket) {
|
||||
if (!socket.IsValid()) {
|
||||
NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s",
|
||||
local_endpoint_name.c_str());
|
||||
std::string(local_endpoint_info).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -723,8 +1029,9 @@ P2pClusterPcpHandler::StartListeningForWebRtcConnections(
|
||||
string remote_device_name = "WebRtcSocket";
|
||||
auto channel = absl::make_unique<WebRtcEndpointChannel>(
|
||||
remote_device_name, socket);
|
||||
ByteArray remote_device_info{remote_device_name};
|
||||
|
||||
OnIncomingConnection(client, remote_device_name,
|
||||
OnIncomingConnection(client, remote_device_info,
|
||||
std::move(channel),
|
||||
proto::connections::WEB_RTC);
|
||||
});
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace connections {
|
||||
// connects over Bluetooth.
|
||||
class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
public:
|
||||
P2pClusterPcpHandler(Mediums& mediums, EndpointManager* endpoint_manager,
|
||||
P2pClusterPcpHandler(Mediums* mediums, EndpointManager* endpoint_manager,
|
||||
EndpointChannelManager* channel_manager,
|
||||
Pcp pcp = Pcp::kP2pCluster);
|
||||
~P2pClusterPcpHandler() override = default;
|
||||
@@ -64,7 +64,7 @@ class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
BasePcpHandler::StartOperationResult StartAdvertisingImpl(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name,
|
||||
const ByteArray& local_endpoint_info,
|
||||
const ConnectionOptions& options) override;
|
||||
|
||||
// @PCPHandlerThread
|
||||
@@ -91,15 +91,36 @@ class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
|
||||
BluetoothDevice bluetooth_device;
|
||||
};
|
||||
struct BleEndpoint : public BasePcpHandler::DiscoveredEndpoint {
|
||||
BleEndpoint(DiscoveredEndpoint endpoint, BlePeripheral peripheral)
|
||||
: DiscoveredEndpoint(std::move(endpoint)),
|
||||
ble_peripheral(std::move(peripheral)) {}
|
||||
BlePeripheral ble_peripheral;
|
||||
};
|
||||
|
||||
// Holds the state required to re-create a BleEndpoint we see on a
|
||||
// BlePeripheral, so BlePeripheralLostHandler can call
|
||||
// BasePcpHandler::OnEndpointLost() with the same information as was passed
|
||||
// in to BasePCPHandler::onEndpointFound().
|
||||
struct BleEndpointState {
|
||||
public:
|
||||
BleEndpointState(const string& endpoint_id, const ByteArray& endpoint_info)
|
||||
: endpoint_id(endpoint_id), endpoint_info(endpoint_info) {}
|
||||
|
||||
std::string endpoint_id;
|
||||
ByteArray endpoint_info;
|
||||
};
|
||||
struct WifiLanEndpoint : public BasePcpHandler::DiscoveredEndpoint {
|
||||
WifiLanEndpoint(DiscoveredEndpoint endpoint, WifiLanService service)
|
||||
: DiscoveredEndpoint(std::move(endpoint)),
|
||||
wifi_lan_service(std::move(service)) {}
|
||||
|
||||
WifiLanService wifi_lan_service;
|
||||
};
|
||||
|
||||
using BluetoothDiscoveredDeviceCallback =
|
||||
BluetoothClassic::DiscoveredDeviceCallback;
|
||||
using BleDiscoveredPeripheralCallback = Ble::DiscoveredPeripheralCallback;
|
||||
using WifiLanDiscoveredServiceCallback = WifiLan::DiscoveredServiceCallback;
|
||||
|
||||
static constexpr BluetoothDeviceName::Version kBluetoothDeviceNameVersion =
|
||||
@@ -113,34 +134,55 @@ class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
bool IsRecognizedBluetoothEndpoint(const std::string& name_string,
|
||||
const std::string& service_id,
|
||||
const BluetoothDeviceName& name) const;
|
||||
std::function<void(BluetoothDevice&)> MakeBluetoothDeviceDiscoveredHandler(
|
||||
ClientProxy* client, const std::string& service_id);
|
||||
std::function<void(BluetoothDevice&)> MakeBluetoothDeviceLostHandler(
|
||||
ClientProxy* client, const std::string& service_id);
|
||||
void BluetoothDeviceDiscoveredHandler(ClientProxy* client,
|
||||
const std::string& service_id,
|
||||
BluetoothDevice& device);
|
||||
void BluetoothDeviceLostHandler(ClientProxy* client,
|
||||
const std::string& service_id,
|
||||
BluetoothDevice& device);
|
||||
proto::connections::Medium StartBluetoothAdvertising(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name);
|
||||
const ByteArray& local_endpoint_info);
|
||||
proto::connections::Medium StartBluetoothDiscovery(
|
||||
BluetoothDiscoveredDeviceCallback callback, ClientProxy* client,
|
||||
const std::string& service_id);
|
||||
BasePcpHandler::ConnectImplResult BluetoothConnectImpl(
|
||||
ClientProxy* client, BluetoothEndpoint* endpoint);
|
||||
|
||||
// Ble
|
||||
// Maps a BlePeripheral to its corresponding BleEndpointState.
|
||||
absl::flat_hash_map<std::string, BleEndpointState> found_ble_endpoints_;
|
||||
bool IsRecognizedBleEndpoint(const std::string& service_id,
|
||||
const BleAdvertisement& advertisement) const;
|
||||
void BlePeripheralDiscoveredHandler(ClientProxy* client,
|
||||
BlePeripheral& peripheral,
|
||||
const std::string& service_id);
|
||||
void BlePeripheralLostHandler(ClientProxy* client, BlePeripheral& peripheral,
|
||||
const std::string& service_id);
|
||||
proto::connections::Medium StartBleAdvertising(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
|
||||
const ByteArray& local_endpoint_info);
|
||||
proto::connections::Medium StartBleScanning(
|
||||
BleDiscoveredPeripheralCallback callback, ClientProxy* client,
|
||||
const std::string& service_id);
|
||||
BasePcpHandler::ConnectImplResult BleConnectImpl(ClientProxy* client,
|
||||
BleEndpoint* endpoint);
|
||||
|
||||
// WifiLan
|
||||
bool IsRecognizedWifiLanEndpoint(
|
||||
const std::string& service_id,
|
||||
const WifiLanServiceInfo& service_info) const;
|
||||
std::function<void(WifiLanService&, const std::string&)>
|
||||
MakeWifiLanServiceDiscoveredHandler(ClientProxy* client,
|
||||
const std::string& service_id);
|
||||
std::function<void(WifiLanService&, const std::string&)>
|
||||
MakeWifiLanServiceLostHandler(ClientProxy* client,
|
||||
const std::string& service_id);
|
||||
void WifiLanServiceDiscoveredHandler(ClientProxy* client,
|
||||
WifiLanService& service,
|
||||
const std::string& service_id);
|
||||
void WifiLanServiceLostHandler(ClientProxy* client, WifiLanService& service,
|
||||
const std::string& service_id);
|
||||
proto::connections::Medium StartWifiLanAdvertising(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name);
|
||||
const ByteArray& local_endpoint_info);
|
||||
proto::connections::Medium StartWifiLanDiscovery(
|
||||
WifiLanDiscoveredServiceCallback callback, ClientProxy* client,
|
||||
const std::string& service_id);
|
||||
@@ -151,12 +193,13 @@ class P2pClusterPcpHandler : public BasePcpHandler {
|
||||
proto::connections::Medium StartListeningForWebRtcConnections(
|
||||
ClientProxy* client, const std::string& service_id,
|
||||
const std::string& local_endpoint_id,
|
||||
const std::string& local_endpoint_name);
|
||||
const ByteArray& local_endpoint_info);
|
||||
BasePcpHandler::ConnectImplResult WebRtcConnectImpl(
|
||||
ClientProxy* client, WebRtcEndpoint* webrtc_endpoint);
|
||||
|
||||
BluetoothRadio& bluetooth_radio_;
|
||||
BluetoothClassic& bluetooth_medium_;
|
||||
Ble& ble_medium_;
|
||||
WifiLan& wifi_lan_medium_;
|
||||
mediums::WebRtc& webrtc_medium_;
|
||||
};
|
||||
|
||||
@@ -29,31 +29,57 @@ namespace nearby {
|
||||
namespace connections {
|
||||
namespace {
|
||||
|
||||
class P2pClusterPcpHandlerTest : public ::testing::Test {
|
||||
constexpr BooleanMediumSelector kTestCases[] = {
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.wifi_lan = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
.wifi_lan = true,
|
||||
},
|
||||
};
|
||||
|
||||
class P2pClusterPcpHandlerTest
|
||||
: public ::testing::TestWithParam<BooleanMediumSelector> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
NEARBY_LOG(INFO, "SetUp: begin");
|
||||
env_.Stop();
|
||||
if (options_.allowed.bluetooth) {
|
||||
NEARBY_LOG(INFO, "SetUp: BT enabled");
|
||||
}
|
||||
if (options_.allowed.wifi_lan) {
|
||||
NEARBY_LOG(INFO, "SetUp: Wifi LAN enabled");
|
||||
}
|
||||
if (options_.allowed.web_rtc) {
|
||||
NEARBY_LOG(INFO, "SetUp: WebRTC enabled");
|
||||
}
|
||||
NEARBY_LOG(INFO, "SetUp: end");
|
||||
}
|
||||
|
||||
ClientProxy client_a_;
|
||||
ClientProxy client_b_;
|
||||
std::string service_id_{"service"};
|
||||
ConnectionOptions options_{.strategy = Strategy::kP2pCluster};
|
||||
ConnectionOptions options_{
|
||||
.strategy = Strategy::kP2pCluster,
|
||||
.allowed = GetParam(),
|
||||
};
|
||||
MediumEnvironment& env_{MediumEnvironment::Instance()};
|
||||
};
|
||||
|
||||
TEST_F(P2pClusterPcpHandlerTest, CanConstructOne) {
|
||||
TEST_P(P2pClusterPcpHandlerTest, CanConstructOne) {
|
||||
env_.Start();
|
||||
Mediums mediums;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
P2pClusterPcpHandler handler(mediums, &em, &ecm);
|
||||
P2pClusterPcpHandler handler(&mediums, &em, &ecm);
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(P2pClusterPcpHandlerTest, CanConstructMultiple) {
|
||||
TEST_P(P2pClusterPcpHandlerTest, CanConstructMultiple) {
|
||||
env_.Start();
|
||||
Mediums mediums_a;
|
||||
Mediums mediums_b;
|
||||
@@ -61,25 +87,26 @@ TEST_F(P2pClusterPcpHandlerTest, CanConstructMultiple) {
|
||||
EndpointChannelManager ecm_b;
|
||||
EndpointManager em_a(&ecm_a);
|
||||
EndpointManager em_b(&ecm_b);
|
||||
P2pClusterPcpHandler handler_a(mediums_a, &em_a, &ecm_a);
|
||||
P2pClusterPcpHandler handler_b(mediums_b, &em_b, &ecm_b);
|
||||
P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a);
|
||||
P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b);
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(P2pClusterPcpHandlerTest, CanAdvertise) {
|
||||
TEST_P(P2pClusterPcpHandlerTest, CanAdvertise) {
|
||||
env_.Start();
|
||||
std::string endpoint_name{"endpoint_name"};
|
||||
Mediums mediums_a;
|
||||
EndpointChannelManager ecm_a;
|
||||
EndpointManager em_a(&ecm_a);
|
||||
P2pClusterPcpHandler handler_a(mediums_a, &em_a, &ecm_a);
|
||||
EXPECT_EQ(handler_a.StartAdvertising(&client_a_, service_id_, options_,
|
||||
{.name = endpoint_name}),
|
||||
Status{Status::kSuccess});
|
||||
P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a);
|
||||
EXPECT_EQ(
|
||||
handler_a.StartAdvertising(&client_a_, service_id_, options_,
|
||||
{.endpoint_info = ByteArray{endpoint_name}}),
|
||||
Status{Status::kSuccess});
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(P2pClusterPcpHandlerTest, CanDiscover) {
|
||||
TEST_P(P2pClusterPcpHandlerTest, CanDiscover) {
|
||||
env_.Start();
|
||||
std::string endpoint_name{"endpoint_name"};
|
||||
Mediums mediums_a;
|
||||
@@ -88,18 +115,19 @@ TEST_F(P2pClusterPcpHandlerTest, CanDiscover) {
|
||||
EndpointChannelManager ecm_b;
|
||||
EndpointManager em_a(&ecm_a);
|
||||
EndpointManager em_b(&ecm_b);
|
||||
P2pClusterPcpHandler handler_a(mediums_a, &em_a, &ecm_a);
|
||||
P2pClusterPcpHandler handler_b(mediums_b, &em_b, &ecm_b);
|
||||
P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a);
|
||||
P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b);
|
||||
CountDownLatch latch(1);
|
||||
EXPECT_EQ(handler_a.StartAdvertising(&client_a_, service_id_, options_,
|
||||
{.name = endpoint_name}),
|
||||
Status{Status::kSuccess});
|
||||
EXPECT_EQ(
|
||||
handler_a.StartAdvertising(&client_a_, service_id_, options_,
|
||||
{.endpoint_info = ByteArray{endpoint_name}}),
|
||||
Status{Status::kSuccess});
|
||||
EXPECT_EQ(handler_b.StartDiscovery(
|
||||
&client_b_, service_id_, options_,
|
||||
{
|
||||
.endpoint_found_cb =
|
||||
[&latch](const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Device discovered: id=%s",
|
||||
endpoint_id.c_str());
|
||||
@@ -108,10 +136,13 @@ TEST_F(P2pClusterPcpHandlerTest, CanDiscover) {
|
||||
}),
|
||||
Status{Status::kSuccess});
|
||||
EXPECT_TRUE(latch.Await(absl::Milliseconds(1000)).result());
|
||||
// We discovered endpoint over one medium. Before we finish the test, we have
|
||||
// to stop discovery for other mediums that may be still ongoing.
|
||||
handler_b.StopDiscovery(&client_b_);
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(P2pClusterPcpHandlerTest, CanConnect) {
|
||||
TEST_P(P2pClusterPcpHandlerTest, CanConnect) {
|
||||
env_.Start();
|
||||
std::string endpoint_name_a{"endpoint_name"};
|
||||
Mediums mediums_a;
|
||||
@@ -124,20 +155,20 @@ TEST_F(P2pClusterPcpHandlerTest, CanConnect) {
|
||||
EndpointChannelManager ecm_b;
|
||||
EndpointManager em_a(&ecm_a);
|
||||
EndpointManager em_b(&ecm_b);
|
||||
P2pClusterPcpHandler handler_a(mediums_a, &em_a, &ecm_a);
|
||||
P2pClusterPcpHandler handler_b(mediums_b, &em_b, &ecm_b);
|
||||
P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a);
|
||||
P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b);
|
||||
CountDownLatch discover_latch(1);
|
||||
CountDownLatch connect_latch(2);
|
||||
struct DiscoveredInfo {
|
||||
std::string endpoint_id;
|
||||
std::string endpoint_name;
|
||||
ByteArray endpoint_info;
|
||||
std::string service_id;
|
||||
} discovered;
|
||||
EXPECT_EQ(
|
||||
handler_a.StartAdvertising(
|
||||
&client_a_, service_id_, options_,
|
||||
{
|
||||
.name = endpoint_name_a,
|
||||
.endpoint_info = ByteArray{endpoint_name_a},
|
||||
.listener =
|
||||
{
|
||||
.initiated_cb =
|
||||
@@ -156,13 +187,13 @@ TEST_F(P2pClusterPcpHandlerTest, CanConnect) {
|
||||
.endpoint_found_cb =
|
||||
[&discover_latch, &discovered](
|
||||
const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Device discovered: id=%s",
|
||||
endpoint_id.c_str());
|
||||
discovered = {
|
||||
.endpoint_id = endpoint_id,
|
||||
.endpoint_name = endpoint_name,
|
||||
.endpoint_info = endpoint_info,
|
||||
.service_id = service_id,
|
||||
};
|
||||
discover_latch.CountDown();
|
||||
@@ -171,12 +202,12 @@ TEST_F(P2pClusterPcpHandlerTest, CanConnect) {
|
||||
Status{Status::kSuccess});
|
||||
|
||||
EXPECT_TRUE(discover_latch.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_EQ(endpoint_name_a, discovered.endpoint_name);
|
||||
EXPECT_EQ(endpoint_name_a, std::string{discovered.endpoint_info});
|
||||
|
||||
handler_b.RequestConnection(
|
||||
&client_b_, discovered.endpoint_id,
|
||||
{
|
||||
.name = discovered.endpoint_name,
|
||||
.endpoint_info = discovered.endpoint_info,
|
||||
.listener =
|
||||
{
|
||||
.initiated_cb =
|
||||
@@ -187,11 +218,15 @@ TEST_F(P2pClusterPcpHandlerTest, CanConnect) {
|
||||
connect_latch.CountDown();
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
options_);
|
||||
EXPECT_TRUE(connect_latch.Await(absl::Milliseconds(1000)).result());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ParametrisedPcpHandlerTest, P2pClusterPcpHandlerTest,
|
||||
::testing::ValuesIn(kTestCases));
|
||||
|
||||
} // namespace
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@@ -21,8 +21,7 @@ namespace connections {
|
||||
P2pPointToPointPcpHandler::P2pPointToPointPcpHandler(
|
||||
Mediums& mediums, EndpointManager& endpoint_manager,
|
||||
EndpointChannelManager& channel_manager, Pcp pcp)
|
||||
: P2pStarPcpHandler(mediums, endpoint_manager, channel_manager, pcp),
|
||||
mediums_(&mediums) {}
|
||||
: P2pStarPcpHandler(mediums, endpoint_manager, channel_manager, pcp) {}
|
||||
|
||||
std::vector<proto::connections::Medium>
|
||||
P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "core_v2/internal/endpoint_channel_manager.h"
|
||||
#include "core_v2/internal/endpoint_manager.h"
|
||||
#include "core_v2/internal/mediums/mediums.h"
|
||||
#include "core_v2/internal/p2p_star_pcp_handler.h"
|
||||
#include "core_v2/internal/pcp.h"
|
||||
#include "core_v2/strategy.h"
|
||||
@@ -29,7 +28,7 @@ namespace connections {
|
||||
// Concrete implementation of the PCPHandler for the P2P_POINT_TO_POINT. This
|
||||
// PCP is for mediums that have limitations on the number of simultaneous
|
||||
// connections; all mediums in P2P_STAR are valid for P2P_POINT_TO_POINT, but
|
||||
// not all mediums in P2P_POINT_TO_POINT and valid for P2P_STAR.
|
||||
// not all mediums in P2P_POINT_TO_POINT are valid for P2P_STAR.
|
||||
//
|
||||
// Currently, this implementation advertises/discovers over Bluetooth
|
||||
// and connects over Bluetooth.
|
||||
@@ -45,9 +44,6 @@ class P2pPointToPointPcpHandler : public P2pStarPcpHandler {
|
||||
|
||||
bool CanSendOutgoingConnection(ClientProxy* client) const override;
|
||||
bool CanReceiveIncomingConnection(ClientProxy* client) const override;
|
||||
|
||||
private:
|
||||
Mediums* mediums_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
|
||||
@@ -24,8 +24,8 @@ P2pStarPcpHandler::P2pStarPcpHandler(Mediums& mediums,
|
||||
EndpointManager& endpoint_manager,
|
||||
EndpointChannelManager& channel_manager,
|
||||
Pcp pcp)
|
||||
: P2pClusterPcpHandler(mediums, &endpoint_manager, &channel_manager, pcp),
|
||||
mediums_(&mediums) {}
|
||||
: P2pClusterPcpHandler(&mediums, &endpoint_manager, &channel_manager, pcp) {
|
||||
}
|
||||
|
||||
std::vector<proto::connections::Medium>
|
||||
P2pStarPcpHandler::GetConnectionMediumsByPriority() {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "core_v2/internal/client_proxy.h"
|
||||
#include "core_v2/internal/endpoint_channel_manager.h"
|
||||
#include "core_v2/internal/endpoint_manager.h"
|
||||
#include "core_v2/internal/mediums/mediums.h"
|
||||
#include "core_v2/internal/p2p_cluster_pcp_handler.h"
|
||||
#include "core_v2/internal/pcp.h"
|
||||
#include "core_v2/strategy.h"
|
||||
@@ -31,7 +30,7 @@ namespace connections {
|
||||
|
||||
// Concrete implementation of the PcpHandler for the P2P_STAR PCP. This Pcp is
|
||||
// for mediums that have one server with (potentially) many clients; all mediums
|
||||
// in P2P_CLUSTER are valid for P2P_STAR, but not all mediums in P2P_STAR and
|
||||
// in P2P_CLUSTER are valid for P2P_STAR, but not all mediums in P2P_STAR are
|
||||
// valid for P2P_CLUSTER.
|
||||
//
|
||||
// Currently, this implementation advertises/discovers over Bluetooth
|
||||
@@ -49,9 +48,6 @@ class P2pStarPcpHandler : public P2pClusterPcpHandler {
|
||||
|
||||
bool CanSendOutgoingConnection(ClientProxy* client) const override;
|
||||
bool CanReceiveIncomingConnection(ClientProxy* client) const override;
|
||||
|
||||
private:
|
||||
Mediums* mediums_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
|
||||
@@ -34,12 +34,27 @@ constexpr absl::string_view kMessage = "message";
|
||||
constexpr absl::Duration kProgressTimeout = absl::Milliseconds(1000);
|
||||
constexpr absl::Duration kDefaultTimeout = absl::Milliseconds(1000);
|
||||
|
||||
constexpr BooleanMediumSelector kTestCases[] = {
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.wifi_lan = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
.wifi_lan = true,
|
||||
},
|
||||
};
|
||||
|
||||
class PayloadSimulationUser : public SimulationUser {
|
||||
public:
|
||||
explicit PayloadSimulationUser(absl::string_view name)
|
||||
: SimulationUser(std::string(name)) {}
|
||||
explicit PayloadSimulationUser(
|
||||
absl::string_view name,
|
||||
BooleanMediumSelector allowed = BooleanMediumSelector())
|
||||
: SimulationUser(std::string(name), allowed) {}
|
||||
~PayloadSimulationUser() override {
|
||||
NEARBY_LOGS(INFO) << "PayloadSimulationUser: [down] name=" << name_;
|
||||
NEARBY_LOGS(INFO) << "PayloadSimulationUser: [down] name=" << info_.data();
|
||||
// SystemClock::Sleep(kDefaultTimeout);
|
||||
}
|
||||
|
||||
@@ -65,7 +80,8 @@ class PayloadSimulationUser : public SimulationUser {
|
||||
Payload::Id sender_payload_id_ = 0;
|
||||
};
|
||||
|
||||
class PayloadManagerTest : public ::testing::Test {
|
||||
class PayloadManagerTest
|
||||
: public ::testing::TestWithParam<BooleanMediumSelector> {
|
||||
protected:
|
||||
PayloadManagerTest() { env_.Stop(); }
|
||||
|
||||
@@ -75,7 +91,7 @@ class PayloadManagerTest : public ::testing::Test {
|
||||
user_b.StartDiscovery(std::string(kServiceId), &discovery_latch_);
|
||||
EXPECT_TRUE(discovery_latch_.Await(kDefaultTimeout).result());
|
||||
EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId);
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_name, user_a.GetName());
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo());
|
||||
EXPECT_FALSE(user_b.GetDiscovered().endpoint_id.empty());
|
||||
NEARBY_LOG(INFO, "EP-B: [discovered] %s",
|
||||
user_b.GetDiscovered().endpoint_id.c_str());
|
||||
@@ -99,23 +115,23 @@ class PayloadManagerTest : public ::testing::Test {
|
||||
MediumEnvironment& env_{MediumEnvironment::Instance()};
|
||||
};
|
||||
|
||||
TEST_F(PayloadManagerTest, CanCreateOne) {
|
||||
TEST_P(PayloadManagerTest, CanCreateOne) {
|
||||
env_.Start();
|
||||
PayloadSimulationUser user_a(kDeviceA);
|
||||
PayloadSimulationUser user_a(kDeviceA, GetParam());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PayloadManagerTest, CanCreateMultiple) {
|
||||
TEST_P(PayloadManagerTest, CanCreateMultiple) {
|
||||
env_.Start();
|
||||
PayloadSimulationUser user_a(kDeviceA);
|
||||
PayloadSimulationUser user_b(kDeviceB);
|
||||
PayloadSimulationUser user_a(kDeviceA, GetParam());
|
||||
PayloadSimulationUser user_b(kDeviceB, GetParam());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PayloadManagerTest, CanSendBytePayload) {
|
||||
TEST_P(PayloadManagerTest, CanSendBytePayload) {
|
||||
env_.Start();
|
||||
PayloadSimulationUser user_a(kDeviceA);
|
||||
PayloadSimulationUser user_b(kDeviceB);
|
||||
PayloadSimulationUser user_a(kDeviceA, GetParam());
|
||||
PayloadSimulationUser user_b(kDeviceB, GetParam());
|
||||
ASSERT_TRUE(SetupConnection(user_a, user_b));
|
||||
|
||||
user_a.ExpectPayload(payload_latch_);
|
||||
@@ -129,10 +145,10 @@ TEST_F(PayloadManagerTest, CanSendBytePayload) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PayloadManagerTest, CanSendStreamPayload) {
|
||||
TEST_P(PayloadManagerTest, CanSendStreamPayload) {
|
||||
env_.Start();
|
||||
PayloadSimulationUser user_a(kDeviceA);
|
||||
PayloadSimulationUser user_b(kDeviceB);
|
||||
PayloadSimulationUser user_a(kDeviceA, GetParam());
|
||||
PayloadSimulationUser user_b(kDeviceB, GetParam());
|
||||
ASSERT_TRUE(SetupConnection(user_a, user_b));
|
||||
|
||||
auto pipe = std::make_shared<Pipe>();
|
||||
@@ -179,10 +195,10 @@ TEST_F(PayloadManagerTest, CanSendStreamPayload) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PayloadManagerTest, CanCancelPayloadOnReceiverSide) {
|
||||
TEST_P(PayloadManagerTest, CanCancelPayloadOnReceiverSide) {
|
||||
env_.Start();
|
||||
PayloadSimulationUser user_a(kDeviceA);
|
||||
PayloadSimulationUser user_b(kDeviceB);
|
||||
PayloadSimulationUser user_a(kDeviceA, GetParam());
|
||||
PayloadSimulationUser user_b(kDeviceB, GetParam());
|
||||
ASSERT_TRUE(SetupConnection(user_a, user_b));
|
||||
|
||||
auto pipe = std::make_shared<Pipe>();
|
||||
@@ -226,7 +242,7 @@ TEST_F(PayloadManagerTest, CanCancelPayloadOnReceiverSide) {
|
||||
[status = PayloadProgressInfo::Status::kCanceled](
|
||||
const PayloadProgressInfo& info) { return info.status == status; },
|
||||
kProgressTimeout));
|
||||
NEARBY_LOG(INFO, "Stream cancelation recevied.");
|
||||
NEARBY_LOG(INFO, "Stream cancelation received.");
|
||||
|
||||
tx.Close();
|
||||
rx.Close();
|
||||
@@ -237,10 +253,10 @@ TEST_F(PayloadManagerTest, CanCancelPayloadOnReceiverSide) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PayloadManagerTest, CanCancelPayloadOnSenderSide) {
|
||||
TEST_P(PayloadManagerTest, CanCancelPayloadOnSenderSide) {
|
||||
env_.Start();
|
||||
PayloadSimulationUser user_a(kDeviceA);
|
||||
PayloadSimulationUser user_b(kDeviceB);
|
||||
PayloadSimulationUser user_a(kDeviceA, GetParam());
|
||||
PayloadSimulationUser user_b(kDeviceB, GetParam());
|
||||
ASSERT_TRUE(SetupConnection(user_a, user_b));
|
||||
|
||||
auto pipe = std::make_shared<Pipe>();
|
||||
@@ -284,7 +300,7 @@ TEST_F(PayloadManagerTest, CanCancelPayloadOnSenderSide) {
|
||||
[status = PayloadProgressInfo::Status::kCanceled](
|
||||
const PayloadProgressInfo& info) { return info.status == status; },
|
||||
kProgressTimeout));
|
||||
NEARBY_LOG(INFO, "Stream cancelation recevied.");
|
||||
NEARBY_LOG(INFO, "Stream cancelation received.");
|
||||
|
||||
tx.Close();
|
||||
rx.Close();
|
||||
@@ -295,6 +311,9 @@ TEST_F(PayloadManagerTest, CanCancelPayloadOnSenderSide) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ParametrisedPayloadManagerTest, PayloadManagerTest,
|
||||
::testing::ValuesIn(kTestCases));
|
||||
|
||||
} // namespace
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@@ -92,12 +92,13 @@ class PcpHandler {
|
||||
// connection, update state on ClientProxy.
|
||||
virtual Status RequestConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const ConnectionRequestInfo& info) = 0;
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options) = 0;
|
||||
|
||||
// Either party may call this to accept connection on their part.
|
||||
// Until both parties call it, connection will not reach a data phase.
|
||||
// Update state in ClientProxy.
|
||||
virtual Status AcceptConnection(ClientProxy* clientProxy,
|
||||
virtual Status AcceptConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const PayloadListener& payload_listener) = 0;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ PcpManager::PcpManager(Mediums& mediums,
|
||||
EndpointChannelManager& channel_manager,
|
||||
EndpointManager& endpoint_manager) {
|
||||
handlers_[Pcp::kP2pCluster] = std::make_unique<P2pClusterPcpHandler>(
|
||||
mediums, &endpoint_manager, &channel_manager);
|
||||
&mediums, &endpoint_manager, &channel_manager);
|
||||
handlers_[Pcp::kP2pStar] = std::make_unique<P2pStarPcpHandler>(
|
||||
mediums, endpoint_manager, channel_manager);
|
||||
handlers_[Pcp::kP2pPointToPoint] =
|
||||
@@ -83,12 +83,13 @@ void PcpManager::StopDiscovery(ClientProxy* client) {
|
||||
|
||||
Status PcpManager::RequestConnection(ClientProxy* client,
|
||||
const string& endpoint_id,
|
||||
const ConnectionRequestInfo& info) {
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options) {
|
||||
if (!current_) {
|
||||
return {Status::kOutOfOrderApiCall};
|
||||
}
|
||||
|
||||
return current_->RequestConnection(client, endpoint_id, info);
|
||||
return current_->RequestConnection(client, endpoint_id, info, options);
|
||||
}
|
||||
|
||||
Status PcpManager::AcceptConnection(ClientProxy* client,
|
||||
|
||||
@@ -46,21 +46,22 @@ class PcpManager {
|
||||
EndpointManager& endpoint_manager);
|
||||
~PcpManager();
|
||||
|
||||
Status StartAdvertising(ClientProxy* client_proxy, const string& service_id,
|
||||
Status StartAdvertising(ClientProxy* client, const string& service_id,
|
||||
const ConnectionOptions& options,
|
||||
const ConnectionRequestInfo& info);
|
||||
void StopAdvertising(ClientProxy* client_proxy);
|
||||
void StopAdvertising(ClientProxy* client);
|
||||
|
||||
Status StartDiscovery(ClientProxy* client_proxy, const string& service_id,
|
||||
Status StartDiscovery(ClientProxy* client, const string& service_id,
|
||||
const ConnectionOptions& options,
|
||||
DiscoveryListener listener);
|
||||
void StopDiscovery(ClientProxy* client_proxy);
|
||||
void StopDiscovery(ClientProxy* client);
|
||||
|
||||
Status RequestConnection(ClientProxy* client_proxy, const string& endpoint_id,
|
||||
const ConnectionRequestInfo& info);
|
||||
Status AcceptConnection(ClientProxy* client_proxy, const string& endpoint_id,
|
||||
Status RequestConnection(ClientProxy* client, const string& endpoint_id,
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options);
|
||||
Status AcceptConnection(ClientProxy* client, const string& endpoint_id,
|
||||
const PayloadListener& payload_listener);
|
||||
Status RejectConnection(ClientProxy* client_proxy, const string& endpoint_id);
|
||||
Status RejectConnection(ClientProxy* client, const string& endpoint_id);
|
||||
|
||||
proto::connections::Medium GetBandwidthUpgradeMedium();
|
||||
void DisconnectFromEndpointManager();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "core_v2/internal/endpoint_channel_manager.h"
|
||||
#include "core_v2/internal/simulation_user.h"
|
||||
#include "core_v2/options.h"
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
#include "gmock/gmock.h"
|
||||
@@ -33,58 +34,71 @@ constexpr char kServiceId[] = "service-id";
|
||||
constexpr char kDeviceA[] = "device-A";
|
||||
constexpr char kDeviceB[] = "device-B";
|
||||
|
||||
class PcpManagerTest : public ::testing::Test {
|
||||
constexpr BooleanMediumSelector kTestCases[] = {
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.wifi_lan = true,
|
||||
},
|
||||
BooleanMediumSelector{
|
||||
.bluetooth = true,
|
||||
.wifi_lan = true,
|
||||
},
|
||||
};
|
||||
|
||||
class PcpManagerTest : public ::testing::TestWithParam<BooleanMediumSelector> {
|
||||
protected:
|
||||
PcpManagerTest() { env_.Stop(); }
|
||||
|
||||
MediumEnvironment& env_{MediumEnvironment::Instance()};
|
||||
};
|
||||
|
||||
TEST_F(PcpManagerTest, CanCreateOne) {
|
||||
TEST_P(PcpManagerTest, CanCreateOne) {
|
||||
env_.Start();
|
||||
SimulationUser user(kDeviceA);
|
||||
SimulationUser user(kDeviceA, GetParam());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PcpManagerTest, CanCreateMany) {
|
||||
TEST_P(PcpManagerTest, CanCreateMany) {
|
||||
env_.Start();
|
||||
SimulationUser user_a(kDeviceA);
|
||||
SimulationUser user_b(kDeviceB);
|
||||
SimulationUser user_a(kDeviceA, GetParam());
|
||||
SimulationUser user_b(kDeviceB, GetParam());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PcpManagerTest, CanAdvertise) {
|
||||
TEST_P(PcpManagerTest, CanAdvertise) {
|
||||
env_.Start();
|
||||
SimulationUser user_a(kDeviceA);
|
||||
SimulationUser user_b(kDeviceB);
|
||||
SimulationUser user_a(kDeviceA, GetParam());
|
||||
SimulationUser user_b(kDeviceB, GetParam());
|
||||
user_a.StartAdvertising(kServiceId, nullptr);
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PcpManagerTest, CanDiscover) {
|
||||
TEST_P(PcpManagerTest, CanDiscover) {
|
||||
env_.Start();
|
||||
SimulationUser user_a("device-a");
|
||||
SimulationUser user_b("device-b");
|
||||
SimulationUser user_a("device-a", GetParam());
|
||||
SimulationUser user_b("device-b", GetParam());
|
||||
user_a.StartAdvertising(kServiceId, nullptr);
|
||||
CountDownLatch latch(1);
|
||||
user_b.StartDiscovery(kServiceId, &latch);
|
||||
EXPECT_TRUE(latch.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId);
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_name, user_a.GetName());
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PcpManagerTest, CanConnect) {
|
||||
TEST_P(PcpManagerTest, CanConnect) {
|
||||
env_.Start();
|
||||
SimulationUser user_a("device-a");
|
||||
SimulationUser user_b("device-b");
|
||||
SimulationUser user_a("device-a", GetParam());
|
||||
SimulationUser user_b("device-b", GetParam());
|
||||
CountDownLatch discovery_latch(1);
|
||||
CountDownLatch connection_latch(2);
|
||||
user_a.StartAdvertising(kServiceId, &connection_latch);
|
||||
user_b.StartDiscovery(kServiceId, &discovery_latch);
|
||||
EXPECT_TRUE(discovery_latch.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId);
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_name, user_a.GetName());
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo());
|
||||
user_b.RequestConnection(&connection_latch);
|
||||
EXPECT_TRUE(connection_latch.Await(absl::Milliseconds(1000)).result());
|
||||
user_a.Stop();
|
||||
@@ -92,10 +106,10 @@ TEST_F(PcpManagerTest, CanConnect) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PcpManagerTest, CanAccept) {
|
||||
TEST_P(PcpManagerTest, CanAccept) {
|
||||
env_.Start();
|
||||
SimulationUser user_a("device-a");
|
||||
SimulationUser user_b("device-b");
|
||||
SimulationUser user_a("device-a", GetParam());
|
||||
SimulationUser user_b("device-b", GetParam());
|
||||
CountDownLatch discovery_latch(1);
|
||||
CountDownLatch connection_latch(2);
|
||||
CountDownLatch accept_latch(2);
|
||||
@@ -103,7 +117,7 @@ TEST_F(PcpManagerTest, CanAccept) {
|
||||
user_b.StartDiscovery(kServiceId, &discovery_latch);
|
||||
EXPECT_TRUE(discovery_latch.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId);
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_name, user_a.GetName());
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo());
|
||||
user_b.RequestConnection(&connection_latch);
|
||||
EXPECT_TRUE(connection_latch.Await(absl::Milliseconds(1000)).result());
|
||||
user_a.AcceptConnection(&accept_latch);
|
||||
@@ -114,10 +128,10 @@ TEST_F(PcpManagerTest, CanAccept) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(PcpManagerTest, CanReject) {
|
||||
TEST_P(PcpManagerTest, CanReject) {
|
||||
env_.Start();
|
||||
SimulationUser user_a("device-a");
|
||||
SimulationUser user_b("device-b");
|
||||
SimulationUser user_a("device-a", GetParam());
|
||||
SimulationUser user_b("device-b", GetParam());
|
||||
CountDownLatch discovery_latch(1);
|
||||
CountDownLatch connection_latch(2);
|
||||
CountDownLatch reject_latch(1);
|
||||
@@ -125,7 +139,7 @@ TEST_F(PcpManagerTest, CanReject) {
|
||||
user_b.StartDiscovery(kServiceId, &discovery_latch);
|
||||
EXPECT_TRUE(discovery_latch.Await(absl::Milliseconds(1000)).result());
|
||||
EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId);
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_name, user_a.GetName());
|
||||
EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo());
|
||||
user_b.RequestConnection(&connection_latch);
|
||||
EXPECT_TRUE(connection_latch.Await(absl::Milliseconds(1000)).result());
|
||||
user_b.ExpectRejectedConnection(reject_latch);
|
||||
@@ -136,6 +150,9 @@ TEST_F(PcpManagerTest, CanReject) {
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ParametrisedPcpManagerTest, PcpManagerTest,
|
||||
::testing::ValuesIn(kTestCases));
|
||||
|
||||
} // namespace
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
|
||||
@@ -62,7 +62,8 @@ class ServiceController {
|
||||
|
||||
virtual Status RequestConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const ConnectionRequestInfo& info) = 0;
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options) = 0;
|
||||
virtual Status AcceptConnection(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
const PayloadListener& listener) = 0;
|
||||
@@ -76,8 +77,7 @@ class ServiceController {
|
||||
const std::vector<std::string>& endpoint_ids,
|
||||
Payload payload) = 0;
|
||||
|
||||
virtual Status CancelPayload(ClientProxy* client,
|
||||
Payload::Id payload_id) = 0;
|
||||
virtual Status CancelPayload(ClientProxy* client, Payload::Id payload_id) = 0;
|
||||
|
||||
virtual void DisconnectFromEndpoint(ClientProxy* client,
|
||||
const std::string& endpoint_id) = 0;
|
||||
|
||||
@@ -106,23 +106,25 @@ void ServiceControllerRouter::StopDiscovery(ClientProxy* client,
|
||||
|
||||
void ServiceControllerRouter::RequestConnection(
|
||||
ClientProxy* client, absl::string_view endpoint_id,
|
||||
const ConnectionRequestInfo& info, const ResultCallback& callback) {
|
||||
RouteToServiceController(
|
||||
[this, client, endpoint_id = std::string(endpoint_id), info, callback]() {
|
||||
if (!ClientHasAcquiredServiceController(client)) {
|
||||
callback.result_cb({Status::kOutOfOrderApiCall});
|
||||
return;
|
||||
}
|
||||
const ConnectionRequestInfo& info, const ConnectionOptions& options,
|
||||
const ResultCallback& callback) {
|
||||
RouteToServiceController([this, client,
|
||||
endpoint_id = std::string(endpoint_id), info,
|
||||
options, callback]() {
|
||||
if (!ClientHasAcquiredServiceController(client)) {
|
||||
callback.result_cb({Status::kOutOfOrderApiCall});
|
||||
return;
|
||||
}
|
||||
|
||||
if (client->HasPendingConnectionToEndpoint(endpoint_id) ||
|
||||
client->IsConnectedToEndpoint(endpoint_id)) {
|
||||
callback.result_cb({Status::kAlreadyConnectedToEndpoint});
|
||||
return;
|
||||
}
|
||||
if (client->HasPendingConnectionToEndpoint(endpoint_id) ||
|
||||
client->IsConnectedToEndpoint(endpoint_id)) {
|
||||
callback.result_cb({Status::kAlreadyConnectedToEndpoint});
|
||||
return;
|
||||
}
|
||||
|
||||
callback.result_cb(
|
||||
service_controller_->RequestConnection(client, endpoint_id, info));
|
||||
});
|
||||
callback.result_cb(service_controller_->RequestConnection(
|
||||
client, endpoint_id, info, options));
|
||||
});
|
||||
}
|
||||
|
||||
void ServiceControllerRouter::AcceptConnection(ClientProxy* client,
|
||||
@@ -218,7 +220,7 @@ void ServiceControllerRouter::SendPayload(
|
||||
std::vector<std::string>(endpoint_ids.begin(), endpoint_ids.end());
|
||||
|
||||
RouteToServiceController(
|
||||
[this, client, shared_payload, endpoints, &callback]() {
|
||||
[this, client, shared_payload, endpoints, callback]() {
|
||||
if (!ClientHasAcquiredServiceController(client)) {
|
||||
callback.result_cb({Status::kOutOfOrderApiCall});
|
||||
return;
|
||||
|
||||
@@ -73,6 +73,7 @@ class ServiceControllerRouter {
|
||||
|
||||
void RequestConnection(ClientProxy* client, absl::string_view endpoint_id,
|
||||
const ConnectionRequestInfo& info,
|
||||
const ConnectionOptions& options,
|
||||
const ResultCallback& callback);
|
||||
void AcceptConnection(ClientProxy* client, absl::string_view endpoint_id,
|
||||
const PayloadListener& listener,
|
||||
|
||||
@@ -115,20 +115,22 @@ class ServiceControllerRouterTest : public testing::Test {
|
||||
ResultCallback callback) {
|
||||
EXPECT_CALL(mock_, RequestConnection)
|
||||
.WillOnce(Return(Status{Status::kSuccess}));
|
||||
ConnectionOptions options;
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
complete_ = false;
|
||||
router_.RequestConnection(client, endpoint_id, request_info, callback);
|
||||
router_.RequestConnection(client, endpoint_id, request_info, options,
|
||||
callback);
|
||||
while (!complete_) cond_.Wait();
|
||||
EXPECT_EQ(result_, Status{Status::kSuccess});
|
||||
}
|
||||
ConnectionResponseInfo response_info{
|
||||
.remote_endpoint_name = "endpoint_name",
|
||||
.remote_endpoint_info = ByteArray{"endpoint_name"},
|
||||
.authentication_token = "auth_token",
|
||||
.raw_authentication_token = ByteArray("auth_token"),
|
||||
.raw_authentication_token = ByteArray{"auth_token"},
|
||||
.is_incoming_connection = true,
|
||||
};
|
||||
client->OnConnectionInitiated(endpoint_id, response_info,
|
||||
client->OnConnectionInitiated(endpoint_id, response_info, options,
|
||||
request_info.listener);
|
||||
EXPECT_TRUE(client->HasPendingConnectionToEndpoint(endpoint_id));
|
||||
}
|
||||
@@ -256,7 +258,7 @@ class ServiceControllerRouterTest : public testing::Test {
|
||||
std::vector<proto::connections::Medium> mediums_{
|
||||
proto::connections::Medium::BLUETOOTH};
|
||||
const ConnectionRequestInfo kConnectionRequestInfo{
|
||||
.name = kRequestorName,
|
||||
.endpoint_info = ByteArray{kRequestorName},
|
||||
.listener = ConnectionListener(),
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ void SimulationUser::OnConnectionInitiated(const std::string& endpoint_id,
|
||||
NEARBY_LOG(INFO, "StartAdvertising: initiated_cb called");
|
||||
discovered_ = DiscoveredInfo{
|
||||
.endpoint_id = endpoint_id,
|
||||
.endpoint_name = name_,
|
||||
.endpoint_info = GetInfo(),
|
||||
.service_id = service_id_,
|
||||
};
|
||||
}
|
||||
@@ -49,12 +49,12 @@ void SimulationUser::OnConnectionRejected(const std::string& endpoint_id,
|
||||
}
|
||||
|
||||
void SimulationUser::OnEndpointFound(const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Device discovered: id=%s", endpoint_id.c_str());
|
||||
discovered_ = DiscoveredInfo{
|
||||
.endpoint_id = endpoint_id,
|
||||
.endpoint_name = endpoint_name,
|
||||
.endpoint_info = endpoint_info,
|
||||
.service_id = service_id,
|
||||
};
|
||||
if (found_latch_) found_latch_->CountDown();
|
||||
@@ -111,7 +111,7 @@ void SimulationUser::StartAdvertising(const std::string& service_id,
|
||||
};
|
||||
EXPECT_TRUE(mgr_.StartAdvertising(&client_, service_id_, options_,
|
||||
{
|
||||
.name = name_,
|
||||
.endpoint_info = info_,
|
||||
.listener = std::move(listener),
|
||||
})
|
||||
.Ok());
|
||||
@@ -142,12 +142,14 @@ void SimulationUser::RequestConnection(CountDownLatch* latch) {
|
||||
.rejected_cb =
|
||||
absl::bind_front(&SimulationUser::OnConnectionRejected, this),
|
||||
};
|
||||
EXPECT_TRUE(mgr_.RequestConnection(&client_, discovered_.endpoint_id,
|
||||
{
|
||||
.name = discovered_.endpoint_name,
|
||||
.listener = std::move(listener),
|
||||
})
|
||||
.Ok());
|
||||
EXPECT_TRUE(
|
||||
mgr_.RequestConnection(&client_, discovered_.endpoint_id,
|
||||
{
|
||||
.endpoint_info = discovered_.endpoint_info,
|
||||
.listener = std::move(listener),
|
||||
},
|
||||
connection_options_)
|
||||
.Ok());
|
||||
}
|
||||
|
||||
void SimulationUser::AcceptConnection(CountDownLatch* latch) {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "core_v2/internal/endpoint_manager.h"
|
||||
#include "core_v2/internal/payload_manager.h"
|
||||
#include "core_v2/internal/pcp_manager.h"
|
||||
#include "core_v2/options.h"
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "platform_v2/public/condition_variable.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
@@ -41,18 +42,22 @@ class SimulationUser {
|
||||
public:
|
||||
struct DiscoveredInfo {
|
||||
std::string endpoint_id;
|
||||
std::string endpoint_name;
|
||||
ByteArray endpoint_info;
|
||||
std::string service_id;
|
||||
|
||||
bool Empty() const { return endpoint_id.empty(); }
|
||||
void Clear() { endpoint_id.clear(); }
|
||||
};
|
||||
|
||||
explicit SimulationUser(const std::string& device_name)
|
||||
: name_(device_name) {}
|
||||
virtual ~SimulationUser() {
|
||||
Stop();
|
||||
}
|
||||
explicit SimulationUser(
|
||||
const std::string& device_name,
|
||||
BooleanMediumSelector allowed = BooleanMediumSelector())
|
||||
: info_{ByteArray{device_name}},
|
||||
options_{
|
||||
.strategy = Strategy::kP2pCluster,
|
||||
.allowed = allowed,
|
||||
} {}
|
||||
virtual ~SimulationUser() { Stop(); }
|
||||
void Stop() {
|
||||
pm_.DisconnectFromEndpointManager();
|
||||
mgr_.DisconnectFromEndpointManager();
|
||||
@@ -94,7 +99,7 @@ class SimulationUser {
|
||||
void ExpectPayload(CountDownLatch& latch) { payload_latch_ = &latch; }
|
||||
|
||||
const DiscoveredInfo& GetDiscovered() const { return discovered_; }
|
||||
std::string GetName() const { return name_; }
|
||||
ByteArray GetInfo() const { return info_; }
|
||||
|
||||
bool WaitForProgress(std::function<bool(const PayloadProgressInfo&)> pred,
|
||||
absl::Duration timeout);
|
||||
@@ -109,7 +114,7 @@ class SimulationUser {
|
||||
|
||||
// DiscoveryListener callbacks
|
||||
void OnEndpointFound(const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id);
|
||||
void OnEndpointLost(const std::string& endpoint_id);
|
||||
|
||||
@@ -120,6 +125,7 @@ class SimulationUser {
|
||||
|
||||
std::string service_id_;
|
||||
DiscoveredInfo discovered_;
|
||||
ConnectionOptions connection_options_;
|
||||
Mutex progress_mutex_;
|
||||
ConditionVariable progress_sync_{&progress_mutex_};
|
||||
PayloadProgressInfo progress_info_;
|
||||
@@ -132,9 +138,9 @@ class SimulationUser {
|
||||
CountDownLatch* payload_latch_ = nullptr;
|
||||
Future<bool>* future_ = nullptr;
|
||||
std::function<bool(const PayloadProgressInfo&)> predicate_;
|
||||
std::string name_;
|
||||
ByteArray info_;
|
||||
Mediums mediums_;
|
||||
ConnectionOptions options_{.strategy = Strategy::kP2pCluster};
|
||||
ConnectionOptions options_;
|
||||
ClientProxy client_;
|
||||
EndpointChannelManager ecm_;
|
||||
EndpointManager em_{&ecm_};
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace connections {
|
||||
WifiLanServiceInfo::WifiLanServiceInfo(Version version, Pcp pcp,
|
||||
absl::string_view endpoint_id,
|
||||
const ByteArray& service_id_hash,
|
||||
absl::string_view endpoint_name) {
|
||||
const ByteArray& endpoint_info) {
|
||||
if (version != Version::kV1 || endpoint_id.empty() ||
|
||||
endpoint_id.length() != kEndpointIdLength ||
|
||||
service_id_hash.size() != kServiceIdHashLength) {
|
||||
@@ -50,7 +50,7 @@ WifiLanServiceInfo::WifiLanServiceInfo(Version version, Pcp pcp,
|
||||
pcp_ = pcp;
|
||||
service_id_hash_ = service_id_hash;
|
||||
endpoint_id_ = std::string(endpoint_id);
|
||||
endpoint_name_ = std::string(endpoint_name);
|
||||
endpoint_info_ = endpoint_info;
|
||||
}
|
||||
|
||||
WifiLanServiceInfo::WifiLanServiceInfo(absl::string_view service_info_string) {
|
||||
@@ -80,11 +80,11 @@ WifiLanServiceInfo::WifiLanServiceInfo(absl::string_view service_info_string) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (service_info_bytes.size() > kMaxEndpointNameLength) {
|
||||
if (service_info_bytes.size() > kMaxEndpointInfoLength) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Cannot deserialize WifiLanServiceInfo: expecting max %d raw "
|
||||
"bytes, got %" PRIu64,
|
||||
kMaxEndpointNameLength, service_info_bytes.size());
|
||||
kMaxEndpointInfoLength, service_info_bytes.size());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,24 +119,22 @@ WifiLanServiceInfo::WifiLanServiceInfo(absl::string_view service_info_string) {
|
||||
// The next 3 bytes are supposed to be the service_id_hash.
|
||||
service_id_hash_ = base_input_stream.ReadBytes(kServiceIdHashLength);
|
||||
|
||||
// The next 1 byte are supposed to be the length of the endpoint_name.
|
||||
std::uint32_t expected_endpoint_name_length = base_input_stream.ReadUint8();
|
||||
// The next 1 byte are supposed to be the length of the endpoint_info.
|
||||
std::uint32_t expected_endpoint_info_length = base_input_stream.ReadUint8();
|
||||
|
||||
// The rest bytes are supposed to be the endpoint_name
|
||||
auto endpoint_name_bytes =
|
||||
base_input_stream.ReadBytes(expected_endpoint_name_length);
|
||||
if (endpoint_name_bytes.Empty() ||
|
||||
endpoint_name_bytes.size() != expected_endpoint_name_length) {
|
||||
// The rest bytes are supposed to be the endpoint_info
|
||||
endpoint_info_ = base_input_stream.ReadBytes(expected_endpoint_info_length);
|
||||
if (endpoint_info_.Empty() ||
|
||||
endpoint_info_.size() != expected_endpoint_info_length) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Cannot deserialize WifiLanServiceInfo: expected "
|
||||
"endpointName to be %d bytes, got %" PRIu64,
|
||||
expected_endpoint_name_length, endpoint_name_bytes.size());
|
||||
"endpoint info to be %d bytes, got %" PRIu64,
|
||||
expected_endpoint_info_length, endpoint_info_.size());
|
||||
|
||||
// Clear enpoint_id for validadity.
|
||||
endpoint_id_.clear();
|
||||
return;
|
||||
}
|
||||
endpoint_name_ = std::string{endpoint_name_bytes};
|
||||
}
|
||||
|
||||
WifiLanServiceInfo::operator std::string() const {
|
||||
@@ -151,22 +149,23 @@ WifiLanServiceInfo::operator std::string() const {
|
||||
version_and_pcp_byte |=
|
||||
static_cast<char>(static_cast<uint32_t>(pcp_) & kPcpBitmask);
|
||||
|
||||
std::string usable_endpoint_name(endpoint_name_);
|
||||
if (endpoint_name_.size() > kMaxEndpointNameLength) {
|
||||
ByteArray usable_endpoint_info(endpoint_info_);
|
||||
if (endpoint_info_.size() > kMaxEndpointInfoLength) {
|
||||
NEARBY_LOG(
|
||||
INFO,
|
||||
"While serializing WifiLanServiceInfo, truncating Endpoint Name %s "
|
||||
"While serializing WifiLanServiceInfo, truncating Endpoint info %s "
|
||||
"(%lu bytes) down to %d bytes",
|
||||
endpoint_name_.c_str(), endpoint_name_.size(), kMaxEndpointNameLength);
|
||||
usable_endpoint_name.erase(kMaxEndpointNameLength);
|
||||
std::string(endpoint_info_).c_str(), endpoint_info_.size(),
|
||||
kMaxEndpointInfoLength);
|
||||
usable_endpoint_info.SetData(endpoint_info_.data(), kMaxEndpointInfoLength);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
std::string out = absl::StrCat(std::string(1, version_and_pcp_byte),
|
||||
endpoint_id_,
|
||||
std::string(service_id_hash_),
|
||||
std::string(1, usable_endpoint_name.size()),
|
||||
usable_endpoint_name);
|
||||
std::string(1, usable_endpoint_info.size()),
|
||||
std::string(usable_endpoint_info));
|
||||
// clang-format on
|
||||
|
||||
return Base64Utils::Encode(ByteArray{std::move(out)});
|
||||
|
||||
@@ -42,7 +42,7 @@ class WifiLanServiceInfo {
|
||||
WifiLanServiceInfo() = default;
|
||||
WifiLanServiceInfo(Version version, Pcp pcp, absl::string_view endpoint_id,
|
||||
const ByteArray& service_id_hash,
|
||||
absl::string_view endpoint_name);
|
||||
const ByteArray& endpoint_info);
|
||||
explicit WifiLanServiceInfo(absl::string_view service_info_string);
|
||||
WifiLanServiceInfo(const WifiLanServiceInfo&) = default;
|
||||
WifiLanServiceInfo& operator=(const WifiLanServiceInfo&) = default;
|
||||
@@ -56,7 +56,7 @@ class WifiLanServiceInfo {
|
||||
Version GetVersion() const { return version_; }
|
||||
Pcp GetPcp() const { return pcp_; }
|
||||
std::string GetEndpointId() const { return endpoint_id_; }
|
||||
std::string GetEndpointName() const { return endpoint_name_; }
|
||||
ByteArray GetEndpointInfo() const { return endpoint_info_; }
|
||||
ByteArray GetServiceIdHash() const { return service_id_hash_; }
|
||||
|
||||
private:
|
||||
@@ -67,7 +67,7 @@ class WifiLanServiceInfo {
|
||||
// The length for endpoint id in encrypted WifiLanServiceInfo string.
|
||||
static constexpr int kEndpointIdLength = 4;
|
||||
// The maximum length for endpoint id in encrypted WifiLanServiceInfo string.
|
||||
static constexpr int kMaxEndpointNameLength = 131;
|
||||
static constexpr int kMaxEndpointInfoLength = 131;
|
||||
|
||||
static constexpr int kVersionBitmask = 0x0E0;
|
||||
static constexpr int kPcpBitmask = 0x01F;
|
||||
@@ -81,8 +81,8 @@ class WifiLanServiceInfo {
|
||||
std::string endpoint_id_;
|
||||
// Connected hash service id.
|
||||
ByteArray service_id_hash_;
|
||||
// Connected endpoint name.
|
||||
std::string endpoint_name_;
|
||||
// Connected endpoint info.
|
||||
ByteArray endpoint_info_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
|
||||
@@ -34,21 +34,23 @@ constexpr absl::string_view kEndPointName{"RAWK + ROWL!"};
|
||||
|
||||
TEST(WifiLanServiceInfoTest, ConstructionWorks) {
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
WifiLanServiceInfo wifi_lan_service_info{kVersion, kPcp, kEndPointID,
|
||||
service_id_hash, kEndPointName};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
WifiLanServiceInfo wifi_lan_service_info{
|
||||
kVersion, kPcp, kEndPointID, service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_TRUE(wifi_lan_service_info.IsValid());
|
||||
EXPECT_EQ(kPcp, wifi_lan_service_info.GetPcp());
|
||||
EXPECT_EQ(kVersion, wifi_lan_service_info.GetVersion());
|
||||
EXPECT_EQ(kEndPointID, wifi_lan_service_info.GetEndpointId());
|
||||
EXPECT_EQ(service_id_hash, wifi_lan_service_info.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointName, wifi_lan_service_info.GetEndpointName());
|
||||
EXPECT_EQ(endpoint_info, wifi_lan_service_info.GetEndpointInfo());
|
||||
}
|
||||
|
||||
TEST(WifiLanServiceInfoTest, ConstructionFromSerializedStringWorks) {
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
WifiLanServiceInfo org_wifi_lan_service_info{kVersion, kPcp, kEndPointID,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
std::string wifi_lan_service_info_string{org_wifi_lan_service_info};
|
||||
|
||||
WifiLanServiceInfo wifi_lan_service_info{wifi_lan_service_info_string};
|
||||
@@ -58,15 +60,16 @@ TEST(WifiLanServiceInfoTest, ConstructionFromSerializedStringWorks) {
|
||||
EXPECT_EQ(kVersion, wifi_lan_service_info.GetVersion());
|
||||
EXPECT_EQ(kEndPointID, wifi_lan_service_info.GetEndpointId());
|
||||
EXPECT_EQ(service_id_hash, wifi_lan_service_info.GetServiceIdHash());
|
||||
EXPECT_EQ(kEndPointName, wifi_lan_service_info.GetEndpointName());
|
||||
EXPECT_EQ(endpoint_info, wifi_lan_service_info.GetEndpointInfo());
|
||||
}
|
||||
|
||||
TEST(WifiLanServiceInfoTest, ConstructionFailsWithBadVersion) {
|
||||
auto bad_version = static_cast<WifiLanServiceInfo::Version>(666);
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
WifiLanServiceInfo wifi_lan_service_info{bad_version, kPcp, kEndPointID,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(wifi_lan_service_info.IsValid());
|
||||
}
|
||||
@@ -75,8 +78,9 @@ TEST(WifiLanServiceInfoTest, ConstructionFailsWithBadPCP) {
|
||||
auto bad_pcp = static_cast<Pcp>(666);
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
WifiLanServiceInfo wifi_lan_service_info{kVersion, bad_pcp, kEndPointID,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(wifi_lan_service_info.IsValid());
|
||||
}
|
||||
@@ -85,8 +89,9 @@ TEST(WifiLanServiceInfoTest, ConstructionFailsWithShortEndpointId) {
|
||||
std::string short_endpoint_id("AB1");
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
WifiLanServiceInfo wifi_lan_service_info{kVersion, kPcp, short_endpoint_id,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(wifi_lan_service_info.IsValid());
|
||||
}
|
||||
@@ -95,8 +100,9 @@ TEST(WifiLanServiceInfoTest, ConstructionFailsWithLongEndpointId) {
|
||||
std::string long_endpoint_id("AB12X");
|
||||
|
||||
ByteArray service_id_hash{std::string(kServiceIDHashBytes)};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
WifiLanServiceInfo wifi_lan_service_info{kVersion, kPcp, long_endpoint_id,
|
||||
service_id_hash, kEndPointName};
|
||||
service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(wifi_lan_service_info.IsValid());
|
||||
}
|
||||
@@ -105,8 +111,9 @@ TEST(WifiLanServiceInfoTest, ConstructionFailsWithShortServiceIdHash) {
|
||||
char short_service_id_hash_bytes[] = "\x0a\x0b";
|
||||
|
||||
ByteArray short_service_id_hash{short_service_id_hash_bytes};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
WifiLanServiceInfo wifi_lan_service_info{
|
||||
kVersion, kPcp, kEndPointID, short_service_id_hash, kEndPointName};
|
||||
kVersion, kPcp, kEndPointID, short_service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(wifi_lan_service_info.IsValid());
|
||||
}
|
||||
@@ -115,8 +122,9 @@ TEST(WifiLanServiceInfoTest, ConstructionFailsWithLongServiceIdHash) {
|
||||
char long_service_id_hash_bytes[] = "\x0a\x0b\x0c\x0d";
|
||||
|
||||
ByteArray long_service_id_hash{long_service_id_hash_bytes};
|
||||
ByteArray endpoint_info{std::string(kEndPointName)};
|
||||
WifiLanServiceInfo wifi_lan_service_info{kVersion, kPcp, kEndPointID,
|
||||
long_service_id_hash, kEndPointName};
|
||||
long_service_id_hash, endpoint_info};
|
||||
|
||||
EXPECT_FALSE(wifi_lan_service_info.IsValid());
|
||||
}
|
||||
|
||||
@@ -49,10 +49,9 @@ struct ResultCallback {
|
||||
};
|
||||
|
||||
struct ConnectionResponseInfo {
|
||||
std::string remote_endpoint_name;
|
||||
ByteArray remote_endpoint_info;
|
||||
std::string authentication_token;
|
||||
ByteArray raw_authentication_token;
|
||||
ByteArray endpoint_info;
|
||||
bool is_incoming_connection = false;
|
||||
bool is_connection_verified = false;
|
||||
};
|
||||
@@ -135,13 +134,13 @@ struct DiscoveryListener {
|
||||
// Called when a remote endpoint is discovered.
|
||||
//
|
||||
// endpoint_id - The ID of the remote endpoint that was discovered.
|
||||
// endpoint_name - The human readable name of the remote endpoint.
|
||||
// endpoint_info - The info of the remote endpoint representd by ByteArray.
|
||||
// service_id - The ID of the service advertised by the remote endpoint.
|
||||
std::function<void(const std::string& endpoint_id,
|
||||
const std::string& endpoint_name,
|
||||
const ByteArray& endpoint_info,
|
||||
const std::string& service_id)>
|
||||
endpoint_found_cb =
|
||||
DefaultCallback<const std::string&, const std::string&,
|
||||
DefaultCallback<const std::string&, const ByteArray&,
|
||||
const std::string&>();
|
||||
|
||||
// Called when a remote endpoint is no longer discoverable; only called for
|
||||
|
||||
+59
-6
@@ -16,17 +16,64 @@
|
||||
#define CORE_V2_OPTIONS_H_
|
||||
|
||||
#include "core_v2/strategy.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "proto/connections_enums.pb.h"
|
||||
#include "proto/connections_enums.pb.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
using Medium = ::location::nearby::proto::connections::Medium;
|
||||
|
||||
// Generic type: allows definition of a feature T for every Medium.
|
||||
template <typename T>
|
||||
struct MediumSelector {
|
||||
T bluetooth;
|
||||
T ble;
|
||||
T web_rtc;
|
||||
T wifi_lan;
|
||||
|
||||
constexpr MediumSelector() = default;
|
||||
constexpr MediumSelector(const MediumSelector&) = default;
|
||||
constexpr MediumSelector& operator=(const MediumSelector&) = default;
|
||||
|
||||
constexpr bool Any(T value) const {
|
||||
return bluetooth == value || ble == value || web_rtc == value ||
|
||||
wifi_lan == value;
|
||||
}
|
||||
|
||||
constexpr bool All(T value) const {
|
||||
return bluetooth == value && ble == value && web_rtc == value &&
|
||||
wifi_lan == value;
|
||||
}
|
||||
|
||||
constexpr int Count(T value) const {
|
||||
int count = 0;
|
||||
if (bluetooth == value) count++;
|
||||
if (ble == value) count++;
|
||||
if (wifi_lan == value) count++;
|
||||
if (web_rtc == value) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
constexpr MediumSelector& SetAll(T value) {
|
||||
bluetooth = value;
|
||||
ble = value;
|
||||
web_rtc = value;
|
||||
wifi_lan = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector<Medium> GetMediums(T value) const {
|
||||
std::vector<Medium> mediums;
|
||||
// Mediums are sorted in order of decreasing preference.
|
||||
if (wifi_lan == value) mediums.push_back(Medium::WIFI_LAN);
|
||||
if (web_rtc == value) mediums.push_back(Medium::WEB_RTC);
|
||||
if (ble == value) mediums.push_back(Medium::BLE);
|
||||
if (bluetooth == value) mediums.push_back(Medium::BLUETOOTH);
|
||||
return mediums;
|
||||
}
|
||||
};
|
||||
|
||||
// Feature On/Off switch for mediums.
|
||||
@@ -36,17 +83,23 @@ using BooleanMediumSelector = MediumSelector<bool>;
|
||||
// All fields are mutable, to make the type copy-assignable.
|
||||
struct ConnectionOptions {
|
||||
Strategy strategy;
|
||||
BooleanMediumSelector allowed;
|
||||
BooleanMediumSelector allowed{BooleanMediumSelector().SetAll(true)};
|
||||
bool auto_upgrade_bandwidth;
|
||||
bool enforce_topology_constraints;
|
||||
ByteArray remote_bluetooth_mac_address;
|
||||
// Verify if ConnectionOptions is in a not-initialized (Empty) state.
|
||||
bool Empty() const {
|
||||
return strategy.IsNone();
|
||||
}
|
||||
bool Empty() const { return strategy.IsNone(); }
|
||||
// Bring ConnectionOptions to a not-initialized (Empty) state.
|
||||
void Clear() {
|
||||
strategy.Clear();
|
||||
void Clear() { strategy.Clear(); }
|
||||
// Returns a copy, but if no mediums are allowed, allowes all mediums.
|
||||
ConnectionOptions CompatibleOptions() const {
|
||||
ConnectionOptions result = *this;
|
||||
if (!allowed.Any(true)) {
|
||||
result.allowed.SetAll(true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
std::vector<Medium> GetMediums() const { return allowed.GetMediums(true); }
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "core_v2/listeners.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -26,11 +27,11 @@ namespace connections {
|
||||
// Used by Discovery in Core::RequestConnection().
|
||||
// Used by Advertising in Core::StartAdvertising().
|
||||
struct ConnectionRequestInfo {
|
||||
// name - A human readable name for this endpoint, to appear on
|
||||
// other devices.
|
||||
// listener - A set of callbacks notified when remote endpoints request a
|
||||
// connection to this endpoint.
|
||||
std::string name;
|
||||
// endpoint_info - Identifing information about this endpoint (eg. name,
|
||||
// device type).
|
||||
// listener - A set of callbacks notified when remote endpoints request a
|
||||
// connection to this endpoint.
|
||||
ByteArray endpoint_info;
|
||||
ConnectionListener listener;
|
||||
};
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ struct Status {
|
||||
kAlreadyConnectedToEndpoint,
|
||||
kNotConnectedToEndpoint,
|
||||
kBluetoothError,
|
||||
kBleError,
|
||||
kWifiLanError,
|
||||
kPayloadUnknown,
|
||||
};
|
||||
|
||||
@@ -21,7 +21,6 @@ cc_library(
|
||||
"system_clock_impl.h",
|
||||
],
|
||||
visibility = [
|
||||
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
|
||||
"//core:__subpackages__",
|
||||
"//platform:__subpackages__",
|
||||
],
|
||||
|
||||
@@ -19,11 +19,7 @@ cc_library(
|
||||
"sample_platform.cc",
|
||||
"settable_future_impl.h",
|
||||
],
|
||||
visibility = [
|
||||
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
|
||||
"//core:__subpackages__",
|
||||
"//location/nearby/setup/core:__subpackages__",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//platform:types",
|
||||
"//platform:utils",
|
||||
|
||||
@@ -24,7 +24,6 @@ cc_library(
|
||||
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
|
||||
"//core:__subpackages__",
|
||||
"//platform/impl:__subpackages__",
|
||||
"//location/nearby/setup/core:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//platform:types",
|
||||
|
||||
+36
-41
@@ -19,7 +19,6 @@
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -29,15 +28,17 @@ namespace api {
|
||||
// particular BLE device to connect to its GATT server.
|
||||
class BlePeripheral {
|
||||
public:
|
||||
virtual ~BlePeripheral() {}
|
||||
virtual ~BlePeripheral() = default;
|
||||
|
||||
// The returned reference lifetime matches BlePeripheral object.
|
||||
virtual BluetoothDevice& GetBluetoothDevice() = 0;
|
||||
virtual std::string GetName() const = 0;
|
||||
|
||||
virtual ByteArray GetAdvertisementBytes(
|
||||
const std::string& service_id) const = 0;
|
||||
};
|
||||
|
||||
class BleSocket {
|
||||
public:
|
||||
virtual ~BleSocket() {}
|
||||
virtual ~BleSocket() = default;
|
||||
|
||||
// Returns the InputStream of the BleSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
@@ -59,64 +60,58 @@ class BleSocket {
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
virtual Exception Close() = 0;
|
||||
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the BleSocket object is destroyed.
|
||||
virtual BlePeripheral& GetRemotePeripheral() = 0;
|
||||
// Returns valid BlePeripheral pointer if there is a connection, and
|
||||
// nullptr otherwise.
|
||||
virtual BlePeripheral* GetRemotePeripheral() = 0;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the BLE medium.
|
||||
class BleMedium {
|
||||
public:
|
||||
virtual ~BleMedium() {}
|
||||
virtual ~BleMedium() = default;
|
||||
|
||||
virtual bool StartAdvertising(absl::string_view service_id,
|
||||
const ByteArray& advertisement) = 0;
|
||||
virtual void StopAdvertising(absl::string_view service_id) = 0;
|
||||
virtual bool StartAdvertising(const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes) = 0;
|
||||
virtual bool StopAdvertising(const std::string& service_id) = 0;
|
||||
|
||||
class DiscoveredPeripheralCallback {
|
||||
public:
|
||||
virtual ~DiscoveredPeripheralCallback() {}
|
||||
|
||||
// The BlePeripheral* is not owned by callbacks.
|
||||
// It is passed to give access to its non-const methods.
|
||||
// It is guaranteed to be valid for the duration of call.
|
||||
virtual void OnPeripheralDiscovered(BlePeripheral* ble_peripheral,
|
||||
absl::string_view service_id,
|
||||
const ByteArray& advertisement) = 0;
|
||||
virtual void OnPeripheralLost(BlePeripheral* ble_peripheral,
|
||||
absl::string_view service_id) = 0;
|
||||
// Callback that is invoked when a discovered peripheral is found or lost.
|
||||
struct DiscoveredPeripheralCallback {
|
||||
std::function<void(BlePeripheral& peripheral,
|
||||
const std::string& service_id)>
|
||||
peripheral_discovered_cb =
|
||||
DefaultCallback<BlePeripheral&, const std::string&>();
|
||||
std::function<void(BlePeripheral& peripheral,
|
||||
const std::string& service_id)>
|
||||
peripheral_lost_cb =
|
||||
DefaultCallback<BlePeripheral&, const std::string&>();
|
||||
};
|
||||
|
||||
// Returns true once the BLE scan has been initiated.
|
||||
virtual bool StartScanning(
|
||||
absl::string_view service_id,
|
||||
const DiscoveredPeripheralCallback& discovered_peripheral_callback) = 0;
|
||||
virtual bool StartScanning(const std::string& service_id,
|
||||
DiscoveredPeripheralCallback callback) = 0;
|
||||
|
||||
// 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.
|
||||
virtual void StopScanning(absl::string_view service_id) = 0;
|
||||
virtual bool StopScanning(const std::string& service_id) = 0;
|
||||
|
||||
// Callback that is invoked when a new connection is accepted.
|
||||
class AcceptedConnectionCallback {
|
||||
public:
|
||||
virtual ~AcceptedConnectionCallback() {}
|
||||
|
||||
virtual void OnConnectionAccepted(std::unique_ptr<BleSocket> socket,
|
||||
absl::string_view service_id) = 0;
|
||||
struct AcceptedConnectionCallback {
|
||||
std::function<void(BleSocket& socket, const std::string& service_id)>
|
||||
accepted_cb = DefaultCallback<BleSocket&, const std::string&>();
|
||||
};
|
||||
|
||||
// Returns true once BLE socket connection requests to service_id can be
|
||||
// accepted.
|
||||
virtual bool StartAcceptingConnections(
|
||||
absl::string_view service_id,
|
||||
const AcceptedConnectionCallback& accepted_connection_callback) = 0;
|
||||
virtual void StopAcceptingConnections(const std::string& service_id) = 0;
|
||||
const std::string& service_id, AcceptedConnectionCallback callback) = 0;
|
||||
virtual bool StopAcceptingConnections(const std::string& service_id) = 0;
|
||||
|
||||
// BlePeripheral* is not owned by this call;
|
||||
// it must remain valid for the duration of a call.
|
||||
virtual std::unique_ptr<BleSocket> Connect(BlePeripheral* ble_peripheral,
|
||||
absl::string_view service_id) = 0;
|
||||
// Connects to a BLE peripheral.
|
||||
// On success, returns a new BleSocket.
|
||||
// On error, returns nullptr.
|
||||
virtual std::unique_ptr<BleSocket> Connect(BlePeripheral& peripheral,
|
||||
const std::string& service_id) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -63,6 +63,9 @@ class BluetoothAdapter {
|
||||
virtual std::string GetName() const = 0;
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
|
||||
virtual bool SetName(absl::string_view name) = 0;
|
||||
|
||||
// Returns BT MAC address assigned to this adapter.
|
||||
virtual std::string GetMacAddress() const = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -35,6 +35,9 @@ class BluetoothDevice {
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getName()
|
||||
virtual std::string GetName() const = 0;
|
||||
|
||||
// Returns BT MAC address assigned to this device.
|
||||
virtual std::string GetMacAddress() const = 0;
|
||||
};
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html.
|
||||
@@ -146,6 +149,8 @@ class BluetoothClassicMedium {
|
||||
// Returns nullptr error.
|
||||
virtual std::unique_ptr<BluetoothServerSocket> ListenForService(
|
||||
const std::string& service_name, const std::string& service_uuid) = 0;
|
||||
|
||||
virtual BluetoothDevice* FindRemoteDevice(const std::string& mac_address) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -34,6 +34,10 @@ class WifiLanService {
|
||||
virtual ~WifiLanService() = default;
|
||||
|
||||
virtual std::string GetName() const = 0;
|
||||
|
||||
// Returns the local device's <IP address, port> as a pair.
|
||||
// IP address is in byte sequence, in network order.
|
||||
virtual std::pair<std::string, int> GetServiceAddress() const = 0;
|
||||
};
|
||||
|
||||
class WifiLanSocket {
|
||||
@@ -102,8 +106,7 @@ class WifiLanMedium {
|
||||
// Returns true once WifiLan socket connection requests to service_id can be
|
||||
// accepted.
|
||||
virtual bool StartAcceptingConnections(
|
||||
const std::string& service_id,
|
||||
AcceptedConnectionCallback callback) = 0;
|
||||
const std::string& service_id, AcceptedConnectionCallback callback) = 0;
|
||||
virtual bool StopAcceptingConnections(const std::string& service_id) = 0;
|
||||
|
||||
// Connects to a WifiLan service.
|
||||
@@ -111,6 +114,9 @@ class WifiLanMedium {
|
||||
// On error, returns nullptr.
|
||||
virtual std::unique_ptr<WifiLanSocket> Connect(
|
||||
WifiLanService& service, const std::string& service_id) = 0;
|
||||
|
||||
virtual WifiLanService* FindRemoteService(const std::string& ip_address,
|
||||
int port) = 0;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -18,10 +18,12 @@ cc_library(
|
||||
name = "base",
|
||||
srcs = [
|
||||
"base64_utils.cc",
|
||||
"bluetooth_utils.cc",
|
||||
"prng.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"base64_utils.h",
|
||||
"bluetooth_utils.h",
|
||||
"byte_array.h",
|
||||
"callable.h",
|
||||
"exception.h",
|
||||
@@ -42,6 +44,7 @@ cc_library(
|
||||
deps = [
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/strings",
|
||||
"//absl/strings:str_format",
|
||||
"//absl/time",
|
||||
],
|
||||
)
|
||||
@@ -110,6 +113,7 @@ cc_library(
|
||||
cc_test(
|
||||
name = "platform_base_test",
|
||||
srcs = [
|
||||
"bluetooth_utils_test.cc",
|
||||
"byte_array_test.cc",
|
||||
"prng_test.cc",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "platform_v2/base/bluetooth_utils.h"
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
std::string BluetoothUtils::ToString(const ByteArray& bluetooth_mac_address) {
|
||||
std::string colon_delimited_string;
|
||||
|
||||
if (bluetooth_mac_address.size() != kBluetoothMacAddressLength)
|
||||
return colon_delimited_string;
|
||||
|
||||
if (IsBluetoothMacAddressUnset(bluetooth_mac_address))
|
||||
return colon_delimited_string;
|
||||
|
||||
for (auto byte : std::string(bluetooth_mac_address)) {
|
||||
if (!colon_delimited_string.empty())
|
||||
absl::StrAppend(&colon_delimited_string, ":");
|
||||
absl::StrAppend(&colon_delimited_string, absl::StrFormat("%02X", byte));
|
||||
}
|
||||
return colon_delimited_string;
|
||||
}
|
||||
|
||||
ByteArray BluetoothUtils::FromString(absl::string_view bluetooth_mac_address) {
|
||||
std::string bt_mac_address(bluetooth_mac_address);
|
||||
|
||||
// Remove the colon delimiters.
|
||||
bt_mac_address.erase(
|
||||
std::remove(bt_mac_address.begin(), bt_mac_address.end(), ':'),
|
||||
bt_mac_address.end());
|
||||
|
||||
// If the bluetooth mac address is invalid (wrong size), return a null byte
|
||||
// array.
|
||||
if (bt_mac_address.length() != kBluetoothMacAddressLength * 2) {
|
||||
return ByteArray();
|
||||
}
|
||||
|
||||
// Convert to bytes. If MAC Address bytes are unset, return a null byte array.
|
||||
auto bt_mac_address_string(absl::HexStringToBytes(bt_mac_address));
|
||||
auto bt_mac_address_bytes =
|
||||
ByteArray(bt_mac_address_string.data(), bt_mac_address_string.size());
|
||||
if (IsBluetoothMacAddressUnset(bt_mac_address_bytes)) {
|
||||
return ByteArray();
|
||||
}
|
||||
return bt_mac_address_bytes;
|
||||
}
|
||||
|
||||
bool BluetoothUtils::IsBluetoothMacAddressUnset(
|
||||
const ByteArray& bluetooth_mac_address_bytes) {
|
||||
for (int i = 0; i < bluetooth_mac_address_bytes.size(); i++) {
|
||||
if (bluetooth_mac_address_bytes.data()[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef PLATFORM_V2_BASE_BLUETOOTH_UTILS_H_
|
||||
#define PLATFORM_V2_BASE_BLUETOOTH_UTILS_H_
|
||||
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class BluetoothUtils {
|
||||
public:
|
||||
static constexpr int kBluetoothMacAddressLength = 6;
|
||||
|
||||
// Converts a Bluetooth MAC address from byte array to String format. Returns
|
||||
// empty if input byte array is not of correct format.
|
||||
// e.g. {-84, 55, 67, -68, -87, 40} -> "AC:37:43:BC:A9:28".
|
||||
static std::string ToString(const ByteArray& bluetooth_mac_address);
|
||||
|
||||
// Converts a Bluetooth MAC address from String format to byte array. Returns
|
||||
// empty if input string is not of correct format.
|
||||
// e.g. "AC:37:43:BC:A9:28" -> {-84, 55, 67, -68, -87, 40}.
|
||||
static ByteArray FromString(absl::string_view bluetooth_mac_address);
|
||||
|
||||
// Checks if a Bluetooth MAC address is zero for every byte.
|
||||
static bool IsBluetoothMacAddressUnset(
|
||||
const ByteArray& bluetooth_mac_address);
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_BASE_BLUETOOTH_UTILS_H_
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "platform_v2/base/bluetooth_utils.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
constexpr absl::string_view kBluetoothMacAddress{"00:00:E6:88:64:13"};
|
||||
constexpr char kBluetoothMacAddressBytes[] = {0x00, 0x00, 0xe6,
|
||||
0x88, 0x64, 0x13};
|
||||
|
||||
TEST(BluetoothUtilsTest, ToStringWorks) {
|
||||
ByteArray bt_mac_address_bytes{
|
||||
kBluetoothMacAddressBytes, sizeof(kBluetoothMacAddressBytes)};
|
||||
|
||||
auto bt_mac_address = BluetoothUtils::ToString(bt_mac_address_bytes);
|
||||
|
||||
EXPECT_EQ(kBluetoothMacAddress, bt_mac_address);
|
||||
}
|
||||
|
||||
TEST(BluetoothUtilsTest, FromStringWorks) {
|
||||
ByteArray bt_mac_address_bytes{
|
||||
kBluetoothMacAddressBytes, sizeof(kBluetoothMacAddressBytes)};
|
||||
|
||||
auto bt_mac_address_bytes_result =
|
||||
BluetoothUtils::FromString(kBluetoothMacAddress);
|
||||
|
||||
EXPECT_EQ(bt_mac_address_bytes, bt_mac_address_bytes_result);
|
||||
}
|
||||
|
||||
TEST(BluetoothUtilsTest, InvalidBytesReturnsEmptyString) {
|
||||
std::string string_result;
|
||||
|
||||
char bad_bt_mac_address_1[] = {0x02, 0x20, 0x00};
|
||||
ByteArray bad_bt_mac_address_bytes_1{bad_bt_mac_address_1,
|
||||
sizeof(bad_bt_mac_address_1)};
|
||||
string_result = BluetoothUtils::ToString(bad_bt_mac_address_bytes_1);
|
||||
EXPECT_TRUE(string_result.empty());
|
||||
|
||||
char bad_bt_mac_address_2[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
ByteArray bad_bt_mac_address_bytes_2{bad_bt_mac_address_2,
|
||||
sizeof(bad_bt_mac_address_2)};
|
||||
string_result = BluetoothUtils::ToString(bad_bt_mac_address_bytes_2);
|
||||
EXPECT_TRUE(string_result.empty());
|
||||
|
||||
char bad_bt_mac_address_3[] = {0x11, 0x22, 0x33, 0x44, 0x55,
|
||||
0x66, 0x77, 0x88, 0x99};
|
||||
ByteArray bad_bt_mac_address_bytes_3{bad_bt_mac_address_3,
|
||||
sizeof(bad_bt_mac_address_3)};
|
||||
string_result = BluetoothUtils::ToString(bad_bt_mac_address_bytes_3);
|
||||
EXPECT_TRUE(string_result.empty());
|
||||
}
|
||||
|
||||
TEST(BluetoothUtilsTest, InvalidStringReturnsEmptyByteArray) {
|
||||
ByteArray bytes_result;
|
||||
|
||||
std::string bad_bt_mac_address_1 = "022:00";
|
||||
bytes_result = BluetoothUtils::FromString(bad_bt_mac_address_1);
|
||||
EXPECT_TRUE(bytes_result.Empty());
|
||||
|
||||
std::string bad_bt_mac_address_2 = "22:00:11:33:77:aa::bb::99";
|
||||
bytes_result = BluetoothUtils::FromString(bad_bt_mac_address_2);
|
||||
EXPECT_TRUE(bytes_result.Empty());
|
||||
|
||||
std::string bad_bt_mac_address_3 = "00:00:00:00:00:00";
|
||||
bytes_result = BluetoothUtils::FromString(bad_bt_mac_address_3);
|
||||
EXPECT_TRUE(bytes_result.Empty());
|
||||
|
||||
std::string bad_bt_mac_address_4 = "BLUETOOTHCHIP";
|
||||
bytes_result = BluetoothUtils::FromString(bad_bt_mac_address_4);
|
||||
EXPECT_TRUE(bytes_result.Empty());
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -88,7 +88,7 @@ class ByteArray {
|
||||
|
||||
// Moves string out of temporary ByteArray, allowing for a zero-copy
|
||||
// operation.
|
||||
explicit operator std::string() const&& { return std::move(data_); }
|
||||
explicit operator std::string() && { return std::move(data_); }
|
||||
|
||||
private:
|
||||
std::string data_;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
#include "platform_v2/api/ble.h"
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
@@ -56,6 +57,7 @@ void MediumEnvironment::Reset() {
|
||||
NEARBY_LOG(INFO, "MediumEnvironment::Reset()");
|
||||
bluetooth_adapters_.clear();
|
||||
bluetooth_mediums_.clear();
|
||||
ble_mediums_.clear();
|
||||
wifi_lan_mediums_.clear();
|
||||
});
|
||||
Sync();
|
||||
@@ -168,6 +170,48 @@ void MediumEnvironment::OnBluetoothDeviceStateChanged(
|
||||
}
|
||||
}
|
||||
|
||||
api::BluetoothDevice* MediumEnvironment::FindBluetoothDevice(
|
||||
const std::string& mac_address) {
|
||||
api::BluetoothDevice* device = nullptr;
|
||||
CountDownLatch latch(1);
|
||||
RunOnMediumEnvironmentThread([this, &device, &latch, &mac_address](){
|
||||
for (auto& item : bluetooth_mediums_) {
|
||||
auto* adapter = item.second.adapter;
|
||||
if (!adapter) continue;
|
||||
if (adapter->GetMacAddress() == mac_address) {
|
||||
device = bluetooth_adapters_[adapter];
|
||||
break;
|
||||
}
|
||||
}
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
return device;
|
||||
}
|
||||
|
||||
void MediumEnvironment::OnBlePeripheralStateChanged(
|
||||
BleMediumContext& info, api::BlePeripheral& peripheral,
|
||||
const std::string& service_id, bool enabled) {
|
||||
if (!enabled_) return;
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 OnBleServiceStateChanged [peripheral impl=%p]; context=%p; "
|
||||
"service_id=%s; notify=%d",
|
||||
&peripheral, &info, service_id.c_str(),
|
||||
enable_notifications_.load());
|
||||
if (!enable_notifications_) return;
|
||||
RunOnMediumEnvironmentThread([&info, enabled, &peripheral, service_id]() {
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 [Run] OnBlePeripheralStateChanged [peripheral impl=%p]; "
|
||||
"context=%p; service_id=%s; enabled=%d",
|
||||
&peripheral, &info, service_id.c_str(), enabled);
|
||||
if (enabled) {
|
||||
info.discovery_callback.peripheral_discovered_cb(peripheral, service_id);
|
||||
} else {
|
||||
info.discovery_callback.peripheral_lost_cb(peripheral, service_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::OnWifiLanServiceStateChanged(
|
||||
WifiLanMediumContext& info, api::WifiLanService& service,
|
||||
const std::string& service_id, bool enabled) {
|
||||
@@ -178,6 +222,10 @@ void MediumEnvironment::OnWifiLanServiceStateChanged(
|
||||
&service, &info, service_id.c_str(), enable_notifications_.load());
|
||||
if (!enable_notifications_) return;
|
||||
RunOnMediumEnvironmentThread([&info, enabled, &service, service_id]() {
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 [Run] OnWifiLanServiceStateChanged [service impl=%p]; "
|
||||
"context=%p; service_id=%s; enabled=%d",
|
||||
&service, &info, service_id.c_str(), enabled);
|
||||
auto service_id_context = info.services.find(service_id);
|
||||
if (service_id_context == info.services.end()) return;
|
||||
|
||||
@@ -260,6 +308,125 @@ void MediumEnvironment::UnregisterBluetoothMedium(
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::RegisterBleMedium(api::BleMedium& medium) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium]() {
|
||||
ble_mediums_.insert({&medium, BleMediumContext{}});
|
||||
NEARBY_LOG(INFO, "Registered: medium=%p", &medium);
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::UpdateBleMediumForAdvertising(
|
||||
api::BleMedium& medium, api::BlePeripheral& peripheral,
|
||||
const std::string& service_id, bool enabled) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium, &peripheral, service_id,
|
||||
enabled]() {
|
||||
auto item = ble_mediums_.find(&medium);
|
||||
if (item == ble_mediums_.end()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"UpdateBleMediumForAdvertising failed. There is no medium "
|
||||
"registered.");
|
||||
return;
|
||||
}
|
||||
auto& context = item->second;
|
||||
context.ble_peripheral = &peripheral;
|
||||
context.advertising = enabled;
|
||||
NEARBY_LOG(INFO,
|
||||
"Update Ble medium for advertising: this=%p; medium=%p; "
|
||||
"service_id=%s; name=%s; enabled=%d; ",
|
||||
this, &medium, service_id.c_str(), peripheral.GetName().c_str(),
|
||||
enabled);
|
||||
for (auto& medium_info : ble_mediums_) {
|
||||
auto& local_medium = medium_info.first;
|
||||
auto& info = medium_info.second;
|
||||
// Do not send notification to the same medium.
|
||||
if (local_medium == &medium) continue;
|
||||
OnBlePeripheralStateChanged(info, peripheral, service_id, enabled);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::UpdateBleMediumForScanning(
|
||||
api::BleMedium& medium, const std::string& service_id,
|
||||
BleDiscoveredPeripheralCallback callback, bool enabled) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium, service_id,
|
||||
callback = std::move(callback), enabled]() {
|
||||
auto item = ble_mediums_.find(&medium);
|
||||
if (item == ble_mediums_.end()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"UpdateBleMediumFoScanning failed. There is no medium "
|
||||
"registered.");
|
||||
return;
|
||||
}
|
||||
auto& context = item->second;
|
||||
context.discovery_callback = std::move(callback);
|
||||
NEARBY_LOG(INFO,
|
||||
"Update Ble medium for scanning: this=%p; medium=%p; "
|
||||
"service_id=%s; enabled=%d ;",
|
||||
this, &medium, service_id.c_str(), enabled);
|
||||
for (auto& medium_info : ble_mediums_) {
|
||||
auto& local_medium = medium_info.first;
|
||||
auto& info = medium_info.second;
|
||||
// Do not send notification to the same medium.
|
||||
if (local_medium == &medium) continue;
|
||||
// Search advertising mediums and send notification.
|
||||
if (info.advertising && enabled) {
|
||||
OnBlePeripheralStateChanged(context, *(info.ble_peripheral), service_id,
|
||||
enabled);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::UpdateBleMediumForAcceptedConnection(
|
||||
api::BleMedium& medium, const std::string& service_id,
|
||||
BleAcceptedConnectionCallback callback) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium, service_id,
|
||||
callback = std::move(callback)]() {
|
||||
auto item = ble_mediums_.find(&medium);
|
||||
if (item == ble_mediums_.end()) {
|
||||
NEARBY_LOG(
|
||||
INFO, "Update Ble medium failed. There is no medium registered.");
|
||||
return;
|
||||
}
|
||||
auto& context = item->second;
|
||||
context.accepted_connection_callback = std::move(callback);
|
||||
NEARBY_LOG(INFO,
|
||||
"Update Ble medium for accepted callback: this=%p; "
|
||||
"medium=%p; service_id=%s; ",
|
||||
this, &medium, service_id.c_str());
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::UnregisterBleMedium(api::BleMedium& medium) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium]() {
|
||||
auto item = ble_mediums_.extract(&medium);
|
||||
if (item.empty()) return;
|
||||
NEARBY_LOG(INFO, "Unregistered Ble medium");
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::CallBleAcceptedConnectionCallback(
|
||||
api::BleMedium& medium, api::BleSocket& socket,
|
||||
const std::string& service_id) {
|
||||
if (!enabled_) return;
|
||||
RunOnMediumEnvironmentThread([this, &medium, &socket, service_id]() {
|
||||
auto item = ble_mediums_.find(&medium);
|
||||
if (item == ble_mediums_.end()) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Call AcceptedConnectionCallback failed.. There is no medium "
|
||||
"registered.");
|
||||
return;
|
||||
}
|
||||
auto& info = item->second;
|
||||
info.accepted_connection_callback.accepted_cb(socket, service_id);
|
||||
});
|
||||
}
|
||||
|
||||
void MediumEnvironment::RegisterWebRtcSignalingMessenger(
|
||||
absl::string_view self_id, OnSignalingMessageCallback callback) {
|
||||
if (!enabled_) return;
|
||||
@@ -451,5 +618,26 @@ void MediumEnvironment::CallWifiLanAcceptedConnectionCallback(
|
||||
});
|
||||
}
|
||||
|
||||
api::WifiLanService* MediumEnvironment::FindWifiLanService(
|
||||
const std::string& ip_address, int port) {
|
||||
api::WifiLanService* remote_service = nullptr;
|
||||
CountDownLatch latch(1);
|
||||
RunOnMediumEnvironmentThread(
|
||||
[this, &remote_service, &ip_address, port, &latch]() {
|
||||
for (auto& item : wifi_lan_mediums_) {
|
||||
auto* service = item.second.wifi_lan_service;
|
||||
if (!service) continue;
|
||||
auto addr = remote_service->GetServiceAddress();
|
||||
if (addr.first == ip_address && addr.second == port) {
|
||||
remote_service = service;
|
||||
break;
|
||||
}
|
||||
}
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
return remote_service;
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -47,6 +47,10 @@ class MediumEnvironment {
|
||||
public:
|
||||
using BluetoothDiscoveryCallback =
|
||||
api::BluetoothClassicMedium::DiscoveryCallback;
|
||||
using BleDiscoveredPeripheralCallback =
|
||||
api::BleMedium::DiscoveredPeripheralCallback;
|
||||
using BleAcceptedConnectionCallback =
|
||||
api::BleMedium::AcceptedConnectionCallback;
|
||||
using OnSignalingMessageCallback =
|
||||
api::WebRtcSignalingMessenger::OnSignalingMessageCallback;
|
||||
using WifiLanDiscoveredServiceCallback =
|
||||
@@ -117,6 +121,9 @@ class MediumEnvironment {
|
||||
// Removes medium-related info. This should correspond to device power off.
|
||||
void UnregisterBluetoothMedium(api::BluetoothClassicMedium& medium);
|
||||
|
||||
// Returns a Bluetooth Device object matching given mac address to nullptr.
|
||||
api::BluetoothDevice* FindBluetoothDevice(const std::string& mac_address);
|
||||
|
||||
const EnvironmentConfig& GetEnvironmentConfig();
|
||||
|
||||
// Registers |callback| to receive messages sent to device with id |self_id|.
|
||||
@@ -130,6 +137,48 @@ class MediumEnvironment {
|
||||
// |peer_id|.
|
||||
void SendWebRtcSignalingMessage(absl::string_view peer_id,
|
||||
const ByteArray& message);
|
||||
|
||||
// Adds medium-related info to allow for scanning/advertising to work.
|
||||
// This provides acccess to this medium from other mediums, when protocol
|
||||
// expects they should communicate.
|
||||
void RegisterBleMedium(api::BleMedium& medium);
|
||||
|
||||
// Updates advertising info to indicate the current medium is exposing
|
||||
// advertising event.
|
||||
void UpdateBleMediumForAdvertising(api::BleMedium& medium,
|
||||
api::BlePeripheral& peripheral,
|
||||
const std::string& service_id,
|
||||
bool enabled);
|
||||
|
||||
// Updates discovery callback info to allow for dispatch of discovery events.
|
||||
//
|
||||
// Invokes callback asynchronously when any changes happen to discoverable
|
||||
// devices, or if the defice is turned off, whether or not it is discoverable,
|
||||
// if it was ever reported as discoverable.
|
||||
//
|
||||
// This should be called when discoverable state changes.
|
||||
// with user-specified callback when discovery is enabled, and with default
|
||||
// (empty) callback otherwise.
|
||||
void UpdateBleMediumForScanning(api::BleMedium& medium,
|
||||
const std::string& service_id,
|
||||
BleDiscoveredPeripheralCallback callback,
|
||||
bool enabled);
|
||||
|
||||
// Updates Accepted connection callback info to allow for dispatch of
|
||||
// advertising events.
|
||||
void UpdateBleMediumForAcceptedConnection(
|
||||
api::BleMedium& medium, const std::string& service_id,
|
||||
BleAcceptedConnectionCallback callback);
|
||||
|
||||
// Removes medium-related info. This should correspond to device power off.
|
||||
void UnregisterBleMedium(api::BleMedium& medium);
|
||||
|
||||
// Call back when advertising has created the server socket and is ready for
|
||||
// connect.
|
||||
void CallBleAcceptedConnectionCallback(api::BleMedium& medium,
|
||||
api::BleSocket& socket,
|
||||
const std::string& service_id);
|
||||
|
||||
// Adds medium-related info to allow for discovery/advertising to work.
|
||||
// This provides acccess to this medium from other mediums, when protocol
|
||||
// expects they should communicate.
|
||||
@@ -137,9 +186,10 @@ class MediumEnvironment {
|
||||
|
||||
// Updates advertising info to indicate the current medium is exposing
|
||||
// advertising event.
|
||||
void UpdateWifiLanMediumForAdvertising(
|
||||
api::WifiLanMedium& medium, api::WifiLanService& service,
|
||||
const std::string& service_id, bool enabled);
|
||||
void UpdateWifiLanMediumForAdvertising(api::WifiLanMedium& medium,
|
||||
api::WifiLanService& service,
|
||||
const std::string& service_id,
|
||||
bool enabled);
|
||||
|
||||
// Updates discovery callback info to allow for dispatch of discovery events.
|
||||
//
|
||||
@@ -169,6 +219,10 @@ class MediumEnvironment {
|
||||
api::WifiLanSocket& socket,
|
||||
const std::string& service_id);
|
||||
|
||||
// Returns WiFi LAN service matching IP address and port, or nullptr.
|
||||
api::WifiLanService* FindWifiLanService(const std::string& ip_address,
|
||||
int port);
|
||||
|
||||
private:
|
||||
struct BluetoothMediumContext {
|
||||
BluetoothDiscoveryCallback callback;
|
||||
@@ -177,6 +231,13 @@ class MediumEnvironment {
|
||||
absl::flat_hash_map<api::BluetoothDevice*, std::string> devices;
|
||||
};
|
||||
|
||||
struct BleMediumContext {
|
||||
BleDiscoveredPeripheralCallback discovery_callback;
|
||||
BleAcceptedConnectionCallback accepted_connection_callback;
|
||||
api::BlePeripheral* ble_peripheral = nullptr;
|
||||
bool advertising = false;
|
||||
};
|
||||
|
||||
struct WifiLanServiceIdContext {
|
||||
WifiLanDiscoveredServiceCallback discovery_callback;
|
||||
WifiLanAcceptedConnectionCallback accepted_connection_callback;
|
||||
@@ -201,6 +262,10 @@ class MediumEnvironment {
|
||||
api::BluetoothAdapter::ScanMode mode,
|
||||
bool enabled);
|
||||
|
||||
void OnBlePeripheralStateChanged(BleMediumContext& info,
|
||||
api::BlePeripheral& peripheral,
|
||||
const std::string& service_id, bool enabled);
|
||||
|
||||
void OnWifiLanServiceStateChanged(WifiLanMediumContext& info,
|
||||
api::WifiLanService& service,
|
||||
const std::string& service_id,
|
||||
@@ -221,6 +286,8 @@ class MediumEnvironment {
|
||||
absl::flat_hash_map<api::BluetoothClassicMedium*, BluetoothMediumContext>
|
||||
bluetooth_mediums_;
|
||||
|
||||
absl::flat_hash_map<api::BleMedium*, BleMediumContext> ble_mediums_;
|
||||
|
||||
// Maps peer id to callback for receiving signaling messages.
|
||||
absl::flat_hash_map<std::string, OnSignalingMessageCallback>
|
||||
webrtc_signaling_callback_;
|
||||
|
||||
@@ -53,12 +53,14 @@ 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",
|
||||
@@ -90,9 +92,7 @@ cc_library(
|
||||
srcs = [
|
||||
"crypto.cc",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/g3:__pkg__",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//platform_v2/api:types",
|
||||
"//platform_v2/base",
|
||||
@@ -108,7 +108,6 @@ cc_library(
|
||||
"platform.cc",
|
||||
],
|
||||
visibility = [
|
||||
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
|
||||
"//core_v2:__subpackages__",
|
||||
"//platform_v2:__subpackages__",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
#include "platform_v2/impl/g3/ble.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/api/ble.h"
|
||||
#include "platform_v2/base/logging.h"
|
||||
#include "platform_v2/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) {
|
||||
NEARBY_LOGS(INFO) << "G3 Ble StartAdvertising: service_id=" << service_id
|
||||
<< ", advertisement bytes=" << advertisement_bytes.data()
|
||||
<< "(" << advertisement_bytes.size() << ")";
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
auto& peripheral = adapter_->GetPeripheral();
|
||||
peripheral.SetAdvertisementBytes(service_id, advertisement_bytes);
|
||||
env.UpdateBleMediumForAdvertising(*this, peripheral, service_id, 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, 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,
|
||||
DiscoveredPeripheralCallback callback) {
|
||||
NEARBY_LOGS(INFO) << "G3 Ble StartScanning: service_id=" << service_id;
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.UpdateBleMediumForScanning(*this, service_id, 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
|
||||
@@ -0,0 +1,213 @@
|
||||
#ifndef PLATFORM_V2_IMPL_G3_BLE_H_
|
||||
#define PLATFORM_V2_IMPL_G3_BLE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/api/ble.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "platform_v2/impl/g3/bluetooth_adapter.h"
|
||||
#include "platform_v2/impl/g3/bluetooth_classic.h"
|
||||
#include "platform_v2/impl/g3/multi_thread_executor.h"
|
||||
#include "platform_v2/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) 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,
|
||||
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_V2_IMPL_G3_BLE_H_
|
||||
@@ -17,21 +17,57 @@
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "platform_v2/base/prng.h"
|
||||
#include "platform_v2/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::SetMedium(api::BluetoothClassicMedium* medium) {
|
||||
medium_ = medium;
|
||||
void BluetoothAdapter::SetBluetoothClassicMedium(
|
||||
api::BluetoothClassicMedium* medium) {
|
||||
bluetooth_classic_medium_ = medium;
|
||||
}
|
||||
|
||||
void BluetoothAdapter::SetBleMedium(api::BleMedium* medium) {
|
||||
ble_medium_ = medium;
|
||||
}
|
||||
|
||||
bool BluetoothAdapter::SetStatus(Status status) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform_v2/api/ble.h"
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
#include "platform_v2/impl/g3/single_thread_executor.h"
|
||||
@@ -31,6 +32,28 @@ 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:
|
||||
@@ -38,6 +61,7 @@ class BluetoothDevice : public api::BluetoothDevice {
|
||||
|
||||
// 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:
|
||||
@@ -55,7 +79,7 @@ class BluetoothAdapter : public api::BluetoothAdapter {
|
||||
using Status = api::BluetoothAdapter::Status;
|
||||
using ScanMode = api::BluetoothAdapter::ScanMode;
|
||||
|
||||
explicit BluetoothAdapter() = default;
|
||||
BluetoothAdapter();
|
||||
~BluetoothAdapter() override;
|
||||
|
||||
// Synchronously sets the status of the BluetoothAdapter to 'status', and
|
||||
@@ -82,15 +106,30 @@ class BluetoothAdapter : public api::BluetoothAdapter {
|
||||
// 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 SetMedium(api::BluetoothClassicMedium* medium);
|
||||
api::BluetoothClassicMedium* GetMedium() { return medium_; }
|
||||
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};
|
||||
api::BluetoothClassicMedium* medium_ = nullptr;
|
||||
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;
|
||||
|
||||
@@ -48,9 +48,7 @@ bool BluetoothSocket::IsClosed() const {
|
||||
return closed_;
|
||||
}
|
||||
|
||||
bool BluetoothSocket::IsConnectedLocked() const {
|
||||
return input_ != nullptr;
|
||||
}
|
||||
bool BluetoothSocket::IsConnectedLocked() const { return input_ != nullptr; }
|
||||
|
||||
InputStream& BluetoothSocket::GetInputStream() {
|
||||
auto* remote_socket = GetRemoteSocket();
|
||||
@@ -177,13 +175,13 @@ Exception BluetoothServerSocket::DoClose() {
|
||||
BluetoothClassicMedium::BluetoothClassicMedium(api::BluetoothAdapter& adapter)
|
||||
// TODO(apolyudov): implement and use downcast<> with static assertions.
|
||||
: adapter_(static_cast<BluetoothAdapter*>(&adapter)) {
|
||||
adapter_->SetMedium(this);
|
||||
adapter_->SetBluetoothClassicMedium(this);
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.RegisterBluetoothMedium(*this, GetAdapter());
|
||||
}
|
||||
|
||||
BluetoothClassicMedium::~BluetoothClassicMedium() {
|
||||
adapter_->SetMedium(nullptr);
|
||||
adapter_->SetBluetoothClassicMedium(nullptr);
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
env.UnregisterBluetoothMedium(*this);
|
||||
}
|
||||
@@ -207,7 +205,8 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
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.GetMedium());
|
||||
auto* medium =
|
||||
static_cast<BluetoothClassicMedium*>(adapter.GetBluetoothClassicMedium());
|
||||
|
||||
if (!medium) return {}; // Adapter is not bound to medium. Bail out.
|
||||
|
||||
@@ -255,6 +254,12 @@ BluetoothClassicMedium::ListenForService(const std::string& service_name,
|
||||
return socket;
|
||||
}
|
||||
|
||||
api::BluetoothDevice* BluetoothClassicMedium::FindRemoteDevice(
|
||||
const std::string& mac_address) {
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
return env.FindBluetoothDevice(mac_address);
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -96,7 +96,7 @@ class BluetoothSocket : public api::BluetoothSocket {
|
||||
// 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> output_{new Pipe};
|
||||
std::shared_ptr<Pipe> input_;
|
||||
mutable absl::Mutex mutex_;
|
||||
BluetoothAdapter* adapter_ = nullptr; // Our Adapter. Read only.
|
||||
@@ -221,6 +221,9 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
|
||||
const std::string& service_name, const std::string& service_uuid) override
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
api::BluetoothDevice* FindRemoteDevice(
|
||||
const std::string& mac_address) override;
|
||||
|
||||
private:
|
||||
absl::Mutex mutex_;
|
||||
BluetoothAdapter* adapter_; // Our device adapter; read-only.
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "platform_v2/api/atomic_boolean.h"
|
||||
#include "platform_v2/api/atomic_reference.h"
|
||||
#include "platform_v2/api/ble.h"
|
||||
#include "platform_v2/api/ble_v2.h"
|
||||
#include "platform_v2/api/bluetooth_adapter.h"
|
||||
#include "platform_v2/api/bluetooth_classic.h"
|
||||
@@ -35,6 +34,7 @@
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "platform_v2/impl/g3/atomic_boolean.h"
|
||||
#include "platform_v2/impl/g3/atomic_reference.h"
|
||||
#include "platform_v2/impl/g3/ble.h"
|
||||
#include "platform_v2/impl/g3/bluetooth_adapter.h"
|
||||
#include "platform_v2/impl/g3/bluetooth_classic.h"
|
||||
#include "platform_v2/impl/g3/condition_variable.h"
|
||||
@@ -126,7 +126,7 @@ ImplementationPlatform::CreateBluetoothClassicMedium(
|
||||
|
||||
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(
|
||||
api::BluetoothAdapter& adapter) {
|
||||
return std::unique_ptr<BleMedium>();
|
||||
return absl::make_unique<g3::BleMedium>(adapter);
|
||||
}
|
||||
|
||||
std::unique_ptr<ble_v2::BleMedium> ImplementationPlatform::CreateBleV2Medium(
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
#include "platform_v2/base/logging.h"
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "platform_v2/base/prng.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace location {
|
||||
@@ -99,7 +100,8 @@ OutputStream& WifiLanSocket::GetLocalOutputStream() {
|
||||
return output_->GetOutputStream();
|
||||
}
|
||||
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::Accept() {
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::Accept(
|
||||
WifiLanService* service) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
if (closed_) return {};
|
||||
while (pending_sockets_.empty()) {
|
||||
@@ -110,7 +112,7 @@ std::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::Accept() {
|
||||
auto* remote_socket =
|
||||
pending_sockets_.extract(pending_sockets_.begin()).value();
|
||||
CHECK(remote_socket);
|
||||
auto local_socket = std::make_unique<WifiLanSocket>();
|
||||
auto local_socket = std::make_unique<WifiLanSocket>(service);
|
||||
local_socket->Connect(*remote_socket);
|
||||
remote_socket->Connect(*local_socket);
|
||||
cond_.SignalAll();
|
||||
@@ -169,6 +171,15 @@ Exception WifiLanServerSocket::DoClose() {
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -181,8 +192,7 @@ WifiLanMedium::~WifiLanMedium() {
|
||||
StopAdvertising(advertising_info_.service_id);
|
||||
StopDiscovery(discovering_info_.service_id);
|
||||
|
||||
NEARBY_LOG(INFO,
|
||||
"WifiLanMedium dtor advertising_accept_thread_running_ = %d",
|
||||
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_) {
|
||||
@@ -200,6 +210,7 @@ bool WifiLanMedium::StartAdvertising(const std::string& service_id,
|
||||
"G3 WifiLan StartAdvertising: service_id=%s, service_info_name=%s",
|
||||
service_id.c_str(), service_info_name.c_str());
|
||||
auto& env = MediumEnvironment::Instance();
|
||||
service_.SetName(service_info_name);
|
||||
env.UpdateWifiLanMediumForAdvertising(*this, service_, service_id, true);
|
||||
|
||||
absl::MutexLock lock(&mutex_);
|
||||
@@ -210,10 +221,10 @@ bool WifiLanMedium::StartAdvertising(const std::string& service_id,
|
||||
accept_loops_runner_.Execute([&env, this, service_id]() mutable {
|
||||
if (!accept_loops_runner_.InShutdown()) {
|
||||
while (true) {
|
||||
auto client_socket = server_socket_->Accept();
|
||||
auto client_socket = server_socket_->Accept(&service_);
|
||||
if (client_socket == nullptr) break;
|
||||
env.CallWifiLanAcceptedConnectionCallback(*this, *client_socket,
|
||||
service_id);
|
||||
env.CallWifiLanAcceptedConnectionCallback(
|
||||
*this, *(client_socket.release()), service_id);
|
||||
}
|
||||
}
|
||||
acceptance_thread_running_.exchange(false);
|
||||
@@ -241,8 +252,8 @@ bool WifiLanMedium::StopAdvertising(const std::string& service_id) {
|
||||
accept_loops_runner_.Shutdown();
|
||||
if (server_socket_ == nullptr) {
|
||||
NEARBY_LOGS(ERROR) << "G3 WifiLan StopAdvertising: failed to find WifiLan "
|
||||
"Server socket: service_id="
|
||||
<< service_id;
|
||||
"Server socket: service_id="
|
||||
<< service_id;
|
||||
// Fall through for server socket not found.
|
||||
return true;
|
||||
}
|
||||
@@ -310,8 +321,11 @@ bool WifiLanMedium::StopAcceptingConnections(const std::string& service_id) {
|
||||
|
||||
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_id=%s",
|
||||
this, &service_, service_id.c_str());
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 WifiLan Connect: medium=%p, service=%p, service_info_name=%s, "
|
||||
"service_id=%s",
|
||||
this, &service_, remote_service.GetName().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();
|
||||
|
||||
@@ -319,8 +333,10 @@ std::unique_ptr<api::WifiLanSocket> WifiLanMedium::Connect(
|
||||
|
||||
WifiLanServerSocket* remote_server_socket = nullptr;
|
||||
NEARBY_LOG(INFO,
|
||||
"G3 WifiLan Connect [peer]: medium=%p, service=%p, service_id=%s",
|
||||
medium, &remote_service, service_id.c_str());
|
||||
"G3 WifiLan Connect [peer]: medium=%p, service=%p, "
|
||||
"service_info_name=%s, service_id=%s",
|
||||
medium, &remote_service, remote_service.GetName().c_str(),
|
||||
service_id.c_str());
|
||||
// Then, find our server socket context in this medium.
|
||||
{
|
||||
absl::MutexLock medium_lock(&medium->mutex_);
|
||||
@@ -335,7 +351,8 @@ std::unique_ptr<api::WifiLanSocket> WifiLanMedium::Connect(
|
||||
}
|
||||
}
|
||||
|
||||
auto socket = std::make_unique<WifiLanSocket>();
|
||||
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,
|
||||
@@ -349,6 +366,12 @@ std::unique_ptr<api::WifiLanSocket> WifiLanMedium::Connect(
|
||||
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
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "platform_v2/api/wifi_lan.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
@@ -46,13 +47,23 @@ class WifiLanService : public api::WifiLanService {
|
||||
service_info_name_ = std::move(service_info_name);
|
||||
}
|
||||
std::string GetName() const override { return service_info_name_; }
|
||||
std::pair<std::string, int> GetServiceAddress() const override {
|
||||
return std::make_pair(ip_address_, port_);
|
||||
}
|
||||
|
||||
void SetMedium(WifiLanMedium* medium) { medium_ = medium; }
|
||||
WifiLanMedium* GetMedium() { return medium_; }
|
||||
|
||||
void SetServiceAddress(const std::string& ip_address, int port) {
|
||||
ip_address_ = ip_address;
|
||||
port_ = port;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string service_info_name_;
|
||||
WifiLanMedium* medium_ = nullptr;
|
||||
std::string ip_address_;
|
||||
int port_;
|
||||
};
|
||||
|
||||
class WifiLanSocket : public api::WifiLanSocket {
|
||||
@@ -108,7 +119,7 @@ class WifiLanSocket : public api::WifiLanSocket {
|
||||
// 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> output_{new Pipe};
|
||||
std::shared_ptr<Pipe> input_;
|
||||
mutable absl::Mutex mutex_;
|
||||
WifiLanService* service_;
|
||||
@@ -130,7 +141,8 @@ class WifiLanServerSocket {
|
||||
// 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() ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
std::unique_ptr<api::WifiLanSocket> Accept(WifiLanService* service)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Blocks until either:
|
||||
// - connection is available, or
|
||||
@@ -200,6 +212,9 @@ class WifiLanMedium : public api::WifiLanMedium {
|
||||
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;
|
||||
|
||||
|
||||
@@ -34,9 +34,7 @@ cc_library(
|
||||
hdrs = [
|
||||
"posix_condition_variable.h",
|
||||
],
|
||||
visibility = [
|
||||
"//platform_v2/impl:__subpackages__",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":posix_mutex",
|
||||
"//platform_v2/api:types",
|
||||
|
||||
@@ -59,10 +59,12 @@ cc_library(
|
||||
cc_library(
|
||||
name = "comm",
|
||||
srcs = [
|
||||
"ble.cc",
|
||||
"bluetooth_classic.cc",
|
||||
"wifi_lan.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"ble.h",
|
||||
"bluetooth_adapter.h",
|
||||
"bluetooth_classic.h",
|
||||
"webrtc.h",
|
||||
@@ -105,6 +107,7 @@ cc_test(
|
||||
srcs = [
|
||||
"atomic_boolean_test.cc",
|
||||
"atomic_reference_test.cc",
|
||||
"ble_test.cc",
|
||||
"bluetooth_adapter_test.cc",
|
||||
"bluetooth_classic_test.cc",
|
||||
"cancelable_alarm_test.cc",
|
||||
@@ -129,6 +132,7 @@ cc_test(
|
||||
"//platform_v2/base:test_util",
|
||||
"//platform_v2/impl/g3", # build_cleaner: keep
|
||||
"//testing/base/public:gunit_main",
|
||||
"//absl/strings",
|
||||
"//absl/synchronization",
|
||||
"//absl/time",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#include "platform_v2/public/ble.h"
|
||||
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "platform_v2/public/mutex_lock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
bool BleMedium::StartAdvertising(const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes) {
|
||||
return impl_->StartAdvertising(service_id, advertisement_bytes);
|
||||
}
|
||||
|
||||
bool BleMedium::StopAdvertising(const std::string& service_id) {
|
||||
return impl_->StopAdvertising(service_id);
|
||||
}
|
||||
|
||||
bool BleMedium::StartScanning(const std::string& service_id,
|
||||
DiscoveredPeripheralCallback callback) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
discovered_peripheral_callback_ = std::move(callback);
|
||||
peripherals_.clear();
|
||||
}
|
||||
return impl_->StartScanning(
|
||||
service_id,
|
||||
{
|
||||
.peripheral_discovered_cb =
|
||||
[this](api::BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
auto pair = peripherals_.emplace(
|
||||
&peripheral, absl::make_unique<ScanningInfo>());
|
||||
auto& context = *pair.first->second;
|
||||
if (!pair.second) {
|
||||
NEARBY_LOG(INFO,
|
||||
"Discovering (again) peripheral=%p, impl=%p, "
|
||||
"peripheral name=%s",
|
||||
&context.peripheral, &peripheral,
|
||||
peripheral.GetName().c_str());
|
||||
} else {
|
||||
context.peripheral = BlePeripheral(&peripheral);
|
||||
NEARBY_LOG(INFO,
|
||||
"Discovering peripheral=%p, impl=%p, "
|
||||
"peripheral name=%s",
|
||||
&context.peripheral, &peripheral,
|
||||
peripheral.GetName().c_str());
|
||||
discovered_peripheral_callback_.peripheral_discovered_cb(
|
||||
context.peripheral, service_id);
|
||||
}
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[this](api::BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
if (peripherals_.empty()) return;
|
||||
auto context = peripherals_.find(&peripheral);
|
||||
if (context == peripherals_.end()) return;
|
||||
NEARBY_LOG(INFO, "Removing peripheral=%p, impl=%p",
|
||||
&(context->second->peripheral), &peripheral);
|
||||
discovered_peripheral_callback_.peripheral_lost_cb(
|
||||
context->second->peripheral, service_id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
bool BleMedium::StopScanning(const std::string& service_id) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
discovered_peripheral_callback_ = {};
|
||||
peripherals_.clear();
|
||||
NEARBY_LOG(INFO, "Ble Scanning disabled: impl=%p", &GetImpl());
|
||||
}
|
||||
return impl_->StopScanning(service_id);
|
||||
}
|
||||
|
||||
bool BleMedium::StartAcceptingConnections(const std::string& service_id,
|
||||
AcceptedConnectionCallback callback) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
accepted_connection_callback_ = std::move(callback);
|
||||
}
|
||||
return impl_->StartAcceptingConnections(
|
||||
service_id,
|
||||
{
|
||||
.accepted_cb =
|
||||
[this](api::BleSocket& socket, const std::string& service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
auto pair = sockets_.emplace(
|
||||
&socket, absl::make_unique<AcceptedConnectionInfo>());
|
||||
auto& context = *pair.first->second;
|
||||
if (!pair.second) {
|
||||
NEARBY_LOG(INFO, "Accepting (again) socket=%p, impl=%p",
|
||||
&context.socket, &socket);
|
||||
} else {
|
||||
context.socket = BleSocket(&socket);
|
||||
NEARBY_LOG(INFO, "Accepting socket=%p, impl=%p",
|
||||
&context.socket, &socket);
|
||||
}
|
||||
accepted_connection_callback_.accepted_cb(context.socket,
|
||||
service_id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
bool BleMedium::StopAcceptingConnections(const std::string& service_id) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
accepted_connection_callback_ = {};
|
||||
sockets_.clear();
|
||||
NEARBY_LOG(INFO, "Ble accepted connection disabled: impl=%p", &GetImpl());
|
||||
}
|
||||
return impl_->StopAcceptingConnections(service_id);
|
||||
}
|
||||
|
||||
BleSocket BleMedium::Connect(BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
NEARBY_LOG(INFO, "BleMedium::Connect: peripheral=%p [impl=%p]", &peripheral,
|
||||
&peripheral.GetImpl());
|
||||
}
|
||||
return BleSocket(impl_->Connect(peripheral.GetImpl(), service_id));
|
||||
}
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,146 @@
|
||||
#ifndef PLATFORM_V2_PUBLIC_BLE_H_
|
||||
#define PLATFORM_V2_PUBLIC_BLE_H_
|
||||
|
||||
#include "platform_v2/api/ble.h"
|
||||
#include "platform_v2/api/platform.h"
|
||||
#include "platform_v2/base/byte_array.h"
|
||||
#include "platform_v2/base/input_stream.h"
|
||||
#include "platform_v2/base/output_stream.h"
|
||||
#include "platform_v2/public/bluetooth_adapter.h"
|
||||
#include "platform_v2/public/mutex.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
|
||||
class BleSocket final {
|
||||
public:
|
||||
BleSocket() = default;
|
||||
BleSocket(const BleSocket&) = default;
|
||||
BleSocket& operator=(const BleSocket&) = default;
|
||||
explicit BleSocket(api::BleSocket* socket) : impl_(socket) {}
|
||||
explicit BleSocket(std::unique_ptr<api::BleSocket> socket)
|
||||
: impl_(socket.release()) {}
|
||||
~BleSocket() = default;
|
||||
|
||||
// Returns the InputStream of the BleSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the BleSocket object is destroyed.
|
||||
InputStream& GetInputStream() { return impl_->GetInputStream(); }
|
||||
|
||||
// Returns the OutputStream of the BleSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the BleSocket object is destroyed.
|
||||
OutputStream& GetOutputStream() { return impl_->GetOutputStream(); }
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception Close() { return impl_->Close(); }
|
||||
|
||||
BlePeripheral GetRemotePeripheral() {
|
||||
return BlePeripheral(impl_->GetRemotePeripheral());
|
||||
}
|
||||
|
||||
// Returns true if a socket is usable. If this method returns false,
|
||||
// it is not safe to call any other method.
|
||||
// NOTE(socket validity):
|
||||
// Socket created by a default public constructor is not valid, because
|
||||
// it is missing platform implementation.
|
||||
// The only way to obtain a valid socket is through connection, such as
|
||||
// an object returned by BleMedium::Connect
|
||||
// These methods may also return an invalid socket if connection failed for
|
||||
// any reason.
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
// Returns reference to platform implementation.
|
||||
// This is used to communicate with platform code, and for debugging purposes.
|
||||
// Returned reference will remain valid for while BleSocket object is
|
||||
// itself valid. Typically BleSocket lifetime matches duration of the
|
||||
// connection, and is controlled by end user, since they hold the instance.
|
||||
api::BleSocket& GetImpl() { return *impl_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<api::BleSocket> impl_;
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the BLE medium.
|
||||
class BleMedium final {
|
||||
public:
|
||||
using Platform = api::ImplementationPlatform;
|
||||
struct DiscoveredPeripheralCallback {
|
||||
std::function<void(BlePeripheral& peripheral,
|
||||
const std::string& service_id)>
|
||||
peripheral_discovered_cb =
|
||||
DefaultCallback<BlePeripheral&, const std::string&>();
|
||||
std::function<void(BlePeripheral& peripheral,
|
||||
const std::string& service_id)>
|
||||
peripheral_lost_cb =
|
||||
DefaultCallback<BlePeripheral&, const std::string&>();
|
||||
};
|
||||
struct ScanningInfo {
|
||||
BlePeripheral peripheral;
|
||||
};
|
||||
|
||||
struct AcceptedConnectionCallback {
|
||||
std::function<void(BleSocket& socket, const std::string& service_id)>
|
||||
accepted_cb = DefaultCallback<BleSocket&, const std::string&>();
|
||||
};
|
||||
struct AcceptedConnectionInfo {
|
||||
BleSocket socket;
|
||||
};
|
||||
|
||||
explicit BleMedium(BluetoothAdapter& adapter)
|
||||
: impl_(Platform::CreateBleMedium(adapter.GetImpl())),
|
||||
adapter_(adapter) {}
|
||||
~BleMedium() = default;
|
||||
|
||||
// Returns true once the BLE advertising has been initiated.
|
||||
bool StartAdvertising(const std::string& service_id,
|
||||
const ByteArray& advertisement_bytes);
|
||||
bool StopAdvertising(const std::string& service_id);
|
||||
|
||||
// Returns true once the BLE scan has been initiated.
|
||||
bool StartScanning(const std::string& service_id,
|
||||
DiscoveredPeripheralCallback callback);
|
||||
|
||||
// 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);
|
||||
|
||||
// Returns true once BLE socket connection requests to service_id can be
|
||||
// accepted.
|
||||
bool StartAcceptingConnections(const std::string& service_id,
|
||||
AcceptedConnectionCallback callback);
|
||||
bool StopAcceptingConnections(const std::string& service_id);
|
||||
|
||||
// Returns a new BleSocket. On Success, BleSocket::IsValid()
|
||||
// returns true.
|
||||
BleSocket Connect(BlePeripheral& peripheral, const std::string& service_id);
|
||||
|
||||
bool IsValid() const { return impl_ != nullptr; }
|
||||
|
||||
api::BleMedium& GetImpl() { return *impl_; }
|
||||
BluetoothAdapter& GetAdapter() { return adapter_; }
|
||||
|
||||
private:
|
||||
Mutex mutex_;
|
||||
std::unique_ptr<api::BleMedium> impl_;
|
||||
BluetoothAdapter& adapter_;
|
||||
absl::flat_hash_map<api::BlePeripheral*, std::unique_ptr<ScanningInfo>>
|
||||
peripherals_ ABSL_GUARDED_BY(mutex_);
|
||||
absl::flat_hash_map<api::BleSocket*, std::unique_ptr<AcceptedConnectionInfo>>
|
||||
sockets_ ABSL_GUARDED_BY(mutex_);
|
||||
DiscoveredPeripheralCallback discovered_peripheral_callback_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
AcceptedConnectionCallback accepted_connection_callback_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_V2_PUBLIC_BLE_H_
|
||||
@@ -0,0 +1,189 @@
|
||||
#include "platform_v2/public/ble.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "platform_v2/base/medium_environment.h"
|
||||
#include "platform_v2/public/count_down_latch.h"
|
||||
#include "platform_v2/public/logging.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace {
|
||||
|
||||
constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000);
|
||||
constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"};
|
||||
constexpr absl::string_view kAdvertisementString{"\x0a\x0b\x0c\x0d"};
|
||||
|
||||
class BleMediumTest : public ::testing::Test {
|
||||
protected:
|
||||
using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback;
|
||||
using AcceptedConnectionCallback = BleMedium::AcceptedConnectionCallback;
|
||||
|
||||
BleMediumTest() { env_.Stop(); }
|
||||
|
||||
MediumEnvironment& env_{MediumEnvironment::Instance()};
|
||||
};
|
||||
|
||||
TEST_F(BleMediumTest, ConstructorDestructorWorks) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_a_;
|
||||
BluetoothAdapter adapter_b_;
|
||||
BleMedium ble_a{adapter_a_};
|
||||
BleMedium ble_b{adapter_b_};
|
||||
|
||||
// Make sure we can create functional mediums.
|
||||
ASSERT_TRUE(ble_a.IsValid());
|
||||
ASSERT_TRUE(ble_b.IsValid());
|
||||
|
||||
// Make sure we can create 2 distinct mediums.
|
||||
EXPECT_NE(&ble_a.GetImpl(), &ble_b.GetImpl());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleMediumTest, CanStartAdvertising) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_a_;
|
||||
BluetoothAdapter adapter_b_;
|
||||
BleMedium ble_a{adapter_a_};
|
||||
BleMedium ble_b{adapter_b_};
|
||||
std::string service_id(kServiceID);
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
CountDownLatch found_latch(1);
|
||||
|
||||
ble_a.StartAdvertising(service_id, advertisement_bytes);
|
||||
|
||||
EXPECT_TRUE(ble_b.StartScanning(
|
||||
service_id, DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch](BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
}));
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopAdvertising(service_id));
|
||||
EXPECT_TRUE(ble_b.StopScanning(service_id));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleMediumTest, CanStartScanning) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_a_;
|
||||
BluetoothAdapter adapter_b_;
|
||||
BleMedium ble_a{adapter_a_};
|
||||
BleMedium ble_b{adapter_b_};
|
||||
std::string service_id(kServiceID);
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
ble_a.StartScanning(service_id,
|
||||
DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch](BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[&lost_latch](BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
lost_latch.CountDown();
|
||||
},
|
||||
});
|
||||
EXPECT_TRUE(ble_b.StartAdvertising(service_id, advertisement_bytes));
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_b.StopAdvertising(service_id));
|
||||
EXPECT_TRUE(lost_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopScanning(service_id));
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleMediumTest, CanStopDiscovery) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_a_;
|
||||
BluetoothAdapter adapter_b_;
|
||||
BleMedium ble_a{adapter_a_};
|
||||
BleMedium ble_b{adapter_b_};
|
||||
std::string service_id(kServiceID);
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch lost_latch(1);
|
||||
|
||||
ble_a.StartScanning(service_id,
|
||||
DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch](BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
found_latch.CountDown();
|
||||
},
|
||||
.peripheral_lost_cb =
|
||||
[&lost_latch](BlePeripheral& peripheral,
|
||||
const std::string& service_id) {
|
||||
lost_latch.CountDown();
|
||||
},
|
||||
});
|
||||
EXPECT_TRUE(ble_b.StartAdvertising(service_id, advertisement_bytes));
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(ble_a.StopScanning(service_id));
|
||||
EXPECT_TRUE(ble_b.StopAdvertising(service_id));
|
||||
EXPECT_FALSE(lost_latch.Await(kWaitDuration).result());
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
TEST_F(BleMediumTest, CanStartAcceptingConnectionsAndConnect) {
|
||||
env_.Start();
|
||||
BluetoothAdapter adapter_a_;
|
||||
BluetoothAdapter adapter_b_;
|
||||
BleMedium ble_a{adapter_a_};
|
||||
BleMedium ble_b{adapter_b_};
|
||||
std::string service_id(kServiceID);
|
||||
ByteArray advertisement_bytes{std::string(kAdvertisementString)};
|
||||
CountDownLatch found_latch(1);
|
||||
CountDownLatch accepted_latch(1);
|
||||
|
||||
BlePeripheral* discovered_peripheral = nullptr;
|
||||
ble_a.StartScanning(
|
||||
service_id,
|
||||
DiscoveredPeripheralCallback{
|
||||
.peripheral_discovered_cb =
|
||||
[&found_latch, &discovered_peripheral](
|
||||
BlePeripheral& peripheral, const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Peripheral discovered: %s, %p",
|
||||
peripheral.GetName().c_str(), &peripheral);
|
||||
discovered_peripheral = &peripheral;
|
||||
found_latch.CountDown();
|
||||
},
|
||||
});
|
||||
ble_b.StartAdvertising(service_id, advertisement_bytes);
|
||||
ble_b.StartAcceptingConnections(
|
||||
service_id,
|
||||
AcceptedConnectionCallback{
|
||||
.accepted_cb = [&accepted_latch](BleSocket socket,
|
||||
const std::string& service_id) {
|
||||
NEARBY_LOG(INFO, "Connection accepted: socket=%p, service_id=%s",
|
||||
&socket, service_id.c_str());
|
||||
accepted_latch.CountDown();
|
||||
}});
|
||||
EXPECT_TRUE(found_latch.Await(kWaitDuration).result());
|
||||
|
||||
BleSocket socket_a;
|
||||
EXPECT_FALSE(socket_a.IsValid());
|
||||
{
|
||||
SingleThreadExecutor client_executor;
|
||||
client_executor.Execute(
|
||||
[&ble_a, &socket_a, discovered_peripheral, &service_id]() {
|
||||
socket_a = ble_a.Connect(*discovered_peripheral, service_id);
|
||||
});
|
||||
}
|
||||
EXPECT_TRUE(accepted_latch.Await(kWaitDuration).result());
|
||||
EXPECT_TRUE(socket_a.IsValid());
|
||||
ble_b.StopAdvertising(service_id);
|
||||
ble_a.StopScanning(service_id);
|
||||
env_.Stop();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user