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