1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <lib/zxio/inception.h>
6 #include <lib/zxio/null.h>
7 #include <lib/zxio/ops.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <zircon/syscalls.h>
11
zxio_pipe_release(zxio_t * io,zx_handle_t * out_handle)12 static zx_status_t zxio_pipe_release(zxio_t* io, zx_handle_t* out_handle) {
13 zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io);
14 zx_handle_t socket = pipe->socket;
15 pipe->socket = ZX_HANDLE_INVALID;
16 *out_handle = socket;
17 return ZX_OK;
18 }
19
zxio_pipe_close(zxio_t * io)20 static zx_status_t zxio_pipe_close(zxio_t* io) {
21 zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io);
22 zx_handle_t socket = pipe->socket;
23 pipe->socket = ZX_HANDLE_INVALID;
24 zx_handle_close(socket);
25 return ZX_OK;
26 }
27
zxio_pipe_attr_get(zxio_t * io,zxio_node_attr_t * out_attr)28 static zx_status_t zxio_pipe_attr_get(zxio_t* io, zxio_node_attr_t* out_attr) {
29 memset(out_attr, 0, sizeof(*out_attr));
30 out_attr->mode = S_IFIFO | S_IRUSR | S_IWUSR;
31 return ZX_OK;
32 }
33
zxio_pipe_wait_begin(zxio_t * io,zxio_signals_t zxio_signals,zx_handle_t * out_handle,zx_signals_t * out_zx_signals)34 static void zxio_pipe_wait_begin(zxio_t* io, zxio_signals_t zxio_signals,
35 zx_handle_t* out_handle,
36 zx_signals_t* out_zx_signals) {
37 zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io);
38 *out_handle = pipe->socket;
39
40 zx_signals_t zx_signals = static_cast<zx_signals_t>(zxio_signals);
41 if (zxio_signals & ZXIO_READ_DISABLED) {
42 zx_signals |= ZX_SOCKET_PEER_CLOSED;
43 }
44 *out_zx_signals = zx_signals;
45 }
46
zxio_pipe_wait_end(zxio_t * io,zx_signals_t zx_signals,zxio_signals_t * out_zxio_signals)47 static void zxio_pipe_wait_end(zxio_t* io, zx_signals_t zx_signals,
48 zxio_signals_t* out_zxio_signals) {
49 zxio_signals_t zxio_signals =
50 static_cast<zxio_signals_t>(zx_signals) & ZXIO_SIGNAL_ALL;
51 if (zx_signals & ZX_SOCKET_PEER_CLOSED) {
52 zxio_signals |= ZXIO_READ_DISABLED;
53 }
54 *out_zxio_signals = zxio_signals;
55 }
56
zxio_pipe_read(zxio_t * io,void * buffer,size_t capacity,size_t * out_actual)57 static zx_status_t zxio_pipe_read(zxio_t* io, void* buffer, size_t capacity,
58 size_t* out_actual) {
59 zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io);
60 zx_status_t status = zx_socket_read(pipe->socket, 0, buffer, capacity,
61 out_actual);
62 if (status == ZX_OK && capacity == 0u) {
63 // zx_socket_read() sets *out_actual to the number of bytes in the
64 // buffer when data is NULL and len is 0. zxio_read() should return
65 // 0u in that case.
66 *out_actual = 0u;
67 return ZX_OK;
68 }
69 // We've reached end-of-file, which is signaled by successfully reading zero
70 // bytes.
71 //
72 // If we see |ZX_ERR_BAD_STATE|, that implies reading has been disabled for
73 // this endpoint because the only other case that generates that error is
74 // passing |ZX_SOCKET_CONTROL|, which we don't do above.
75 if (status == ZX_ERR_PEER_CLOSED || status == ZX_ERR_BAD_STATE) {
76 *out_actual = 0u;
77 return ZX_OK;
78 }
79 return status;
80 }
81
zxio_pipe_write(zxio_t * io,const void * buffer,size_t capacity,size_t * out_actual)82 static zx_status_t zxio_pipe_write(zxio_t* io, const void* buffer,
83 size_t capacity, size_t* out_actual) {
84 zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(io);
85 return zx_socket_write(pipe->socket, 0, buffer, capacity, out_actual);
86 }
87
__anon8b9dca320102() 88 static constexpr zxio_ops_t zxio_pipe_ops = []() {
89 zxio_ops_t ops = zxio_default_ops;
90 ops.release = zxio_pipe_release;
91 ops.close = zxio_pipe_close;
92 ops.wait_begin = zxio_pipe_wait_begin;
93 ops.wait_end = zxio_pipe_wait_end;
94 ops.attr_get = zxio_pipe_attr_get;
95 ops.read = zxio_pipe_read;
96 ops.write = zxio_pipe_write;
97 return ops;
98 }();
99
zxio_pipe_init(zxio_storage_t * storage,zx_handle_t socket)100 zx_status_t zxio_pipe_init(zxio_storage_t* storage, zx_handle_t socket) {
101 zxio_pipe_t* pipe = reinterpret_cast<zxio_pipe_t*>(storage);
102 zxio_init(&pipe->io, &zxio_pipe_ops);
103 pipe->socket = socket;
104 return ZX_OK;
105 }
106