| // Copyright 2018 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/inception.h> |
| #include <lib/zxio/null.h> |
| #include <lib/zxio/ops.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <zircon/syscalls.h> |
| |
| static zx_status_t zxio_pipe_close(zxio_t* io) { |
| zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io); |
| zx_handle_t socket = pipe->socket; |
| pipe->socket = ZX_HANDLE_INVALID; |
| zx_handle_close(socket); |
| return ZX_OK; |
| } |
| |
| static zx_status_t zxio_pipe_release(zxio_t* io, zx_handle_t* out_handle) { |
| zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io); |
| zx_handle_t socket = pipe->socket; |
| pipe->socket = ZX_HANDLE_INVALID; |
| *out_handle = socket; |
| return ZX_OK; |
| } |
| |
| static zx_status_t zxio_pipe_clone(zxio_t* io, zx_handle_t* out_handle) { |
| zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io); |
| return zx_handle_duplicate(pipe->socket, ZX_RIGHT_SAME_RIGHTS, out_handle); |
| } |
| |
| static zx_status_t zxio_pipe_attr_get(zxio_t* io, zxio_node_attr_t* out_attr) { |
| memset(out_attr, 0, sizeof(*out_attr)); |
| out_attr->mode = S_IFIFO | S_IRUSR | S_IWUSR; |
| return ZX_OK; |
| } |
| |
| static void zxio_pipe_wait_begin(zxio_t* io, zxio_signals_t zxio_signals, |
| zx_handle_t* out_handle, |
| zx_signals_t* out_zx_signals) { |
| zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io); |
| *out_handle = pipe->socket; |
| |
| zx_signals_t zx_signals = static_cast<zx_signals_t>(zxio_signals); |
| if (zxio_signals & ZXIO_READ_DISABLED) { |
| zx_signals |= ZX_SOCKET_PEER_CLOSED; |
| } |
| *out_zx_signals = zx_signals; |
| } |
| |
| static void zxio_pipe_wait_end(zxio_t* io, zx_signals_t zx_signals, |
| zxio_signals_t* out_zxio_signals) { |
| zxio_signals_t zxio_signals = |
| static_cast<zxio_signals_t>(zx_signals) & ZXIO_SIGNAL_ALL; |
| if (zx_signals & ZX_SOCKET_PEER_CLOSED) { |
| zxio_signals |= ZXIO_READ_DISABLED; |
| } |
| *out_zxio_signals = zxio_signals; |
| } |
| |
| static zx_status_t zxio_pipe_read(zxio_t* io, void* buffer, size_t capacity, |
| size_t* out_actual) { |
| zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io); |
| zx_status_t status = zx_socket_read(pipe->socket, 0, buffer, capacity, |
| out_actual); |
| // We've reached end-of-file, which is signaled by successfully reading zero |
| // bytes. |
| // |
| // If we see |ZX_ERR_BAD_STATE|, that implies reading has been disabled for |
| // this endpoint because the only other case that generates that error is |
| // passing |ZX_SOCKET_CONTROL|, which we don't do above. |
| if (status == ZX_ERR_PEER_CLOSED || status == ZX_ERR_BAD_STATE) { |
| *out_actual = 0u; |
| return ZX_OK; |
| } |
| return status; |
| } |
| |
| static zx_status_t zxio_pipe_write(zxio_t* io, const void* buffer, |
| size_t capacity, size_t* out_actual) { |
| zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io); |
| return zx_socket_write(pipe->socket, 0, buffer, capacity, out_actual); |
| } |
| |
| static constexpr zxio_ops_t zxio_pipe_ops = []() { |
| zxio_ops_t ops = zxio_default_ops; |
| ops.close = zxio_pipe_close; |
| ops.release = zxio_pipe_release; |
| ops.clone = zxio_pipe_clone; |
| ops.wait_begin = zxio_pipe_wait_begin; |
| ops.wait_end = zxio_pipe_wait_end; |
| ops.attr_get = zxio_pipe_attr_get; |
| ops.read = zxio_pipe_read; |
| ops.write = zxio_pipe_write; |
| return ops; |
| }(); |
| |
| zx_status_t zxio_pipe_init(zxio_storage_t* storage, zx_handle_t socket) { |
| zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(storage); |
| zxio_init(&pipe->io, &zxio_pipe_ops); |
| pipe->socket = socket; |
| return ZX_OK; |
| } |