/servers/pfs/dev_uds.c
C | 1180 lines | 623 code | 303 blank | 254 comment | 130 complexity | dd090844b1f5f734705b79918e3ef42d MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
- /*
- * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL)
- * This code handles requests generated by operations on /dev/uds
- *
- * The entry points into this file are...
- *
- * uds_open: handles the open(2) syscall on /dev/uds
- * uds_close: handles the close(2) syscall on /dev/uds
- * uds_select: handles the select(2) syscall on /dev/uds
- * uds_read: handles the read(2) syscall on /dev/uds
- * uds_write: handles the write(2) syscall on /dev/uds
- * uds_ioctl: handles the ioctl(2) syscall on /dev/uds
- * uds_status: handles status requests.
- * uds_cancel: handles cancelled syscalls.
- *
- * Also See...
- *
- * table.c, uds.c, uds.h
- *
- * Overview
- *
- * The interface to unix domain sockets is similar to the
- * the interface to network sockets. There is a character
- * device (/dev/uds) that uses STYLE_CLONE and this server
- * is a 'driver' for that device.
- */
- #define DEBUG 0
- #include "inc.h"
- #include "const.h"
- #include "glo.h"
- #include "uds.h"
- static int uds_perform_read(int minor, endpoint_t m_source, size_t
- size, int pretend);
- static int uds_perform_write(int minor, endpoint_t m_source, size_t
- size, int pretend);
- int uds_open(message *dev_m_in, message *dev_m_out)
- {
- message fs_m_in, fs_m_out;
- struct ucred ucred;
- int rc, i;
- int minor;
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_open() call_count=%d\n", uds_minor(dev_m_in),
- ++call_count);
- printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
- #endif
- /*
- * Find a slot in the descriptor table for the new descriptor.
- * The index of the descriptor in the table will be returned.
- * Subsequent calls to read/write/close/ioctl/etc will use this
- * minor number. The minor number must be different from the
- * the /dev/uds device's minor number (currently 0).
- */
- minor = -1; /* to trap error */
- for (i = 1; i < NR_FDS; i++) {
- if (uds_fd_table[i].state == UDS_FREE) {
- minor = i;
- break;
- }
- }
- if (minor == -1) {
- /* descriptor table full */
- uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, ENFILE);
- return ENFILE;
- }
- /*
- * We found a slot in uds_fd_table, now initialize the descriptor
- */
- /* mark this one as 'in use' so that it doesn't get assigned to
- * another socket
- */
- uds_fd_table[minor].state = UDS_INUSE;
- /* track the system call we are performing in case it gets cancelled */
- uds_fd_table[minor].call_nr = dev_m_in->m_type;
- uds_fd_table[minor].ioctl = 0;
- uds_fd_table[minor].syscall_done = 0;
- /* set the socket owner */
- uds_fd_table[minor].owner = dev_m_in->USER_ENDPT;
- uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
- /* setup select(2) framework */
- uds_fd_table[minor].selecting = 0;
- uds_fd_table[minor].select_proc = 0;
- uds_fd_table[minor].sel_ops_in = 0;
- uds_fd_table[minor].sel_ops_out = 0;
- uds_fd_table[minor].status_updated = 0;
- /* initialize the data pointer (pos) to the start of the PIPE */
- uds_fd_table[minor].pos = 0;
- /* the PIPE is initially empty */
- uds_fd_table[minor].size = 0;
- /* the default for a new socket is to allow reading and writing.
- * shutdown(2) will remove one or both flags.
- */
- uds_fd_table[minor].mode = S_IRUSR|S_IWUSR;
- /* In libc socket(2) sets this to the actual value later with the
- * NWIOSUDSTYPE ioctl().
- */
- uds_fd_table[minor].type = -1;
- /* Clear the backlog by setting each entry to -1 */
- for (i = 0; i < UDS_SOMAXCONN; i++) {
- /* initially no connections are pending */
- uds_fd_table[minor].backlog[i] = -1;
- }
- memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct
- ancillary));
- for (i = 0; i < OPEN_MAX; i++) {
- uds_fd_table[minor].ancillary_data.fds[i] = -1;
- }
- /* default the size to UDS_SOMAXCONN */
- uds_fd_table[minor].backlog_size = UDS_SOMAXCONN;
- /* the socket isn't listening for incoming connections until
- * listen(2) is called
- */
- uds_fd_table[minor].listening = 0;
- /* initially the socket is not connected to a peer */
- uds_fd_table[minor].peer = -1;
- /* there isn't a child waiting to be accept(2)'d */
- uds_fd_table[minor].child = -1;
- /* initially the socket is not bound or listening on an address */
- memset(&(uds_fd_table[minor].addr), '\0', sizeof(struct sockaddr_un));
- memset(&(uds_fd_table[minor].source), '\0', sizeof(struct sockaddr_un));
- memset(&(uds_fd_table[minor].target), '\0', sizeof(struct sockaddr_un));
- /* Initially the socket isn't suspended. */
- uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;
- /* and the socket doesn't have an I/O grant initially */
- uds_fd_table[minor].io_gr = (cp_grant_id_t) 0;
- /* since there is no I/O grant it effectively has no size either */
- uds_fd_table[minor].io_gr_size = 0;
- /* The process isn't suspended so we don't flag it as revivable */
- uds_fd_table[minor].ready_to_revive = 0;
- /* get the effective user id and effective group id from the endpoint */
- /* this is needed in the REQ_NEWNODE request to PFS. */
- rc = getnucred(uds_fd_table[minor].endpoint, &ucred);
- if (rc == -1) {
- /* roll back the changes we made to the descriptor */
- memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));
- /* likely error: invalid endpoint / proc doesn't exist */
- uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, errno);
- return errno;
- }
- /* Prepare Request to the FS side of PFS */
- fs_m_in.m_type = REQ_NEWNODE;
- fs_m_in.REQ_MODE = I_NAMED_PIPE;
- fs_m_in.REQ_DEV = NO_DEV;
- fs_m_in.REQ_UID = ucred.uid;
- fs_m_in.REQ_GID = ucred.gid;
- /* Request a new inode on the pipe file system */
- rc = fs_newnode(&fs_m_in, &fs_m_out);
- if (rc != OK) {
- /* roll back the changes we made to the descriptor */
- memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));
- /* likely error: get_block() failed */
- uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
- return rc;
- }
- /* Process the response */
- uds_fd_table[minor].inode_nr = fs_m_out.RES_INODE_NR;
- /* prepare the reply */
- uds_fd_table[minor].syscall_done = 1;
- uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, minor);
- return minor;
- }
- int uds_close(message *dev_m_in, message *dev_m_out)
- {
- int minor;
- message fs_m_in, fs_m_out;
- int rc;
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_close() call_count=%d\n", uds_minor(dev_m_in),
- ++call_count);
- printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
- #endif
- minor = uds_minor(dev_m_in);
- if (uds_fd_table[minor].state != UDS_INUSE) {
- /* attempted to close a socket that hasn't been opened --
- * something is very wrong :(
- */
- uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
- return EINVAL;
- }
- /* no need to track the syscall in case of cancellation. close() is
- * atomic and can't be cancelled. no need to update the endpoint here,
- * we won't be needing it to kill the socket
- */
- /* if the socket is connected, disconnect it */
- if (uds_fd_table[minor].peer != -1) {
- /* set peer of this peer to -1 */
- uds_fd_table[uds_fd_table[minor].peer].peer = -1;
- /* error to pass to peer */
- uds_fd_table[uds_fd_table[minor].peer].err = ECONNRESET;
- /* if peer was blocked on I/O revive peer */
- if (uds_fd_table[uds_fd_table[minor].peer].suspended) {
- int peer = uds_fd_table[minor].peer;
- uds_fd_table[peer].ready_to_revive = 1;
- uds_unsuspend(dev_m_in->m_source, peer);
- }
- }
- if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
- clear_fds(minor, &(uds_fd_table[minor].ancillary_data));
- }
- /* Prepare Request to the FS side of PFS */
- fs_m_in.m_type = REQ_PUTNODE;
- fs_m_in.REQ_INODE_NR = uds_fd_table[minor].inode_nr;
- fs_m_in.REQ_COUNT = 1;
- /* set the socket back to its original UDS_FREE state */
- memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));
- /* Request the removal of the inode from the pipe file system */
- rc = fs_putnode(&fs_m_in, &fs_m_out);
- if (rc != OK) {
- perror("fs_putnode");
- /* likely error: get_block() failed */
- return rc;
- }
- uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
- return OK;
- }
- int uds_select(message *dev_m_in, message *dev_m_out)
- {
- int i, bytes;
- int minor;
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_select() call_count=%d\n", uds_minor(dev_m_in),
- ++call_count);
- printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
- #endif
- minor = uds_minor(dev_m_in);
- if (uds_fd_table[minor].state != UDS_INUSE) {
- /* attempted to close a socket that hasn't been opened --
- * something is very wrong :(
- */
- uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor, EINVAL);
- return EINVAL;
- }
- /* setup select(2) framework */
- uds_fd_table[minor].selecting = 1;
- uds_fd_table[minor].select_proc = dev_m_in->m_source;
- /* track the system call we are performing in case it gets cancelled */
- uds_fd_table[minor].call_nr = dev_m_in->m_type;
- uds_fd_table[minor].ioctl = 0;
- uds_fd_table[minor].syscall_done = 0;
- /* Can't update the process endpoint here, no info. */
- uds_fd_table[minor].sel_ops_in = dev_m_in->USER_ENDPT;
- uds_fd_table[minor].sel_ops_out = 0;
- /* check if there is data available to read */
- bytes = uds_perform_read(minor, dev_m_in->m_source, 1, 1);
- if (bytes > 0) {
- /* there is data in the pipe for us to read */
- uds_fd_table[minor].sel_ops_out |= SEL_RD;
- } else if (uds_fd_table[minor].listening == 1) {
- /* check for pending connections */
- for (i = 0; i < uds_fd_table[minor].backlog_size; i++) {
- if (uds_fd_table[minor].backlog[i] != -1) {
- uds_fd_table[minor].sel_ops_out |= SEL_RD;
- break;
- }
- }
- }
- /* check if we can write without blocking */
- bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1);
- if (bytes > 0) {
- uds_fd_table[minor].sel_ops_out |= SEL_WR;
- }
- uds_fd_table[minor].syscall_done = 1;
- uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor,
- uds_fd_table[minor].sel_ops_out);
- return uds_fd_table[minor].sel_ops_out;
- }
- static int uds_perform_read(int minor, endpoint_t m_source,
- size_t size, int pretend)
- {
- int rc;
- message fs_m_in;
- message fs_m_out;
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_perform_read() call_count=%d\n", minor,
- ++call_count);
- #endif
- /* skip reads and writes of 0 (or less!) bytes */
- if (size <= 0) {
- return 0;
- }
- /* check if we are allowed to read */
- if (!(uds_fd_table[minor].mode & S_IRUSR)) {
- /* socket is shutdown for reading */
- return EPIPE;
- }
- if (uds_fd_table[minor].size == 0) {
- if (pretend) {
- return SUSPEND;
- }
- /* maybe a process is blocked waiting to write? if
- * needed revive the writer
- */
- if (uds_fd_table[minor].peer != -1 &&
- uds_fd_table[uds_fd_table[minor].peer].suspended) {
- int peer = uds_fd_table[minor].peer;
- uds_fd_table[peer].ready_to_revive = 1;
- uds_unsuspend(m_source, peer);
- }
- #if DEBUG == 1
- printf("(uds) [%d] suspending read request\n", minor);
- #endif
- /* Process is reading from an empty pipe,
- * suspend it so some bytes can be written
- */
- uds_fd_table[minor].suspended = UDS_SUSPENDED_READ;
- return SUSPEND;
- }
- if (pretend) {
- return (size > uds_fd_table[minor].size) ?
- uds_fd_table[minor].size : size;
- }
- /* Prepare Request to the FS side of PFS */
- fs_m_in.m_type = REQ_READ;
- fs_m_in.REQ_INODE_NR = uds_fd_table[minor].inode_nr;
- fs_m_in.REQ_GRANT = uds_fd_table[minor].io_gr;
- fs_m_in.REQ_SEEK_POS_HI = 0;
- fs_m_in.REQ_SEEK_POS_LO = uds_fd_table[minor].pos;
- fs_m_in.REQ_NBYTES = (size > uds_fd_table[minor].size) ?
- uds_fd_table[minor].size : size;
- /* perform the read */
- rc = fs_readwrite(&fs_m_in, &fs_m_out);
- if (rc != OK) {
- perror("fs_readwrite");
- return rc;
- }
- /* Process the response */
- #if DEBUG == 1
- printf("(uds) [%d] read complete\n", minor);
- #endif
- /* move the position of the data pointer up to data we haven't
- * read yet
- */
- uds_fd_table[minor].pos += fs_m_out.RES_NBYTES;
- /* decrease the number of unread bytes */
- uds_fd_table[minor].size -= fs_m_out.RES_NBYTES;
- /* if we have 0 unread bytes, move the data pointer back to the
- * start of the buffer
- */
- if (uds_fd_table[minor].size == 0) {
- uds_fd_table[minor].pos = 0;
- }
- /* maybe a big write was waiting for us to read some data, if
- * needed revive the writer
- */
- if (uds_fd_table[minor].peer != -1 &&
- uds_fd_table[uds_fd_table[minor].peer].suspended) {
- int peer = uds_fd_table[minor].peer;
- uds_fd_table[peer].ready_to_revive = 1;
- uds_unsuspend(m_source, peer);
- }
- /* see if peer is blocked on select() and a write is possible
- * (from peer to minor)
- */
- if (uds_fd_table[minor].peer != -1 &&
- uds_fd_table[uds_fd_table[minor].peer].selecting == 1 &&
- (uds_fd_table[minor].size + uds_fd_table[minor].pos + 1
- < PIPE_BUF)) {
- int peer = uds_fd_table[minor].peer;
- /* if the peer wants to know about write being possible
- * and it doesn't know about it already, then let the peer know.
- */
- if ((uds_fd_table[peer].sel_ops_in & SEL_WR) &&
- !(uds_fd_table[peer].sel_ops_out & SEL_WR)) {
- /* a write on peer is possible now */
- uds_fd_table[peer].sel_ops_out |= SEL_WR;
- uds_fd_table[peer].status_updated = 1;
- uds_unsuspend(m_source, peer);
- }
- }
- return fs_m_out.RES_NBYTES; /* return number of bytes read */
- }
- static int uds_perform_write(int minor, endpoint_t m_source,
- size_t size, int pretend)
- {
- int rc, peer, i;
- message fs_m_in;
- message fs_m_out;
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_perform_write() call_count=%d\n", minor,
- ++call_count);
- #endif
- /* skip reads and writes of 0 (or less!) bytes */
- if (size <= 0) {
- return 0;
- }
- /* check if we are allowed to write */
- if (!(uds_fd_table[minor].mode & S_IWUSR)) {
- /* socket is shutdown for writing */
- return EPIPE;
- }
- if (size > PIPE_BUF) {
- /* message is too big to ever write to the PIPE */
- return EMSGSIZE;
- }
- if (uds_fd_table[minor].type == SOCK_STREAM ||
- uds_fd_table[minor].type == SOCK_SEQPACKET) {
- /* if we're writing with a connection oriented socket,
- * then it needs a peer to write to
- */
- if (uds_fd_table[minor].peer == -1) {
- if (uds_fd_table[minor].err == ECONNRESET) {
- uds_fd_table[minor].err = 0;
- return ECONNRESET;
- } else {
- return ENOTCONN;
- }
- } else {
- peer = uds_fd_table[minor].peer;
- }
- } else /* uds_fd_table[minor].type == SOCK_DGRAM */ {
- peer = -1;
- /* locate the "peer" we want to write to */
- for (i = 0; i < NR_FDS; i++) {
- /* look for a SOCK_DGRAM socket that is bound on
- * the target address
- */
- if (uds_fd_table[i].type == SOCK_DGRAM &&
- uds_fd_table[i].addr.sun_family == AF_UNIX &&
- !strncmp(uds_fd_table[minor].target.sun_path,
- uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) {
- peer = i;
- break;
- }
- }
- }
- if (peer == -1) {
- if (pretend)
- return SUSPEND;
- return ENOENT;
- }
- /* check if write would overrun buffer. check if message
- * boundry preserving types (SEQPACKET and DGRAM) wouldn't write
- * to an empty buffer. check if connectionless sockets have a
- * target to write to.
- */
- if ((uds_fd_table[peer].pos+uds_fd_table[peer].size+size > PIPE_BUF) ||
- ((uds_fd_table[minor].type == SOCK_SEQPACKET ||
- uds_fd_table[minor].type == SOCK_DGRAM) &&
- uds_fd_table[peer].size > 0)) {
- if (pretend) {
- return SUSPEND;
- }
- /* if needed revive the reader */
- if (uds_fd_table[peer].suspended) {
- uds_fd_table[peer].ready_to_revive = 1;
- uds_unsuspend(m_source, peer);
- }
- #if DEBUG == 1
- printf("(uds) [%d] suspending write request\n", minor);
- #endif
- /* Process is reading from an empty pipe,
- * suspend it so some bytes can be written
- */
- uds_fd_table[minor].suspended = UDS_SUSPENDED_WRITE;
- return SUSPEND;
- }
- if (pretend) {
- return size;
- }
- /* Prepare Request to the FS side of PFS */
- fs_m_in.m_type = REQ_WRITE;
- fs_m_in.REQ_INODE_NR = uds_fd_table[peer].inode_nr;
- fs_m_in.REQ_GRANT = uds_fd_table[minor].io_gr;
- fs_m_in.REQ_SEEK_POS_HI = 0;
- fs_m_in.REQ_SEEK_POS_LO = uds_fd_table[peer].pos +
- uds_fd_table[peer].size;
- fs_m_in.REQ_NBYTES = size;
- /* Request the write */
- rc = fs_readwrite(&fs_m_in, &fs_m_out);
- if (rc != OK) {
- perror("fs_readwrite");
- return rc;
- }
- /* Process the response */
- #if DEBUG == 1
- printf("(uds) [%d] write complete\n", minor);
- #endif
- /* increase the count of unread bytes */
- uds_fd_table[peer].size += fs_m_out.RES_NBYTES;
- /* fill in the source address to be returned by recvfrom & recvmsg */
- if (uds_fd_table[minor].type == SOCK_DGRAM) {
- memcpy(&uds_fd_table[peer].source, &uds_fd_table[minor].addr,
- sizeof(struct sockaddr_un));
- }
- /* revive peer that was waiting for us to write */
- if (uds_fd_table[peer].suspended) {
- uds_fd_table[peer].ready_to_revive = 1;
- uds_unsuspend(m_source, peer);
- }
- /* see if peer is blocked on select()*/
- if (uds_fd_table[peer].selecting == 1 && fs_m_out.RES_NBYTES > 0) {
- /* if the peer wants to know about data ready to read
- * and it doesn't know about it already, then let the peer
- * know we have data for it.
- */
- if ((uds_fd_table[peer].sel_ops_in & SEL_RD) &&
- !(uds_fd_table[peer].sel_ops_out & SEL_RD)) {
- /* a read on peer is possible now */
- uds_fd_table[peer].sel_ops_out |= SEL_RD;
- uds_fd_table[peer].status_updated = 1;
- uds_unsuspend(m_source, peer);
- }
- }
- return fs_m_out.RES_NBYTES; /* return number of bytes written */
- }
- int uds_read(message *dev_m_in, message *dev_m_out)
- {
- int bytes;
- int minor;
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in),
- ++call_count);
- printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
- dev_m_in->POSITION);
- #endif
- minor = uds_minor(dev_m_in);
- if (uds_fd_table[minor].state != UDS_INUSE) {
- /* attempted to close a socket that hasn't been opened --
- * something is very wrong :(
- */
- uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
- return EINVAL;
- }
- /* track the system call we are performing in case it gets cancelled */
- uds_fd_table[minor].call_nr = dev_m_in->m_type;
- uds_fd_table[minor].ioctl = 0;
- uds_fd_table[minor].syscall_done = 0;
- /* Update the process endpoint. */
- uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
- /* setup select(2) framework */
- uds_fd_table[minor].selecting = 0;
- /* save I/O Grant info */
- uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT;
- uds_fd_table[minor].io_gr_size = dev_m_in->COUNT;
- bytes = uds_perform_read(minor, dev_m_in->m_source,
- uds_fd_table[minor].io_gr_size, 0);
- uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint,
- uds_fd_table[minor].io_gr, bytes);
- return bytes;
- }
- int uds_write(message *dev_m_in, message *dev_m_out)
- {
- int bytes;
- int minor;
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in),
- ++call_count);
- printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
- dev_m_in->POSITION);
- #endif
- minor = uds_minor(dev_m_in);
- if (uds_fd_table[minor].state != UDS_INUSE) {
- /* attempted to close a socket that hasn't been opened --
- * something is very wrong :(
- */
- uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
- return EINVAL;
- }
- /* track the system call we are performing in case it gets cancelled */
- uds_fd_table[minor].call_nr = dev_m_in->m_type;
- uds_fd_table[minor].ioctl = 0;
- uds_fd_table[minor].syscall_done = 0;
- /* Update the process endpoint. */
- uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
- /* setup select(2) framework */
- uds_fd_table[minor].selecting = 0;
- /* save I/O Grant info */
- uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT;
- uds_fd_table[minor].io_gr_size = dev_m_in->COUNT;
- bytes = uds_perform_write(minor, dev_m_in->m_source,
- uds_fd_table[minor].io_gr_size, 0);
- uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint,
- uds_fd_table[minor].io_gr, bytes);
- return bytes;
- }
- int uds_ioctl(message *dev_m_in, message *dev_m_out)
- {
- int rc, minor;
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in),
- ++call_count);
- printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
- dev_m_in->POSITION);
- #endif
- minor = uds_minor(dev_m_in);
- if (uds_fd_table[minor].state != UDS_INUSE) {
- /* attempted to close a socket that hasn't been opened --
- * something is very wrong :(
- */
- uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
- return EINVAL;
- }
- /* track the system call we are performing in case it gets cancelled */
- uds_fd_table[minor].call_nr = dev_m_in->m_type;
- uds_fd_table[minor].ioctl = dev_m_in->COUNT;
- uds_fd_table[minor].syscall_done = 0;
- /* setup select(2) framework */
- uds_fd_table[minor].selecting = 0;
- /* update the owner endpoint - yes it's really stored in POSITION */
- uds_fd_table[minor].owner = dev_m_in->POSITION;
- switch (dev_m_in->COUNT) { /* Handle the ioctl(2) command */
- case NWIOSUDSCONN:
- /* connect to a listening socket -- connect() */
- rc = do_connect(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSACCEPT:
- /* accept an incoming connection -- accept() */
- rc = do_accept(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSBLOG:
- /* set the backlog_size and put the socket into the
- * listening state -- listen()
- */
- rc = do_listen(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSTYPE:
- /* set the type for this socket (i.e.
- * SOCK_STREAM, SOCK_DGRAM, etc) -- socket()
- */
- rc = do_socket(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSADDR:
- /* set the address for this socket -- bind() */
- rc = do_bind(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSADDR:
- /* get the address for this socket -- getsockname() */
- rc = do_getsockname(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSPADDR:
- /* get the address for the peer -- getpeername() */
- rc = do_getpeername(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSSHUT:
- /* shutdown a socket for reading, writing, or
- * both -- shutdown()
- */
- rc = do_shutdown(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSPAIR:
- /* connect two sockets -- socketpair() */
- rc = do_socketpair(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSPAIROLD:
- /* connect two sockets -- socketpair() */
- rc = do_socketpair_old(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSSOTYPE:
- /* get socket type -- getsockopt(SO_TYPE) */
- rc = do_getsockopt_sotype(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSPEERCRED:
- /* get peer endpoint -- getsockopt(SO_PEERCRED) */
- rc = do_getsockopt_peercred(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSPEERCREDOLD:
- /* get peer endpoint -- getsockopt(SO_PEERCRED) */
- rc = do_getsockopt_peercred_old(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSTADDR:
- /* set target address -- sendto() */
- rc = do_sendto(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSFADDR:
- /* get from address -- recvfrom() */
- rc = do_recvfrom(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSSNDBUF:
- /* get the send buffer size -- getsockopt(SO_SNDBUF) */
- rc = do_getsockopt_sndbuf(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSSNDBUF:
- /* set the send buffer size -- setsockopt(SO_SNDBUF) */
- rc = do_setsockopt_sndbuf(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSRCVBUF:
- /* get the send buffer size -- getsockopt(SO_SNDBUF) */
- rc = do_getsockopt_rcvbuf(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSRCVBUF:
- /* set the send buffer size -- setsockopt(SO_SNDBUF) */
- rc = do_setsockopt_rcvbuf(dev_m_in, dev_m_out);
- break;
- case NWIOSUDSCTRL:
- /* set the control data -- sendmsg() */
- rc = do_sendmsg(dev_m_in, dev_m_out);
- break;
- case NWIOGUDSCTRL:
- /* set the control data -- recvmsg() */
- rc = do_recvmsg(dev_m_in, dev_m_out);
- break;
- default:
- /* the IOCTL command is not valid for /dev/uds --
- * this happens a lot and is normal. a lot of
- * libc functions determine the socket type with
- * IOCTLs. Any not for us simply get a EBADIOCTL
- * response.
- */
- rc = EBADIOCTL;
- }
- if (rc != SUSPEND)
- uds_fd_table[minor].syscall_done = 1;
- uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
- return rc;
- }
- int uds_unsuspend(endpoint_t m_source, int minor)
- {
- int r = OK, bytes;
- message m_out;
- uds_fd_t *fdp;
- fdp = &uds_fd_table[minor];
- if (fdp->status_updated == 1) {
- /* clear the status_updated flag */
- fdp->status_updated = 0;
- fdp->selecting = 0;
- /* prepare the response */
- uds_sel_reply(&m_out, DEV_SEL_REPL2, minor, fdp->sel_ops_out);
- } else if (fdp->ready_to_revive == 1) {
- /* clear the ready to revive flag */
- fdp->ready_to_revive = 0;
- switch (fdp->suspended) {
- case UDS_SUSPENDED_READ:
- bytes = uds_perform_read(minor, m_source,
- fdp->io_gr_size, 0);
- if (bytes == SUSPEND) {
- r = SUSPEND;
- break;
- }
- fdp->suspended = UDS_NOT_SUSPENDED;
- uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
- fdp->io_gr, bytes);
- break;
- case UDS_SUSPENDED_WRITE:
- bytes = uds_perform_write(minor, m_source,
- fdp->io_gr_size, 0);
- if (bytes == SUSPEND) {
- r = SUSPEND;
- break;
- }
- fdp->suspended = UDS_NOT_SUSPENDED;
- uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
- fdp->io_gr, bytes);
- break;
- case UDS_SUSPENDED_CONNECT:
- case UDS_SUSPENDED_ACCEPT:
- /* In both cases, the process
- * that send the notify()
- * already performed the connection.
- * The only thing to do here is
- * unblock.
- */
- fdp->suspended = UDS_NOT_SUSPENDED;
- uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
- fdp->io_gr, OK);
- break;
- default:
- return(OK);
- }
- }
- if (r == OK) reply(m_source, &m_out);
- return(r);
- }
- int uds_cancel(message *dev_m_in, message *dev_m_out)
- {
- int i, j;
- int minor;
- /* XXX: should become a noop? */
- #if DEBUG == 1
- static int call_count = 0;
- printf("(uds) [%d] uds_cancel() call_count=%d\n", uds_minor(dev_m_in),
- ++call_count);
- printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
- #endif
- minor = uds_minor(dev_m_in);
- if (uds_fd_table[minor].state != UDS_INUSE) {
- /* attempted to close a socket that hasn't been opened --
- * something is very wrong :(
- */
- uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
- return EINVAL;
- }
- /* Update the process endpoint. */
- uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
- /* setup select(2) framework */
- uds_fd_table[minor].selecting = 0;
- /* the system call was cancelled, so if the socket was suspended
- * (which is likely the case), then it is not suspended anymore.
- */
- uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;
- /* If there is a system call and it isn't complete, roll back */
- if (uds_fd_table[minor].call_nr && !uds_fd_table[minor].syscall_done) {
- if (uds_fd_table[minor].call_nr == DEV_IOCTL_S) {
- switch (uds_fd_table[minor].ioctl) {
- case NWIOSUDSACCEPT: /* accept() */
- /* partial accept() only changes
- * uds_fd_table[minorparent].child
- */
- for (i = 0; i < NR_FDS; i++) {
- if (uds_fd_table[i].child ==
- minor) {
- uds_fd_table[i].child = -1;
- }
- }
- break;
- case NWIOSUDSCONN: /* connect() */
- /* partial connect() sets addr
- * and adds minor to server backlog
- */
- for (i = 0; i < NR_FDS; i++) {
- /* find a socket that is in
- * use.
- */
- if (uds_fd_table[i].state ==
- UDS_INUSE) {
- /* see if minor is in
- * the backlog
- */
- for (j = 0; j < uds_fd_table[i].backlog_size; j++) {
- if (uds_fd_table[i].backlog[j] == minor) {
- /* remove from backlog */
- uds_fd_table[i].backlog[j] = -1;
- }
- }
- }
- }
- /* clear the address */
- memset(&(uds_fd_table[minor].addr),
- '\0',
- sizeof(struct sockaddr_un));
- break;
- case NWIOSUDSTADDR: /* sendto() */
- case NWIOSUDSADDR: /* bind() */
- case NWIOGUDSADDR: /* getsockname() */
- case NWIOGUDSPADDR: /* getpeername() */
- case NWIOSUDSTYPE: /* socket() */
- case NWIOSUDSBLOG: /* listen() */
- case NWIOSUDSSHUT: /* shutdown() */
- case NWIOSUDSPAIR: /* socketpair() */
- case NWIOGUDSSOTYPE: /* SO_TYPE */
- case NWIOGUDSPEERCRED: /* SO_PEERCRED */
- default:
- /* these are atomic, never suspend,
- * and can't be cancelled once called
- */
- break;
- }
- }
- /* DEV_READ_S or DEV_WRITE_S don't need to do anything
- * when cancelled. DEV_OPEN, DEV_REOPEN, DEV_SELECT,
- * DEV_CLOSE are atomic, never suspend, and can't
- * be cancelled once called.
- */
- uds_fd_table[minor].syscall_done = 1;
- }
- uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT,
- (cp_grant_id_t) dev_m_in->IO_GRANT, EINTR);
- return EINTR;
- }