| // 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; |
| } |
| // Fuchsia has neither exec nor signals. |
| flags &= ~(MSG_CMSG_CLOEXEC | MSG_NOSIGNAL); |
| // TODO(https://fxbug.dev/42146893): support MSG_TRUNC and MSG_CTRUNC used by |
| // android. For now just ignore the flags. |
| flags &= ~(MSG_TRUNC | MSG_CTRUNC); |
| 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; |
| } |
| |
| // This never have ancillary data. |
| msg->msg_controllen = 0; |
| |
| // 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; |
| } |