/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ /* 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 #include static int socket_close (struct shim_handle * hdl) { return 0; } static int socket_read (struct shim_handle * hdl, void * buf, size_t count) { int bytes = 0; 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); 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; } } return bytes; } static int 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; int 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; } return 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 int socket_poll (struct shim_handle * hdl, int poll_type) { struct shim_sock_handle * sock = &hdl->info.sock; int 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)) { debug("socket_poll: Setting -PAL_ERRNO %d\n", PAL_ERRNO); 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.writeable) ret |= FS_POLL_WR; out: if (ret < 0) { debug("Setting sock error %d\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, };