mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Refactor EndpointChannel ownership to use shared_ptr.
PiperOrigin-RevId: 907278448
This commit is contained in:
committed by
Copybara-Service
parent
3fd8fbf2f1
commit
4ae41f4cdf
@@ -108,20 +108,26 @@ std::function<void(const ByteArray&)> MakeDataMonitor(const std::string& label,
|
||||
|
||||
std::pair<std::shared_ptr<EncryptionContext>,
|
||||
std::shared_ptr<EncryptionContext>>
|
||||
DoDhKeyExchange(BaseEndpointChannel* channel_a,
|
||||
BaseEndpointChannel* channel_b) {
|
||||
DoDhKeyExchange(std::shared_ptr<TestEndpointChannel> channel_a,
|
||||
std::shared_ptr<TestEndpointChannel> channel_b) {
|
||||
std::shared_ptr<EncryptionContext> context_a;
|
||||
std::shared_ptr<EncryptionContext> context_b;
|
||||
EncryptionRunner crypto_a;
|
||||
EncryptionRunner crypto_b;
|
||||
ClientProxy proxy_a;
|
||||
ClientProxy proxy_b;
|
||||
CountDownLatch latch(2);
|
||||
std::shared_ptr<EndpointChannel> shared_channel_a = channel_a;
|
||||
std::shared_ptr<EndpointChannel> shared_channel_b = channel_b;
|
||||
|
||||
// Create a shared_ptr for the latch to prevent Use-After-Free if the
|
||||
// negotiation times out and this function returns early.
|
||||
auto latch = std::make_shared<CountDownLatch>(2);
|
||||
|
||||
crypto_a.StartClient(
|
||||
&proxy_a, "endpoint_id", channel_a,
|
||||
&proxy_a, "endpoint_id", shared_channel_a,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&latch, &context_a](
|
||||
[latch, &context_a](
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
|
||||
const std::string& auth_token,
|
||||
@@ -131,20 +137,19 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a,
|
||||
auto context = ukey2->ToConnectionContext();
|
||||
EXPECT_NE(context, nullptr);
|
||||
context_a = std::move(context);
|
||||
latch.CountDown();
|
||||
latch->CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&latch](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
[latch](const std::string& endpoint_id) {
|
||||
LOG(INFO) << "client-A side key negotiation failed";
|
||||
latch.CountDown();
|
||||
latch->CountDown();
|
||||
},
|
||||
});
|
||||
crypto_b.StartServer(
|
||||
&proxy_b, "endpoint_id", channel_b,
|
||||
&proxy_b, "endpoint_id", shared_channel_b,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&latch, &context_b](
|
||||
[latch, &context_b](
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
|
||||
const std::string& auth_token,
|
||||
@@ -154,16 +159,15 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a,
|
||||
auto context = ukey2->ToConnectionContext();
|
||||
EXPECT_NE(context, nullptr);
|
||||
context_b = std::move(context);
|
||||
latch.CountDown();
|
||||
latch->CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&latch](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
[latch](const std::string& endpoint_id) {
|
||||
LOG(INFO) << "client-B side key negotiation failed";
|
||||
latch.CountDown();
|
||||
latch->CountDown();
|
||||
},
|
||||
});
|
||||
EXPECT_TRUE(latch.Await(absl::Milliseconds(5000)).result());
|
||||
EXPECT_TRUE(latch->Await(absl::Milliseconds(5000)).result());
|
||||
return std::make_pair(std::move(context_a), std::move(context_b));
|
||||
}
|
||||
|
||||
@@ -265,20 +269,22 @@ TEST_F(BaseEndpointChannelTest, TryDecrypt) {
|
||||
absl::string_view kMessage = "message";
|
||||
auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b.
|
||||
auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a.
|
||||
TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get());
|
||||
TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get());
|
||||
auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b);
|
||||
auto channel_a = std::make_shared<TestEndpointChannel>(pipe_b.first.get(),
|
||||
pipe_a.second.get());
|
||||
auto channel_b = std::make_shared<TestEndpointChannel>(pipe_a.first.get(),
|
||||
pipe_b.second.get());
|
||||
auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b);
|
||||
ASSERT_NE(context_a, nullptr);
|
||||
ASSERT_NE(context_b, nullptr);
|
||||
channel_a.EnableEncryption(context_a);
|
||||
channel_b.EnableEncryption(context_b);
|
||||
channel_a->EnableEncryption(context_a);
|
||||
channel_b->EnableEncryption(context_b);
|
||||
std::unique_ptr<std::string> encrypted_message =
|
||||
channel_a.EncodeMessageForTests(kMessage);
|
||||
channel_a->EncodeMessageForTests(kMessage);
|
||||
|
||||
ExceptionOr<ByteArray> decrypted_message =
|
||||
channel_b.TryDecrypt(ByteArray(*encrypted_message));
|
||||
channel_b->TryDecrypt(ByteArray(*encrypted_message));
|
||||
|
||||
EXPECT_TRUE(channel_b.IsEncrypted());
|
||||
EXPECT_TRUE(channel_b->IsEncrypted());
|
||||
EXPECT_TRUE(decrypted_message.ok());
|
||||
EXPECT_EQ(decrypted_message.result().AsStringView(), kMessage);
|
||||
}
|
||||
@@ -286,16 +292,18 @@ TEST_F(BaseEndpointChannelTest, TryDecrypt) {
|
||||
TEST_F(BaseEndpointChannelTest, TryDecryptFailsWhenDecryptionFails) {
|
||||
auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b.
|
||||
auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a.
|
||||
TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get());
|
||||
TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get());
|
||||
auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b);
|
||||
auto channel_a = std::make_shared<TestEndpointChannel>(pipe_b.first.get(),
|
||||
pipe_a.second.get());
|
||||
auto channel_b = std::make_shared<TestEndpointChannel>(pipe_a.first.get(),
|
||||
pipe_b.second.get());
|
||||
auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b);
|
||||
ASSERT_NE(context_a, nullptr);
|
||||
channel_a.EnableEncryption(context_a);
|
||||
channel_a->EnableEncryption(context_a);
|
||||
|
||||
ExceptionOr<ByteArray> result =
|
||||
channel_a.TryDecrypt(ByteArray("invalid message"));
|
||||
channel_a->TryDecrypt(ByteArray("invalid message"));
|
||||
|
||||
EXPECT_TRUE(channel_a.IsEncrypted());
|
||||
EXPECT_TRUE(channel_a->IsEncrypted());
|
||||
EXPECT_FALSE(result.ok());
|
||||
EXPECT_EQ(result.exception(), Exception::kExecution);
|
||||
}
|
||||
@@ -366,13 +374,15 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) {
|
||||
// to server "b".
|
||||
auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes
|
||||
// to server "a".
|
||||
TestEndpointChannel channel_a(server_a.first.get(), client_a.second.get());
|
||||
TestEndpointChannel channel_b(server_b.first.get(), client_b.second.get());
|
||||
auto channel_a = std::make_shared<TestEndpointChannel>(server_a.first.get(),
|
||||
client_a.second.get());
|
||||
auto channel_b = std::make_shared<TestEndpointChannel>(server_b.first.get(),
|
||||
client_b.second.get());
|
||||
|
||||
ON_CALL(channel_a, GetMedium).WillByDefault([]() {
|
||||
ON_CALL(*channel_a, GetMedium).WillByDefault([]() {
|
||||
return Medium::BLUETOOTH;
|
||||
});
|
||||
ON_CALL(channel_b, GetMedium).WillByDefault([]() {
|
||||
ON_CALL(*channel_b, GetMedium).WillByDefault([]() {
|
||||
return Medium::BLUETOOTH;
|
||||
});
|
||||
|
||||
@@ -385,21 +395,21 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) {
|
||||
MakeDataMonitor("monitor_b", &capture_b, &mutex)));
|
||||
|
||||
// Run DH key exchange; setup encryption contexts for channels.
|
||||
auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b);
|
||||
auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b);
|
||||
ASSERT_NE(context_a, nullptr);
|
||||
ASSERT_NE(context_b, nullptr);
|
||||
channel_a.EnableEncryption(context_a);
|
||||
channel_b.EnableEncryption(context_b);
|
||||
channel_a->EnableEncryption(context_a);
|
||||
channel_b->EnableEncryption(context_b);
|
||||
|
||||
EXPECT_EQ(channel_a.GetType(), "ENCRYPTED_BLUETOOTH");
|
||||
EXPECT_EQ(channel_b.GetType(), "ENCRYPTED_BLUETOOTH");
|
||||
EXPECT_TRUE(channel_a.IsEncrypted());
|
||||
EXPECT_TRUE(channel_b.IsEncrypted());
|
||||
EXPECT_EQ(channel_a->GetType(), "ENCRYPTED_BLUETOOTH");
|
||||
EXPECT_EQ(channel_b->GetType(), "ENCRYPTED_BLUETOOTH");
|
||||
EXPECT_TRUE(channel_a->IsEncrypted());
|
||||
EXPECT_TRUE(channel_b->IsEncrypted());
|
||||
|
||||
// Start data transfer
|
||||
absl::string_view tx_message = "data message";
|
||||
channel_a.Write(tx_message);
|
||||
ByteArray rx_message = std::move(channel_b.Read().result());
|
||||
channel_a->Write(tx_message);
|
||||
ByteArray rx_message = std::move(channel_b->Read().result());
|
||||
|
||||
// Verify expectations.
|
||||
EXPECT_EQ(rx_message.AsStringView(), tx_message);
|
||||
@@ -411,8 +421,8 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) {
|
||||
}
|
||||
|
||||
// Shutdown test environment.
|
||||
channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION);
|
||||
channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION);
|
||||
channel_a->Close(DisconnectionReason::LOCAL_DISCONNECTION);
|
||||
channel_b->Close(DisconnectionReason::REMOTE_DISCONNECTION);
|
||||
}
|
||||
|
||||
TEST_F(BaseEndpointChannelTest, CanBesuspendedAndResumed) {
|
||||
@@ -486,43 +496,45 @@ TEST_F(BaseEndpointChannelTest, ReadUnencryptedFrameOnEncryptedChannel) {
|
||||
// Setup test communication environment.
|
||||
auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b.
|
||||
auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a.
|
||||
TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get());
|
||||
TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get());
|
||||
auto channel_a = std::make_shared<TestEndpointChannel>(pipe_b.first.get(),
|
||||
pipe_a.second.get());
|
||||
auto channel_b = std::make_shared<TestEndpointChannel>(pipe_a.first.get(),
|
||||
pipe_b.second.get());
|
||||
|
||||
ON_CALL(channel_a, GetMedium).WillByDefault([]() {
|
||||
ON_CALL(*channel_a, GetMedium).WillByDefault([]() {
|
||||
return Medium::BLUETOOTH;
|
||||
});
|
||||
ON_CALL(channel_b, GetMedium).WillByDefault([]() {
|
||||
ON_CALL(*channel_b, GetMedium).WillByDefault([]() {
|
||||
return Medium::BLUETOOTH;
|
||||
});
|
||||
|
||||
// Run DH key exchange; setup encryption contexts for channels. But only
|
||||
// encrypt |channel_b|.
|
||||
auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b);
|
||||
auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b);
|
||||
ASSERT_NE(context_a, nullptr);
|
||||
ASSERT_NE(context_b, nullptr);
|
||||
channel_b.EnableEncryption(context_b);
|
||||
channel_b->EnableEncryption(context_b);
|
||||
|
||||
EXPECT_EQ(channel_a.GetType(), "BLUETOOTH");
|
||||
EXPECT_EQ(channel_b.GetType(), "ENCRYPTED_BLUETOOTH");
|
||||
EXPECT_EQ(channel_a->GetType(), "BLUETOOTH");
|
||||
EXPECT_EQ(channel_b->GetType(), "ENCRYPTED_BLUETOOTH");
|
||||
|
||||
// An unencrypted KeepAlive should succeed.
|
||||
std::string keep_alive_message = parser::ForKeepAlive();
|
||||
channel_a.Write(keep_alive_message);
|
||||
ExceptionOr<ByteArray> result = channel_b.Read();
|
||||
channel_a->Write(keep_alive_message);
|
||||
ExceptionOr<ByteArray> result = channel_b->Read();
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_EQ(result.result().AsStringView(), keep_alive_message);
|
||||
|
||||
// An unencrypted data frame should fail.
|
||||
absl::string_view tx_message = "data message";
|
||||
channel_a.Write(tx_message);
|
||||
result = channel_b.Read();
|
||||
channel_a->Write(tx_message);
|
||||
result = channel_b->Read();
|
||||
EXPECT_FALSE(result.ok());
|
||||
EXPECT_EQ(result.exception(), Exception::kInvalidProtocolBuffer);
|
||||
|
||||
// Shutdown test environment.
|
||||
channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION);
|
||||
channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION);
|
||||
channel_a->Close(DisconnectionReason::LOCAL_DISCONNECTION);
|
||||
channel_b->Close(DisconnectionReason::REMOTE_DISCONNECTION);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -212,8 +212,7 @@ std::vector<ConnectionInfoVariant> BasePcpHandler::GetConnectionInfoFromResult(
|
||||
}
|
||||
WifiLanConnectionInfo info(
|
||||
std::string(ip_address.begin(), ip_address.end()),
|
||||
absl::StrCat(absl::Hex(port, absl::kZeroPad16)), "",
|
||||
{});
|
||||
absl::StrCat(absl::Hex(port, absl::kZeroPad16)), "", {});
|
||||
connection_infos.push_back(info);
|
||||
}
|
||||
}
|
||||
@@ -424,25 +423,25 @@ BooleanMediumSelector BasePcpHandler::ComputeIntersectionOfSupportedMediums(
|
||||
pending_connection_info.connection_options.connection_info
|
||||
.supported_wifi_direct_auth_types;
|
||||
LOG(INFO) << "Remote supported WifiDirect auth types: "
|
||||
<< absl::StrJoin(
|
||||
remote_supported_wifi_direct_auth_types, ", ",
|
||||
[](std::string* out, int auth_type) {
|
||||
absl::StrAppend(
|
||||
out,
|
||||
WifiDirectAuthType_Name(
|
||||
static_cast<WifiDirectAuthType>(auth_type)));
|
||||
});
|
||||
<< absl::StrJoin(
|
||||
remote_supported_wifi_direct_auth_types, ", ",
|
||||
[](std::string* out, int auth_type) {
|
||||
absl::StrAppend(
|
||||
out,
|
||||
WifiDirectAuthType_Name(
|
||||
static_cast<WifiDirectAuthType>(auth_type)));
|
||||
});
|
||||
auto local_supported_wifi_direct_auth_types =
|
||||
mediums_->GetWifiDirect().GetSupportedWifiDirectAuthTypes();
|
||||
LOG(INFO) << "Local supported WifiDirect auth types: "
|
||||
<< absl::StrJoin(
|
||||
local_supported_wifi_direct_auth_types, ", ",
|
||||
[](std::string* out, int auth_type) {
|
||||
absl::StrAppend(
|
||||
out,
|
||||
WifiDirectAuthType_Name(
|
||||
static_cast<WifiDirectAuthType>(auth_type)));
|
||||
});
|
||||
<< absl::StrJoin(
|
||||
local_supported_wifi_direct_auth_types, ", ",
|
||||
[](std::string* out, int auth_type) {
|
||||
absl::StrAppend(
|
||||
out,
|
||||
WifiDirectAuthType_Name(
|
||||
static_cast<WifiDirectAuthType>(auth_type)));
|
||||
});
|
||||
bool found_common_auth_type = false;
|
||||
for (const auto& auth_type : local_supported_wifi_direct_auth_types) {
|
||||
if (auth_type == WifiDirectAuthType::WIFI_DIRECT_TYPE_UNKNOWN) {
|
||||
@@ -587,34 +586,50 @@ void BasePcpHandler::RunOnPcpHandlerThread(const std::string& name,
|
||||
serial_executor_.Execute(name, std::move(runnable));
|
||||
}
|
||||
|
||||
EncryptionRunner::ResultListener BasePcpHandler::GetResultListener() {
|
||||
EncryptionRunner::ResultListener BasePcpHandler::GetResultListener(
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel) {
|
||||
std::weak_ptr<EndpointChannel> weak_channel = endpoint_channel;
|
||||
|
||||
return {
|
||||
.on_success_cb =
|
||||
[this](const std::string& endpoint_id,
|
||||
std::unique_ptr<UKey2Handshake> ukey2,
|
||||
const std::string& auth_token,
|
||||
const ByteArray& raw_auth_token) {
|
||||
[this, weak_channel](const std::string& endpoint_id,
|
||||
std::unique_ptr<UKey2Handshake> ukey2,
|
||||
const std::string& auth_token,
|
||||
const ByteArray& raw_auth_token) {
|
||||
auto channel = weak_channel.lock();
|
||||
if (!channel) return;
|
||||
|
||||
RunOnPcpHandlerThread(
|
||||
"encryption-success",
|
||||
[this, endpoint_id, raw_ukey2 = ukey2.release(), auth_token,
|
||||
raw_auth_token]() RUN_ON_PCP_HANDLER_THREAD() mutable {
|
||||
OnEncryptionSuccessRunnable(
|
||||
endpoint_id, std::unique_ptr<UKey2Handshake>(raw_ukey2),
|
||||
auth_token, raw_auth_token);
|
||||
});
|
||||
[this, endpoint_id, weak_channel, raw_ukey2 = ukey2.release(),
|
||||
auth_token, raw_auth_token]()
|
||||
RUN_ON_PCP_HANDLER_THREAD() mutable {
|
||||
std::unique_ptr<UKey2Handshake> ukey2(raw_ukey2);
|
||||
auto channel = weak_channel.lock();
|
||||
if (!channel) return;
|
||||
OnEncryptionSuccessRunnable(endpoint_id, std::move(ukey2),
|
||||
auth_token, raw_auth_token,
|
||||
channel);
|
||||
});
|
||||
},
|
||||
.on_failure_cb =
|
||||
[this](const std::string& endpoint_id, EndpointChannel* channel) {
|
||||
[this, weak_channel](const std::string& endpoint_id) {
|
||||
auto channel = weak_channel.lock();
|
||||
if (!channel) return;
|
||||
|
||||
RunOnPcpHandlerThread(
|
||||
"encryption-failure",
|
||||
[this, endpoint_id, channel]() RUN_ON_PCP_HANDLER_THREAD() {
|
||||
LOG(ERROR)
|
||||
<< "Encryption failed for endpoint_id=" << endpoint_id
|
||||
<< " on medium="
|
||||
<< location::nearby::proto::connections::Medium_Name(
|
||||
channel->GetMedium());
|
||||
OnEncryptionFailureRunnable(endpoint_id, channel);
|
||||
});
|
||||
[this, endpoint_id, weak_channel]()
|
||||
RUN_ON_PCP_HANDLER_THREAD() {
|
||||
auto channel = weak_channel.lock();
|
||||
if (!channel) return;
|
||||
LOG(ERROR)
|
||||
<< "Encryption failed for endpoint_id=" << endpoint_id
|
||||
<< " on medium="
|
||||
<< location::nearby::proto::connections::Medium_Name(
|
||||
channel->GetMedium());
|
||||
OnEncryptionFailureRunnable(endpoint_id, channel);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -622,36 +637,49 @@ EncryptionRunner::ResultListener BasePcpHandler::GetResultListener() {
|
||||
EncryptionRunner::ResultListener BasePcpHandler::GetResultListenerV3(
|
||||
const NearbyDeviceProvider& device_provider,
|
||||
const NearbyDevice& remote_device,
|
||||
const EndpointChannel& endpoint_channel) {
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel) {
|
||||
std::weak_ptr<EndpointChannel> weak_channel = endpoint_channel;
|
||||
|
||||
return {
|
||||
.on_success_cb =
|
||||
[this, &device_provider, &remote_device, &endpoint_channel](
|
||||
[this, &device_provider, &remote_device, weak_channel](
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<UKey2Handshake> ukey2,
|
||||
const std::string& auth_token, const ByteArray& raw_auth_token) {
|
||||
auto channel = weak_channel.lock();
|
||||
if (!channel) return;
|
||||
|
||||
RunOnPcpHandlerThread(
|
||||
"encryption-success",
|
||||
[this, &device_provider, &remote_device, &endpoint_channel,
|
||||
raw_ukey2 = ukey2.release(), auth_token,
|
||||
raw_auth_token]() RUN_ON_PCP_HANDLER_THREAD() mutable {
|
||||
OnEncryptionSuccessRunnableV3(
|
||||
remote_device, std::unique_ptr<UKey2Handshake>(raw_ukey2),
|
||||
auth_token, raw_auth_token, endpoint_channel,
|
||||
device_provider);
|
||||
});
|
||||
[this, &device_provider, &remote_device, weak_channel,
|
||||
raw_ukey2 = ukey2.release(), auth_token, raw_auth_token]()
|
||||
RUN_ON_PCP_HANDLER_THREAD() mutable {
|
||||
std::unique_ptr<UKey2Handshake> ukey2(raw_ukey2);
|
||||
auto channel = weak_channel.lock();
|
||||
if (!channel) return;
|
||||
OnEncryptionSuccessRunnableV3(
|
||||
remote_device, std::move(ukey2), auth_token,
|
||||
raw_auth_token, channel, device_provider);
|
||||
});
|
||||
},
|
||||
.on_failure_cb =
|
||||
[this](const std::string& endpoint_id, EndpointChannel* channel) {
|
||||
[this, weak_channel](const std::string& endpoint_id) {
|
||||
auto channel = weak_channel.lock();
|
||||
if (!channel) return;
|
||||
|
||||
RunOnPcpHandlerThread(
|
||||
"encryption-failure",
|
||||
[this, endpoint_id, channel]() RUN_ON_PCP_HANDLER_THREAD() {
|
||||
LOG(ERROR)
|
||||
<< "Encryption failed for endpoint_id=" << endpoint_id
|
||||
<< " on medium="
|
||||
<< location::nearby::proto::connections::Medium_Name(
|
||||
channel->GetMedium());
|
||||
OnEncryptionFailureRunnable(endpoint_id, channel);
|
||||
});
|
||||
[this, endpoint_id, weak_channel]()
|
||||
RUN_ON_PCP_HANDLER_THREAD() {
|
||||
auto channel = weak_channel.lock();
|
||||
if (!channel) return;
|
||||
LOG(ERROR)
|
||||
<< "Encryption failed for endpoint_id=" << endpoint_id
|
||||
<< " on medium="
|
||||
<< location::nearby::proto::connections::Medium_Name(
|
||||
channel->GetMedium());
|
||||
OnEncryptionFailureRunnable(endpoint_id, channel);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -659,7 +687,7 @@ EncryptionRunner::ResultListener BasePcpHandler::GetResultListenerV3(
|
||||
void BasePcpHandler::OnEncryptionSuccessRunnableV3(
|
||||
const NearbyDevice& remote_device, std::unique_ptr<UKey2Handshake> ukey2,
|
||||
absl::string_view auth_token, const ByteArray& raw_auth_token,
|
||||
const EndpointChannel& endpoint_channel,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
const NearbyDeviceProvider& device_provider) {
|
||||
// Quick fail if we've been removed from pending connections while we were
|
||||
// busy running UKEY2.
|
||||
@@ -674,7 +702,11 @@ void BasePcpHandler::OnEncryptionSuccessRunnableV3(
|
||||
}
|
||||
|
||||
BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second;
|
||||
|
||||
// Verify pointer equality to avoid accidental action on superseded
|
||||
// channels.
|
||||
if (endpoint_channel != pending_connection_info.channel) {
|
||||
return;
|
||||
}
|
||||
// TODO(b/300149127): Add test coverage.
|
||||
if (!ukey2) {
|
||||
// Fail early, if there is no crypto context.
|
||||
@@ -724,7 +756,8 @@ void BasePcpHandler::OnEncryptionSuccessRunnableV3(
|
||||
|
||||
void BasePcpHandler::OnEncryptionSuccessRunnable(
|
||||
const std::string& endpoint_id, std::unique_ptr<UKey2Handshake> ukey2,
|
||||
const std::string& auth_token, const ByteArray& raw_auth_token) {
|
||||
const std::string& auth_token, const ByteArray& raw_auth_token,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel) {
|
||||
// Quick fail if we've been removed from pending connections while we were
|
||||
// busy running UKEY2.
|
||||
// TODO(b/316421187): Add test coverage
|
||||
@@ -738,6 +771,12 @@ void BasePcpHandler::OnEncryptionSuccessRunnable(
|
||||
|
||||
BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second;
|
||||
|
||||
// Verify pointer equality to avoid accidental action on superseded
|
||||
// channels.
|
||||
if (endpoint_channel != pending_connection_info.channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ukey2) {
|
||||
// Fail early, if there is no crypto context.
|
||||
ProcessPreConnectionInitiationFailure(
|
||||
@@ -801,24 +840,21 @@ void BasePcpHandler::RegisterDeviceAfterEncryptionSuccess(
|
||||
}
|
||||
|
||||
void BasePcpHandler::OnEncryptionFailureRunnable(
|
||||
const std::string& endpoint_id, EndpointChannel* endpoint_channel) {
|
||||
const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel) {
|
||||
auto it = pending_connections_.find(endpoint_id);
|
||||
if (it == pending_connections_.end()) {
|
||||
LOG(INFO)
|
||||
<< "Connection not found on UKEY negotination complete; endpoint_id="
|
||||
<< "Connection not found on UKEY negotiation complete; endpoint_id="
|
||||
<< endpoint_id;
|
||||
return;
|
||||
}
|
||||
|
||||
BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second;
|
||||
// We had a bug here, caused by a race with EncryptionRunner. We now verify
|
||||
// the EndpointChannel to avoid it. In a simultaneous connection, we clean
|
||||
// up one of the two EndpointChannels and then update our pendingConnections
|
||||
// with the winning channel's state. Closing a channel that was in the
|
||||
// middle of EncryptionRunner would trigger onEncryptionFailed, and, since
|
||||
// the map had already updated with the winning EndpointChannel, we closed
|
||||
// it too by accident.
|
||||
if (*endpoint_channel != *pending_connection_info.channel) {
|
||||
|
||||
// Verify pointer equality to avoid accidental action on superseded
|
||||
// channels.
|
||||
if (endpoint_channel != pending_connection_info.channel) {
|
||||
LOG(INFO) << "Not destroying channel [mismatch]: passed="
|
||||
<< endpoint_channel->GetName()
|
||||
<< "; expected=" << pending_connection_info.channel->GetName();
|
||||
@@ -871,8 +907,8 @@ ConnectionInfo BasePcpHandler::FillConnectionInfo(
|
||||
connection_info.supported_wifi_direct_auth_types =
|
||||
mediums_->GetWifiDirect().GetSupportedWifiDirectAuthTypes();
|
||||
VLOG(1) << "Set SupportedWifiDirectAuthTypes for WIFI_DIRECT: "
|
||||
<< absl::StrJoin(connection_info.supported_wifi_direct_auth_types,
|
||||
",");
|
||||
<< absl::StrJoin(connection_info.supported_wifi_direct_auth_types,
|
||||
",");
|
||||
} else {
|
||||
connection_info.supported_wifi_direct_auth_types = {};
|
||||
}
|
||||
@@ -1005,17 +1041,32 @@ Status BasePcpHandler::RequestConnection(
|
||||
pending_connection_info.medium = channel->GetMedium();
|
||||
pending_connection_info.channel = std::move(channel);
|
||||
|
||||
EndpointChannel* endpoint_channel =
|
||||
pending_connections_
|
||||
.emplace(endpoint_id, std::move(pending_connection_info))
|
||||
.first->second.channel.get();
|
||||
std::shared_ptr<EndpointChannel> channel_to_close_on_failure =
|
||||
pending_connection_info.channel;
|
||||
auto [it, inserted] = pending_connections_.emplace(
|
||||
endpoint_id, std::move(pending_connection_info));
|
||||
if (!inserted) {
|
||||
LOG(ERROR) << "Failed to add outgoing connection to pending set; "
|
||||
"endpoint_id="
|
||||
<< endpoint_id
|
||||
<< ". Likely a collision with an existing pending "
|
||||
"connection.";
|
||||
if (channel_to_close_on_failure) {
|
||||
channel_to_close_on_failure->Close(
|
||||
location::nearby::proto::connections::DisconnectionReason::
|
||||
IO_ERROR);
|
||||
}
|
||||
result->Set({Status::kEndpointIoError});
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel = it->second.channel;
|
||||
|
||||
LOG(INFO) << "Initiating secure connection: endpoint_id="
|
||||
<< endpoint_id;
|
||||
// Next, we'll set up encryption. When it's done, our future will return
|
||||
// and RequestConnection() will finish.
|
||||
encryption_runner_.StartClient(client, endpoint_id, endpoint_channel,
|
||||
GetResultListener());
|
||||
GetResultListener(endpoint_channel));
|
||||
});
|
||||
LOG(INFO) << "Waiting for connection to complete: endpoint_id="
|
||||
<< endpoint_id;
|
||||
@@ -1152,10 +1203,25 @@ Status BasePcpHandler::RequestConnectionV3(
|
||||
pending_connection_info.medium = channel->GetMedium();
|
||||
pending_connection_info.channel = std::move(channel);
|
||||
|
||||
EndpointChannel* endpoint_channel =
|
||||
pending_connections_
|
||||
.emplace(endpoint_id, std::move(pending_connection_info))
|
||||
.first->second.channel.get();
|
||||
std::shared_ptr<EndpointChannel> channel_to_close_on_failure =
|
||||
pending_connection_info.channel;
|
||||
auto [it, inserted] = pending_connections_.emplace(
|
||||
endpoint_id, std::move(pending_connection_info));
|
||||
if (!inserted) {
|
||||
LOG(ERROR) << "Failed to add outgoing connection to pending set; "
|
||||
"endpoint_id="
|
||||
<< endpoint_id
|
||||
<< ". Likely a collision with an existing pending "
|
||||
"connection.";
|
||||
if (channel_to_close_on_failure) {
|
||||
channel_to_close_on_failure->Close(
|
||||
location::nearby::proto::connections::DisconnectionReason::
|
||||
IO_ERROR);
|
||||
}
|
||||
result->Set({Status::kEndpointIoError});
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel = it->second.channel;
|
||||
|
||||
LOG(INFO) << "Initiating secure connection: endpoint_id="
|
||||
<< endpoint_id;
|
||||
@@ -1165,7 +1231,7 @@ Status BasePcpHandler::RequestConnectionV3(
|
||||
encryption_runner_.StartClient(
|
||||
client, endpoint_id, endpoint_channel,
|
||||
GetResultListenerV3(*(client->GetLocalDeviceProvider()),
|
||||
remote_device, *endpoint_channel));
|
||||
remote_device, endpoint_channel));
|
||||
});
|
||||
LOG(INFO) << "Waiting for connection to complete: endpoint_id="
|
||||
<< endpoint_id;
|
||||
@@ -2133,14 +2199,23 @@ Exception BasePcpHandler::OnIncomingConnection(
|
||||
pending_connection_info.medium = channel->GetMedium();
|
||||
pending_connection_info.channel = std::move(channel);
|
||||
|
||||
auto* owned_channel = pending_connections_
|
||||
.emplace(connection_request.endpoint_id(),
|
||||
std::move(pending_connection_info))
|
||||
.first->second.channel.get();
|
||||
auto [it, inserted] = pending_connections_.emplace(
|
||||
connection_request.endpoint_id(), std::move(pending_connection_info));
|
||||
// This should not happen since BreakTie() above should have checked that
|
||||
// the endpoint_id is not already in pending_connections_.
|
||||
if (!inserted) {
|
||||
LOG(ERROR) << "Failed to add incoming connection to pending set; "
|
||||
"endpoint_id="
|
||||
<< connection_request.endpoint_id()
|
||||
<< ". Likely a collision with an existing pending connection.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel = it->second.channel;
|
||||
|
||||
// Next, we'll set up encryption.
|
||||
encryption_runner_.StartServer(client, connection_request.endpoint_id(),
|
||||
owned_channel, GetResultListener());
|
||||
endpoint_channel,
|
||||
GetResultListener(endpoint_channel));
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
|
||||
@@ -476,11 +476,11 @@ class BasePcpHandler : public PcpHandler,
|
||||
// Only (possibly) vector for incoming connections.
|
||||
std::vector<location::nearby::proto::connections::Medium> supported_mediums;
|
||||
|
||||
// Keep track of a channel before we pass it to EndpointChannelManager. This
|
||||
// is owned until the call to OnEncryptionSuccessRunnableV3 or
|
||||
// OnEncryptionSuccessRunnable when ownership is transferred to the
|
||||
// EndpointManager.
|
||||
std::unique_ptr<EndpointChannel> channel;
|
||||
// Keep track of a channel before it is registered with the
|
||||
// EndpointManager. This reference is held during the handshake phase and
|
||||
// passed to the EndpointManager upon successful encryption
|
||||
// (OnEncryptionSuccessRunnableV3 or OnEncryptionSuccessRunnable).
|
||||
std::shared_ptr<EndpointChannel> channel;
|
||||
|
||||
// Crypto context; initially empty; established first thing after channel
|
||||
// creation by running UKey2 session. While it is in progress, we keep track
|
||||
@@ -509,24 +509,27 @@ class BasePcpHandler : public PcpHandler,
|
||||
void OnEncryptionFailureImpl(const std::string& endpoint_id,
|
||||
EndpointChannel* channel);
|
||||
|
||||
EncryptionRunner::ResultListener GetResultListener();
|
||||
EncryptionRunner::ResultListener GetResultListener(
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel);
|
||||
EncryptionRunner::ResultListener GetResultListenerV3(
|
||||
const NearbyDeviceProvider& device_provider,
|
||||
const NearbyDevice& remote_device,
|
||||
const EndpointChannel& endpoint_channel);
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel);
|
||||
|
||||
void OnEncryptionSuccessRunnable(
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
|
||||
const std::string& auth_token, const ByteArray& raw_auth_token);
|
||||
const std::string& auth_token, const ByteArray& raw_auth_token,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel);
|
||||
void OnEncryptionSuccessRunnableV3(
|
||||
const NearbyDevice& remote_device,
|
||||
std::unique_ptr<::securegcm::UKey2Handshake> ukey2,
|
||||
absl::string_view auth_token, const ByteArray& raw_auth_token,
|
||||
const EndpointChannel& endpoint_channel,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
const NearbyDeviceProvider& device_provider);
|
||||
void OnEncryptionFailureRunnable(const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel);
|
||||
void OnEncryptionFailureRunnable(
|
||||
const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel);
|
||||
void RegisterDeviceAfterEncryptionSuccess(
|
||||
std::string_view endpoint_id,
|
||||
std::unique_ptr<::securegcm::UKey2Handshake> ukey2,
|
||||
|
||||
@@ -460,9 +460,7 @@ class BasePcpHandlerTest
|
||||
MacAddress::FromString("12:34:56:78:9a:bc", remote_mac_address_);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
env_.Stop();
|
||||
}
|
||||
void TearDown() override { env_.Stop(); }
|
||||
|
||||
void StartAdvertising(ClientProxy* client, MockPcpHandler* pcp_handler,
|
||||
BooleanMediumSelector allowed = GetParam()) {
|
||||
@@ -645,7 +643,7 @@ class BasePcpHandlerTest
|
||||
void RequestConnection(
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<MockEndpointChannel> channel_a,
|
||||
MockEndpointChannel* channel_b, ClientProxy* client,
|
||||
std::shared_ptr<MockEndpointChannel> channel_b, ClientProxy* client,
|
||||
MockPcpHandler* pcp_handler,
|
||||
location::nearby::proto::connections::Medium connect_medium,
|
||||
std::atomic_int* flag = nullptr,
|
||||
@@ -715,7 +713,7 @@ class BasePcpHandlerTest
|
||||
void RequestConnectionV3(
|
||||
const NearbyDevice& remote_device,
|
||||
std::unique_ptr<MockEndpointChannel> channel_a,
|
||||
MockEndpointChannel* channel_b, ClientProxy* client,
|
||||
std::shared_ptr<MockEndpointChannel> channel_b, ClientProxy* client,
|
||||
MockPcpHandler* pcp_handler,
|
||||
location::nearby::proto::connections::Medium connect_medium,
|
||||
FakePresenceDeviceProvider* fake_presence_device_provider,
|
||||
@@ -795,7 +793,7 @@ class BasePcpHandlerTest
|
||||
void RequestConnectionWifiLanFail(
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<MockEndpointChannel> channel_a,
|
||||
MockEndpointChannel* channel_b, ClientProxy* client,
|
||||
std::shared_ptr<MockEndpointChannel> channel_b, ClientProxy* client,
|
||||
MockPcpHandler* pcp_handler, std::atomic_int* flag = nullptr,
|
||||
Status expected_result = {Status::kSuccess}) {
|
||||
ConnectionRequestInfo info{
|
||||
@@ -1136,12 +1134,13 @@ TEST_F(BasePcpHandlerTest, WifiMediumFailFallBackToBT) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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));
|
||||
RequestConnectionWifiLanFail(endpoint_id, std::move(channel_a),
|
||||
channel_b.get(), client_.get(), &pcp_handler);
|
||||
RequestConnectionWifiLanFail(endpoint_id, std::move(channel_a), channel_b,
|
||||
client_.get(), &pcp_handler);
|
||||
LOG(INFO) << "RequestConnection complete";
|
||||
channel_b->Close();
|
||||
bwu.Shutdown();
|
||||
@@ -1161,12 +1160,13 @@ TEST_P(BasePcpHandlerTest, RequestConnectionChangesState) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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("1234", std::move(channel_a), channel_b.get(),
|
||||
client_.get(), &pcp_handler, connect_medium);
|
||||
RequestConnection("1234", std::move(channel_a), channel_b, client_.get(),
|
||||
&pcp_handler, connect_medium);
|
||||
LOG(INFO) << "RequestConnection complete";
|
||||
EXPECT_TRUE(pcp_handler.HasOutgoingConnections(client_.get()));
|
||||
EXPECT_FALSE(pcp_handler.HasIncomingConnections(client_.get()));
|
||||
@@ -1207,12 +1207,13 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionPresence) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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("1234", std::move(channel_a), channel_b.get(),
|
||||
client_.get(), &pcp_handler, connect_medium);
|
||||
RequestConnection("1234", std::move(channel_a), channel_b, client_.get(),
|
||||
&pcp_handler, connect_medium);
|
||||
LOG(INFO) << "RequestConnection complete";
|
||||
channel_b->Close();
|
||||
bwu.Shutdown();
|
||||
@@ -1236,12 +1237,13 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionLegacy) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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("1234", std::move(channel_a), channel_b.get(),
|
||||
client_.get(), &pcp_handler, connect_medium);
|
||||
RequestConnection("1234", std::move(channel_a), channel_b, client_.get(),
|
||||
&pcp_handler, connect_medium);
|
||||
LOG(INFO) << "RequestConnection complete";
|
||||
channel_b->Close();
|
||||
bwu.Shutdown();
|
||||
@@ -1266,11 +1268,12 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
const auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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));
|
||||
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b.get(),
|
||||
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b,
|
||||
client_.get(), &pcp_handler, connect_medium, &provider);
|
||||
LOG(INFO) << "RequestConnectionV3 complete";
|
||||
channel_b->Close();
|
||||
@@ -1297,12 +1300,13 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_AuthenticationFailure) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
const auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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));
|
||||
RequestConnectionV3(
|
||||
mock_device_, std::move(channel_a), channel_b.get(), client_.get(),
|
||||
mock_device_, std::move(channel_a), channel_b, client_.get(),
|
||||
&pcp_handler, connect_medium, &provider, /*flag=*/nullptr,
|
||||
/*expected_result=*/{Status::kSuccess},
|
||||
/*expected_authentication_status=*/AuthenticationStatus::kFailure);
|
||||
@@ -1328,7 +1332,8 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) {
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums(client_.get());
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnectionForConnectFailure(connect_medium);
|
||||
const auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(channel_pair.second);
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
|
||||
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
|
||||
ConnectionRequestInfo info{
|
||||
@@ -1403,7 +1408,8 @@ TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) {
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums(client_.get());
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnectionForConnectFailure(connect_medium);
|
||||
const auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(channel_pair.second);
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(1);
|
||||
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
|
||||
ConnectionRequestInfo info{
|
||||
@@ -1475,12 +1481,13 @@ TEST_P(BasePcpHandlerTest, IoError_RequestConnectionV3Fails) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(channel_pair.second);
|
||||
EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1));
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1));
|
||||
channel_b->broken_write_ = true;
|
||||
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
|
||||
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b.get(),
|
||||
RequestConnectionV3(mock_device_, std::move(channel_a), channel_b,
|
||||
client_.get(), &pcp_handler, connect_medium, nullptr,
|
||||
nullptr, {Status::kEndpointIoError});
|
||||
LOG(INFO) << "RequestConnectionV3 complete";
|
||||
@@ -1503,13 +1510,14 @@ TEST_P(BasePcpHandlerTest, IoError_RequestConnectionFails) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(channel_pair.second);
|
||||
EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1));
|
||||
EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1));
|
||||
channel_b->broken_write_ = true;
|
||||
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0));
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(),
|
||||
client_.get(), &pcp_handler, connect_medium, nullptr,
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(),
|
||||
&pcp_handler, connect_medium, nullptr,
|
||||
{Status::kEndpointIoError});
|
||||
LOG(INFO) << "RequestConnection complete";
|
||||
channel_b->Close();
|
||||
@@ -1531,11 +1539,12 @@ TEST_P(BasePcpHandlerTest, AcceptConnectionChangesState) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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_.get(), &pcp_handler, connect_medium);
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(),
|
||||
&pcp_handler, connect_medium);
|
||||
LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id;
|
||||
EXPECT_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}),
|
||||
Status{Status::kSuccess});
|
||||
@@ -1559,9 +1568,10 @@ TEST_P(BasePcpHandlerTest, RejectConnectionChangesState) {
|
||||
auto mediums = pcp_handler.GetDiscoveryMediums(client_.get());
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(channel_pair.second);
|
||||
EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(1);
|
||||
RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b.get(),
|
||||
RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b,
|
||||
client_.get(), &pcp_handler, connect_medium);
|
||||
LOG(INFO) << "Attempting to reject connection: id=" << endpoint_id;
|
||||
EXPECT_EQ(pcp_handler.RejectConnection(client_.get(), endpoint_id),
|
||||
@@ -1587,11 +1597,12 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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_.get(), &pcp_handler, connect_medium);
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(),
|
||||
&pcp_handler, connect_medium);
|
||||
LOG(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)
|
||||
@@ -1628,10 +1639,11 @@ TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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(),
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b,
|
||||
client_.get(), &pcp_handler, connect_medium,
|
||||
&destroyed_flag);
|
||||
mediums_count = mediums.size();
|
||||
@@ -1670,11 +1682,12 @@ TEST_P(BasePcpHandlerTest, MultipleMediumsProduceSingleEndpointLostEvent) {
|
||||
auto connect_medium = mediums[mediums.size() - 1];
|
||||
auto channel_pair = SetupConnection(connect_medium);
|
||||
auto& channel_a = channel_pair.first;
|
||||
auto& channel_b = channel_pair.second;
|
||||
std::shared_ptr<MockEndpointChannel> channel_b =
|
||||
std::move(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(),
|
||||
RequestConnection(endpoint_id, std::move(channel_a), channel_b,
|
||||
client_.get(), &pcp_handler, connect_medium,
|
||||
&destroyed_flag);
|
||||
auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get());
|
||||
@@ -2543,7 +2556,8 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithPresence) {
|
||||
}
|
||||
|
||||
TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) {
|
||||
env_.Start();
|
||||
env_.Start({.use_simulated_clock = true});
|
||||
client_ = std::make_unique<ClientProxy>(&mock_event_logger_);
|
||||
Mediums m;
|
||||
EndpointChannelManager ecm;
|
||||
EndpointManager em(&ecm);
|
||||
@@ -2600,7 +2614,6 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) {
|
||||
)pb";
|
||||
absl::string_view client_session_log = R"pb(
|
||||
event_type: CLIENT_SESSION
|
||||
client_session { duration_millis: 0 }
|
||||
version: "v1.5.0"
|
||||
)pb";
|
||||
EXPECT_CALL(mock_event_logger_,
|
||||
@@ -2615,9 +2628,8 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) {
|
||||
Log(Matcher<const ConnectionsLog&>(
|
||||
HasEventType(EventType::START_CLIENT_SESSION))))
|
||||
.Times(3);
|
||||
EXPECT_CALL(
|
||||
mock_event_logger_,
|
||||
Log(Matcher<const ConnectionsLog&>(EqualsProto(client_session_log))))
|
||||
EXPECT_CALL(mock_event_logger_, Log(Matcher<const ConnectionsLog&>(Partially(
|
||||
EqualsProto(client_session_log)))))
|
||||
.Times(2);
|
||||
EXPECT_CALL(mock_event_logger_, Log(Matcher<const ConnectionsLog&>(
|
||||
Partially(EqualsProto(expected_log)))));
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
#include "connections/implementation/connections_authentication_transport.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "connections/implementation/endpoint_channel.h"
|
||||
@@ -24,19 +26,18 @@ namespace nearby {
|
||||
namespace connections {
|
||||
|
||||
ConnectionsAuthenticationTransport::ConnectionsAuthenticationTransport(
|
||||
const EndpointChannel& channel) {
|
||||
channel_ = const_cast<EndpointChannel*>(&channel);
|
||||
}
|
||||
std::shared_ptr<EndpointChannel> channel)
|
||||
: channel_(std::move(channel)) {}
|
||||
|
||||
void ConnectionsAuthenticationTransport::WriteMessage(
|
||||
absl::string_view message) const {
|
||||
// channel_ should never be null.
|
||||
// channel_ is guaranteed valid by shared_ptr ownership
|
||||
CHECK(channel_ != nullptr);
|
||||
channel_->Write(message);
|
||||
}
|
||||
|
||||
std::string ConnectionsAuthenticationTransport::ReadMessage() const {
|
||||
// channel_ should never be null.
|
||||
// channel_ is guaranteed valid by shared_ptr ownership
|
||||
CHECK(channel_ != nullptr);
|
||||
auto response = channel_->Read();
|
||||
if (response.ok()) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_CONNECTIONS_AUTHENTICATION_TRANSPORT_H_
|
||||
#define THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_CONNECTIONS_AUTHENTICATION_TRANSPORT_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
@@ -30,12 +31,13 @@ namespace connections {
|
||||
class ConnectionsAuthenticationTransport
|
||||
: public nearby::AuthenticationTransport {
|
||||
public:
|
||||
explicit ConnectionsAuthenticationTransport(const EndpointChannel& channel);
|
||||
explicit ConnectionsAuthenticationTransport(
|
||||
std::shared_ptr<EndpointChannel> channel);
|
||||
void WriteMessage(absl::string_view message) const override;
|
||||
std::string ReadMessage() const override;
|
||||
|
||||
private:
|
||||
EndpointChannel* channel_;
|
||||
std::shared_ptr<EndpointChannel> channel_;
|
||||
};
|
||||
|
||||
} // namespace connections
|
||||
|
||||
@@ -85,35 +85,38 @@ class MockEndpointChannel : public EndpointChannel {
|
||||
};
|
||||
|
||||
TEST(ConnectionsAuthenticationTransportTest, TestWriteMessage) {
|
||||
MockEndpointChannel channel;
|
||||
auto channel = std::make_shared<MockEndpointChannel>();
|
||||
auto* channel_ptr = channel.get();
|
||||
ConnectionsAuthenticationTransport transport(channel);
|
||||
EXPECT_CALL(channel, Write(_)).WillOnce([&channel](absl::string_view data) {
|
||||
channel.messages_.push_back(std::string(data));
|
||||
return Exception{
|
||||
.value = Exception::Value::kSuccess,
|
||||
};
|
||||
});
|
||||
EXPECT_CALL(*channel, Write(_))
|
||||
.WillOnce([channel_ptr](absl::string_view data) {
|
||||
channel_ptr->messages_.push_back(std::string(data));
|
||||
return Exception{
|
||||
.value = Exception::Value::kSuccess,
|
||||
};
|
||||
});
|
||||
transport.WriteMessage("hello world");
|
||||
EXPECT_THAT(channel.messages_, testing::ElementsAre("hello world"));
|
||||
EXPECT_THAT(channel_ptr->messages_, testing::ElementsAre("hello world"));
|
||||
}
|
||||
|
||||
TEST(ConnectionsAuthenticationTransportTest, TestReadMessage) {
|
||||
MockEndpointChannel channel;
|
||||
auto channel = std::make_shared<MockEndpointChannel>();
|
||||
auto* channel_ptr = channel.get();
|
||||
ConnectionsAuthenticationTransport transport(channel);
|
||||
channel.messages_.push_back("hello world");
|
||||
EXPECT_CALL(channel, Read()).WillOnce([&channel]() {
|
||||
std::string ret = channel.messages_[0];
|
||||
channel.messages_.erase(channel.messages_.begin());
|
||||
channel_ptr->messages_.push_back("hello world");
|
||||
EXPECT_CALL(*channel, Read()).WillOnce([channel_ptr]() {
|
||||
std::string ret = channel_ptr->messages_[0];
|
||||
channel_ptr->messages_.erase(channel_ptr->messages_.begin());
|
||||
return ExceptionOr<ByteArray>(ByteArray(ret));
|
||||
});
|
||||
EXPECT_EQ(transport.ReadMessage(), "hello world");
|
||||
}
|
||||
|
||||
TEST(ConnectionsAuthenticationTransportTest, TestReadMessageFail) {
|
||||
MockEndpointChannel channel;
|
||||
auto channel = std::make_shared<MockEndpointChannel>();
|
||||
ConnectionsAuthenticationTransport transport(channel);
|
||||
channel.messages_.push_back("hello world");
|
||||
EXPECT_CALL(channel, Read()).WillOnce([]() {
|
||||
channel->messages_.push_back("hello world");
|
||||
EXPECT_CALL(*channel, Read()).WillOnce([]() {
|
||||
return ExceptionOr<ByteArray>(Exception::Value::kIo);
|
||||
});
|
||||
EXPECT_EQ(transport.ReadMessage(), "");
|
||||
|
||||
@@ -68,9 +68,9 @@ bool HandleEncryptionSuccess(const std::string& endpoint_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
void CancelableAlarmRunnable(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel) {
|
||||
void CancelableAlarmRunnable(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel) {
|
||||
LOG(INFO) << "Timing out encryption for client " << client->GetClientId()
|
||||
<< " to endpoint_id=" << endpoint_id << " after "
|
||||
<< absl::FormatDuration(kTimeout);
|
||||
@@ -80,18 +80,31 @@ void CancelableAlarmRunnable(ClientProxy* client,
|
||||
class ServerRunnable final {
|
||||
public:
|
||||
ServerRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor,
|
||||
const std::string& endpoint_id, EndpointChannel* channel,
|
||||
const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> channel,
|
||||
EncryptionRunner::ResultListener listener)
|
||||
: client_(client),
|
||||
alarm_executor_(alarm_executor),
|
||||
endpoint_id_(endpoint_id),
|
||||
channel_(channel),
|
||||
weak_channel_(channel),
|
||||
listener_(std::move(listener)) {}
|
||||
|
||||
void operator()() {
|
||||
// Lock the weak pointer. If it fails, the channel was freed.
|
||||
auto channel = weak_channel_.lock();
|
||||
// The IsClosed() check is to provide an early exit if channel has been
|
||||
// closed. Otherwise the Read() and Write() calls on the channel below will
|
||||
// return error and exit.
|
||||
if (!channel || channel->IsClosed()) {
|
||||
return;
|
||||
}
|
||||
CancelableAlarm timeout_alarm(
|
||||
"EncryptionRunner.StartServer() timeout",
|
||||
[this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); },
|
||||
[this, weak_channel = weak_channel_]() {
|
||||
if (auto channel = weak_channel.lock()) {
|
||||
CancelableAlarmRunnable(client_, endpoint_id_, channel);
|
||||
}
|
||||
},
|
||||
kTimeout, alarm_executor_);
|
||||
|
||||
std::unique_ptr<securegcm::UKey2Handshake> server =
|
||||
@@ -103,7 +116,7 @@ class ServerRunnable final {
|
||||
}
|
||||
|
||||
// Message 1 (Client Init)
|
||||
ExceptionOr<ByteArray> client_init = channel_->Read();
|
||||
ExceptionOr<ByteArray> client_init = channel->Read();
|
||||
if (!client_init.ok()) {
|
||||
LogException();
|
||||
HandleHandshakeOrIoException(&timeout_alarm);
|
||||
@@ -117,7 +130,7 @@ class ServerRunnable final {
|
||||
if (!parse_result.success) {
|
||||
LogException();
|
||||
if (parse_result.alert_to_send != nullptr) {
|
||||
HandleAlertException(parse_result);
|
||||
HandleAlertException(parse_result, channel);
|
||||
}
|
||||
HandleHandshakeOrIoException(&timeout_alarm);
|
||||
return;
|
||||
@@ -137,7 +150,7 @@ class ServerRunnable final {
|
||||
return;
|
||||
}
|
||||
|
||||
Exception write_exception = channel_->Write(*server_init);
|
||||
Exception write_exception = channel->Write(*server_init);
|
||||
if (!write_exception.Ok()) {
|
||||
LogException();
|
||||
HandleHandshakeOrIoException(&timeout_alarm);
|
||||
@@ -148,7 +161,7 @@ class ServerRunnable final {
|
||||
<< endpoint_id_ << ").";
|
||||
|
||||
// Message 3 (Client Finish)
|
||||
ExceptionOr<ByteArray> client_finish = channel_->Read();
|
||||
ExceptionOr<ByteArray> client_finish = channel->Read();
|
||||
|
||||
if (!client_finish.ok()) {
|
||||
LogException();
|
||||
@@ -163,7 +176,7 @@ class ServerRunnable final {
|
||||
if (!parse_result.success) {
|
||||
LogException();
|
||||
if (parse_result.alert_to_send != nullptr) {
|
||||
HandleAlertException(parse_result);
|
||||
HandleAlertException(parse_result, channel);
|
||||
}
|
||||
HandleHandshakeOrIoException(&timeout_alarm);
|
||||
return;
|
||||
@@ -189,13 +202,13 @@ class ServerRunnable final {
|
||||
|
||||
void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) {
|
||||
timeout_alarm->Cancel();
|
||||
listener_.CallFailureCallback(endpoint_id_, channel_);
|
||||
listener_.CallFailureCallback(endpoint_id_);
|
||||
}
|
||||
|
||||
void HandleAlertException(
|
||||
const securegcm::UKey2Handshake::ParseResult& parse_result) const {
|
||||
Exception write_exception =
|
||||
channel_->Write(*parse_result.alert_to_send);
|
||||
const securegcm::UKey2Handshake::ParseResult& parse_result,
|
||||
std::shared_ptr<EndpointChannel> channel) const {
|
||||
Exception write_exception = channel->Write(*parse_result.alert_to_send);
|
||||
if (!write_exception.Ok()) {
|
||||
LOG(WARNING) << "In StartServer(), client " << client_->GetClientId()
|
||||
<< " failed to pass the alert error message to endpoint(id="
|
||||
@@ -206,25 +219,39 @@ class ServerRunnable final {
|
||||
ClientProxy* client_;
|
||||
ScheduledExecutor* alarm_executor_;
|
||||
const std::string endpoint_id_;
|
||||
EndpointChannel* channel_;
|
||||
std::weak_ptr<EndpointChannel> weak_channel_;
|
||||
EncryptionRunner::ResultListener listener_;
|
||||
};
|
||||
|
||||
class ClientRunnable final {
|
||||
public:
|
||||
ClientRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor,
|
||||
const std::string& endpoint_id, EndpointChannel* channel,
|
||||
const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> channel,
|
||||
EncryptionRunner::ResultListener listener)
|
||||
: client_(client),
|
||||
alarm_executor_(alarm_executor),
|
||||
endpoint_id_(endpoint_id),
|
||||
channel_(channel),
|
||||
weak_channel_(channel),
|
||||
listener_(std::move(listener)) {}
|
||||
|
||||
void operator()() {
|
||||
// Lock the weak pointer. If it fails, the channel was freed.
|
||||
auto channel = weak_channel_.lock();
|
||||
// The IsClosed() check is to provide an early exit if channel has been
|
||||
// closed. Otherwise the Read() and Write() calls on the channel below will
|
||||
// return error and exit.
|
||||
if (!channel || channel->IsClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CancelableAlarm timeout_alarm(
|
||||
"EncryptionRunner.StartClient() timeout",
|
||||
[this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); },
|
||||
[this, weak_channel = weak_channel_]() {
|
||||
if (auto channel = weak_channel.lock()) {
|
||||
CancelableAlarmRunnable(client_, endpoint_id_, channel);
|
||||
}
|
||||
},
|
||||
kTimeout, alarm_executor_);
|
||||
|
||||
std::unique_ptr<securegcm::UKey2Handshake> crypto =
|
||||
@@ -248,7 +275,7 @@ class ClientRunnable final {
|
||||
return;
|
||||
}
|
||||
|
||||
Exception write_init_exception = channel_->Write(*client_init);
|
||||
Exception write_init_exception = channel->Write(*client_init);
|
||||
if (!write_init_exception.Ok()) {
|
||||
LogException();
|
||||
HandleHandshakeOrIoException(&timeout_alarm);
|
||||
@@ -259,7 +286,7 @@ class ClientRunnable final {
|
||||
<< endpoint_id_ << ").";
|
||||
|
||||
// Message 2 (Server Init)
|
||||
ExceptionOr<ByteArray> server_init = channel_->Read();
|
||||
ExceptionOr<ByteArray> server_init = channel->Read();
|
||||
|
||||
if (!server_init.ok()) {
|
||||
LogException();
|
||||
@@ -274,7 +301,7 @@ class ClientRunnable final {
|
||||
if (!parse_result.success) {
|
||||
LogException();
|
||||
if (parse_result.alert_to_send != nullptr) {
|
||||
HandleAlertException(parse_result);
|
||||
HandleAlertException(parse_result, channel);
|
||||
}
|
||||
HandleHandshakeOrIoException(&timeout_alarm);
|
||||
return;
|
||||
@@ -294,8 +321,7 @@ class ClientRunnable final {
|
||||
return;
|
||||
}
|
||||
|
||||
Exception write_finish_exception =
|
||||
channel_->Write(*client_finish);
|
||||
Exception write_finish_exception = channel->Write(*client_finish);
|
||||
if (!write_finish_exception.Ok()) {
|
||||
LogException();
|
||||
HandleHandshakeOrIoException(&timeout_alarm);
|
||||
@@ -322,12 +348,13 @@ class ClientRunnable final {
|
||||
|
||||
void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) {
|
||||
timeout_alarm->Cancel();
|
||||
listener_.CallFailureCallback(endpoint_id_, channel_);
|
||||
listener_.CallFailureCallback(endpoint_id_);
|
||||
}
|
||||
|
||||
void HandleAlertException(
|
||||
const securegcm::UKey2Handshake::ParseResult& parse_result) const {
|
||||
Exception write_exception = channel_->Write(*parse_result.alert_to_send);
|
||||
const securegcm::UKey2Handshake::ParseResult& parse_result,
|
||||
std::shared_ptr<EndpointChannel> channel) const {
|
||||
Exception write_exception = channel->Write(*parse_result.alert_to_send);
|
||||
if (!write_exception.Ok()) {
|
||||
LOG(WARNING) << "In StartClient(), client " << client_->GetClientId()
|
||||
<< " failed to pass the alert error message to endpoint(id="
|
||||
@@ -338,7 +365,7 @@ class ClientRunnable final {
|
||||
ClientProxy* client_;
|
||||
ScheduledExecutor* alarm_executor_;
|
||||
const std::string endpoint_id_;
|
||||
EndpointChannel* channel_;
|
||||
std::weak_ptr<EndpointChannel> weak_channel_;
|
||||
EncryptionRunner::ResultListener listener_;
|
||||
};
|
||||
|
||||
@@ -346,19 +373,19 @@ class ClientRunnable final {
|
||||
|
||||
EncryptionRunner::~EncryptionRunner() { Shutdown(); }
|
||||
|
||||
void EncryptionRunner::StartServer(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
EncryptionRunner::ResultListener listener) {
|
||||
void EncryptionRunner::StartServer(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
EncryptionRunner::ResultListener listener) {
|
||||
ServerRunnable runnable(client, &alarm_executor_, endpoint_id,
|
||||
endpoint_channel, std::move(listener));
|
||||
server_executor_.Execute("encryption-server", std::move(runnable));
|
||||
}
|
||||
|
||||
void EncryptionRunner::StartClient(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
EncryptionRunner::ResultListener listener) {
|
||||
void EncryptionRunner::StartClient(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
EncryptionRunner::ResultListener listener) {
|
||||
ClientRunnable runnable(client, &alarm_executor_, endpoint_id,
|
||||
endpoint_channel, std::move(listener));
|
||||
client_executor_.Execute("encryption-client", std::move(runnable));
|
||||
@@ -387,9 +414,9 @@ void EncryptionRunner::ResultListener::CallSuccessCallback(
|
||||
}
|
||||
|
||||
void EncryptionRunner::ResultListener::CallFailureCallback(
|
||||
const std::string& endpoint_id, EndpointChannel* channel) {
|
||||
const std::string& endpoint_id) {
|
||||
if (on_failure_cb) {
|
||||
std::move(on_failure_cb)(endpoint_id, channel);
|
||||
std::move(on_failure_cb)(endpoint_id);
|
||||
}
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -45,8 +45,7 @@ class EncryptionRunner {
|
||||
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
|
||||
const std::string& auth_token,
|
||||
const ByteArray& raw_auth_token);
|
||||
void CallFailureCallback(const std::string& endpoint_id,
|
||||
EndpointChannel* channel);
|
||||
void CallFailureCallback(const std::string& endpoint_id);
|
||||
void Reset();
|
||||
|
||||
// @EncryptionRunnerThread
|
||||
@@ -56,27 +55,19 @@ class EncryptionRunner {
|
||||
const ByteArray& raw_auth_token) &&>
|
||||
on_success_cb;
|
||||
|
||||
// Encryption has failed. The remote_endpoint_id and channel are given so
|
||||
// that any pending state can be cleaned up.
|
||||
//
|
||||
// We return the EndpointChannel because, at this stage, simultaneous
|
||||
// connections are a possibility. Use this channel to verify that the state
|
||||
// you're cleaning up is for this EndpointChannel, and not state for another
|
||||
// channel to the same endpoint.
|
||||
// Encryption has failed.
|
||||
//
|
||||
// @EncryptionRunnerThread
|
||||
absl::AnyInvocable<void(const std::string& endpoint_id,
|
||||
EndpointChannel* channel) &&>
|
||||
on_failure_cb;
|
||||
absl::AnyInvocable<void(const std::string& endpoint_id)> on_failure_cb;
|
||||
};
|
||||
|
||||
// @AnyThread
|
||||
void StartServer(ClientProxy* client, const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
ResultListener result_listener);
|
||||
// @AnyThread
|
||||
void StartClient(ClientProxy* client, const std::string& endpoint_id,
|
||||
EndpointChannel* endpoint_channel,
|
||||
std::shared_ptr<EndpointChannel> endpoint_channel,
|
||||
ResultListener result_listener);
|
||||
|
||||
// @AnyThread
|
||||
|
||||
@@ -123,21 +123,24 @@ class FakeEndpointChannel : public EndpointChannel {
|
||||
};
|
||||
|
||||
struct User {
|
||||
User(InputStream* reader, OutputStream* writer) : channel(reader, writer) {}
|
||||
User(InputStream* reader, OutputStream* writer)
|
||||
: channel(std::make_shared<FakeEndpointChannel>(reader, writer)) {}
|
||||
|
||||
FakeEndpointChannel channel;
|
||||
std::shared_ptr<FakeEndpointChannel> channel;
|
||||
EncryptionRunner crypto;
|
||||
ClientProxy client;
|
||||
};
|
||||
|
||||
struct Response {
|
||||
Response() : latch(2) {}
|
||||
explicit Response(int count) : latch(count) {}
|
||||
enum class Status {
|
||||
kUnknown = 0,
|
||||
kDone = 1,
|
||||
kFailed = 2,
|
||||
};
|
||||
|
||||
CountDownLatch latch{2};
|
||||
CountDownLatch latch;
|
||||
Status server_status = Status::kUnknown;
|
||||
Status client_status = Status::kUnknown;
|
||||
};
|
||||
@@ -154,7 +157,7 @@ TEST(EncryptionRunnerTest, ReadWrite) {
|
||||
Response response;
|
||||
|
||||
user_a.crypto.StartServer(
|
||||
&user_a.client, "endpoint_id", &user_a.channel,
|
||||
&user_a.client, "endpoint_id", user_a.channel,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
@@ -165,15 +168,14 @@ TEST(EncryptionRunnerTest, ReadWrite) {
|
||||
response.latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
channel->Close();
|
||||
[&response, &user_a](const std::string& endpoint_id) {
|
||||
user_a.channel->Close();
|
||||
response.server_status = Response::Status::kFailed;
|
||||
response.latch.CountDown();
|
||||
},
|
||||
});
|
||||
user_b.crypto.StartClient(
|
||||
&user_b.client, "endpoint_id", &user_b.channel,
|
||||
&user_b.client, "endpoint_id", user_b.channel,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
@@ -184,9 +186,8 @@ TEST(EncryptionRunnerTest, ReadWrite) {
|
||||
response.latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
channel->Close();
|
||||
[&response, &user_b](const std::string& endpoint_id) {
|
||||
user_b.channel->Close();
|
||||
response.client_status = Response::Status::kFailed;
|
||||
response.latch.CountDown();
|
||||
},
|
||||
@@ -203,14 +204,13 @@ TEST(EncryptionRunnerTest, ClientWriteFails) {
|
||||
/*writer=*/from_a_to_b.second.get());
|
||||
User user_b(/*reader=*/from_a_to_b.first.get(),
|
||||
/*writer=*/from_b_to_a.second.get());
|
||||
Response response;
|
||||
response.latch = CountDownLatch(1);
|
||||
Response response(1);
|
||||
|
||||
// Close server's input stream, so client can't write to it.
|
||||
from_b_to_a.first->Close();
|
||||
|
||||
user_b.crypto.StartClient(
|
||||
&user_b.client, "endpoint_id", &user_b.channel,
|
||||
&user_b.client, "endpoint_id", user_b.channel,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
@@ -221,9 +221,8 @@ TEST(EncryptionRunnerTest, ClientWriteFails) {
|
||||
response.latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
channel->Close();
|
||||
[&response, &user_a](const std::string& endpoint_id) {
|
||||
user_a.channel->Close();
|
||||
response.client_status = Response::Status::kFailed;
|
||||
response.latch.CountDown();
|
||||
},
|
||||
@@ -239,14 +238,13 @@ TEST(EncryptionRunnerTest, ServerWriteFails) {
|
||||
/*writer=*/from_a_to_b.second.get());
|
||||
User user_b(/*reader=*/from_a_to_b.first.get(),
|
||||
/*writer=*/from_b_to_a.second.get());
|
||||
Response response;
|
||||
response.latch = CountDownLatch(1);
|
||||
Response response(1);
|
||||
|
||||
// Close client's input stream, so server can't write to it.
|
||||
from_a_to_b.first->Close();
|
||||
|
||||
user_a.crypto.StartServer(
|
||||
&user_a.client, "endpoint_id", &user_a.channel,
|
||||
&user_a.client, "endpoint_id", user_a.channel,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
@@ -257,24 +255,22 @@ TEST(EncryptionRunnerTest, ServerWriteFails) {
|
||||
response.latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
channel->Close();
|
||||
[&response, &user_a](const std::string& endpoint_id) {
|
||||
user_a.channel->Close();
|
||||
response.server_status = Response::Status::kFailed;
|
||||
response.latch.CountDown();
|
||||
},
|
||||
});
|
||||
user_b.crypto.StartClient(
|
||||
&user_b.client, "endpoint_id", &user_b.channel,
|
||||
&user_b.client, "endpoint_id", user_b.channel,
|
||||
{
|
||||
.on_success_cb =
|
||||
[](const std::string& endpoint_id,
|
||||
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
|
||||
const std::string& auth_token,
|
||||
const ByteArray& raw_auth_token) {},
|
||||
.on_success_cb = [](const std::string& endpoint_id,
|
||||
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
|
||||
const std::string& auth_token,
|
||||
const ByteArray& raw_auth_token) {},
|
||||
.on_failure_cb =
|
||||
[](const std::string& endpoint_id, EndpointChannel* channel) {
|
||||
channel->Close();
|
||||
[&user_b](const std::string& endpoint_id) {
|
||||
user_b.channel->Close();
|
||||
},
|
||||
});
|
||||
EXPECT_TRUE(response.latch.Await(absl::Milliseconds(5000)).result());
|
||||
@@ -286,11 +282,10 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage1) {
|
||||
auto from_client_to_server = CreatePipe();
|
||||
User user_a(/*reader=*/from_client_to_server.first.get(),
|
||||
/*writer=*/from_server_to_client.second.get());
|
||||
Response response;
|
||||
response.latch = CountDownLatch(1);
|
||||
Response response(1);
|
||||
|
||||
user_a.crypto.StartServer(
|
||||
&user_a.client, "endpoint_id", &user_a.channel,
|
||||
&user_a.client, "endpoint_id", user_a.channel,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
@@ -301,9 +296,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage1) {
|
||||
response.latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
channel->Close();
|
||||
[&response, &user_a](const std::string& endpoint_id) {
|
||||
user_a.channel->Close();
|
||||
response.server_status = Response::Status::kFailed;
|
||||
response.latch.CountDown();
|
||||
},
|
||||
@@ -327,11 +321,10 @@ TEST(EncryptionRunnerTest, ServerSendsGarbageMessage2) {
|
||||
auto from_client_to_server = CreatePipe();
|
||||
User user_b(/*reader=*/from_server_to_client.first.get(),
|
||||
/*writer=*/from_client_to_server.second.get());
|
||||
Response response;
|
||||
response.latch = CountDownLatch(1);
|
||||
Response response(1);
|
||||
|
||||
user_b.crypto.StartClient(
|
||||
&user_b.client, "endpoint_id", &user_b.channel,
|
||||
&user_b.client, "endpoint_id", user_b.channel,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
@@ -342,9 +335,8 @@ TEST(EncryptionRunnerTest, ServerSendsGarbageMessage2) {
|
||||
response.latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
channel->Close();
|
||||
[&response, &user_b](const std::string& endpoint_id) {
|
||||
user_b.channel->Close();
|
||||
response.client_status = Response::Status::kFailed;
|
||||
response.latch.CountDown();
|
||||
},
|
||||
@@ -373,11 +365,10 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) {
|
||||
/*writer=*/from_server_to_client.second.get());
|
||||
User user_b(/*reader=*/from_server_to_client.first.get(),
|
||||
/*writer=*/from_client_to_server.second.get());
|
||||
Response response;
|
||||
response.latch = CountDownLatch(1);
|
||||
Response response(1);
|
||||
|
||||
user_a.crypto.StartServer(
|
||||
&user_a.client, "endpoint_id", &user_a.channel,
|
||||
&user_a.client, "endpoint_id", user_a.channel,
|
||||
{
|
||||
.on_success_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
@@ -388,9 +379,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) {
|
||||
response.latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&response](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
channel->Close();
|
||||
[&response, &user_a](const std::string& endpoint_id) {
|
||||
user_a.channel->Close();
|
||||
response.server_status = Response::Status::kFailed;
|
||||
response.latch.CountDown();
|
||||
},
|
||||
@@ -410,7 +400,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) {
|
||||
EXPECT_TRUE(server_init.ok());
|
||||
|
||||
// Client crypto parses message 2.
|
||||
client_crypto->ParseHandshakeMessage(std::string(server_init.result()));
|
||||
client_crypto->ParseHandshakeMessage(
|
||||
std::string(server_init.result().data(), server_init.result().size()));
|
||||
|
||||
// Client sends garbage instead of message 3
|
||||
from_client_to_server.second->Write("Garbage");
|
||||
|
||||
@@ -46,7 +46,7 @@ EndpointChannelManager::~EndpointChannelManager() {
|
||||
|
||||
void EndpointChannelManager::RegisterChannelForEndpoint(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::unique_ptr<EndpointChannel> channel) {
|
||||
std::shared_ptr<EndpointChannel> channel) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
LOG(INFO) << "EndpointChannelManager registered channel of type "
|
||||
@@ -59,7 +59,7 @@ void EndpointChannelManager::RegisterChannelForEndpoint(
|
||||
|
||||
void EndpointChannelManager::ReplaceChannelForEndpoint(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::unique_ptr<EndpointChannel> channel, bool enable_encryption) {
|
||||
std::shared_ptr<EndpointChannel> channel, bool enable_encryption) {
|
||||
MutexLock lock(&mutex_);
|
||||
if (client->IsSafeToDisconnectEnabled(endpoint_id) &&
|
||||
channel_state_.IsWaitingForSafeToDisconnectTimeout(endpoint_id)) {
|
||||
@@ -106,7 +106,7 @@ std::shared_ptr<EndpointChannel> EndpointChannelManager::GetChannelForEndpoint(
|
||||
|
||||
void EndpointChannelManager::SetActiveEndpointChannel(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
std::unique_ptr<EndpointChannel> channel, bool enable_encryption) {
|
||||
std::shared_ptr<EndpointChannel> channel, bool enable_encryption) {
|
||||
// Update the channel first, then encrypt this new channel, if
|
||||
// crypto context is present.
|
||||
channel->SetAnalyticsRecorder(&client->GetAnalyticsRecorder(), endpoint_id);
|
||||
@@ -189,7 +189,7 @@ void EndpointChannelManager::ChannelState::DestroyAll() {
|
||||
}
|
||||
|
||||
void EndpointChannelManager::ChannelState::UpdateChannelForEndpoint(
|
||||
const std::string& endpoint_id, std::unique_ptr<EndpointChannel> channel) {
|
||||
const std::string& endpoint_id, std::shared_ptr<EndpointChannel> channel) {
|
||||
// Create EndpointData instance, if necessary, and populate channel.
|
||||
endpoints_[endpoint_id].channel = std::move(channel);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ class EndpointChannelManager final {
|
||||
// be closed before continuing the registration.
|
||||
void RegisterChannelForEndpoint(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<EndpointChannel> channel)
|
||||
std::shared_ptr<EndpointChannel> channel)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
// Replaces the EndpointChannel to be associated with an endpoint from here on
|
||||
@@ -67,7 +67,7 @@ class EndpointChannelManager final {
|
||||
// to the newly-provided EndpointChannel.
|
||||
void ReplaceChannelForEndpoint(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<EndpointChannel> channel,
|
||||
std::shared_ptr<EndpointChannel> channel,
|
||||
bool enable_encryption)
|
||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||
|
||||
@@ -168,7 +168,7 @@ class EndpointChannelManager final {
|
||||
// Stores a new EndpointChannel for the endpoint.
|
||||
// Prevoius one is destroyed, if it existed.
|
||||
void UpdateChannelForEndpoint(const std::string& endpoint_id,
|
||||
std::unique_ptr<EndpointChannel> channel);
|
||||
std::shared_ptr<EndpointChannel> channel);
|
||||
|
||||
// Stores a new EncryptionContext for the endpoint.
|
||||
// Prevoius one is destroyed, if it existed.
|
||||
@@ -207,7 +207,7 @@ class EndpointChannelManager final {
|
||||
|
||||
void SetActiveEndpointChannel(ClientProxy* client,
|
||||
const std::string& endpoint_id,
|
||||
std::unique_ptr<EndpointChannel> channel,
|
||||
std::shared_ptr<EndpointChannel> channel,
|
||||
bool enable_encryption)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ std::function<void(const ByteArray&)> MakeDataMonitor(absl::string_view label,
|
||||
|
||||
std::pair<std::unique_ptr<EncryptionContext>,
|
||||
std::unique_ptr<EncryptionContext>>
|
||||
DoDhKeyExchange(BaseEndpointChannel* channel_a,
|
||||
BaseEndpointChannel* channel_b) {
|
||||
DoDhKeyExchange(std::shared_ptr<EndpointChannel> channel_a,
|
||||
std::shared_ptr<EndpointChannel> channel_b) {
|
||||
std::unique_ptr<EncryptionContext> context_a;
|
||||
std::unique_ptr<EncryptionContext> context_b;
|
||||
EncryptionRunner crypto_a;
|
||||
@@ -136,8 +136,7 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a,
|
||||
latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&latch](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
[&latch](const std::string& endpoint_id) {
|
||||
LOG(INFO) << "client-A side key negotiation failed";
|
||||
latch.CountDown();
|
||||
},
|
||||
@@ -159,8 +158,7 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a,
|
||||
latch.CountDown();
|
||||
},
|
||||
.on_failure_cb =
|
||||
[&latch](const std::string& endpoint_id,
|
||||
EndpointChannel* channel) {
|
||||
[&latch](const std::string& endpoint_id) {
|
||||
LOG(INFO) << "client-B side key negotiation failed";
|
||||
latch.CountDown();
|
||||
},
|
||||
@@ -185,9 +183,9 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
|
||||
// to server "b".
|
||||
auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes
|
||||
// to server "a".
|
||||
auto channel_a = std::make_unique<MockEndpointChannel>(server_a.first.get(),
|
||||
auto channel_a = std::make_shared<MockEndpointChannel>(server_a.first.get(),
|
||||
client_a.second.get());
|
||||
auto channel_b = std::make_unique<MockEndpointChannel>(server_b.first.get(),
|
||||
auto channel_b = std::make_shared<MockEndpointChannel>(server_b.first.get(),
|
||||
client_b.second.get());
|
||||
auto channel_a_raw = channel_a.get();
|
||||
auto channel_b_raw = channel_b.get();
|
||||
@@ -208,7 +206,7 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) {
|
||||
MakeDataMonitor(kMonitorB, &capture_b, &mutex)));
|
||||
|
||||
// Run DH key exchange; setup encryption contexts for channels.
|
||||
auto context = DoDhKeyExchange(channel_a.get(), channel_b.get());
|
||||
auto context = DoDhKeyExchange(channel_a, channel_b);
|
||||
ASSERT_NE(context.first, nullptr);
|
||||
ASSERT_NE(context.second, nullptr);
|
||||
|
||||
@@ -266,9 +264,9 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
|
||||
// to server "b".
|
||||
auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes
|
||||
// to server "a".
|
||||
auto channel_a = std::make_unique<MockEndpointChannel>(server_a.first.get(),
|
||||
auto channel_a = std::make_shared<MockEndpointChannel>(server_a.first.get(),
|
||||
client_a.second.get());
|
||||
auto channel_b = std::make_unique<MockEndpointChannel>(server_b.first.get(),
|
||||
auto channel_b = std::make_shared<MockEndpointChannel>(server_b.first.get(),
|
||||
client_b.second.get());
|
||||
auto channel_a_raw = channel_a.get();
|
||||
auto channel_b_raw = channel_b.get();
|
||||
@@ -289,7 +287,7 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) {
|
||||
MakeDataMonitor(kMonitorB, &capture_b, &mutex)));
|
||||
|
||||
// Run DH key exchange; setup encryption contexts for channels.
|
||||
auto context = DoDhKeyExchange(channel_a.get(), channel_b.get());
|
||||
auto context = DoDhKeyExchange(channel_a, channel_b);
|
||||
ASSERT_NE(context.first, nullptr);
|
||||
ASSERT_NE(context.second, nullptr);
|
||||
|
||||
|
||||
@@ -539,103 +539,94 @@ void EndpointManager::RegisterEndpoint(
|
||||
ClientProxy* client, const std::string& endpoint_id,
|
||||
const ConnectionResponseInfo& info,
|
||||
const ConnectionOptions& connection_options,
|
||||
std::unique_ptr<EndpointChannel> channel,
|
||||
std::shared_ptr<EndpointChannel> channel,
|
||||
const ConnectionListener& listener, const std::string& connection_token) {
|
||||
CountDownLatch latch(1);
|
||||
|
||||
// NOTE (unique_ptr<> capture):
|
||||
// std::unique_ptr<> is not copyable, so we can not pass it to
|
||||
// lambda capture, because lambda eventually is converted to
|
||||
// std::function<>. Instead, we release() a pointer, and pass a raw pointer,
|
||||
// which is copyalbe. We ignore the risk of job not scheduled (and an
|
||||
// associated risk of memory leak), because this may only happen during
|
||||
// service shutdown.
|
||||
RunOnEndpointManagerThread(
|
||||
"register-endpoint",
|
||||
[this, client, channel = channel.release(), &endpoint_id, &info,
|
||||
&connection_options, &listener, &connection_token, &latch]() {
|
||||
if (endpoints_.contains(endpoint_id)) {
|
||||
LOG(WARNING) << "Registering duplicate endpoint " << endpoint_id;
|
||||
// We must remove old endpoint state before registering a new one
|
||||
// for the same endpoint_id.
|
||||
RemoveEndpointState(endpoint_id);
|
||||
}
|
||||
RunOnEndpointManagerThread("register-endpoint", [this, client, channel,
|
||||
&endpoint_id, &info,
|
||||
&connection_options,
|
||||
&listener, &connection_token,
|
||||
&latch]() {
|
||||
if (endpoints_.contains(endpoint_id)) {
|
||||
LOG(WARNING) << "Registering duplicate endpoint " << endpoint_id;
|
||||
// We must remove old endpoint state before registering a new one
|
||||
// for the same endpoint_id.
|
||||
RemoveEndpointState(endpoint_id);
|
||||
}
|
||||
|
||||
absl::Duration keep_alive_interval =
|
||||
absl::Milliseconds(connection_options.keep_alive_interval_millis);
|
||||
absl::Duration keep_alive_timeout =
|
||||
absl::Milliseconds(connection_options.keep_alive_timeout_millis);
|
||||
LOG(INFO) << "Registering endpoint " << endpoint_id << " for client "
|
||||
<< client->GetClientId()
|
||||
<< " with keep-alive frame as interval="
|
||||
<< absl::FormatDuration(keep_alive_interval)
|
||||
<< ", timeout=" << absl::FormatDuration(keep_alive_timeout);
|
||||
absl::Duration keep_alive_interval =
|
||||
absl::Milliseconds(connection_options.keep_alive_interval_millis);
|
||||
absl::Duration keep_alive_timeout =
|
||||
absl::Milliseconds(connection_options.keep_alive_timeout_millis);
|
||||
LOG(INFO) << "Registering endpoint " << endpoint_id << " for client "
|
||||
<< client->GetClientId() << " with keep-alive frame as interval="
|
||||
<< absl::FormatDuration(keep_alive_interval)
|
||||
<< ", timeout=" << absl::FormatDuration(keep_alive_timeout);
|
||||
|
||||
// Pass ownership of channel to EndpointChannelManager
|
||||
LOG(INFO) << "Registering endpoint with channel manager: endpoint "
|
||||
<< endpoint_id;
|
||||
channel_manager_->RegisterChannelForEndpoint(
|
||||
client, endpoint_id, std::unique_ptr<EndpointChannel>(channel));
|
||||
// Pass ownership of channel to EndpointChannelManager
|
||||
LOG(INFO) << "Registering endpoint with channel manager: endpoint "
|
||||
<< endpoint_id;
|
||||
channel_manager_->RegisterChannelForEndpoint(client, endpoint_id, channel);
|
||||
|
||||
EndpointState& endpoint_state =
|
||||
endpoints_
|
||||
.emplace(endpoint_id,
|
||||
EndpointState(endpoint_id, channel_manager_))
|
||||
.first->second;
|
||||
EndpointState& endpoint_state =
|
||||
endpoints_
|
||||
.emplace(endpoint_id, EndpointState(endpoint_id, channel_manager_))
|
||||
.first->second;
|
||||
|
||||
LOG(INFO) << "Starting workers: endpoint " << endpoint_id;
|
||||
// For every endpoint, there's normally only one Read handler instance
|
||||
// running on a dedicated thread. This instance reads data from the
|
||||
// endpoint and delegates incoming frames to various FrameProcessors.
|
||||
// Once the frame has been properly handled, it starts reading again
|
||||
// for the next frame. If the handler fails its read and no other
|
||||
// EndpointChannels are available for this endpoint, a disconnection
|
||||
// will be initiated.
|
||||
endpoint_state.StartEndpointReader([this, client, endpoint_id]() {
|
||||
LOG(INFO) << "Starting workers: endpoint " << endpoint_id;
|
||||
// For every endpoint, there's normally only one Read handler instance
|
||||
// running on a dedicated thread. This instance reads data from the
|
||||
// endpoint and delegates incoming frames to various FrameProcessors.
|
||||
// Once the frame has been properly handled, it starts reading again
|
||||
// for the next frame. If the handler fails its read and no other
|
||||
// EndpointChannels are available for this endpoint, a disconnection
|
||||
// will be initiated.
|
||||
endpoint_state.StartEndpointReader([this, client, endpoint_id]() {
|
||||
EndpointChannelLoopRunnable(
|
||||
"Read", client, endpoint_id,
|
||||
[this, client, endpoint_id](EndpointChannel* channel) {
|
||||
return HandleData(endpoint_id, client, channel);
|
||||
});
|
||||
});
|
||||
|
||||
// For every endpoint, there's only one KeepAliveManager instance
|
||||
// running on a dedicated thread. This instance will periodically send
|
||||
// out a ping* to the endpoint while listening for an incoming pong**.
|
||||
// If it fails to send the ping, or if no pong is heard within
|
||||
// keep_alive_timeout, it initiates a disconnection.
|
||||
//
|
||||
// (*) Bluetooth requires a constant outgoing stream of messages. If
|
||||
// there's silence, Android will break the socket. This is why we
|
||||
// ping.
|
||||
// (**) Wifi Hotspots can fail to notice a connection has been lost,
|
||||
// and they will happily keep writing to /dev/null. This is why we
|
||||
// listen for the pong.
|
||||
VLOG(1) << "EndpointManager enabling KeepAlive for endpoint "
|
||||
<< endpoint_id;
|
||||
endpoint_state.StartEndpointKeepAliveManager(
|
||||
[this, client, endpoint_id, keep_alive_interval, keep_alive_timeout](
|
||||
Mutex* keep_alive_waiter_mutex,
|
||||
ConditionVariable* keep_alive_waiter) {
|
||||
EndpointChannelLoopRunnable(
|
||||
"Read", client, endpoint_id,
|
||||
[this, client, endpoint_id](EndpointChannel* channel) {
|
||||
return HandleData(endpoint_id, client, channel);
|
||||
"KeepAliveManager", client, endpoint_id,
|
||||
[this, keep_alive_interval, keep_alive_timeout,
|
||||
keep_alive_waiter_mutex,
|
||||
keep_alive_waiter](EndpointChannel* channel) {
|
||||
return HandleKeepAlive(
|
||||
channel, keep_alive_interval, keep_alive_timeout,
|
||||
keep_alive_waiter_mutex, keep_alive_waiter);
|
||||
});
|
||||
});
|
||||
LOG(INFO) << "Registering endpoint " << endpoint_id
|
||||
<< ", workers started and notifying client.";
|
||||
|
||||
// For every endpoint, there's only one KeepAliveManager instance
|
||||
// running on a dedicated thread. This instance will periodically send
|
||||
// out a ping* to the endpoint while listening for an incoming pong**.
|
||||
// If it fails to send the ping, or if no pong is heard within
|
||||
// keep_alive_timeout, it initiates a disconnection.
|
||||
//
|
||||
// (*) Bluetooth requires a constant outgoing stream of messages. If
|
||||
// there's silence, Android will break the socket. This is why we
|
||||
// ping.
|
||||
// (**) Wifi Hotspots can fail to notice a connection has been lost,
|
||||
// and they will happily keep writing to /dev/null. This is why we
|
||||
// listen for the pong.
|
||||
VLOG(1) << "EndpointManager enabling KeepAlive for endpoint "
|
||||
<< endpoint_id;
|
||||
endpoint_state.StartEndpointKeepAliveManager(
|
||||
[this, client, endpoint_id, keep_alive_interval,
|
||||
keep_alive_timeout](Mutex* keep_alive_waiter_mutex,
|
||||
ConditionVariable* keep_alive_waiter) {
|
||||
EndpointChannelLoopRunnable(
|
||||
"KeepAliveManager", client, endpoint_id,
|
||||
[this, keep_alive_interval, keep_alive_timeout,
|
||||
keep_alive_waiter_mutex,
|
||||
keep_alive_waiter](EndpointChannel* channel) {
|
||||
return HandleKeepAlive(
|
||||
channel, keep_alive_interval, keep_alive_timeout,
|
||||
keep_alive_waiter_mutex, keep_alive_waiter);
|
||||
});
|
||||
});
|
||||
LOG(INFO) << "Registering endpoint " << endpoint_id
|
||||
<< ", workers started and notifying 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, connection_options,
|
||||
listener, connection_token);
|
||||
latch.CountDown();
|
||||
});
|
||||
// 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, connection_options,
|
||||
listener, connection_token);
|
||||
latch.CountDown();
|
||||
});
|
||||
latch.Await();
|
||||
}
|
||||
|
||||
@@ -722,7 +713,7 @@ void EndpointManager::DiscardEndpoint(ClientProxy* client,
|
||||
// of `serial_executor_` and will still have access to a valid
|
||||
// `is_shutdown_`.
|
||||
//
|
||||
// TODO(b/280653613): Develop a more robost solution to prevent
|
||||
// TODO(b/280653613): Develop a more robust solution to prevent
|
||||
// accessing an already destroyed `ClientProxy` during destruction.
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
@@ -953,8 +944,7 @@ std::vector<std::string> EndpointManager::SendTransferFrameBytes(
|
||||
continue;
|
||||
}
|
||||
|
||||
Exception write_exception =
|
||||
channel->Write(bytes, packet_meta_data);
|
||||
Exception write_exception = channel->Write(bytes, packet_meta_data);
|
||||
if (!write_exception.Ok()) {
|
||||
failed_endpoint_ids.push_back(endpoint_id);
|
||||
LOG(INFO) << "Failed to send packet; endpoint_id=" << endpoint_id;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "connections/connection_options.h"
|
||||
#include "connections/implementation/analytics/packet_meta_data.h"
|
||||
#include "connections/implementation/client_proxy.h"
|
||||
#include "connections/implementation/endpoint_channel.h"
|
||||
@@ -34,6 +35,8 @@
|
||||
#include "internal/platform/byte_array.h"
|
||||
#include "internal/platform/condition_variable.h"
|
||||
#include "internal/platform/count_down_latch.h"
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/mutex.h"
|
||||
#include "internal/platform/runnable.h"
|
||||
#include "internal/platform/single_thread_executor.h"
|
||||
|
||||
@@ -112,7 +115,7 @@ class EndpointManager {
|
||||
void RegisterEndpoint(ClientProxy* client, const std::string& endpoint_id,
|
||||
const ConnectionResponseInfo& info,
|
||||
const ConnectionOptions& connection_options,
|
||||
std::unique_ptr<EndpointChannel> channel,
|
||||
std::shared_ptr<EndpointChannel> channel,
|
||||
const ConnectionListener& listener,
|
||||
const std::string& connection_token);
|
||||
// Called when a client explicitly asks to disconnect from this endpoint. In
|
||||
|
||||
Reference in New Issue
Block a user