blob: e2aed5ef9d8dc75280402fb6048f654cdfb94e67 [file] [log] [blame]
// Copyright 2025 The Fuchsia 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 "src/virtualization/lib/guest_interaction/interactive_debian_guest/running_guest.h"
#include <lib/syslog/cpp/macros.h>
#include <zircon/errors.h>
#include "src/virtualization/lib/grpc/fdio_util.h"
#include "src/virtualization/lib/guest_interaction/proto/guest_interaction.pb.h"
namespace {
zx_status_t ToZxStatus(int proto_status) {
switch (proto_status) {
case OperationStatus::OK:
return ZX_OK;
case OperationStatus::GRPC_FAILURE:
return ZX_ERR_INTERNAL;
case OperationStatus::CLIENT_MISSING_FILE_FAILURE:
case OperationStatus::SERVER_MISSING_FILE_FAILURE:
return ZX_ERR_NOT_FOUND;
case OperationStatus::CLIENT_CREATE_FILE_FAILURE:
case OperationStatus::SERVER_CREATE_FILE_FAILURE:
case OperationStatus::CLIENT_FILE_READ_FAILURE:
case OperationStatus::SERVER_FILE_READ_FAILURE:
case OperationStatus::CLIENT_FILE_WRITE_FAILURE:
case OperationStatus::SERVER_FILE_WRITE_FAILURE:
return ZX_ERR_IO;
case OperationStatus::SERVER_EXEC_COMMAND_PARSE_FAILURE:
return ZX_ERR_INVALID_ARGS;
case OperationStatus::SERVER_EXEC_FORK_FAILURE:
return ZX_ERR_NO_RESOURCES;
default:
return ZX_ERR_INTERNAL;
}
}
} // namespace
namespace interactive_debian_guest {
RunningGuest::RunningGuest(std::string name, fbl::unique_fd vsock_fd,
async_dispatcher_t* dispatcher,
fidl::SyncClient<fuchsia_virtualization::Guest> guest_sync)
: name_(std::move(name)), dispatcher_(dispatcher), guest_sync_(std::move(guest_sync)) {
// SetNonBlocking defined in src/virtualization/lib/grpc/fdio_util.h
int ret = SetNonBlocking(vsock_fd);
FX_CHECK(ret == 0) << std::format(
"[{}] Failed to set the vsock port as non-blocking with errno: {}", Name(), strerror(ret));
interaction_client_ = std::make_unique<ClientImpl<PosixPlatform>>(vsock_fd.release());
int thrd_ret = interaction_client_->Start(guest_interaction_service_thread_);
FX_CHECK(thrd_ret == thrd_success)
<< std::format("[{}] Failed to start guest interaction client thread with errno: {}", Name(),
strerror(thrd_ret));
}
RunningGuest::~RunningGuest() {
// All teardowns should be gracefully done by the owning class, and failure to do so
// puts the interaction client in an indeterminte state with regards to bound ports.
FX_CHECK(interaction_client_ && interaction_client_->IsRunning())
<< "An invalid teardown sequence has occurred.";
}
void RunningGuest::PutFile(fidl::ClientEnd<fuchsia_io::File> host_source,
const std::string& guest_dest, FileTransferCallback result) {
FX_CHECK(interaction_client_ && interaction_client_->IsRunning());
interaction_client_->Put(
std::move(host_source), guest_dest, [this, cb = std::move(result)](auto status) {
if (status != OperationStatus::OK) {
FX_LOGST(WARNING, Name())
<< "PutFile operation failed with status: " << OperationStatus_Name(status);
}
cb(ToZxStatus(status));
});
}
void RunningGuest::GetFile(const std::string& guest_source,
fidl::ClientEnd<fuchsia_io::File> host_dest,
FileTransferCallback result) {
FX_CHECK(interaction_client_ && interaction_client_->IsRunning());
interaction_client_->Get(
guest_source, std::move(host_dest), [this, cb = std::move(result)](auto status) {
if (status != OperationStatus::OK) {
FX_LOGST(WARNING, Name())
<< "GetFile operation failed with status: " << OperationStatus_Name(status);
}
cb(ToZxStatus(status));
});
}
void RunningGuest::Execute(
std::string command, std::map<std::string, std::string> env_variables, zx::socket std_in,
zx::socket std_out, zx::socket std_err,
fidl::ServerEnd<fuchsia_virtualization_guest_interaction::CommandListener> listener) {
interaction_client_->Exec(std::move(command), env_variables, std::move(std_in),
std::move(std_out), std::move(std_err), std::move(listener),
dispatcher_);
}
void RunningGuest::Shutdown() {
FX_LOGST(INFO, Name()) << "Beginning shutdown procedures.";
interaction_client_->Stop();
}
const char* RunningGuest::Name() { return name_.c_str(); }
} // namespace interactive_debian_guest