blob: 85f725ac0979f0e1be4860c0a68c2b56b312519e [file] [log] [blame]
// Copyright 2016 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/host/security_key/security_key_message_handler.h"
#include <cstdint>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "remoting/host/security_key/security_key_ipc_client.h"
#include "remoting/host/security_key/security_key_ipc_constants.h"
#include "remoting/host/security_key/security_key_message_reader_impl.h"
#include "remoting/host/security_key/security_key_message_writer_impl.h"
namespace remoting {
SecurityKeyMessageHandler::SecurityKeyMessageHandler() = default;
SecurityKeyMessageHandler::~SecurityKeyMessageHandler() {
DCHECK(thread_checker_.CalledOnValidThread());
}
void SecurityKeyMessageHandler::Start(
base::File message_read_stream,
base::File message_write_stream,
std::unique_ptr<SecurityKeyIpcClient> ipc_client,
const base::Closure& error_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(message_read_stream.IsValid());
DCHECK(message_write_stream.IsValid());
DCHECK(ipc_client);
DCHECK(!error_callback.is_null());
DCHECK(error_callback_.is_null());
if (!reader_) {
reader_.reset(
new SecurityKeyMessageReaderImpl(std::move(message_read_stream)));
}
if (!writer_) {
writer_.reset(
new SecurityKeyMessageWriterImpl(std::move(message_write_stream)));
}
ipc_client_ = std::move(ipc_client);
error_callback_ = error_callback;
reader_->Start(
base::Bind(&SecurityKeyMessageHandler::ProcessSecurityKeyMessage,
base::Unretained(this)),
base::Bind(&SecurityKeyMessageHandler::OnError, base::Unretained(this)));
}
void SecurityKeyMessageHandler::SetSecurityKeyMessageReaderForTest(
std::unique_ptr<SecurityKeyMessageReader> reader) {
DCHECK(!reader_);
reader_ = std::move(reader);
}
void SecurityKeyMessageHandler::SetSecurityKeyMessageWriterForTest(
std::unique_ptr<SecurityKeyMessageWriter> writer) {
DCHECK(!writer_);
writer_ = std::move(writer);
}
void SecurityKeyMessageHandler::ProcessSecurityKeyMessage(
std::unique_ptr<SecurityKeyMessage> message) {
DCHECK(thread_checker_.CalledOnValidThread());
SecurityKeyMessageType message_type = message->type();
if (message_type == SecurityKeyMessageType::CONNECT) {
HandleConnectRequest(message->payload());
} else if (message_type == SecurityKeyMessageType::REQUEST) {
HandleSecurityKeyRequest(message->payload());
} else {
LOG(ERROR) << "Unknown message type: "
<< static_cast<uint8_t>(message_type);
SendMessage(SecurityKeyMessageType::UNKNOWN_COMMAND);
}
}
void SecurityKeyMessageHandler::HandleIpcConnectionChange(
bool connection_established) {
DCHECK(thread_checker_.CalledOnValidThread());
if (connection_established) {
SendMessageWithPayload(SecurityKeyMessageType::CONNECT_RESPONSE,
std::string(1, kConnectResponseActiveSession));
} else {
SendMessageWithPayload(SecurityKeyMessageType::CONNECT_RESPONSE,
std::string(1, kConnectResponseNoSession));
// We expect the server to close the IPC channel in this scenario.
expect_ipc_channel_close_ = true;
}
}
void SecurityKeyMessageHandler::HandleIpcConnectionError() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!expect_ipc_channel_close_) {
SendMessageWithPayload(SecurityKeyMessageType::CONNECT_ERROR,
"Unknown error occurred during connection.");
}
}
void SecurityKeyMessageHandler::HandleSecurityKeyResponse(
const std::string& response_data) {
if (response_data.compare(kSecurityKeyConnectionError) == 0) {
SendMessageWithPayload(SecurityKeyMessageType::REQUEST_ERROR,
"An error occurred during the request.");
return;
}
if (response_data.empty()) {
SendMessageWithPayload(SecurityKeyMessageType::REQUEST_ERROR,
"Invalid client response received.");
return;
}
SendMessageWithPayload(SecurityKeyMessageType::REQUEST_RESPONSE,
response_data);
}
void SecurityKeyMessageHandler::HandleConnectRequest(
const std::string& message_payload) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!message_payload.empty()) {
SendMessageWithPayload(SecurityKeyMessageType::CONNECT_ERROR,
"Unexpected payload data received.");
return;
}
if (ipc_client_->CheckForSecurityKeyIpcServerChannel()) {
// If we find an IPC server, then attempt to establish a connection.
ipc_client_->EstablishIpcConnection(
base::Bind(&SecurityKeyMessageHandler::HandleIpcConnectionChange,
base::Unretained(this)),
base::Bind(&SecurityKeyMessageHandler::HandleIpcConnectionError,
base::Unretained(this)));
} else {
SendMessageWithPayload(SecurityKeyMessageType::CONNECT_RESPONSE,
std::string(1, kConnectResponseNoSession));
}
}
void SecurityKeyMessageHandler::HandleSecurityKeyRequest(
const std::string& message_payload) {
DCHECK(thread_checker_.CalledOnValidThread());
if (message_payload.empty()) {
SendMessageWithPayload(SecurityKeyMessageType::REQUEST_ERROR,
"Request sent without request data.");
return;
}
if (!ipc_client_->SendSecurityKeyRequest(
message_payload,
base::Bind(&SecurityKeyMessageHandler::HandleSecurityKeyResponse,
base::Unretained(this)))) {
SendMessageWithPayload(SecurityKeyMessageType::REQUEST_ERROR,
"Failed to send request data.");
}
}
void SecurityKeyMessageHandler::SendMessage(
SecurityKeyMessageType message_type) {
if (!writer_->WriteMessage(message_type)) {
OnError();
}
}
void SecurityKeyMessageHandler::SendMessageWithPayload(
SecurityKeyMessageType message_type,
const std::string& message_payload) {
if (!writer_->WriteMessageWithPayload(message_type, message_payload)) {
OnError();
}
}
void SecurityKeyMessageHandler::OnError() {
DCHECK(thread_checker_.CalledOnValidThread());
ipc_client_.reset();
writer_.reset();
reader_.reset();
if (!error_callback_.is_null()) {
base::ResetAndReturn(&error_callback_).Run();
}
}
} // namespace remoting