Commit 1a71ff1e authored by Yuwei Huang's avatar Yuwei Huang Committed by Commit Bot

[remoting][FTL] Implement FtlSignalingPlayground

This CL implements FtlSignalingPlayground for testing
JingleSessionManager::AcceptIncoming() and
JingleSessionManager::Connect(). The test currently ends once the
session is authenticated.

This also changes some spammy VLOG(0) logs to VLOG(1) so that signaling
messages are easier to read.

Bug: 947337
Change-Id: I33c84c6e06a311ecdf58d3aad7ad6111bc52ef13
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1554480
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#649296}
parent 1fd2b4c7
...@@ -116,12 +116,12 @@ void FtlMessageReceptionChannel::OnMessageReceived( ...@@ -116,12 +116,12 @@ void FtlMessageReceptionChannel::OnMessageReceived(
const ftl::ReceiveMessagesResponse& response) { const ftl::ReceiveMessagesResponse& response) {
switch (response.body_case()) { switch (response.body_case()) {
case ftl::ReceiveMessagesResponse::BodyCase::kInboxMessage: { case ftl::ReceiveMessagesResponse::BodyCase::kInboxMessage: {
VLOG(0) << "Received message"; VLOG(1) << "Received message";
on_incoming_msg_.Run(response.inbox_message()); on_incoming_msg_.Run(response.inbox_message());
break; break;
} }
case ftl::ReceiveMessagesResponse::BodyCase::kPong: case ftl::ReceiveMessagesResponse::BodyCase::kPong:
VLOG(0) << "Received pong"; VLOG(1) << "Received pong";
stream_pong_timer_->Reset(); stream_pong_timer_->Reset();
break; break;
case ftl::ReceiveMessagesResponse::BodyCase::kStartOfBatch: case ftl::ReceiveMessagesResponse::BodyCase::kStartOfBatch:
...@@ -130,7 +130,7 @@ void FtlMessageReceptionChannel::OnMessageReceived( ...@@ -130,7 +130,7 @@ void FtlMessageReceptionChannel::OnMessageReceived(
BeginStreamTimers(); BeginStreamTimers();
break; break;
case ftl::ReceiveMessagesResponse::BodyCase::kEndOfBatch: case ftl::ReceiveMessagesResponse::BodyCase::kEndOfBatch:
VLOG(0) << "Received end of batch"; VLOG(1) << "Received end of batch";
break; break;
default: default:
LOG(WARNING) << "Received unknown message type: " << response.body_case(); LOG(WARNING) << "Received unknown message type: " << response.body_case();
......
...@@ -109,7 +109,7 @@ void GrpcAsyncExecutor::ExecuteRpc(std::unique_ptr<GrpcAsyncRequest> request) { ...@@ -109,7 +109,7 @@ void GrpcAsyncExecutor::ExecuteRpc(std::unique_ptr<GrpcAsyncRequest> request) {
VLOG(0) << "RPC is canceled before execution: " << unowned_request; VLOG(0) << "RPC is canceled before execution: " << unowned_request;
return; return;
} }
VLOG(0) << "Enqueuing RPC: " << unowned_request; VLOG(1) << "Enqueuing RPC: " << unowned_request;
// User can potentially delete the executor in the callback, so we should // User can potentially delete the executor in the callback, so we should
// delay it to prevent race condition. We also bind the closure with the // delay it to prevent race condition. We also bind the closure with the
...@@ -150,14 +150,14 @@ void GrpcAsyncExecutor::OnDequeue(std::unique_ptr<GrpcAsyncRequest> request, ...@@ -150,14 +150,14 @@ void GrpcAsyncExecutor::OnDequeue(std::unique_ptr<GrpcAsyncRequest> request,
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!request->OnDequeue(operation_succeeded)) { if (!request->OnDequeue(operation_succeeded)) {
VLOG(0) << "Dequeuing RPC: " << request.get(); VLOG(1) << "Dequeuing RPC: " << request.get();
auto iter = FindRequest(request.get()); auto iter = FindRequest(request.get());
DCHECK(iter != pending_requests_.end()); DCHECK(iter != pending_requests_.end());
pending_requests_.erase(iter); pending_requests_.erase(iter);
return; return;
} }
VLOG(0) << "Re-enqueuing RPC: " << request.get(); VLOG(1) << "Re-enqueuing RPC: " << request.get();
DCHECK(FindRequest(request.get()) != pending_requests_.end()); DCHECK(FindRequest(request.get()) != pending_requests_.end());
auto* unowned_request = request.get(); auto* unowned_request = request.get();
auto task = std::make_unique<DispatchTask>(); auto task = std::make_unique<DispatchTask>();
......
...@@ -16,7 +16,7 @@ GrpcAsyncRequest::GrpcAsyncRequest(std::unique_ptr<grpc::ClientContext> context) ...@@ -16,7 +16,7 @@ GrpcAsyncRequest::GrpcAsyncRequest(std::unique_ptr<grpc::ClientContext> context)
GrpcAsyncRequest::~GrpcAsyncRequest() = default; GrpcAsyncRequest::~GrpcAsyncRequest() = default;
void GrpcAsyncRequest::CancelRequest() { void GrpcAsyncRequest::CancelRequest() {
VLOG(0) << "Canceling request: " << this; VLOG(1) << "Canceling request: " << this;
context_->TryCancel(); context_->TryCancel();
OnRequestCanceled(); OnRequestCanceled();
} }
......
...@@ -35,18 +35,18 @@ bool GrpcAsyncServerStreamingRequestBase::OnDequeue(bool operation_succeeded) { ...@@ -35,18 +35,18 @@ bool GrpcAsyncServerStreamingRequestBase::OnDequeue(bool operation_succeeded) {
return false; return false;
} }
if (!operation_succeeded) { if (!operation_succeeded) {
VLOG(0) << "Can't read any more data. Figuring out the reason..." VLOG(1) << "Can't read any more data. Figuring out the reason..."
<< " Streaming call: " << this; << " Streaming call: " << this;
state_ = State::FINISHING; state_ = State::FINISHING;
return true; return true;
} }
if (state_ == State::STARTING) { if (state_ == State::STARTING) {
VLOG(0) << "Streaming call started: " << this; VLOG(1) << "Streaming call started: " << this;
state_ = State::STREAMING; state_ = State::STREAMING;
return true; return true;
} }
DCHECK_EQ(State::STREAMING, state_); DCHECK_EQ(State::STREAMING, state_);
VLOG(0) << "Streaming call received message: " << this; VLOG(1) << "Streaming call received message: " << this;
ResolveIncomingMessage(); ResolveIncomingMessage();
return true; return true;
} }
......
...@@ -79,6 +79,10 @@ static_library("test_support") { ...@@ -79,6 +79,10 @@ static_library("test_support") {
deps = [ deps = [
"//google_apis", "//google_apis",
"//remoting/base:authorization",
"//remoting/base:test_support",
"//services/network:network_service",
"//services/network/public/mojom",
"//skia", "//skia",
"//testing/gmock", "//testing/gmock",
"//testing/gtest", "//testing/gtest",
...@@ -190,14 +194,25 @@ executable("ftl_services_playground") { ...@@ -190,14 +194,25 @@ executable("ftl_services_playground") {
] ]
deps = [ deps = [
":test_support", ":test_support",
"//google_apis",
"//mojo/core/embedder", "//mojo/core/embedder",
"//remoting/base", "//remoting/base",
"//remoting/base:authorization",
"//remoting/base:test_support",
"//remoting/signaling", "//remoting/signaling",
"//services/network:network_service", ]
"//services/network/public/mojom", }
# A binary for testing and fiddling the FTL signaling process.
executable("ftl_signaling_playground") {
testonly = true
sources = [
"ftl_signaling_playground.cc",
"ftl_signaling_playground.h",
"ftl_signaling_playground_main.cc",
]
deps = [
":test_support",
"//mojo/core/embedder",
"//remoting/base",
"//remoting/signaling",
] ]
} }
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/test/ftl_signaling_playground.h"
#include <inttypes.h>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/guid.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "jingle/glue/thread_wrapper.h"
#include "remoting/base/logging.h"
#include "remoting/base/oauth_token_getter_impl.h"
#include "remoting/base/rsa_key_pair.h"
#include "remoting/protocol/auth_util.h"
#include "remoting/protocol/jingle_session_manager.h"
#include "remoting/protocol/me2me_host_authenticator_factory.h"
#include "remoting/protocol/negotiating_client_authenticator.h"
#include "remoting/protocol/pairing_registry.h"
#include "remoting/protocol/transport.h"
#include "remoting/signaling/ftl_device_id_provider.h"
#include "remoting/signaling/ftl_grpc_context.h"
#include "remoting/signaling/ftl_services.grpc.pb.h"
#include "remoting/signaling/ftl_signal_strategy.h"
#include "remoting/signaling/grpc_support/grpc_async_unary_request.h"
#include "remoting/test/cli_util.h"
#include "remoting/test/test_oauth_token_getter.h"
#include "remoting/test/test_token_storage.h"
namespace remoting {
namespace {
constexpr char kSwitchNameHelp[] = "help";
constexpr char kSwitchNameUsername[] = "username";
constexpr char kSwitchNameStoragePath[] = "storage-path";
constexpr char kSwitchNamePin[] = "pin";
constexpr char kSwitchNameHostId[] = "host-id";
const char* SignalStrategyErrorToString(SignalStrategy::Error error) {
switch (error) {
case SignalStrategy::OK:
return "OK";
case SignalStrategy::AUTHENTICATION_FAILED:
return "AUTHENTICATION_FAILED";
case SignalStrategy::NETWORK_ERROR:
return "NETWORK_ERROR";
case SignalStrategy::PROTOCOL_ERROR:
return "PROTOCOL_ERROR";
}
return "";
}
class FakeTransport : public protocol::Transport {
public:
FakeTransport() = default;
~FakeTransport() override = default;
void Start(protocol::Authenticator* authenticator,
SendTransportInfoCallback send_transport_info_callback) override {}
bool ProcessTransportInfo(jingle_xmpp::XmlElement* transport_info) override {
return false;
}
};
} // namespace
FtlSignalingPlayground::FtlSignalingPlayground() = default;
FtlSignalingPlayground::~FtlSignalingPlayground() = default;
bool FtlSignalingPlayground::ShouldPrintHelp() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchNameHelp);
}
void FtlSignalingPlayground::PrintHelp() {
printf(
"Usage: %s [--auth-code=<auth-code>] [--host-id=<host-id>] [--pin=<pin>] "
"[--storage-path=<storage-path>] [--username=<example@gmail.com>]\n",
base::CommandLine::ForCurrentProcess()
->GetProgram()
.MaybeAsASCII()
.c_str());
}
void FtlSignalingPlayground::StartLoop() {
jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
std::string username = cmd_line->GetSwitchValueASCII(kSwitchNameUsername);
base::FilePath storage_path =
cmd_line->GetSwitchValuePath(kSwitchNameStoragePath);
storage_ = test::TestTokenStorage::OnDisk(username, storage_path);
token_getter_ = std::make_unique<test::TestOAuthTokenGetter>(storage_.get());
base::RunLoop initialize_token_getter_loop;
token_getter_->Initialize(initialize_token_getter_loop.QuitClosure());
initialize_token_getter_loop.Run();
std::vector<test::CommandOption> options{
{"AcceptIncoming",
base::BindRepeating(&FtlSignalingPlayground::AcceptIncoming,
base::Unretained(this))},
{"ConnectToHost",
base::BindRepeating(&FtlSignalingPlayground::ConnectToHost,
base::Unretained(this))}};
test::RunCommandOptionsLoop(options);
}
void FtlSignalingPlayground::AcceptIncoming(base::OnceClosure on_done) {
current_callback_ = std::move(on_done);
SetUpSignaling();
std::string host_id;
auto* cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch(kSwitchNameHostId)) {
host_id = cmd->GetSwitchValueASCII(kSwitchNameHostId);
} else {
host_id = base::GenerateGUID();
}
HOST_LOG << "Using host ID: " << host_id;
std::string pin =
test::ReadStringFromCommandLineOrStdin(kSwitchNamePin, "Pin: ");
std::string pin_hash = protocol::GetSharedSecretHash(host_id, pin);
auto key_pair = RsaKeyPair::Generate();
std::string cert = key_pair->GenerateCertificate();
auto factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithPin(
/* use_service_account */ false, storage_->FetchUserEmail(), cert,
key_pair, /* domain_list */ {}, pin_hash, /* pairing_registry */ {});
session_manager_->set_authenticator_factory(std::move(factory));
HOST_LOG << "Waiting for incoming session...";
session_manager_->AcceptIncoming(base::BindRepeating(
&FtlSignalingPlayground::OnIncomingSession, base::Unretained(this)));
}
void FtlSignalingPlayground::OnIncomingSession(
protocol::Session* owned_session,
protocol::SessionManager::IncomingSessionResponse* response) {
HOST_LOG << "Received incoming session!\n";
RegisterSession(base::WrapUnique(owned_session));
*response = protocol::SessionManager::ACCEPT;
}
void FtlSignalingPlayground::ConnectToHost(base::OnceClosure on_done) {
current_callback_ = std::move(on_done);
on_signaling_connected_callback_ =
base::BindOnce(&FtlSignalingPlayground::OnClientSignalingConnected,
base::Unretained(this));
SetUpSignaling();
}
void FtlSignalingPlayground::OnClientSignalingConnected() {
std::string host_id =
test::ReadStringFromCommandLineOrStdin(kSwitchNameHostId, "Host ID: ");
printf("Host JID: ");
std::string host_jid = test::ReadString();
protocol::ClientAuthenticationConfig client_auth_config;
client_auth_config.host_id = host_id;
client_auth_config.fetch_secret_callback = base::BindRepeating(
&FtlSignalingPlayground::FetchSecret, base::Unretained(this));
auto session = session_manager_->Connect(
SignalingAddress(host_jid),
std::make_unique<protocol::NegotiatingClientAuthenticator>(
signal_strategy_->GetLocalAddress().id(), host_jid,
client_auth_config));
RegisterSession(std::move(session));
}
void FtlSignalingPlayground::FetchSecret(
bool pairing_supported,
const protocol::SecretFetchedCallback& secret_fetched_callback) {
std::string pin =
test::ReadStringFromCommandLineOrStdin(kSwitchNamePin, "Pin: ");
HOST_LOG << "Using PIN: " << pin;
secret_fetched_callback.Run(pin);
}
void FtlSignalingPlayground::SetUpSignaling() {
signal_strategy_ = std::make_unique<FtlSignalStrategy>(
token_getter_.get(),
std::make_unique<FtlDeviceIdProvider>(storage_.get()));
signal_strategy_->AddListener(this);
session_manager_ =
std::make_unique<protocol::JingleSessionManager>(signal_strategy_.get());
session_manager_->set_protocol_config(
protocol::CandidateSessionConfig::CreateDefault());
signal_strategy_->Connect();
}
void FtlSignalingPlayground::TearDownSignaling() {
session_.reset();
fake_transport_.reset();
signal_strategy_->RemoveListener(this);
session_manager_.reset();
signal_strategy_.reset();
}
void FtlSignalingPlayground::RegisterSession(
std::unique_ptr<protocol::Session> session) {
session_ = std::move(session);
fake_transport_ = std::make_unique<FakeTransport>();
session_->SetEventHandler(this);
session_->SetTransport(fake_transport_.get());
}
void FtlSignalingPlayground::OnSignalStrategyStateChange(
SignalStrategy::State state) {
if (state == SignalStrategy::CONNECTING) {
HOST_LOG << "Connecting";
return;
}
if (state == SignalStrategy::CONNECTED) {
HOST_LOG << "Signaling connected. New JID: "
<< signal_strategy_->GetLocalAddress().jid();
if (on_signaling_connected_callback_) {
std::move(on_signaling_connected_callback_).Run();
}
return;
}
DCHECK(state == SignalStrategy::DISCONNECTED);
auto error = signal_strategy_->GetError();
TearDownSignaling();
HOST_LOG << "Signaling disconnected. error="
<< SignalStrategyErrorToString(error);
if (error == SignalStrategy::AUTHENTICATION_FAILED) {
if (current_callback_) {
token_getter_->ResetWithAuthenticationFlow(std::move(current_callback_));
} else {
token_getter_->InvalidateCache();
}
return;
}
if (current_callback_) {
std::move(current_callback_).Run();
}
}
bool FtlSignalingPlayground::OnSignalStrategyIncomingStanza(
const jingle_xmpp::XmlElement* stanza) {
return false;
}
void FtlSignalingPlayground::OnSessionStateChange(
protocol::Session::State state) {
HOST_LOG << "New session state: " << state;
switch (state) {
case protocol::Session::INITIALIZING:
case protocol::Session::CONNECTING:
case protocol::Session::ACCEPTING:
case protocol::Session::ACCEPTED:
case protocol::Session::AUTHENTICATING:
// Don't care about these events.
return;
case protocol::Session::AUTHENTICATED:
HOST_LOG << "Session is successfully authenticated!!!";
break;
case protocol::Session::CLOSED:
case protocol::Session::FAILED:
LOG(ERROR) << "Session failed/closed. Error: " << session_->error();
break;
}
TearDownSignaling();
if (current_callback_) {
std::move(current_callback_).Run();
}
}
} // namespace remoting
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_TEST_FTL_SIGNALING_PLAYGROUND_H_
#define REMOTING_TEST_FTL_SIGNALING_PLAYGROUND_H_
#include <memory>
#include <string>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "remoting/base/oauth_token_getter.h"
#include "remoting/protocol/client_authentication_config.h"
#include "remoting/protocol/session.h"
#include "remoting/protocol/session_manager.h"
#include "remoting/signaling/ftl_messaging_client.h"
#include "remoting/signaling/ftl_registration_manager.h"
#include "remoting/signaling/signal_strategy.h"
namespace remoting {
namespace protocol {
class Transport;
} // namespace protocol
namespace test {
class TestOAuthTokenGetter;
class TestTokenStorage;
} // namespace test
class FtlSignalingPlayground final : public SignalStrategy::Listener,
public protocol::Session::EventHandler {
public:
FtlSignalingPlayground();
~FtlSignalingPlayground() override;
bool ShouldPrintHelp();
void PrintHelp();
void StartLoop();
private:
void AcceptIncoming(base::OnceClosure on_done);
void OnIncomingSession(
protocol::Session* owned_session,
protocol::SessionManager::IncomingSessionResponse* response);
void ConnectToHost(base::OnceClosure on_done);
void OnClientSignalingConnected();
void FetchSecret(
bool pairing_supported,
const protocol::SecretFetchedCallback& secret_fetched_callback);
void SetUpSignaling();
void TearDownSignaling();
void RegisterSession(std::unique_ptr<protocol::Session> session);
// SignalStrategy::Listener interface.
void OnSignalStrategyStateChange(SignalStrategy::State state) override;
bool OnSignalStrategyIncomingStanza(
const jingle_xmpp::XmlElement* stanza) override;
// Session::EventHandler interface.
void OnSessionStateChange(protocol::Session::State state) override;
std::unique_ptr<test::TestTokenStorage> storage_;
std::unique_ptr<test::TestOAuthTokenGetter> token_getter_;
std::unique_ptr<SignalStrategy> signal_strategy_;
std::unique_ptr<protocol::SessionManager> session_manager_;
std::unique_ptr<protocol::Transport> fake_transport_;
std::unique_ptr<protocol::Session> session_;
base::OnceClosure current_callback_;
base::OnceClosure on_signaling_connected_callback_;
DISALLOW_COPY_AND_ASSIGN(FtlSignalingPlayground);
};
} // namespace remoting
#endif // REMOTING_TEST_FTL_SIGNALING_PLAYGROUND_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/task/task_scheduler/task_scheduler.h"
#include "mojo/core/embedder/embedder.h"
#include "remoting/test/ftl_signaling_playground.h"
int main(int argc, char const* argv[]) {
base::AtExitManager exitManager;
base::CommandLine::Init(argc, argv);
base::MessageLoopForIO message_loop;
remoting::FtlSignalingPlayground playground;
if (playground.ShouldPrintHelp()) {
playground.PrintHelp();
return 0;
}
base::TaskScheduler::CreateAndStartWithDefaultParams(
"FtlSignalingPlayground");
mojo::core::Init();
playground.StartLoop();
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment