Roll forward to cl/328359974

Change-Id: If2b57ecc852aecf7dea454648f485fd7c08e72a9
This commit is contained in:
Alexey Polyudov
2020-08-25 11:27:27 -07:00
parent 6f9228fa6b
commit c673bf6ac0
110 changed files with 4758 additions and 1245 deletions
+2 -3
View File
@@ -6,9 +6,7 @@ cc_library(
hdrs = [
"core.h",
],
visibility = [
"//core_v2:__subpackages__",
],
visibility = ["//visibility:private"],
deps = [
":core_types",
"//core_v2/internal",
@@ -42,6 +40,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
View File
@@ -54,10 +54,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
View File
@@ -104,7 +104,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.
+6
View File
@@ -4,6 +4,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",
@@ -28,6 +29,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",
@@ -69,8 +71,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",
@@ -96,6 +100,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",
@@ -107,6 +112,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",
@@ -108,8 +108,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 {
+138 -91
View File
@@ -8,11 +8,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 {
@@ -25,9 +27,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) {}
@@ -58,25 +62,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) {
@@ -95,10 +101,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;
@@ -106,7 +113,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));
@@ -125,7 +132,7 @@ void BasePcpHandler::StopDiscovery(ClientProxy* client) {
latch.CountDown();
});
WaitForLatch("stopDiscovery", &latch);
WaitForLatch("StopDiscovery", &latch);
}
void BasePcpHandler::WaitForLatch(const std::string& method_name,
@@ -148,10 +155,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();
}
@@ -218,11 +227,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) {
@@ -265,9 +275,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
@@ -288,8 +299,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());
@@ -297,24 +307,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()) {
@@ -338,7 +348,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",
@@ -354,18 +364,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),
})
@@ -374,20 +385,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);
@@ -397,6 +409,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);
@@ -432,10 +458,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(
@@ -529,7 +555,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);
}
@@ -581,7 +607,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);
}
@@ -648,44 +674,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;
}
}
@@ -699,19 +733,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(
@@ -732,17 +769,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()) {
@@ -763,7 +807,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};
@@ -777,7 +822,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};
@@ -801,20 +847,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,
@@ -1079,8 +1125,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)));
}
+67 -39
View File
@@ -10,6 +10,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"
@@ -17,6 +18,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"
@@ -29,6 +31,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"
@@ -77,7 +80,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;
@@ -87,44 +90,45 @@ class BasePcpHandler : public PcpHandler,
// Notifies ConnectionListener (info.listener) in case of any event.
// See
// https://source.corp.google.com/piper///depot/google3/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
@@ -135,7 +139,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;
@@ -167,21 +171,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)),
@@ -200,54 +220,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_;
@@ -272,13 +302,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.
@@ -322,7 +353,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 =
@@ -330,8 +361,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.
@@ -353,8 +383,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.
@@ -366,7 +395,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.
@@ -377,9 +406,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.
@@ -390,7 +418,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);
@@ -413,7 +441,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
+199 -79
View File
@@ -8,11 +8,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"
@@ -30,6 +32,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)
@@ -58,8 +74,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;
@@ -80,9 +98,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));
@@ -98,8 +116,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.
@@ -110,22 +127,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 {
@@ -135,7 +167,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,
@@ -153,7 +186,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)>>
@@ -163,39 +196,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_),
@@ -205,7 +242,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
@@ -221,7 +259,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));
@@ -233,7 +271,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));
@@ -244,39 +282,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.
@@ -285,8 +334,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");
}
@@ -313,26 +363,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());
@@ -340,19 +393,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());
@@ -360,40 +415,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, {}),
@@ -404,18 +465,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});
@@ -424,20 +488,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)
@@ -448,28 +515,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, {}),
@@ -479,9 +551,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
+86 -94
View File
@@ -13,12 +13,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;
}
@@ -35,20 +56,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,
@@ -82,43 +112,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();
}
@@ -133,74 +164,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
+36 -23
View File
@@ -2,6 +2,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 {
@@ -11,8 +12,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 {
@@ -25,28 +29,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;
@@ -56,25 +67,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_;
};
+243 -113
View File
@@ -9,81 +9,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());
}
@@ -91,13 +148,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());
}
@@ -105,13 +172,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());
}
@@ -119,13 +195,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());
}
@@ -133,125 +208,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_
+18 -19
View File
@@ -8,6 +8,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 {
@@ -17,7 +18,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) {
@@ -36,7 +37,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(
@@ -106,24 +107,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 {
@@ -140,14 +139,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
@@ -155,8 +154,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)});
+5 -5
View File
@@ -30,7 +30,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;
@@ -45,15 +45,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;
@@ -63,7 +63,7 @@ class BluetoothDeviceName {
Pcp pcp_{Pcp::kUnknown};
std::string endpoint_id_;
ByteArray service_id_hash_;
std::string endpoint_name_;
ByteArray endpoint_info_;
};
} // namespace connections
@@ -20,38 +20,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());
}
@@ -60,8 +62,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());
}
@@ -70,8 +73,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());
}
@@ -80,8 +84,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());
}
@@ -90,8 +95,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());
}
@@ -100,8 +106,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());
}
@@ -119,8 +126,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.
@@ -145,9 +153,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());
@@ -156,7 +165,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
+41 -19
View File
@@ -12,6 +12,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 {
@@ -24,21 +25,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() {
@@ -55,6 +57,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};
}
@@ -64,6 +67,7 @@ void ClientProxy::StoppedAdvertising() {
if (IsAdvertising()) {
advertising_info_.Clear();
}
if (connections_.empty()) local_endpoint_id_.clear();
}
bool ClientProxy::IsAdvertising() const {
@@ -83,6 +87,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};
}
@@ -93,6 +98,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 {
@@ -115,13 +121,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());
@@ -133,7 +140,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);
}
@@ -150,6 +157,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_);
@@ -160,6 +168,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.
@@ -234,6 +243,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();
}
}
@@ -248,6 +258,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);
}
@@ -469,6 +490,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(
+8 -2
View File
@@ -6,6 +6,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"
@@ -35,7 +36,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();
@@ -64,7 +65,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,
@@ -73,6 +74,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.
@@ -88,6 +90,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.
@@ -157,6 +161,7 @@ class ClientProxy final {
Status status{kPending};
ConnectionListener connection_listener;
PayloadListener payload_listener;
ConnectionOptions connection_options;
};
struct AdvertisingInfo {
@@ -188,6 +193,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
+14 -10
View File
@@ -3,6 +3,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"
@@ -22,7 +23,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)>>
@@ -52,14 +53,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_));
@@ -68,8 +69,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_));
@@ -78,7 +79,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) {
@@ -91,8 +93,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));
}
@@ -208,6 +211,7 @@ class ClientProxyTest : public testing::Test {
.payload_progress_cb =
mock_discovery_payload_.payload_progress_cb.AsStdFunction(),
};
ConnectionOptions connection_options_;
};
TEST_F(ClientProxyTest, ConstructorDestructorWorks) { SUCCEED(); }
@@ -217,8 +221,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) {
+12 -12
View File
@@ -52,13 +52,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();
}
@@ -76,7 +76,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_);
@@ -109,7 +109,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)
@@ -131,7 +131,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)
@@ -156,7 +156,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();
@@ -170,7 +170,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());
}
@@ -185,7 +185,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());
}
@@ -342,22 +342,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();
});
+2 -2
View File
@@ -51,11 +51,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);
@@ -74,6 +74,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
@@ -80,6 +80,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
@@ -97,9 +99,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;
@@ -134,6 +134,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
@@ -146,7 +147,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_);
};
+5 -4
View File
@@ -227,8 +227,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);
@@ -318,6 +317,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);
@@ -329,7 +329,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());
@@ -382,7 +383,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();
+4 -4
View File
@@ -81,8 +81,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);
@@ -91,6 +91,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
@@ -201,8 +202,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_;
+11 -8
View File
@@ -6,6 +6,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"
@@ -40,8 +41,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));
@@ -89,22 +89,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 {
@@ -158,8 +159,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())
+5
View File
@@ -2,6 +2,7 @@ cc_library(
name = "mediums",
srcs = [
"advertisement_read_result.cc",
"ble.cc",
"ble_advertisement.cc",
"ble_advertisement_header.cc",
"ble_packet.cc",
@@ -15,6 +16,7 @@ cc_library(
],
hdrs = [
"advertisement_read_result.h",
"ble.h",
"ble_advertisement.h",
"ble_advertisement_header.h",
"ble_packet.h",
@@ -56,6 +58,7 @@ cc_library(
srcs = ["utils.cc"],
hdrs = ["utils.h"],
visibility = [
"//core_v2/internal:__pkg__",
"//core_v2/internal/mediums/webrtc:__pkg__",
],
deps = [
@@ -74,6 +77,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",
@@ -93,6 +97,7 @@ cc_test(
"//platform_v2/public:logging",
"//platform_v2/public:types",
"//testing/base/public:gunit_main",
"//absl/strings",
"//absl/time",
],
)
+269
View File
@@ -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
+162
View File
@@ -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_
+162
View File
@@ -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
@@ -368,6 +368,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));
}
@@ -100,6 +100,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;
+2
View File
@@ -12,6 +12,8 @@ BluetoothClassic& Mediums::GetBluetoothClassic() {
return bluetooth_classic_;
}
Ble& Mediums::GetBle() { return ble_; }
WifiLan& Mediums::GetWifiLan() {
return wifi_lan_;
}
+5
View File
@@ -1,6 +1,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"
@@ -22,6 +23,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();
@@ -39,6 +43,7 @@ class Mediums {
// corresponding radio.
BluetoothRadio bluetooth_radio_;
BluetoothClassic bluetooth_classic_{bluetooth_radio_};
Ble ble_{bluetooth_radio_};
WifiLan wifi_lan_;
mediums::WebRtc webrtc_;
};
+10 -4
View File
@@ -44,8 +44,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;
}
@@ -208,7 +207,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;
@@ -228,13 +228,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
+4 -1
View File
@@ -69,6 +69,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(); }
@@ -115,7 +118,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_);
+11 -10
View File
@@ -8,6 +8,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 {
@@ -33,7 +34,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());
@@ -45,19 +45,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));
@@ -69,11 +69,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, {
@@ -100,17 +100,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(
@@ -118,7 +118,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());
@@ -135,6 +135,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();
}
@@ -35,7 +35,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,
+117 -16
View File
@@ -4,6 +4,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 {
@@ -13,7 +14,6 @@ namespace parser {
namespace {
using ExceptionOrOfflineFrame = ExceptionOr<OfflineFrame>;
using Medium = proto::connections::Medium;
using MessageLite = ::google::protobuf::MessageLite;
ByteArray ToBytes(OfflineFrame&& frame) {
@@ -44,7 +44,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;
@@ -54,8 +54,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));
@@ -108,7 +108,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;
@@ -120,8 +120,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);
@@ -131,7 +130,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);
@@ -144,7 +182,7 @@ ByteArray ForBandwidthUpgradeLastWrite() {
return ToBytes(std::move(frame));
}
ByteArray ForBandwidthUpgradeSafeToClose() {
ByteArray ForBwuSafeToClose() {
OfflineFrame frame;
frame.set_version(OfflineFrame::V1);
@@ -157,7 +195,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);
@@ -172,6 +210,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;
@@ -183,8 +236,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;
@@ -209,8 +311,7 @@ ConnectionRequestFrame::Medium MediumToConnectionRequestMedium(
}
}
proto::connections::Medium ConnectionRequestMediumToMedium(
ConnectionRequestFrame::Medium medium) {
Medium ConnectionRequestMediumToMedium(ConnectionRequestFrame::Medium medium) {
switch (medium) {
case ConnectionRequestFrame::MDNS:
return Medium::MDNS;
@@ -235,9 +336,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)));
+25 -13
View File
@@ -4,6 +4,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"
@@ -14,6 +15,8 @@ namespace nearby {
namespace connections {
namespace parser {
using UpgradePathInfo = BandwidthUpgradeNegotiationFrame::UpgradePathInfo;
// Serialize/Deserialize Nearby Connections Protocol messages.
// Parses incoming message.
@@ -25,12 +28,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);
@@ -38,19 +42,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
+55 -9
View File
@@ -79,7 +79,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());
@@ -157,7 +157,7 @@ TEST(OfflineFramesTest, CanGenerateDataPayloadTransfer) {
EXPECT_THAT(message, EqualsProto(kExpected));
}
TEST(OfflineFramesTest, CanGenerateBandwidthUpgradeWifiHotspot) {
TEST(OfflineFramesTest, CanGenerateBwuWifiHotspotPathAvailable) {
constexpr char kExpected[] =
R"pb(
version: V1
@@ -175,14 +175,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
@@ -190,14 +236,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
@@ -205,14 +251,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
@@ -223,7 +269,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();
@@ -6,9 +6,7 @@ namespace location {
namespace nearby {
namespace connections {
OfflineServiceController::~OfflineServiceController() {
Stop();
}
OfflineServiceController::~OfflineServiceController() { Stop(); }
void OfflineServiceController::Stop() {
if (stop_.Set(true)) return;
@@ -38,8 +36,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(
@@ -40,7 +40,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;
@@ -51,8 +52,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;
@@ -25,7 +25,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(); }
@@ -35,7 +49,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());
@@ -53,29 +67,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}));
@@ -83,10 +98,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}));
@@ -99,10 +114,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),
@@ -117,29 +132,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}));
@@ -154,10 +179,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_),
@@ -171,10 +196,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_),
@@ -195,10 +220,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}));
@@ -216,10 +241,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));
@@ -231,10 +256,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>();
@@ -258,10 +283,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>();
@@ -298,11 +323,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);
@@ -315,6 +340,10 @@ TEST_F(OfflineServiceControllerTest, CanDisconnect) {
env_.Stop();
}
INSTANTIATE_TEST_SUITE_P(ParametrisedOfflineServiceControllerTest,
OfflineServiceControllerTest,
::testing::ValuesIn(kTestCases));
} // namespace
} // namespace connections
} // namespace nearby
+16 -11
View File
@@ -1,6 +1,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"
@@ -18,7 +19,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_,
};
}
@@ -43,12 +44,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();
@@ -107,7 +108,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),
});
}
@@ -117,8 +118,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),
@@ -144,11 +147,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) {
+25 -10
View File
@@ -5,6 +5,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"
@@ -25,15 +26,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().
@@ -45,9 +52,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();
@@ -79,7 +90,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);
@@ -109,6 +120,8 @@ class OfflineSimulationUser {
}
void Stop() {
StopAdvertising();
StopDiscovery();
ctrl_.Stop();
}
@@ -123,7 +136,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);
@@ -134,6 +147,8 @@ class OfflineSimulationUser {
std::string service_id_;
DiscoveredInfo discovered_;
ConnectionOptions connection_options_;
Mutex progress_mutex_;
ConditionVariable progress_sync_{&progress_mutex_};
PayloadProgressInfo progress_info_;
@@ -148,8 +163,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_;
};
+530 -223
View File
@@ -1,6 +1,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"
@@ -8,6 +10,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 {
@@ -22,13 +26,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.
@@ -45,6 +50,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;
}
@@ -54,35 +62,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()) {
@@ -106,6 +134,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());
@@ -146,90 +176,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(
@@ -266,90 +416,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(
@@ -357,28 +501,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()) {
@@ -397,6 +567,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};
}
@@ -415,6 +586,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) {
@@ -441,7 +619,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(
@@ -460,20 +638,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);
});
@@ -487,11 +667,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 "
@@ -564,10 +745,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,
@@ -584,21 +887,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);
});
@@ -613,11 +918,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 "
@@ -687,20 +993,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;
}
@@ -709,8 +1015,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);
});
+58 -15
View File
@@ -36,7 +36,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;
@@ -50,7 +50,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
@@ -77,15 +77,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 =
@@ -99,34 +120,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);
@@ -137,12 +179,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_;
};
@@ -15,31 +15,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;
@@ -47,25 +73,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;
@@ -74,18 +101,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());
@@ -94,10 +122,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;
@@ -110,20 +141,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 =
@@ -142,13 +173,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();
@@ -157,12 +188,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 =
@@ -173,11 +204,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
@@ -7,8 +7,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() {
@@ -3,7 +3,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"
@@ -15,7 +14,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.
@@ -31,9 +30,6 @@ class P2pPointToPointPcpHandler : public P2pStarPcpHandler {
bool CanSendOutgoingConnection(ClientProxy* client) const override;
bool CanReceiveIncomingConnection(ClientProxy* client) const override;
private:
Mediums* mediums_;
};
} // namespace connections
+2 -2
View File
@@ -10,8 +10,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() {
+1 -5
View File
@@ -6,7 +6,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"
@@ -17,7 +16,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
@@ -35,9 +34,6 @@ class P2pStarPcpHandler : public P2pClusterPcpHandler {
bool CanSendOutgoingConnection(ClientProxy* client) const override;
bool CanReceiveIncomingConnection(ClientProxy* client) const override;
private:
Mediums* mediums_;
};
} // namespace connections
+43 -24
View File
@@ -20,12 +20,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);
}
@@ -51,7 +66,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(); }
@@ -61,7 +77,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());
@@ -85,23 +101,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_);
@@ -115,10 +131,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>();
@@ -165,10 +181,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>();
@@ -212,7 +228,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();
@@ -223,10 +239,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>();
@@ -270,7 +286,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();
@@ -281,6 +297,9 @@ TEST_F(PayloadManagerTest, CanCancelPayloadOnSenderSide) {
env_.Stop();
}
INSTANTIATE_TEST_SUITE_P(ParametrisedPayloadManagerTest, PayloadManagerTest,
::testing::ValuesIn(kTestCases));
} // namespace
} // namespace connections
} // namespace nearby
+3 -2
View File
@@ -79,12 +79,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;
+4 -3
View File
@@ -13,7 +13,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] =
@@ -69,12 +69,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,
+9 -8
View File
@@ -32,21 +32,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();
+42 -25
View File
@@ -4,6 +4,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"
@@ -19,58 +20,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();
@@ -78,10 +92,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);
@@ -89,7 +103,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);
@@ -100,10 +114,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);
@@ -111,7 +125,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);
@@ -122,6 +136,9 @@ TEST_F(PcpManagerTest, CanReject) {
env_.Stop();
}
INSTANTIATE_TEST_SUITE_P(ParametrisedPcpManagerTest, PcpManagerTest,
::testing::ValuesIn(kTestCases));
} // namespace
} // namespace connections
} // namespace nearby
+3 -3
View File
@@ -49,7 +49,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;
@@ -63,8 +64,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;
@@ -92,23 +92,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,
@@ -204,7 +206,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;
@@ -59,6 +59,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,
@@ -101,20 +101,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));
}
@@ -242,7 +244,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(),
};
+12 -10
View File
@@ -18,7 +18,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_,
};
}
@@ -35,12 +35,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();
@@ -97,7 +97,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());
@@ -128,12 +128,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) {
+16 -10
View File
@@ -8,6 +8,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"
@@ -27,18 +28,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();
@@ -80,7 +85,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);
@@ -95,7 +100,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);
@@ -106,6 +111,7 @@ class SimulationUser {
std::string service_id_;
DiscoveredInfo discovered_;
ConnectionOptions connection_options_;
Mutex progress_mutex_;
ConditionVariable progress_sync_{&progress_mutex_};
PayloadProgressInfo progress_info_;
@@ -118,9 +124,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_};
+20 -21
View File
@@ -17,7 +17,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) {
@@ -36,7 +36,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) {
@@ -66,11 +66,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;
}
@@ -105,24 +105,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 {
@@ -137,22 +135,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)});
+5 -5
View File
@@ -28,7 +28,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;
@@ -42,7 +42,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:
@@ -53,7 +53,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;
@@ -67,8 +67,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
@@ -20,21 +20,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};
@@ -44,15 +46,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());
}
@@ -61,8 +64,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());
}
@@ -71,8 +75,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());
}
@@ -81,8 +86,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());
}
@@ -91,8 +97,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());
}
@@ -101,8 +108,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());
}
+4 -5
View File
@@ -35,10 +35,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;
};
@@ -121,13 +120,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
View File
@@ -2,17 +2,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.
@@ -22,17 +69,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
+6 -5
View File
@@ -4,6 +4,7 @@
#include <string>
#include "core_v2/listeners.h"
#include "platform_v2/base/byte_array.h"
namespace location {
namespace nearby {
@@ -12,11 +13,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;
};
+1
View File
@@ -24,6 +24,7 @@ struct Status {
kAlreadyConnectedToEndpoint,
kNotConnectedToEndpoint,
kBluetoothError,
kBleError,
kWifiLanError,
kPayloadUnknown,
};