blob: d5398fcca6f212f8b070c9547f264d1b8b7bacec [file] [log] [blame]
// Copyright 2016 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 <fidl/fuchsia.hardware.pty/cpp/wire.h>
#include <fidl/>
#include <fidl/fuchsia.posix.socket.packet/cpp/wire.h>
#include <fidl/fuchsia.posix.socket.raw/cpp/wire.h>
#include <fidl/fuchsia.posix.socket/cpp/wire.h>
#include <fidl/fuchsia.unknown/cpp/wire.h>
#include <lib/zx/channel.h>
#include <lib/zx/debuglog.h>
#include <lib/zx/event.h>
#include <lib/zxio/cpp/vector.h>
#include <lib/zxio/ops.h>
#include <lib/zxio/zxio.h>
#include <zircon/availability.h>
#include <zircon/types.h>
#include <algorithm>
#include <functional>
template <typename F>
zx_status_t zxio_vmo_do_vector(size_t start, size_t length, size_t* offset,
const zx_iovec_t* vector, size_t vector_count, size_t* out_actual,
F fn) {
if (*offset > length) {
return zxio_do_vector(vector, vector_count, out_actual,
[&](void* buffer, size_t capacity, size_t* out_actual) {
capacity = std::min(capacity, length - *offset);
zx_status_t status = fn(buffer, start + *offset, capacity);
if (status != ZX_OK) {
return status;
*offset += capacity;
*out_actual = capacity;
return ZX_OK;
// A utility which helps implementing the C-style |zxio_ops_t| ops table
// from a C++ class. The specific backend implementation should inherit
// from |HasIo| as the first base class, ensuring that the |zxio_t| part
// appears that the beginning of its object layout.
class HasIo {
explicit HasIo(const zxio_ops_t& ops) { zxio_init(&io_, &ops); }
zxio_t* io() { return &io_; }
const zxio_t* io() const { return &io_; }
template <typename T>
struct Adaptor {
static_assert(std::is_base_of<HasIo, T>::value);
static_assert(sizeof(T) <= sizeof(zxio_storage_t),
"C++ implementation class must fit inside zxio_storage_t.");
static_assert(!std::is_polymorphic_v<T>, "C++ implementation class must not contain vtables.");
// Converts a member function in the implementation C++ class to a signature
// compatible with the definition in the ops table.
// This class assumes the |zxio_t*| pointer as passed as the first argument to
// all |zxio_ops_t| entries is the pointer to the C++ implementation instance.
// For example, given the |release| call with the following signature:
// zx_status_t (*release)(zxio_t* io, zx_handle_t* out_handle);
// The C++ implementation may define a member function with this signature:
// zx_status_t MyClass::Release(zx_handle_t* out_handle);
// And |Adaptor<MyClass>::From<&Release>| will evaluate to a function with a
// signature compatible to the C-style definition, treating |io| as a pointer
// to the |HasIo|, invoking the corresponding member function automatically.
template <auto fn, typename... Args>
static auto From(zxio_t* io, Args... args) {
T& instance = *reinterpret_cast<T*>(io);
return (instance.*fn)(args...);
static constexpr void CheckLayout();
zxio_t io_;
constexpr void HasIo::CheckLayout() {
static_assert(offsetof(HasIo, io_) == 0);
static_assert(alignof(HasIo) == alignof(zxio_t));
uint32_t zxio_node_protocols_to_posix_type(zxio_node_protocols_t protocols);
bool zxio_is_valid(const zxio_t* io);
zx_status_t zxio_dir_init(zxio_storage_t* storage, fidl::ClientEnd<fuchsia_io::Directory> client);
zx_status_t zxio_file_init(zxio_storage_t* storage, zx::event event, zx::stream stream,
fidl::ClientEnd<fuchsia_io::File> client);
zx_status_t zxio_node_init(zxio_storage_t* storage, fidl::ClientEnd<fuchsia_io::Node> client);
zx_status_t zxio_pty_init(zxio_storage_t* storage, zx::eventpair event,
fidl::ClientEnd<fuchsia_hardware_pty::Device> client);
zx_status_t zxio_pipe_init(zxio_storage_t* pipe, zx::socket socket, zx_info_socket_t info);
#if __Fuchsia_API_level__ >= FUCHSIA_HEAD
zx_status_t zxio_symlink_init(zxio_storage_t* storage, fidl::ClientEnd<fuchsia_io::Symlink> client,
std::vector<uint8_t> target);
// debuglog --------------------------------------------------------------------
// Initializes a |zxio_storage_t| to use the given |handle| for output.
// The |handle| should be a Zircon debuglog object.
zx_status_t zxio_debuglog_init(zxio_storage_t* storage, zx::debuglog handle);
// pipe ------------------------------------------------------------------------
// A |zxio_t| backend that uses a Zircon socket object.
// The |socket| handle is a Zircon socket object.
// Will eventually be an implementation detail of zxio once fdio completes its
// transition to the zxio backend.
using zxio_pipe_t = struct zxio_pipe {
zxio_t io;
zx::socket socket;
static_assert(sizeof(zxio_pipe_t) <= sizeof(zxio_storage_t),
"zxio_pipe_t must fit inside zxio_storage_t.");
// synchronous datagram socket (channel backed) --------------------------------------------
zx_status_t zxio_synchronous_datagram_socket_init(
zxio_storage_t* storage, zx::eventpair event,
fidl::ClientEnd<fuchsia_posix_socket::SynchronousDatagramSocket> client);
// datagram socket (channel backed)
zx_status_t zxio_datagram_socket_init(zxio_storage_t* storage, zx::socket socket,
const zx_info_socket_t& info,
const zxio_datagram_prelude_size_t& prelude_size,
fidl::ClientEnd<fuchsia_posix_socket::DatagramSocket> client);
// stream socket (channel backed) --------------------------------------------
zx_status_t zxio_stream_socket_init(zxio_storage_t* storage, zx::socket socket,
const zx_info_socket_t& info, bool is_connected,
fidl::ClientEnd<fuchsia_posix_socket::StreamSocket> client);
// raw socket (channel backed) -------------------------------------------------
zx_status_t zxio_raw_socket_init(zxio_storage_t* storage, zx::eventpair event,
fidl::ClientEnd<fuchsia_posix_socket_raw::Socket> client);
// packet socket (channel backed) ----------------------------------------------
zx_status_t zxio_packet_socket_init(zxio_storage_t* storage, zx::eventpair event,
fidl::ClientEnd<fuchsia_posix_socket_packet::Socket> client);
// vmo -------------------------------------------------------------------------
// Initialize |file| with from a VMO.
// The file will be sized to match the underlying VMO by reading the size of the
// VMO from the kernel. The size of a VMO is always a multiple of the page size,
// which means the size of the file will also be a multiple of the page size.
zx_status_t zxio_vmo_init(zxio_storage_t* file, zx::vmo vmo, zx::stream stream);
zx_status_t zxio_create_with_nodeinfo(fidl::ClientEnd<fuchsia_io::Node> node,
fuchsia_io::wire::NodeInfoDeprecated& node_info,
zxio_storage_t* storage);
zx_status_t zxio_create_with_representation(fidl::ClientEnd<fuchsia_io::Node> node,
fuchsia_io::wire::Representation& reresentation,
zxio_node_attributes_t* attr, zxio_storage_t* storage);
zx::result<zxio_object_type_t> zxio_get_object_type(
const fidl::ClientEnd<fuchsia_unknown::Queryable>& queryable);