1// Copyright 2017 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 <errno.h> 6#include <stdatomic.h> 7#include <stdlib.h> 8 9#include <zircon/errors.h> 10#include <zircon/syscalls.h> 11 12#include "private.h" 13#include "private-remoteio.h" 14#include "unistd.h" 15 16typedef struct { 17 fdio_t io; 18 zx_handle_t h; 19} zxsvc_t; 20 21static zx_status_t zxsvc_close(fdio_t* io) { 22 zxsvc_t* svc = (zxsvc_t*) io; 23 zx_handle_close(svc->h); 24 svc->h = ZX_HANDLE_INVALID; 25 return ZX_OK; 26} 27 28static fdio_ops_t zx_svc_ops = { 29 .read = fdio_default_read, 30 .read_at = fdio_default_read_at, 31 .write = fdio_default_write, 32 .write_at = fdio_default_write_at, 33 .seek = fdio_default_seek, 34 .misc = fdio_default_misc, 35 .close = zxsvc_close, 36 .open = fdio_default_open, 37 .clone = fdio_default_clone, 38 .ioctl = fdio_default_ioctl, 39 .wait_begin = fdio_default_wait_begin, 40 .wait_end = fdio_default_wait_end, 41 .unwrap = fdio_default_unwrap, 42 .posix_ioctl = fdio_default_posix_ioctl, 43 .get_vmo = fdio_default_get_vmo, 44 .get_token = fdio_default_get_token, 45 .get_attr = fdio_default_get_attr, 46 .set_attr = fdio_default_set_attr, 47 .sync = fdio_default_sync, 48 .readdir = fdio_default_readdir, 49 .rewind = fdio_default_rewind, 50 .unlink = fdio_default_unlink, 51 .truncate = fdio_default_truncate, 52 .rename = fdio_default_rename, 53 .link = fdio_default_link, 54 .get_flags = fdio_default_get_flags, 55 .set_flags = fdio_default_set_flags, 56 .recvfrom = fdio_default_recvfrom, 57 .sendto = fdio_default_sendto, 58 .recvmsg = fdio_default_recvmsg, 59 .sendmsg = fdio_default_sendmsg, 60 .shutdown = fdio_default_shutdown, 61}; 62 63__EXPORT 64fdio_t* fdio_service_create(zx_handle_t h) { 65 zxsvc_t* svc = fdio_alloc(sizeof(*svc)); 66 if (svc == NULL) { 67 zx_handle_close(h); 68 return NULL; 69 } 70 svc->io.ops = &zx_svc_ops; 71 svc->io.magic = FDIO_MAGIC; 72 svc->h = h; 73 atomic_init(&svc->io.refcount, 1); 74 return &svc->io; 75} 76 77__EXPORT 78zx_status_t fdio_get_service_handle(int fd, zx_handle_t* out) { 79 mtx_lock(&fdio_lock); 80 if ((fd < 0) || (fd >= FDIO_MAX_FD) || (fdio_fdtab[fd] == NULL)) { 81 mtx_unlock(&fdio_lock); 82 return ZX_ERR_NOT_FOUND; 83 } 84 fdio_t* io = fdio_fdtab[fd]; 85 io->dupcount--; 86 fdio_fdtab[fd] = NULL; 87 if (io->dupcount > 0) { 88 // still alive in other fdtab slots 89 // this fd goes away but we can't give away the handle 90 mtx_unlock(&fdio_lock); 91 fdio_release(io); 92 return ZX_ERR_UNAVAILABLE; 93 } else { 94 mtx_unlock(&fdio_lock); 95 zx_status_t r; 96 if (io->ops == &zx_svc_ops) { 97 // is an unknown service, extract handle 98 zxsvc_t* svc = (zxsvc_t*) io; 99 *out = svc->h; 100 svc->h = ZX_HANDLE_INVALID; 101 r = ZX_OK; 102 } else if (io->ops == &zx_remote_ops) { 103 // is a fuchsia.io.* service, extract handle 104 zxrio_t* rio = (zxrio_t*) io; 105 *out = rio->h; 106 rio->h = ZX_HANDLE_INVALID; 107 zx_handle_close(rio->event); 108 rio->event = ZX_HANDLE_INVALID; 109 r = ZX_OK; 110 } else { 111 r = ZX_ERR_NOT_SUPPORTED; 112 io->ops->close(io); 113 } 114 fdio_release(io); 115 return r; 116 } 117} 118 119__EXPORT 120zx_handle_t __fdio_borrow_channel(fdio_t* io) { 121 if (io == NULL) { 122 return ZX_HANDLE_INVALID; 123 } 124 125 if (io->ops == &zx_svc_ops) { 126 zxsvc_t* svc = (zxsvc_t*) io; 127 return svc->h; 128 } else if (io->ops == &zx_remote_ops) { 129 zxrio_t* rio = (zxrio_t*) io; 130 return rio->h; 131 } 132 return ZX_HANDLE_INVALID; 133} 134