| // Copyright 2017 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 <errno.h> |
| #include <stdatomic.h> |
| #include <stdlib.h> |
| |
| #include <zircon/errors.h> |
| #include <zircon/syscalls.h> |
| |
| #include "private.h" |
| #include "unistd.h" |
| |
| typedef struct { |
| fdio_t io; |
| zx_handle_t h; |
| } mxsvc_t; |
| |
| static zx_status_t mxsvc_close(fdio_t* io) { |
| mxsvc_t* svc = (mxsvc_t*) io; |
| zx_handle_close(svc->h); |
| svc->h = ZX_HANDLE_INVALID; |
| return ZX_OK; |
| } |
| |
| static fdio_ops_t zx_svc_ops = { |
| .read = fdio_default_read, |
| .read_at = fdio_default_read_at, |
| .write = fdio_default_write, |
| .write_at = fdio_default_write_at, |
| .recvfrom = fdio_default_recvfrom, |
| .sendto = fdio_default_sendto, |
| .recvmsg = fdio_default_recvmsg, |
| .sendmsg = fdio_default_sendmsg, |
| .seek = fdio_default_seek, |
| .misc = fdio_default_misc, |
| .close = mxsvc_close, |
| .open = fdio_default_open, |
| .clone = fdio_default_clone, |
| .ioctl = fdio_default_ioctl, |
| .wait_begin = fdio_default_wait_begin, |
| .wait_end = fdio_default_wait_end, |
| .unwrap = fdio_default_unwrap, |
| .shutdown = fdio_default_shutdown, |
| .posix_ioctl = fdio_default_posix_ioctl, |
| .get_vmo = fdio_default_get_vmo, |
| }; |
| |
| fdio_t* fdio_service_create(zx_handle_t h) { |
| mxsvc_t* svc = calloc(1, sizeof(*svc)); |
| if (svc == NULL) { |
| zx_handle_close(h); |
| return NULL; |
| } |
| svc->io.ops = &zx_svc_ops; |
| svc->io.magic = FDIO_MAGIC; |
| svc->h = h; |
| atomic_init(&svc->io.refcount, 1); |
| return &svc->io; |
| } |
| |
| zx_status_t fdio_get_service_handle(int fd, zx_handle_t* out) { |
| mtx_lock(&fdio_lock); |
| if ((fd < 0) || (fd >= MAX_FDIO_FD) || (fdio_fdtab[fd] == NULL)) { |
| mtx_unlock(&fdio_lock); |
| return ERRNO(EBADF); |
| } |
| fdio_t* io = fdio_fdtab[fd]; |
| io->dupcount--; |
| fdio_fdtab[fd] = NULL; |
| if (io->dupcount > 0) { |
| // still alive in other fdtab slots |
| // this fd goes away but we can't give away the handle |
| mtx_unlock(&fdio_lock); |
| fdio_release(io); |
| return ZX_ERR_UNAVAILABLE; |
| } else { |
| mtx_unlock(&fdio_lock); |
| int r; |
| if (io->ops == &zx_svc_ops) { |
| // is a service, extract handle |
| mxsvc_t* svc = (mxsvc_t*) io; |
| *out = svc->h; |
| svc->h = ZX_HANDLE_INVALID; |
| r = ZX_OK; |
| } else { |
| r = io->ops->close(io); |
| fdio_release(io); |
| } |
| return STATUS(r); |
| } |
| } |