blob: 78104764ae51a5692ddf19e49ea92938ec099a79 [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.
#pragma once
#include <magenta/types.h>
#include <mxio/limits.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <threads.h>
typedef struct mxio mxio_t;
typedef struct mxio_namespace mxio_ns_t;
// MXIO provides open/close/read/write io over various transports
// via the mxio_t interface abstraction.
//
// The PIPE protocol uses message ports as simple, no-flow-control
// io pipes with a maximum message size of MX_PIPE_SIZE.
//
// The REMOTEIO protocol uses message ports to implement simple
// synchronous remoting of read/write/close operations.
//
// The NULL protocol absorbs writes and is never readable.
typedef struct mxio_ops {
ssize_t (*read)(mxio_t* io, void* data, size_t len);
ssize_t (*read_at)(mxio_t* io, void* data, size_t len, off_t offset);
ssize_t (*write)(mxio_t* io, const void* data, size_t len);
ssize_t (*write_at)(mxio_t* io, const void* data, size_t len, off_t offset);
ssize_t (*recvfrom)(mxio_t* io, void* data, size_t len, int flags, struct sockaddr* restrict addr, socklen_t* restrict addrlen);
ssize_t (*sendto)(mxio_t* io, const void* data, size_t len, int flags, const struct sockaddr* addr, socklen_t addrlen);
ssize_t (*recvmsg)(mxio_t* io, struct msghdr* msg, int flags);
ssize_t (*sendmsg)(mxio_t* io, const struct msghdr* msg, int flags);
off_t (*seek)(mxio_t* io, off_t offset, int whence);
mx_status_t (*misc)(mxio_t* io, uint32_t op, int64_t off, uint32_t maxreply, void* data, size_t len);
mx_status_t (*close)(mxio_t* io);
mx_status_t (*open)(mxio_t* io, const char* path, int32_t flags, uint32_t mode, mxio_t** out);
mx_status_t (*clone)(mxio_t* io, mx_handle_t* out_handles, uint32_t* out_types);
mx_status_t (*unwrap)(mxio_t* io, mx_handle_t* out_handles, uint32_t* out_types);
mx_status_t (*shutdown)(mxio_t* io, int how);
void (*wait_begin)(mxio_t* io, uint32_t events, mx_handle_t* handle, mx_signals_t* signals);
void (*wait_end)(mxio_t* io, mx_signals_t signals, uint32_t* events);
ssize_t (*ioctl)(mxio_t* io, uint32_t op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len);
ssize_t (*posix_ioctl)(mxio_t* io, int req, va_list va);
mx_status_t (*get_vmo)(mxio_t* io, mx_handle_t* out, size_t* off, size_t* len);
} mxio_ops_t;
// mxio_t flags
#define MXIO_FLAG_CLOEXEC ((int32_t)1 << 0)
#define MXIO_FLAG_SOCKET ((int32_t)1 << 1)
#define MXIO_FLAG_EPOLL ((int32_t)1 << 2)
#define MXIO_FLAG_WAITABLE ((int32_t)1 << 3)
#define MXIO_FLAG_SOCKET_CONNECTING ((int32_t)1 << 4)
#define MXIO_FLAG_SOCKET_CONNECTED ((int32_t)1 << 5)
#define MXIO_FLAG_NONBLOCK ((int32_t)1 << 6)
// The subset of mxio_t per-fd flags queryable via fcntl.
// Static assertions in unistd.c ensure we aren't colliding.
#define MXIO_FD_FLAGS MXIO_FLAG_CLOEXEC
typedef struct mxio {
mxio_ops_t* ops;
uint32_t magic;
atomic_int_fast32_t refcount;
int32_t dupcount;
int32_t flags;
} mxio_t;
// Lifecycle notes:
//
// Upon creation, mxio objects have a refcount of 1.
// mxio_acquire() and mxio_release() are used to upref
// and downref, respectively. Upon downref to 0,
// mxio_free() is called, which poisons the object and
// free()s it.
//
// The close hook must be called before free and should
// only be called once. In normal use, mxio objects are
// accessed through the mxio_fdtab, and when close is
// called they are removed from the fdtab and the reference
// that the fdtab itself is holding is released, at which
// point they will be free()'d unless somebody is holding
// a ref due to an ongoing io transaction, which will
// certainly fail doe to underlying handles being closed
// at which point a downref will happen and destruction
// will follow.
//
// dupcount tracks how many fdtab entries an mxio object
// is in. close() reduces the dupcount, and only actually
// closes the underlying object when it reaches zero.
#define MXIO_MAGIC 0x4f49584d // MXIO
static inline ssize_t mxio_read(mxio_t* io, void* data, size_t len) {
return io->ops->read(io, data, len);
}
static inline ssize_t mxio_read_at(mxio_t* io, void* data, size_t len, off_t offset) {
return io->ops->read_at(io, data, len, offset);
}
static inline ssize_t mxio_write(mxio_t* io, const void* data, size_t len) {
return io->ops->write(io, data, len);
}
static inline ssize_t mxio_write_at(mxio_t* io, const void* data, size_t len, off_t offset) {
return io->ops->write_at(io, data, len, offset);
}
static inline off_t mxio_seek(mxio_t* io, off_t offset, int whence) {
return io->ops->seek(io, offset, whence);
}
static inline mx_status_t mxio_misc(mxio_t* io, uint32_t op, int64_t off, uint32_t maxreply, void* data, size_t len) {
return io->ops->misc(io, op, off, maxreply, data, len);
}
static inline mx_status_t mxio_open(mxio_t* io, const char* path, int32_t flags, uint32_t mode, mxio_t** out) {
return io->ops->open(io, path, flags, mode, out);
}
mx_status_t mxio_close(mxio_t* io);
mx_status_t mxio_wait(mxio_t* io, uint32_t events, mx_time_t deadline,
uint32_t* out_pending);
// Wraps a socket with an mxio_t using simple io.
// Takes ownership of h.
mxio_t* mxio_pipe_create(mx_handle_t h);
mx_status_t mxio_pipe_posix_ioctl(mxio_t* io, int req, va_list va);
// Wraps a vmo, offset, length with an mxio_t providing a readonly file.
// Takens ownership of h.
mxio_t* mxio_vmofile_create(mx_handle_t h, mx_off_t off, mx_off_t len);
// Wraps a socket with an mxio_t using socket io.
// Takes ownership of h and s.
mxio_t* mxio_socket_create(mx_handle_t h, mx_handle_t s, int flags);
// creates a message port and pair of simple io mxio_t's
int mxio_pipe_pair(mxio_t** a, mxio_t** b);
// create a mxio (if possible) from type, handles and extradata
mx_status_t mxio_from_handles(uint32_t type, mx_handle_t* handles, int hcount,
void* extra, uint32_t esize, mxio_t** out);
void mxio_free(mxio_t* io);
static inline void mxio_acquire(mxio_t* io) {
atomic_fetch_add(&io->refcount, 1);
}
static inline void mxio_release(mxio_t* io) {
if (atomic_fetch_sub(&io->refcount, 1) == 1) {
mxio_free(io);
}
}
mxio_t* mxio_ns_open_root(mxio_ns_t* ns);
// io will be consumed by this and must not be shared
void mxio_chdir(mxio_t* io, const char* path);
// Wraps an arbitrary handle with a mxio_t that works with wait hooks.
// Takes ownership of handle unless shared_handle is true.
mxio_t* mxio_waitable_create(mx_handle_t h, mx_signals_t signals_in, mx_signals_t signals_out, bool shared_handle);
void mxio_socket_set_stream_ops(mxio_t* io);
void mxio_socket_set_dgram_ops(mxio_t* io);
mx_status_t mxio_socket_posix_ioctl(mxio_t* io, int req, va_list va);
mx_status_t mxio_socket_shutdown(mxio_t* io, int how);
mx_status_t mxio_socketpair_shutdown(mxio_t* io, int how);
// unsupported / do-nothing hooks shared by implementations
ssize_t mxio_default_read(mxio_t* io, void* _data, size_t len);
ssize_t mxio_default_read_at(mxio_t* io, void* _data, size_t len, off_t offset);
ssize_t mxio_default_write(mxio_t* io, const void* _data, size_t len);
ssize_t mxio_default_write_at(mxio_t* io, const void* _data, size_t len, off_t offset);
ssize_t mxio_default_recvfrom(mxio_t* io, void* _data, size_t len, int flags, struct sockaddr* restrict addr, socklen_t* restrict addrlen);
ssize_t mxio_default_sendto(mxio_t* io, const void* _data, size_t len, int flags, const struct sockaddr* addr, socklen_t addrlen);
ssize_t mxio_default_recvmsg(mxio_t* io, struct msghdr* msg, int flags);
ssize_t mxio_default_sendmsg(mxio_t* io, const struct msghdr* msg, int flags);
off_t mxio_default_seek(mxio_t* io, off_t offset, int whence);
mx_status_t mxio_default_misc(mxio_t* io, uint32_t op, int64_t off, uint32_t arg, void* data, size_t len);
mx_status_t mxio_default_close(mxio_t* io);
mx_status_t mxio_default_open(mxio_t* io, const char* path, int32_t flags, uint32_t mode, mxio_t** out);
mx_status_t mxio_default_clone(mxio_t* io, mx_handle_t* handles, uint32_t* types);
ssize_t mxio_default_ioctl(mxio_t* io, uint32_t op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len);
void mxio_default_wait_begin(mxio_t* io, uint32_t events, mx_handle_t* handle, mx_signals_t* _signals);
void mxio_default_wait_end(mxio_t* io, mx_signals_t signals, uint32_t* _events);
mx_status_t mxio_default_unwrap(mxio_t* io, mx_handle_t* handles, uint32_t* types);
mx_status_t mxio_default_shutdown(mxio_t* io, int how);
ssize_t mxio_default_posix_ioctl(mxio_t* io, int req, va_list va);
mx_status_t mxio_default_get_vmo(mxio_t* io, mx_handle_t* out, size_t* off, size_t* len);
void __mxio_startup_handles_init(uint32_t num, mx_handle_t handles[],
uint32_t handle_info[])
__attribute__((visibility("hidden")));
void __mxio_rchannel_init(void) __attribute__((visibility("hidden")));
typedef struct {
mtx_t lock;
mtx_t cwd_lock;
bool init;
mode_t umask;
mxio_t* root;
mxio_t* cwd;
mxio_t* fdtab[MAX_MXIO_FD];
mxio_ns_t* ns;
char cwd_path[PATH_MAX];
} mxio_state_t;
extern mxio_state_t __mxio_global_state;
#define mxio_lock (__mxio_global_state.lock)
#define mxio_root_handle (__mxio_global_state.root)
#define mxio_cwd_handle (__mxio_global_state.cwd)
#define mxio_cwd_lock (__mxio_global_state.cwd_lock)
#define mxio_cwd_path (__mxio_global_state.cwd_path)
#define mxio_fdtab (__mxio_global_state.fdtab)
#define mxio_root_init (__mxio_global_state.init)
#define mxio_root_ns (__mxio_global_state.ns)