/* Copyright (C) 2014 Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * fs.c * * This file contains codes for implementation of 'socket' filesystem. */ #include #include #include #include #include #include #include #include #include #include #include // TODO: For some reason S_IF* macros are missing if this file is included before our headers. We // should investigate and fix this behavior. #include static int socket_close(struct shim_handle* hdl) { /* XXX: Shouldn't this do something? */ __UNUSED(hdl); return 0; } static ssize_t socket_read(struct shim_handle* hdl, void* buf, size_t count) { struct shim_sock_handle* sock = &hdl->info.sock; if (!count) return 0; lock(&hdl->lock); if (sock->sock_type == SOCK_STREAM && sock->sock_state != SOCK_ACCEPTED && sock->sock_state != SOCK_CONNECTED && sock->sock_state != SOCK_BOUNDCONNECTED) { sock->error = ENOTCONN; unlock(&hdl->lock); return -ENOTCONN; } if (sock->sock_type == SOCK_DGRAM && sock->sock_state != SOCK_CONNECTED && sock->sock_state != SOCK_BOUNDCONNECTED) { sock->error = EDESTADDRREQ; unlock(&hdl->lock); return -EDESTADDRREQ; } unlock(&hdl->lock); PAL_NUM bytes = DkStreamRead(hdl->pal_handle, 0, count, buf, NULL, 0); if (!bytes) switch (PAL_NATIVE_ERRNO) { case PAL_ERROR_ENDOFSTREAM: return 0; default: { int err = PAL_ERRNO; lock(&hdl->lock); sock->error = err; unlock(&hdl->lock); return -err; } } assert((ssize_t)bytes > 0); return (ssize_t)bytes; } static ssize_t socket_write(struct shim_handle* hdl, const void* buf, size_t count) { struct shim_sock_handle* sock = &hdl->info.sock; lock(&hdl->lock); if (sock->sock_type == SOCK_STREAM && sock->sock_state != SOCK_ACCEPTED && sock->sock_state != SOCK_CONNECTED && sock->sock_state != SOCK_BOUNDCONNECTED) { sock->error = ENOTCONN; unlock(&hdl->lock); return -ENOTCONN; } if (sock->sock_type == SOCK_DGRAM && sock->sock_state != SOCK_CONNECTED && sock->sock_state != SOCK_BOUNDCONNECTED) { sock->error = EDESTADDRREQ; unlock(&hdl->lock); return -EDESTADDRREQ; } unlock(&hdl->lock); if (!count) return 0; PAL_NUM bytes = DkStreamWrite(hdl->pal_handle, 0, count, (void*)buf, NULL); if (!bytes) { int err; switch (PAL_NATIVE_ERRNO) { case PAL_ERROR_CONNFAILED: err = EPIPE; break; default: err = PAL_ERRNO; break; } lock(&hdl->lock); sock->error = err; unlock(&hdl->lock); return -err; } assert((ssize_t)bytes > 0); return (ssize_t)bytes; } static int socket_hstat(struct shim_handle* hdl, struct stat* stat) { if (!stat) return 0; PAL_STREAM_ATTR attr; if (!DkStreamAttributesQueryByHandle(hdl->pal_handle, &attr)) return -PAL_ERRNO; memset(stat, 0, sizeof(struct stat)); stat->st_ino = 0; stat->st_size = (off_t)attr.pending_size; stat->st_mode = S_IFSOCK; return 0; } static int socket_checkout(struct shim_handle* hdl) { hdl->fs = NULL; return 0; } static off_t socket_poll(struct shim_handle* hdl, int poll_type) { struct shim_sock_handle* sock = &hdl->info.sock; off_t ret = 0; lock(&hdl->lock); if (poll_type & FS_POLL_RD) { if (sock->sock_type == SOCK_STREAM) { if (sock->sock_state == SOCK_CREATED || sock->sock_state == SOCK_BOUND || sock->sock_state == SOCK_SHUTDOWN) { ret = -ENOTCONN; goto out; } } if (sock->sock_type == SOCK_DGRAM && sock->sock_state == SOCK_SHUTDOWN) { ret = -ENOTCONN; goto out; } } if (poll_type & FS_POLL_WR) { if (sock->sock_type == SOCK_STREAM) { if (sock->sock_state == SOCK_CREATED || sock->sock_state == SOCK_BOUND || sock->sock_state == SOCK_LISTENED || sock->sock_state == SOCK_SHUTDOWN) { ret = -ENOTCONN; goto out; } } if (sock->sock_type == SOCK_DGRAM && sock->sock_state == SOCK_SHUTDOWN) { ret = -ENOTCONN; goto out; } } if (!hdl->pal_handle) { ret = -EBADF; goto out; } PAL_STREAM_ATTR attr; if (!DkStreamAttributesQueryByHandle(hdl->pal_handle, &attr)) { ret = -PAL_ERRNO; goto out; } if (poll_type == FS_POLL_SZ) { ret = attr.pending_size; goto out; } ret = 0; if (attr.disconnected) ret |= FS_POLL_ER; if ((poll_type & FS_POLL_RD) && attr.readable) ret |= FS_POLL_RD; if ((poll_type & FS_POLL_WR) && attr.writable) ret |= FS_POLL_WR; out: if (ret < 0) { debug("socket_poll failed (%ld)\n", ret); sock->error = -ret; } unlock(&hdl->lock); return ret; } static int socket_setflags(struct shim_handle* hdl, int flags) { if (!hdl->pal_handle) return 0; PAL_STREAM_ATTR attr; if (!DkStreamAttributesQueryByHandle(hdl->pal_handle, &attr)) return -PAL_ERRNO; if (attr.nonblocking) { if (flags & O_NONBLOCK) return 0; attr.nonblocking = PAL_FALSE; } else { if (!(flags & O_NONBLOCK)) return 0; attr.nonblocking = PAL_TRUE; } if (!DkStreamAttributesSetByHandle(hdl->pal_handle, &attr)) return -PAL_ERRNO; return 0; } struct shim_fs_ops socket_fs_ops = { .close = &socket_close, .read = &socket_read, .write = &socket_write, .hstat = &socket_hstat, .checkout = &socket_checkout, .poll = &socket_poll, .setflags = &socket_setflags, }; struct shim_mount socket_builtin_fs = { .type = "socket", .fs_ops = &socket_fs_ops, };