blob: 944ec5fdfc17c571ec0a69be17cf14cdc1547ff2 [file] [log] [blame] [edit]
// Copyright 2018 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/bin/guest/socat.h"
#include <fuchsia/virtualization/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/status.h>
#include <zircon/status.h>
#include <iostream>
#include "lib/fidl/cpp/binding.h"
#include "src/lib/fsl/handles/object_info.h"
#include "src/virtualization/bin/guest/serial.h"
#include "src/virtualization/bin/guest/services.h"
namespace {
class HostVsockAcceptor : public fuchsia::virtualization::HostVsockAcceptor {
public:
HostVsockAcceptor(uint32_t port, async::Loop* loop) : port_(port), console_(loop) {}
// |fuchsia::virtualization::HostVsockAcceptor|
void Accept(uint32_t src_cid, uint32_t src_port, uint32_t port,
AcceptCallback callback) override {
if (port != port_) {
std::cerr << "Unexpected port " << port << "\n";
callback(ZX_ERR_CONNECTION_REFUSED, zx::handle());
return;
}
zx::socket socket, remote_socket;
zx_status_t status = zx::socket::create(ZX_SOCKET_STREAM, &socket, &remote_socket);
if (status != ZX_OK) {
std::cerr << "Failed to create socket " << status << "\n";
callback(ZX_ERR_CONNECTION_REFUSED, zx::handle());
return;
}
callback(ZX_OK, std::move(remote_socket));
console_.Start(zx::socket(std::move(socket)));
}
private:
uint32_t port_;
GuestConsole console_;
};
// Connect the the vsock endpoint of the given environment.
zx::status<fuchsia::virtualization::HostVsockEndpointSyncPtr> connect_to_vsock_endpoint(
uint32_t env_id, uint32_t port, sys::ComponentContext* context) {
// Connect to environment.
zx::status<fuchsia::virtualization::RealmSyncPtr> realm = ConnectToEnvironment(context, env_id);
if (realm.is_error()) {
return realm.take_error();
}
fuchsia::virtualization::HostVsockEndpointSyncPtr vsock_endpoint;
zx_status_t status = realm->GetHostVsockEndpoint(vsock_endpoint.NewRequest());
if (status != ZX_OK) {
std::cerr << "Could not fetch vsock endpoint: " << zx_status_get_string(status) << ".\n";
return zx::error(status);
}
return zx::ok(std::move(vsock_endpoint));
}
} // namespace
zx_status_t handle_socat_listen(uint32_t env_id, uint32_t port, async::Loop* loop,
sys::ComponentContext* context) {
zx::status<fuchsia::virtualization::HostVsockEndpointSyncPtr> vsock_endpoint =
connect_to_vsock_endpoint(env_id, port, context);
if (vsock_endpoint.is_error()) {
return vsock_endpoint.error_value();
}
HostVsockAcceptor acceptor(port, loop);
fidl::Binding<fuchsia::virtualization::HostVsockAcceptor> binding(&acceptor);
zx_status_t status;
vsock_endpoint->Listen(port, binding.NewBinding(), &status);
if (status != ZX_OK) {
std::cerr << "Failed to listen on port " << port << "\n";
return status;
}
return loop->Run();
}
zx_status_t handle_socat_connect(uint32_t env_id, uint32_t cid, uint32_t port, async::Loop* loop,
sys::ComponentContext* context) {
zx::status<fuchsia::virtualization::HostVsockEndpointSyncPtr> vsock_endpoint =
connect_to_vsock_endpoint(env_id, port, context);
if (vsock_endpoint.is_error()) {
return vsock_endpoint.error_value();
}
zx::socket socket, remote_socket;
zx_status_t status = zx::socket::create(ZX_SOCKET_STREAM, &socket, &remote_socket);
if (status != ZX_OK) {
std::cerr << "Failed to create socket " << status << "\n";
return status;
}
vsock_endpoint->Connect(cid, port, std::move(remote_socket), &status);
if (status != ZX_OK) {
std::cerr << "Failed to connect " << status << "\n";
return status;
}
GuestConsole console(loop);
console.Start(std::move(socket));
return loop->Run();
}