1// Copyright 2016 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 <assert.h>
6#include <fcntl.h>
7#include <limits.h>
8#include <poll.h>
9#include <pthread.h>
10#include <stdatomic.h>
11#include <stddef.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/ioctl.h>
15#include <threads.h>
16
17#include <zircon/assert.h>
18#include <zircon/device/device.h>
19#include <zircon/device/ioctl.h>
20#include <zircon/device/vfs.h>
21#include <zircon/processargs.h>
22#include <zircon/syscalls.h>
23
24#include <fuchsia/io/c/fidl.h>
25#include <lib/fdio/debug.h>
26#include <lib/fdio/io.h>
27#include <lib/fdio/namespace.h>
28#include <lib/fdio/remoteio.h>
29#include <lib/fdio/util.h>
30#include <lib/fdio/vfs.h>
31
32#include "private-fidl.h"
33#include "private-remoteio.h"
34
35#define ZXDEBUG 0
36
37// POLL_MASK and POLL_SHIFT intend to convert the lower five POLL events into
38// ZX_USER_SIGNALs and vice-versa. Other events need to be manually converted to
39// a zx_signals_t, if they are desired.
40#define POLL_SHIFT  24
41#define POLL_MASK   0x1F
42
43static_assert(ZX_USER_SIGNAL_0 == (1 << POLL_SHIFT), "");
44static_assert((POLLIN << POLL_SHIFT) == DEVICE_SIGNAL_READABLE, "");
45static_assert((POLLPRI << POLL_SHIFT) == DEVICE_SIGNAL_OOB, "");
46static_assert((POLLOUT << POLL_SHIFT) == DEVICE_SIGNAL_WRITABLE, "");
47static_assert((POLLERR << POLL_SHIFT) == DEVICE_SIGNAL_ERROR, "");
48static_assert((POLLHUP << POLL_SHIFT) == DEVICE_SIGNAL_HANGUP, "");
49
50zx_handle_t zxrio_handle(zxrio_t* rio) {
51    return rio->h;
52}
53
54// Acquire the additional handle from |info|.
55//
56// Returns |ZX_OK| if a handle was returned.
57// Returns |ZX_ERR_NOT_FOUND| if no handle can be returned.
58static zx_status_t zxrio_object_extract_handle(const zxrio_node_info_t* info,
59                                               zx_handle_t* out) {
60    switch (info->tag) {
61    case fuchsia_io_NodeInfoTag_file:
62        if (info->file.e != ZX_HANDLE_INVALID) {
63            *out = info->file.e;
64            return ZX_OK;
65        }
66        break;
67    case fuchsia_io_NodeInfoTag_pipe:
68        if (info->pipe.s != ZX_HANDLE_INVALID) {
69            *out = info->pipe.s;
70            return ZX_OK;
71        }
72        break;
73    case fuchsia_io_NodeInfoTag_vmofile:
74        if (info->vmofile.v != ZX_HANDLE_INVALID) {
75            *out = info->vmofile.v;
76            return ZX_OK;
77        }
78        break;
79    case fuchsia_io_NodeInfoTag_device:
80        if (info->device.e != ZX_HANDLE_INVALID) {
81            *out = info->device.e;
82            return ZX_OK;
83        }
84        break;
85    }
86    return ZX_ERR_NOT_FOUND;
87}
88
89static zx_status_t zxrio_close(fdio_t* io) {
90    zxrio_t* rio = (zxrio_t*)io;
91
92    zx_status_t r = fidl_close(rio);
93    zx_handle_t h = rio->h;
94    rio->h = ZX_HANDLE_INVALID;
95    zx_handle_close(h);
96    if (rio->event != ZX_HANDLE_INVALID) {
97        h = rio->event;
98        rio->event = ZX_HANDLE_INVALID;
99        zx_handle_close(h);
100    }
101    return r;
102}
103
104// Open an object without waiting for the response.
105// This function always consumes the cnxn handle
106// The svc handle is only used to send a message
107static zx_status_t zxrio_connect(zx_handle_t svc, zx_handle_t cnxn,
108                                 uint32_t op, uint32_t flags, uint32_t mode,
109                                 const char* name) {
110    size_t len = strlen(name);
111    if (len >= PATH_MAX) {
112        zx_handle_close(cnxn);
113        return ZX_ERR_BAD_PATH;
114    }
115    if (flags & ZX_FS_FLAG_DESCRIBE) {
116        zx_handle_close(cnxn);
117        return ZX_ERR_INVALID_ARGS;
118    }
119
120    zx_status_t r;
121    switch (op) {
122    case fuchsia_io_NodeCloneOrdinal:
123        r = fidl_clone_request(svc, cnxn, flags);
124        break;
125    case fuchsia_io_DirectoryOpenOrdinal:
126        r = fidl_open_request(svc, cnxn, flags, mode, name, len);
127        break;
128    default:
129        zx_handle_close(cnxn);
130        r = ZX_ERR_NOT_SUPPORTED;
131    }
132    return r;
133}
134
135static ssize_t zxrio_write(fdio_t* io, const void* data, size_t len) {
136    zxrio_t* rio = (zxrio_t*) io;
137    zx_status_t status = ZX_OK;
138    uint64_t count = 0;
139    uint64_t xfer;
140    while (len > 0) {
141        xfer = (len > FDIO_CHUNK_SIZE) ? FDIO_CHUNK_SIZE : len;
142        uint64_t actual = 0;
143        if ((status = fidl_write(rio, data, xfer, &actual)) != ZX_OK) {
144            return status;
145        }
146        count += actual;
147        data += actual;
148        len -= actual;
149        if (xfer != actual) {
150            break;
151        }
152    }
153    if (count == 0) {
154        return status;
155    }
156    return count;
157}
158
159static ssize_t zxrio_write_at(fdio_t* io, const void* data, size_t len, off_t offset) {
160    zxrio_t* rio = (zxrio_t*) io;
161    zx_status_t status = ZX_OK;
162    uint64_t count = 0;
163    uint64_t xfer;
164    while (len > 0) {
165        xfer = (len > FDIO_CHUNK_SIZE) ? FDIO_CHUNK_SIZE : len;
166        uint64_t actual = 0;
167        if ((status = fidl_writeat(rio, data, xfer, offset, &actual)) != ZX_OK) {
168            return status;
169        }
170        count += actual;
171        data += actual;
172        offset += actual;
173        len -= actual;
174        if (xfer != actual) {
175            break;
176        }
177    }
178    if (count == 0) {
179        return status;
180    }
181    return count;
182}
183
184static zx_status_t zxrio_get_attr(fdio_t* io, vnattr_t* out) {
185    zxrio_t* rio = (zxrio_t*)io;
186    return fidl_stat(rio, out);
187}
188
189static ssize_t zxrio_read(fdio_t* io, void* data, size_t len) {
190    zxrio_t* rio = (zxrio_t*) io;
191    zx_status_t status = ZX_OK;
192    uint64_t count = 0;
193    uint64_t xfer;
194    while (len > 0) {
195        xfer = (len > FDIO_CHUNK_SIZE) ? FDIO_CHUNK_SIZE : len;
196        uint64_t actual = 0;
197        if ((status = fidl_read(rio, data, xfer, &actual)) != ZX_OK) {
198            return status;
199        }
200        count += actual;
201        data += actual;
202        len -= actual;
203        if (xfer != actual) {
204            break;
205        }
206    }
207    if (count == 0) {
208        return status;
209    }
210    return count;
211}
212
213static ssize_t zxrio_read_at(fdio_t* io, void* data, size_t len, off_t offset) {
214    zxrio_t* rio = (zxrio_t*) io;
215    zx_status_t status = ZX_OK;
216    uint64_t count = 0;
217    uint64_t xfer;
218    while (len > 0) {
219        xfer = (len > FDIO_CHUNK_SIZE) ? FDIO_CHUNK_SIZE : len;
220        uint64_t actual = 0;
221        if ((status = fidl_readat(rio, data, xfer, offset, &actual)) != ZX_OK) {
222            return status;
223        }
224        offset += actual;
225        count += actual;
226        data += actual;
227        len -= actual;
228        if (xfer != actual) {
229            break;
230        }
231    }
232    if (count == 0) {
233        return status;
234    }
235    return count;
236}
237
238static off_t zxrio_seek(fdio_t* io, off_t offset, int whence) {
239    zxrio_t* rio = (zxrio_t*)io;
240    zx_status_t status = fidl_seek(rio, offset, whence, &offset);
241    if (status != ZX_OK) {
242        return status;
243    }
244    return offset;
245}
246
247static ssize_t zxrio_ioctl(fdio_t* io, uint32_t op, const void* in_buf,
248                    size_t in_len, void* out_buf, size_t out_len) {
249    zxrio_t* rio = (zxrio_t*)io;
250    if (in_len > FDIO_IOCTL_MAX_INPUT || out_len > FDIO_CHUNK_SIZE) {
251        return ZX_ERR_INVALID_ARGS;
252    }
253    size_t actual;
254    zx_status_t status = fidl_ioctl(rio, op, in_buf, in_len, out_buf, out_len, &actual);
255    if (status != ZX_OK) {
256        return status;
257    }
258    return actual;
259}
260
261// Takes ownership of the optional |extra_handle|.
262//
263// Decodes the handle into |info|, if it exists and should
264// be decoded.
265static zx_status_t zxrio_decode_describe_handle(zxrio_describe_t* info,
266                                                zx_handle_t extra_handle) {
267    bool have_handle = (extra_handle != ZX_HANDLE_INVALID);
268    bool want_handle = false;
269    zx_handle_t* handle_target = NULL;
270
271    switch (info->extra.tag) {
272    // Case: No extra handles expected
273    case fuchsia_io_NodeInfoTag_service:
274    case fuchsia_io_NodeInfoTag_directory:
275        break;
276    // Case: Extra handles optional
277    case fuchsia_io_NodeInfoTag_file:
278        handle_target = &info->extra.file.e;
279        goto handle_optional;
280    case fuchsia_io_NodeInfoTag_device:
281        handle_target = &info->extra.device.e;
282        goto handle_optional;
283handle_optional:
284        want_handle = *handle_target == FIDL_HANDLE_PRESENT;
285        break;
286    // Case: Extra handles required
287    case fuchsia_io_NodeInfoTag_pipe:
288        handle_target = &info->extra.pipe.s;
289        goto handle_required;
290    case fuchsia_io_NodeInfoTag_vmofile:
291        handle_target = &info->extra.vmofile.v;
292        goto handle_required;
293handle_required:
294        want_handle = *handle_target == FIDL_HANDLE_PRESENT;
295        if (!want_handle) {
296            goto fail;
297        }
298        break;
299    default:
300        printf("Unexpected protocol type opening connection\n");
301        goto fail;
302    }
303
304    if (have_handle != want_handle) {
305        goto fail;
306    }
307    if (have_handle) {
308        *handle_target = extra_handle;
309    }
310    return ZX_OK;
311
312fail:
313    if (have_handle) {
314        zx_handle_close(extra_handle);
315    }
316    return ZX_ERR_IO;
317}
318
319// Wait/Read from a new client connection, with the expectation of
320// acquiring an Open response.
321//
322// Shared implementation between RemoteIO and FIDL, since the response
323// message is aligned.
324//
325// Does not close |h|, even on error.
326static zx_status_t zxrio_process_open_response(zx_handle_t h, zxrio_describe_t* info) {
327    zx_object_wait_one(h, ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED,
328                       ZX_TIME_INFINITE, NULL);
329
330    // Attempt to read the description from open
331    uint32_t dsize = sizeof(*info);
332    zx_handle_t extra_handle = ZX_HANDLE_INVALID;
333    uint32_t actual_handles;
334    zx_status_t r = zx_channel_read(h, 0, info, &extra_handle, dsize, 1, &dsize,
335                                    &actual_handles);
336    if (r != ZX_OK) {
337        return r;
338    }
339    if (dsize < ZXRIO_DESCRIBE_HDR_SZ || info->hdr.ordinal != fuchsia_io_NodeOnOpenOrdinal) {
340        r = ZX_ERR_IO;
341    } else {
342        r = info->status;
343    }
344
345    if (dsize != sizeof(zxrio_describe_t)) {
346        r = (r != ZX_OK) ? r : ZX_ERR_IO;
347    }
348
349    if (r != ZX_OK) {
350        if (extra_handle != ZX_HANDLE_INVALID) {
351            zx_handle_close(extra_handle);
352        }
353        return r;
354    }
355
356    // Confirm that the objects "zxrio_describe_t" and "fuchsia_io_NodeOnOpenEvent"
357    // are aligned enough to be compatible.
358    //
359    // This is somewhat complicated by the fact that the "fuchsia_io_NodeOnOpenEvent"
360    // object has an optional "fuchsia_io_NodeInfo" secondary which exists immediately
361    // following the struct.
362    static_assert(__builtin_offsetof(zxrio_describe_t, extra) ==
363                  FIDL_ALIGN(sizeof(fuchsia_io_NodeOnOpenEvent)),
364                  "RIO Description message doesn't align with FIDL response secondary");
365    static_assert(sizeof(zxrio_node_info_t) == sizeof(fuchsia_io_NodeInfo),
366                  "RIO Node Info doesn't align with FIDL object info");
367    static_assert(__builtin_offsetof(zxrio_node_info_t, file.e) ==
368                  __builtin_offsetof(fuchsia_io_NodeInfo, file.event), "Unaligned File");
369    static_assert(__builtin_offsetof(zxrio_node_info_t, pipe.s) ==
370                  __builtin_offsetof(fuchsia_io_NodeInfo, pipe.socket), "Unaligned Pipe");
371    static_assert(__builtin_offsetof(zxrio_node_info_t, vmofile.v) ==
372                  __builtin_offsetof(fuchsia_io_NodeInfo, vmofile.vmo), "Unaligned Vmofile");
373    static_assert(__builtin_offsetof(zxrio_node_info_t, device.e) ==
374                  __builtin_offsetof(fuchsia_io_NodeInfo, device.event), "Unaligned Device");
375    // Connection::NodeDescribe also relies on these static_asserts.
376    // fidl_describe also relies on these static_asserts.
377
378    return zxrio_decode_describe_handle(info, extra_handle);
379}
380
381__EXPORT
382zx_status_t fdio_service_connect(const char* svcpath, zx_handle_t h) {
383    if (svcpath == NULL) {
384        zx_handle_close(h);
385        return ZX_ERR_INVALID_ARGS;
386    }
387    // Otherwise attempt to connect through the root namespace
388    if (fdio_root_ns != NULL) {
389        return fdio_ns_connect(fdio_root_ns, svcpath,
390                               ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, h);
391    }
392    // Otherwise we fail
393    zx_handle_close(h);
394    return ZX_ERR_NOT_FOUND;
395}
396
397__EXPORT
398zx_status_t fdio_service_connect_at(zx_handle_t dir, const char* path, zx_handle_t h) {
399    if (path == NULL) {
400        zx_handle_close(h);
401        return ZX_ERR_INVALID_ARGS;
402    }
403    if (dir == ZX_HANDLE_INVALID) {
404        zx_handle_close(h);
405        return ZX_ERR_UNAVAILABLE;
406    }
407    return zxrio_connect(dir, h, fuchsia_io_DirectoryOpenOrdinal, ZX_FS_RIGHT_READABLE |
408                         ZX_FS_RIGHT_WRITABLE, 0755, path);
409}
410
411__EXPORT
412zx_status_t fdio_open_at(zx_handle_t dir, const char* path, uint32_t flags, zx_handle_t h) {
413    if (path == NULL) {
414        zx_handle_close(h);
415        return ZX_ERR_INVALID_ARGS;
416    }
417    if (dir == ZX_HANDLE_INVALID) {
418        zx_handle_close(h);
419        return ZX_ERR_UNAVAILABLE;
420    }
421    return zxrio_connect(dir, h, fuchsia_io_DirectoryOpenOrdinal, flags, 0755, path);
422}
423
424__EXPORT
425zx_handle_t fdio_service_clone(zx_handle_t svc) {
426    zx_handle_t cli, srv;
427    zx_status_t r;
428    if (svc == ZX_HANDLE_INVALID) {
429        return ZX_HANDLE_INVALID;
430    }
431    if ((r = zx_channel_create(0, &cli, &srv)) < 0) {
432        return ZX_HANDLE_INVALID;
433    }
434    if ((r = zxrio_connect(svc, srv, fuchsia_io_NodeCloneOrdinal, ZX_FS_RIGHT_READABLE |
435                           ZX_FS_RIGHT_WRITABLE, 0755, "")) < 0) {
436        zx_handle_close(cli);
437        return ZX_HANDLE_INVALID;
438    }
439    return cli;
440}
441
442__EXPORT
443zx_status_t fdio_service_clone_to(zx_handle_t svc, zx_handle_t srv) {
444    if (srv == ZX_HANDLE_INVALID) {
445        return ZX_ERR_INVALID_ARGS;
446    }
447    if (svc == ZX_HANDLE_INVALID) {
448        zx_handle_close(srv);
449        return ZX_ERR_INVALID_ARGS;
450    }
451    return zxrio_connect(svc, srv, fuchsia_io_NodeCloneOrdinal, ZX_FS_RIGHT_READABLE |
452                         ZX_FS_RIGHT_WRITABLE, 0755, "");
453}
454
455zx_status_t fdio_acquire_socket(zx_handle_t socket, fdio_t** out_io) {
456    zx_info_socket_t info;
457    memset(&info, 0, sizeof(info));
458    zx_status_t status = zx_object_get_info(socket, ZX_INFO_SOCKET, &info, sizeof(info), NULL, NULL);
459    if (status != ZX_OK) {
460        zx_handle_close(socket);
461        return status;
462    }
463    fdio_t* io = NULL;
464    if ((info.options & ZX_SOCKET_HAS_CONTROL) != 0) {
465        // If the socket has a control plane, then the socket is either
466        // a stream or a datagram socket.
467        if ((info.options & ZX_SOCKET_DATAGRAM) != 0) {
468            io = fdio_socket_create_datagram(socket, IOFLAG_SOCKET_CONNECTED);
469        } else {
470            io = fdio_socket_create_stream(socket, IOFLAG_SOCKET_CONNECTED);
471        }
472    } else {
473        // Without a control plane, the socket is a pipe.
474        io = fdio_pipe_create(socket);
475    }
476    if (!io) {
477        return ZX_ERR_NO_RESOURCES;
478    }
479    *out_io = io;
480    return ZX_OK;
481}
482
483// Create a fdio (if possible) from handles and info.
484//
485// The Control channel is provided in |handle|, and auxillary
486// handles may be provided in the |info| object.
487//
488// This function always takes control of all handles.
489// They are transferred into the |out| object on success,
490// or closed on failure.
491static zx_status_t fdio_from_handles(zx_handle_t handle, zxrio_node_info_t* info,
492                                     fdio_t** out) {
493    // All failure cases which discard handles set r and break
494    // to the end. All other cases in which handle ownership is moved
495    // on return locally.
496    zx_status_t r;
497    fdio_t* io;
498    switch (info->tag) {
499    case fuchsia_io_NodeInfoTag_directory:
500    case fuchsia_io_NodeInfoTag_service:
501        if (handle == ZX_HANDLE_INVALID) {
502            r = ZX_ERR_INVALID_ARGS;
503            break;
504        }
505        io = fdio_remote_create(handle, 0);
506        xprintf("rio (%x,%x) -> %p\n", handle, 0, io);
507        if (io == NULL) {
508            return ZX_ERR_NO_RESOURCES;
509        }
510        *out = io;
511        return ZX_OK;
512    case fuchsia_io_NodeInfoTag_file:
513        if (info->file.e == ZX_HANDLE_INVALID) {
514            io = fdio_remote_create(handle, 0);
515            xprintf("rio (%x,%x) -> %p\n", handle, 0, io);
516        } else {
517            io = fdio_remote_create(handle, info->file.e);
518            xprintf("rio (%x,%x) -> %p\n", handle, info->file.e, io);
519        }
520        if (io == NULL) {
521            return ZX_ERR_NO_RESOURCES;
522        }
523        *out = io;
524        return ZX_OK;
525    case fuchsia_io_NodeInfoTag_device:
526        if (info->device.e == ZX_HANDLE_INVALID) {
527            io = fdio_remote_create(handle, 0);
528            xprintf("rio (%x,%x) -> %p\n", handle, 0, io);
529        } else {
530            io = fdio_remote_create(handle, info->device.e);
531            xprintf("rio (%x,%x) -> %p\n", handle, info->device.e, io);
532        }
533        if (io == NULL) {
534            return ZX_ERR_NO_RESOURCES;
535        }
536        *out = io;
537        return ZX_OK;
538    case fuchsia_io_NodeInfoTag_vmofile: {
539        if (info->vmofile.v == ZX_HANDLE_INVALID) {
540            r = ZX_ERR_INVALID_ARGS;
541            break;
542        }
543        *out = fdio_vmofile_create(handle, info->vmofile.v, info->vmofile.offset,
544                                   info->vmofile.length);
545        if (*out == NULL) {
546            return ZX_ERR_NO_RESOURCES;
547        }
548        return ZX_OK;
549    }
550    case fuchsia_io_NodeInfoTag_pipe: {
551        if (info->pipe.s == ZX_HANDLE_INVALID) {
552            r = ZX_ERR_INVALID_ARGS;
553            break;
554        }
555        zx_handle_close(handle);
556        return fdio_acquire_socket(info->pipe.s, out);
557    }
558    default:
559        printf("fdio_from_handles: Not supported\n");
560        r = ZX_ERR_NOT_SUPPORTED;
561        break;
562    }
563    zx_handle_t extra;
564    if (zxrio_object_extract_handle(info, &extra) == ZX_OK) {
565        zx_handle_close(extra);
566    }
567    zx_handle_close(handle);
568    return r;
569}
570
571__EXPORT
572zx_status_t fdio_create_fd(zx_handle_t* handles, uint32_t* types, size_t hcount,
573                           int* fd_out) {
574    fdio_t* io;
575    zx_status_t r;
576    int fd;
577    zxrio_node_info_t info;
578
579    // Pack additional handles into |info|, if possible.
580    switch (PA_HND_TYPE(types[0])) {
581    case PA_FDIO_REMOTE:
582        switch (hcount) {
583        case 1:
584            io = fdio_remote_create(handles[0], 0);
585            goto bind;
586        case 2:
587            io = fdio_remote_create(handles[0], handles[1]);
588            goto bind;
589        default:
590            r = ZX_ERR_INVALID_ARGS;
591            goto fail;
592        }
593    case PA_FDIO_SOCKET:
594        info.tag = fuchsia_io_NodeInfoTag_pipe;
595        // Expected: Single socket handle
596        if (hcount != 1) {
597            r = ZX_ERR_INVALID_ARGS;
598            goto fail;
599        }
600        info.pipe.s = handles[0];
601        break;
602    default:
603        r = ZX_ERR_IO;
604        goto fail;
605    }
606
607    if ((r = fdio_from_handles(ZX_HANDLE_INVALID, &info, &io)) != ZX_OK) {
608        return r;
609    }
610
611bind:
612    fd = fdio_bind_to_fd(io, -1, 0);
613    if (fd < 0) {
614        fdio_close(io);
615        fdio_release(io);
616        return ZX_ERR_BAD_STATE;
617    }
618
619    *fd_out = fd;
620    return ZX_OK;
621fail:
622    zx_handle_close_many(handles, hcount);
623    return r;
624}
625
626// Synchronously (non-pipelined) open an object
627// The svc handle is only used to send a message
628static zx_status_t zxrio_sync_open_connection(zx_handle_t svc, uint32_t op,
629                                              uint32_t flags, uint32_t mode,
630                                              const char* path, size_t pathlen,
631                                              zxrio_describe_t* info, zx_handle_t* out) {
632    if (!(flags & ZX_FS_FLAG_DESCRIBE)) {
633        return ZX_ERR_INVALID_ARGS;
634    }
635
636    zx_status_t r;
637    zx_handle_t h;
638    zx_handle_t cnxn;
639    if ((r = zx_channel_create(0, &h, &cnxn)) != ZX_OK) {
640        return r;
641    }
642
643    switch (op) {
644    case fuchsia_io_NodeCloneOrdinal:
645        r = fidl_clone_request(svc, cnxn, flags);
646        break;
647    case fuchsia_io_DirectoryOpenOrdinal:
648        r = fidl_open_request(svc, cnxn, flags, mode, path, pathlen);
649        break;
650    default:
651        zx_handle_close(cnxn);
652        r = ZX_ERR_NOT_SUPPORTED;
653    }
654
655    if (r != ZX_OK) {
656        zx_handle_close(h);
657        return r;
658    }
659
660    if ((r = zxrio_process_open_response(h, info)) != ZX_OK) {
661        zx_handle_close(h);
662        return r;
663    }
664    *out = h;
665    return ZX_OK;
666}
667
668// Acquires a new connection to an object.
669//
670// Returns a description of the opened object in |info|, and
671// the control channel to the object in |out|.
672//
673// |info| may contain an additional handle.
674static zx_status_t zxrio_getobject(zx_handle_t rio_h, uint32_t op, const char* name,
675                                   uint32_t flags, uint32_t mode,
676                                   zxrio_describe_t* info, zx_handle_t* out) {
677    if (name == NULL) {
678        return ZX_ERR_INVALID_ARGS;
679    }
680
681    size_t len = strlen(name);
682    if (len >= PATH_MAX) {
683        return ZX_ERR_BAD_PATH;
684    }
685
686    if (flags & ZX_FS_FLAG_DESCRIBE) {
687        return zxrio_sync_open_connection(rio_h, op, flags, mode, name, len, info, out);
688    } else {
689        zx_handle_t h0, h1;
690        zx_status_t r;
691        if ((r = zx_channel_create(0, &h0, &h1)) < 0) {
692            return r;
693        }
694        if ((r = zxrio_connect(rio_h, h1, op, flags, mode, name)) < 0) {
695            zx_handle_close(h0);
696            return r;
697        }
698        // fake up a reply message since pipelined opens don't generate one
699        info->status = ZX_OK;
700        info->extra.tag = fuchsia_io_NodeInfoTag_service;
701        *out = h0;
702        return ZX_OK;
703    }
704}
705
706zx_status_t zxrio_open_handle(zx_handle_t h, const char* path, uint32_t flags,
707                              uint32_t mode, fdio_t** out) {
708    zx_handle_t control_channel;
709    zxrio_describe_t info;
710    zx_status_t r = zxrio_getobject(h, fuchsia_io_DirectoryOpenOrdinal, path, flags, mode, &info, &control_channel);
711    if (r < 0) {
712        return r;
713    }
714    return fdio_from_handles(control_channel, &info.extra, out);
715}
716
717static zx_status_t zxrio_open(fdio_t* io, const char* path, uint32_t flags, uint32_t mode, fdio_t** out) {
718    zxrio_t* rio = (void*)io;
719    return zxrio_open_handle(rio->h, path, flags, mode, out);
720}
721
722static zx_status_t zxrio_clone(fdio_t* io, zx_handle_t* handles, uint32_t* types) {
723    zxrio_t* rio = (void*)io;
724    zx_handle_t h;
725    zxrio_describe_t info;
726    zx_status_t r = zxrio_getobject(rio->h, fuchsia_io_NodeCloneOrdinal, "", 0, 0, &info, &h);
727    if (r < 0) {
728        return r;
729    }
730    handles[0] = h;
731    types[0] = PA_FDIO_REMOTE;
732    return 1;
733}
734
735static zx_status_t zxrio_unwrap(fdio_t* io, zx_handle_t* handles, uint32_t* types) {
736    zxrio_t* rio = (void*)io;
737    LOG(1, "fdio: zxrio_unwrap(%p,...)\n");
738    handles[0] = rio->h;
739    types[0] = PA_FDIO_REMOTE;
740    if (rio->event != ZX_HANDLE_INVALID) {
741        zx_handle_close(rio->event);
742        rio->event = ZX_HANDLE_INVALID;
743    }
744    return 1;
745}
746
747static void zxrio_wait_begin(fdio_t* io, uint32_t events, zx_handle_t* handle, zx_signals_t* _signals) {
748    zxrio_t* rio = (void*)io;
749    *handle = rio->event;
750
751    zx_signals_t signals = 0;
752    // Manually add signals that don't fit within POLL_MASK
753    if (events & POLLRDHUP) {
754        signals |= ZX_CHANNEL_PEER_CLOSED;
755    }
756
757    // POLLERR is always detected
758    *_signals = (((POLLERR | events) & POLL_MASK) << POLL_SHIFT) | signals;
759}
760
761static void zxrio_wait_end(fdio_t* io, zx_signals_t signals, uint32_t* _events) {
762    // Manually add events that don't fit within POLL_MASK
763    uint32_t events = 0;
764    if (signals & ZX_CHANNEL_PEER_CLOSED) {
765        events |= POLLRDHUP;
766    }
767    *_events = ((signals >> POLL_SHIFT) & POLL_MASK) | events;
768}
769
770static zx_status_t zxrio_get_vmo(fdio_t* io, int flags, zx_handle_t* out) {
771    zx_handle_t vmo;
772    zxrio_t* rio = (zxrio_t*)io;
773    zx_status_t r = fidl_getvmo(rio, flags, &vmo);
774    if (r != ZX_OK) {
775        return r;
776    }
777    *out = vmo;
778    return ZX_OK;
779}
780
781static zx_status_t zxrio_get_token(fdio_t* io, zx_handle_t* out) {
782    zxrio_t* rio = (zxrio_t*)io;
783    return fidl_gettoken(rio, out);
784}
785
786static zx_status_t zxrio_set_attr(fdio_t* io, const vnattr_t* attr) {
787    zxrio_t* rio = (zxrio_t*)io;
788    return fidl_setattr(rio, attr);
789}
790
791static zx_status_t zxrio_sync(fdio_t* io) {
792    zxrio_t* rio = (zxrio_t*)io;
793    return fidl_sync(rio);
794}
795
796static zx_status_t zxrio_readdir(fdio_t* io, void* ptr, size_t max, size_t* actual) {
797    zxrio_t* rio = (zxrio_t*)io;
798    return fidl_readdirents(rio, ptr, max, actual);
799}
800
801static zx_status_t zxrio_rewind(fdio_t* io) {
802    zxrio_t* rio = (zxrio_t*)io;
803    return fidl_rewind(rio);
804}
805
806static zx_status_t zxrio_unlink(fdio_t* io, const char* path, size_t len) {
807    zxrio_t* rio = (zxrio_t*)io;
808    return fidl_unlink(rio, path, len);
809}
810
811static zx_status_t zxrio_truncate(fdio_t* io, off_t off) {
812    zxrio_t* rio = (zxrio_t*)io;
813    return fidl_truncate(rio, off);
814}
815
816static zx_status_t zxrio_rename(fdio_t* io, const char* src, size_t srclen,
817                                zx_handle_t dst_token, const char* dst, size_t dstlen) {
818    zxrio_t* rio = (zxrio_t*)io;
819    return fidl_rename(rio, src, srclen, dst_token, dst, dstlen);
820}
821
822static zx_status_t zxrio_link(fdio_t* io, const char* src, size_t srclen,
823                              zx_handle_t dst_token, const char* dst, size_t dstlen) {
824    zxrio_t* rio = (zxrio_t*)io;
825    return fidl_link(rio, src, srclen, dst_token, dst, dstlen);
826}
827
828static zx_status_t zxrio_get_flags(fdio_t* io, uint32_t* out_flags) {
829    zxrio_t* rio = (zxrio_t*)io;
830    return fidl_getflags(rio, out_flags);
831}
832
833static zx_status_t zxrio_set_flags(fdio_t* io, uint32_t flags) {
834    zxrio_t* rio = (zxrio_t*)io;
835    return fidl_setflags(rio, flags);
836}
837
838fdio_ops_t zx_remote_ops = {
839    .read = zxrio_read,
840    .read_at = zxrio_read_at,
841    .write = zxrio_write,
842    .write_at = zxrio_write_at,
843    .seek = zxrio_seek,
844    .misc = fdio_default_misc,
845    .close = zxrio_close,
846    .open = zxrio_open,
847    .clone = zxrio_clone,
848    .ioctl = zxrio_ioctl,
849    .wait_begin = zxrio_wait_begin,
850    .wait_end = zxrio_wait_end,
851    .unwrap = zxrio_unwrap,
852    .posix_ioctl = fdio_default_posix_ioctl,
853    .get_vmo = zxrio_get_vmo,
854    .get_token = zxrio_get_token,
855    .get_attr = zxrio_get_attr,
856    .set_attr = zxrio_set_attr,
857    .sync = zxrio_sync,
858    .readdir = zxrio_readdir,
859    .rewind = zxrio_rewind,
860    .unlink = zxrio_unlink,
861    .truncate = zxrio_truncate,
862    .rename = zxrio_rename,
863    .link = zxrio_link,
864    .get_flags = zxrio_get_flags,
865    .set_flags = zxrio_set_flags,
866    .recvfrom = fdio_default_recvfrom,
867    .sendto = fdio_default_sendto,
868    .recvmsg = fdio_default_recvmsg,
869    .sendmsg = fdio_default_sendmsg,
870    .shutdown = fdio_default_shutdown,
871};
872
873__EXPORT
874fdio_t* fdio_remote_create(zx_handle_t h, zx_handle_t event) {
875    zxrio_t* rio = fdio_alloc(sizeof(*rio));
876    if (rio == NULL) {
877        zx_handle_close(h);
878        zx_handle_close(event);
879        return NULL;
880    }
881    rio->io.ops = &zx_remote_ops;
882    rio->io.magic = FDIO_MAGIC;
883    atomic_init(&rio->io.refcount, 1);
884    rio->h = h;
885    rio->event = event;
886    return &rio->io;
887}
888