blob: 0ebe1d1617cdf508f0cc67f2bd16a6f7ed610d80 [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.
#ifndef ZIRCON_SYSTEM_ULIB_ZXIO_PRIVATE_H_
#define ZIRCON_SYSTEM_ULIB_ZXIO_PRIVATE_H_
#include <lib/zx/channel.h>
#include <lib/zx/event.h>
#include <lib/zxio/extensions.h>
#include <lib/zxio/zxio.h>
#include <zircon/types.h>
#include <algorithm>
#include <functional>
namespace {
template <typename F>
zx_status_t zxio_do_vector(const zx_iovec_t* vector, size_t vector_count, size_t* out_actual,
F fn) {
size_t total = 0;
for (size_t i = 0; i < vector_count; ++i) {
size_t actual;
zx_status_t status = fn(vector[i].buffer, vector[i].capacity, &actual);
if (status != ZX_OK) {
// This can't be `i > 0` because the first buffer supplied by the caller
// might've been of length zero, and we may never have attempted an I/O
// operation with it.
if (total > 0) {
break;
}
return status;
}
total += actual;
if (actual != vector[i].capacity) {
// Short.
break;
}
}
*out_actual = total;
return ZX_OK;
}
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 ZX_ERR_INVALID_ARGS;
}
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;
});
}
} // namespace
// 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 {
protected:
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 be 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 zx_status_t From(Args... args) {
auto memfn = std::mem_fn(fn);
return FromImpl(memfn, args...);
}
private:
template <typename MemFn, typename... Args>
static zx_status_t FromImpl(MemFn memfn, zxio_t* io, Args... args) {
T* instance = reinterpret_cast<T*>(io);
return memfn(instance, args...);
}
};
private:
static constexpr void CheckLayout();
zxio_t io_;
};
constexpr void HasIo::CheckLayout() {
static_assert(offsetof(HasIo, io_) == 0);
static_assert(alignof(HasIo) == alignof(zxio_t));
}
bool zxio_is_valid(const zxio_t* io);
zx_status_t zxio_datagram_pipe_readv(zxio_t* io, const zx_iovec_t* vector, size_t vector_count,
zxio_flags_t flags, size_t* out_actual);
zx_status_t zxio_datagram_pipe_writev(zxio_t* io, const zx_iovec_t* vector, size_t vector_count,
zxio_flags_t flags, size_t* out_actual);
void zxio_node_init(zxio_node_t* node, zx_handle_t control, const zxio_extension_ops_t* ops);
zx_status_t zxio_vmo_get_common(const zx::vmo& vmo, size_t content_size, uint32_t flags,
zx_handle_t* out_vmo, size_t* out_size);
// Common functionalities shared by the fuchsia.io v1 |node| and |remote| transports.
// These operate on the raw FIDL channel directly, as |node| and |remote|
// have different object layouts.
// Send a |fuchsia.io/Node.Close| message on |control|. Note: does not close the channel.
zx_status_t zxio_raw_remote_close(zx::unowned_channel control);
zx_status_t zxio_raw_remote_clone(zx::unowned_channel source, zx_handle_t* out_handle);
zx_status_t zxio_raw_remote_attr_get(zx::unowned_channel control, zxio_node_attributes_t* out_attr);
zx_status_t zxio_raw_remote_attr_set(zx::unowned_channel control,
const zxio_node_attributes_t* attr);
#endif // ZIRCON_SYSTEM_ULIB_ZXIO_PRIVATE_H_