Skip to content

Commit

Permalink
Implement FileTransferMessageHandler
Browse files Browse the repository at this point in the history
This change completes the initial Linux implementation of the file
transfer feature.

Change-Id: I529501c6a2f76806a0cfb6aca23efc446b44e857
Reviewed-on: https://chromium-review.googlesource.com/624763
Commit-Queue: Joseph Arhar <jarhar@google.com>
Reviewed-by: Joe Downing <joedow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#497896}
  • Loading branch information
josepharhar authored and Commit Bot committed Aug 28, 2017
1 parent b8c3418 commit 10e5edd
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 6 deletions.
1 change: 1 addition & 0 deletions remoting/host/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ source_set("unit_tests") {
"desktop_process_unittest.cc",
"desktop_session_agent_unittest.cc",
"file_proxy_wrapper_linux_unittest.cc",
"file_transfer_message_handler_unittest.cc",
"gcd_rest_client_unittest.cc",
"gcd_state_updater_unittest.cc",
"heartbeat_sender_unittest.cc",
Expand Down
103 changes: 97 additions & 6 deletions remoting/host/file_transfer_message_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,120 @@

#include "remoting/host/file_transfer_message_handler.h"

#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "remoting/base/compound_buffer.h"

namespace remoting {

FileTransferMessageHandler::FileTransferMessageHandler(
const std::string& name,
std::unique_ptr<protocol::MessagePipe> pipe,
std::unique_ptr<FileProxyWrapper> file_proxy)
: protocol::NamedMessagePipeHandler(name, std::move(pipe)) {}
std::unique_ptr<FileProxyWrapper> file_proxy_wrapper)
: protocol::NamedMessagePipeHandler(name, std::move(pipe)),
file_proxy_wrapper_(std::move(file_proxy_wrapper)) {
DCHECK(file_proxy_wrapper_);
}

FileTransferMessageHandler::~FileTransferMessageHandler() = default;

void FileTransferMessageHandler::OnConnected() {
// TODO(jarhar): Implement open logic.
// base::Unretained is safe here because |file_proxy_wrapper_| is owned by
// this class, so the callback cannot be run after this class is destroyed.
file_proxy_wrapper_->Init(base::BindOnce(
&FileTransferMessageHandler::StatusCallback, base::Unretained(this)));
}

void FileTransferMessageHandler::OnIncomingMessage(
std::unique_ptr<CompoundBuffer> message) {
// TODO(jarhar): Implement message received logic.
std::unique_ptr<CompoundBuffer> buffer) {
FileProxyWrapper::State proxy_state = file_proxy_wrapper_->state();
if (proxy_state == FileProxyWrapper::kClosing ||
proxy_state == FileProxyWrapper::kClosed ||
proxy_state == FileProxyWrapper::kFailed) {
return;
}

if (request_) {
// File transfer is already in progress, just pass the buffer to
// FileProxyWrapper to be written.
SendToFileProxy(std::move(buffer));
} else {
// A new file transfer has been started, parse the message into a request
// protobuf.
ParseNewRequest(std::move(buffer));
}
}

void FileTransferMessageHandler::OnDisconnecting() {
// TODO(jarhar): Implement close logic.
FileProxyWrapper::State proxy_state = file_proxy_wrapper_->state();
if (proxy_state != FileProxyWrapper::kClosed &&
proxy_state != FileProxyWrapper::kFailed) {
// Channel was closed earlier than expected, cancel the transfer.
file_proxy_wrapper_->Cancel();
}
}

void FileTransferMessageHandler::StatusCallback(
FileProxyWrapper::State state,
base::Optional<protocol::FileTransferResponse_ErrorCode> error) {
protocol::FileTransferResponse response;
if (error.has_value()) {
DCHECK_EQ(state, FileProxyWrapper::kFailed);
response.set_error(error.value());
} else {
DCHECK_EQ(state, FileProxyWrapper::kClosed);
response.set_state(protocol::FileTransferResponse_TransferState_DONE);
response.set_total_bytes_written(request_->filesize());
}
Send(&response, base::Closure());
}

void FileTransferMessageHandler::SendToFileProxy(
std::unique_ptr<CompoundBuffer> buffer) {
DCHECK_EQ(file_proxy_wrapper_->state(), FileProxyWrapper::kFileCreated);

total_bytes_written_ += buffer->total_bytes();
file_proxy_wrapper_->WriteChunk(std::move(buffer));
if (total_bytes_written_ >= request_->filesize()) {
file_proxy_wrapper_->Close();
}

if (total_bytes_written_ > request_->filesize()) {
LOG(ERROR) << "File transfer received " << total_bytes_written_
<< " bytes, but request said there would only be "
<< request_->filesize() << " bytes.";
}
}

void FileTransferMessageHandler::ParseNewRequest(
std::unique_ptr<CompoundBuffer> buffer) {
std::string message;
message.resize(buffer->total_bytes());
buffer->CopyTo(base::string_as_array(&message), message.size());

request_ = base::MakeUnique<protocol::FileTransferRequest>();
if (!request_->ParseFromString(message)) {
CancelAndSendError("Failed to parse request protobuf");
return;
}

base::FilePath target_directory;
if (!PathService::Get(base::DIR_USER_DESKTOP, &target_directory)) {
CancelAndSendError("Failed to get DIR_USER_DESKTOP from PathService::Get");
return;
}

file_proxy_wrapper_->CreateFile(target_directory, request_->filename());
}

void FileTransferMessageHandler::CancelAndSendError(const std::string& error) {
LOG(ERROR) << error;
file_proxy_wrapper_->Cancel();
protocol::FileTransferResponse response;
response.set_error(protocol::FileTransferResponse_ErrorCode_UNEXPECTED_ERROR);
Send(&response, base::Closure());
}

} // namespace remoting
17 changes: 17 additions & 0 deletions remoting/host/file_transfer_message_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
#ifndef REMOTING_HOST_FILE_TRANSFER_MESSAGE_HANDLER_H_
#define REMOTING_HOST_FILE_TRANSFER_MESSAGE_HANDLER_H_

#include <cstdint>
#include <memory>
#include <string>

#include "remoting/host/file_proxy_wrapper.h"
#include "remoting/proto/file_transfer.pb.h"
#include "remoting/protocol/named_message_pipe_handler.h"

namespace remoting {
Expand All @@ -23,6 +28,18 @@ class FileTransferMessageHandler : public protocol::NamedMessagePipeHandler {
void OnConnected() override;
void OnIncomingMessage(std::unique_ptr<CompoundBuffer> message) override;
void OnDisconnecting() override;

private:
void StatusCallback(
FileProxyWrapper::State state,
base::Optional<protocol::FileTransferResponse_ErrorCode> error);
void SendToFileProxy(std::unique_ptr<CompoundBuffer> buffer);
void ParseNewRequest(std::unique_ptr<CompoundBuffer> buffer);
void CancelAndSendError(const std::string& error);

std::unique_ptr<FileProxyWrapper> file_proxy_wrapper_;
std::unique_ptr<protocol::FileTransferRequest> request_;
uint64_t total_bytes_written_ = 0;
};

} // namespace remoting
Expand Down
Loading

0 comments on commit 10e5edd

Please sign in to comment.