blob: 013ea3c420791dc0a08ba4924c8280be9e62d78c [file] [log] [blame]
// Copyright 2022 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 <lib/zxio/cpp/transitional.h>
#include <lib/zxio/types.h>
#include <lib/zxio/zxio.h>
#include <poll.h>
#include <sys/socket.h>
#include <zircon/types.h>
#include <algorithm>
zx_status_t zxio_sendmsg_inner(zxio_t* io, const struct msghdr* msg, int flags,
size_t* out_actual) {
if (flags) {
// TODO(https://fxbug.dev/42146893): support MSG_OOB
return ZX_ERR_NOT_SUPPORTED;
}
if (msg->msg_iovlen > IOV_MAX) {
return ZX_ERR_INVALID_ARGS;
}
// Variable length arrays have to have nonzero sizes, so we can't allocate a zx_iov for an empty
// io vector. Instead, we can allocate 1 entry when msg_iovlen is 0. This way zx_iov can still be
// non-nullptr (for example, to avoid failure due to vector nullptr when calling
// zx_stream_writev() further down; more generally so implementations further down don't need to
// worry about allowing zx_iovec_t* nullptr but only when vector_count == 0), but we won't
// actually use the 1 entry since msg->msg_iovlen is zero.
zx_iovec_t zx_iov[std::max(msg->msg_iovlen, 1)];
for (int i = 0; i < msg->msg_iovlen; ++i) {
zx_iov[i] = {
.buffer = msg->msg_iov[i].iov_base,
.capacity = msg->msg_iov[i].iov_len,
};
}
return zxio_writev(io, zx_iov, msg->msg_iovlen, 0, out_actual);
}
zx_status_t zxio_recvmsg_inner(zxio_t* io, struct msghdr* msg, int flags, size_t* out_actual) {
zxio_flags_t zxio_flags = 0;
if (flags & MSG_PEEK) {
zxio_flags |= ZXIO_PEEK;
flags &= ~MSG_PEEK;
}
if (flags) {
// TODO(https://fxbug.dev/42146893): support MSG_OOB
return ZX_ERR_NOT_SUPPORTED;
}
if (msg->msg_iovlen > IOV_MAX) {
return ZX_ERR_INVALID_ARGS;
}
// Variable length arrays have to have nonzero sizes, so we can't allocate a zx_iov for an empty
// io vector. Instead, we can allocate 1 entry when msg_iovlen is 0. This way zx_iov can still be
// non-nullptr (for example, to avoid failure due to vector nullptr when calling
// zx_stream_readv() further down; more generally so implementations further down don't need to
// worry about allowing zx_iovec_t* nullptr but only when vector_count == 0), but we won't
// actually use the 1 entry since msg->msg_iovlen is zero.
zx_iovec_t zx_iov[std::max(msg->msg_iovlen, 1)];
for (int i = 0; i < msg->msg_iovlen; ++i) {
iovec const& iov = msg->msg_iov[i];
zx_iov[i] = {
.buffer = iov.iov_base,
.capacity = iov.iov_len,
};
}
return zxio_readv(io, zx_iov, msg->msg_iovlen, zxio_flags, out_actual);
}
// TODO(https://fxbug.dev/42122379): This is mainly used by pipes. Consider merging this with the
// POSIX-to-zxio signal translation in |remote::wait_begin|.
// TODO(https://fxbug.dev/42123845): Do not change the signal mapping here and in |wait_end|
// until linked issue is resolved.
void zxio_wait_begin_inner(zxio_t* io, uint32_t events, zx_signals_t signals,
zx_handle_t* out_handle, zx_signals_t* out_signals) {
if (events & POLLIN) {
signals |= ZXIO_SIGNAL_READABLE | ZXIO_SIGNAL_PEER_CLOSED | ZXIO_SIGNAL_READ_DISABLED;
}
if (events & POLLOUT) {
signals |= ZXIO_SIGNAL_WRITABLE | ZXIO_SIGNAL_WRITE_DISABLED;
}
if (events & POLLRDHUP) {
signals |= ZXIO_SIGNAL_READ_DISABLED | ZXIO_SIGNAL_PEER_CLOSED;
}
zxio_wait_begin(io, signals, out_handle, out_signals);
}
void zxio_wait_end_inner(zxio_t* io, zx_signals_t signals, uint32_t* out_events,
zx_signals_t* out_signals) {
zxio_signals_t zxio_signals;
zxio_wait_end(io, signals, &zxio_signals);
if (out_signals) {
*out_signals = zxio_signals;
}
uint32_t events = 0;
if (zxio_signals & (ZXIO_SIGNAL_READABLE | ZXIO_SIGNAL_PEER_CLOSED | ZXIO_SIGNAL_READ_DISABLED)) {
events |= POLLIN;
}
if (zxio_signals & (ZXIO_SIGNAL_WRITABLE | ZXIO_SIGNAL_WRITE_DISABLED)) {
events |= POLLOUT;
}
if (zxio_signals & (ZXIO_SIGNAL_READ_DISABLED | ZXIO_SIGNAL_PEER_CLOSED)) {
events |= POLLRDHUP;
}
*out_events = events;
}