]> Zhao Yanbai Git Server - minix.git/commitdiff
Add UNIX Domain Sockets internals to PFS. Contributed by Thomas Cort
authorThomas Veerman <thomas@minix3.org>
Thu, 15 Jul 2010 13:39:57 +0000 (13:39 +0000)
committerThomas Veerman <thomas@minix3.org>
Thu, 15 Jul 2010 13:39:57 +0000 (13:39 +0000)
18 files changed:
servers/pfs/Makefile
servers/pfs/const.h
servers/pfs/dev_uds.c [new file with mode: 0644]
servers/pfs/fs.h
servers/pfs/glo.h
servers/pfs/inc.h
servers/pfs/inode.c
servers/pfs/link.c
servers/pfs/main.c
servers/pfs/misc.c
servers/pfs/open.c
servers/pfs/proto.h
servers/pfs/read.c
servers/pfs/stadir.c
servers/pfs/table.c
servers/pfs/uds.c [new file with mode: 0644]
servers/pfs/uds.h [new file with mode: 0644]
servers/pfs/utility.c

index 9e84d39290940e5560786d94b14e0cb362a4ee43..c36260425ef3b896cb612b05aff71f0243efc725 100644 (file)
@@ -1,10 +1,11 @@
 # Makefile for Pipe File System (PFS)
 PROG=  pfs
 SRCS=  open.c table.c inode.c main.c super.c link.c \
-       buffer.c read.c misc.c utility.c stadir.c
+       buffer.c read.c misc.c utility.c stadir.c \
+       uds.c dev_uds.c
 
-DPADD+=        ${LIBSYS}
-LDADD+=        -lsys
+DPADD+=        ${LIBDRIVER} ${LIBSYS}
+LDADD+=        -ldriver -lsys
 
 MAN=
 
index 25c5bc83aeebe5a15bfeac8d55af4b55b453b175..443c61f4020b31a43ae33bf8643b54a7891aba39 100644 (file)
@@ -3,6 +3,11 @@
 
 #define NR_INODES        256   /* # slots in "in core" inode table */
 
+/* Size of descriptor table for unix domain sockets. This should be 
+ * equal to the maximum number of minor devices (currently 256).
+ */
+#define NR_FDS           256
+
 #define INODE_HASH_LOG2   7     /* 2 based logarithm of the inode hash size */
 #define INODE_HASH_SIZE   ((unsigned long)1<<INODE_HASH_LOG2)
 #define INODE_HASH_MASK   (((unsigned long)1<<INODE_HASH_LOG2)-1)
@@ -31,5 +36,8 @@
 #define FS_BITCHUNK_BITS               (usizeof(bitchunk_t) * CHAR_BIT)
 #define FS_BITS_PER_BLOCK(b)   (FS_BITMAP_CHUNKS(b) * FS_BITCHUNK_BITS)
 
+#define FS_CALL_VEC_SIZE 31
+#define DEV_CALL_VEC_SIZE 25
+
 #endif
 
diff --git a/servers/pfs/dev_uds.c b/servers/pfs/dev_uds.c
new file mode 100644 (file)
index 0000000..84d2dd0
--- /dev/null
@@ -0,0 +1,1191 @@
+/*
+ * 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"
+
+PUBLIC 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->IO_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.
+        */
+
+       minor = -1; /* to trap error */
+
+       for (i = 0; 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, TASK_REPLY, dev_m_in->IO_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->IO_ENDPT;
+       uds_fd_table[minor].endpoint = dev_m_in->IO_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;
+       }
+
+       /* 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));
+
+       /* 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, TASK_REPLY, dev_m_in->IO_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, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, errno);
+               return errno;
+       }
+
+       /* 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, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, minor);
+       return minor;
+}
+
+PUBLIC 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->IO_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, TASK_REPLY, dev_m_in->IO_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;
+                       notify(dev_m_in->m_source);
+               }
+       }
+
+       /* 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, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+       return OK;
+}
+
+PUBLIC int uds_select(message *dev_m_in, message *dev_m_out)
+{
+       int i, bytes;
+       int minor;
+       message fs_m_in, fs_m_out;
+
+#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->IO_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, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, 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->IO_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 at least 1 byte */
+       bytes = uds_perform_write(minor, dev_m_in->m_source, 1, 1);
+       if (bytes > 0) {
+               uds_fd_table[minor].sel_ops_out |= SEL_WR;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, 
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, 
+                       uds_fd_table[minor].sel_ops_out);
+
+       return uds_fd_table[minor].sel_ops_out;
+}
+
+PRIVATE int uds_perform_read(int minor, endpoint_t m_source, size_t 
+                               size, int pretend)
+{
+       int rc, bytes;
+       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 */
+               errno = EPIPE;
+               return -1;
+       }
+
+       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;
+                       notify(m_source);
+               }
+
+#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) {
+
+               uds_fd_table[uds_fd_table[minor].peer].ready_to_revive = 1;
+               notify(m_source);
+       }
+
+       /* 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;
+                       notify(uds_fd_table[peer].select_proc);
+               }
+       }
+
+       return fs_m_out.RES_NBYTES; /* return number of bytes read */
+}
+
+PRIVATE 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 */
+               errno = EPIPE;
+               return -1;
+       }
+
+       if (size > PIPE_BUF) {
+
+               /* message is too big to ever write to the PIPE */
+               errno = EMSGSIZE;
+               return -1;
+       }
+
+       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;
+                               errno = ECONNRESET;
+                       } else {
+                               errno = ENOTCONN;
+                       }
+
+                       return -1;
+               } 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;
+                       }
+               }
+       }
+
+       /* 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) || (peer == -1)) {
+
+               if (pretend) {
+                       return SUSPEND;
+               }
+
+               /* if needed revive the reader */
+               if (uds_fd_table[peer].suspended) {
+
+                       uds_fd_table[peer].ready_to_revive = 1;
+                       notify(m_source);
+               }
+
+#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;
+               notify(m_source);
+       }
+
+       /* 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;
+                       notify(uds_fd_table[peer].select_proc);
+               }
+       }
+
+       return fs_m_out.RES_NBYTES; /* return number of bytes written */
+}
+
+PUBLIC int uds_read(message *dev_m_in, message *dev_m_out)
+{
+       int rc, bytes;
+       int minor;
+       message fs_m_in, fs_m_out;
+
+#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->IO_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, TASK_REPLY, dev_m_in->IO_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->IO_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);
+
+       if (bytes == -1) {
+
+               uds_set_reply(dev_m_out, TASK_REPLY,
+                               uds_fd_table[minor].endpoint, 
+                               uds_fd_table[minor].io_gr,
+                               errno);
+
+               return errno;
+       } else {
+
+               uds_set_reply(dev_m_out, TASK_REPLY, 
+                               uds_fd_table[minor].endpoint, 
+                               uds_fd_table[minor].io_gr,
+                               bytes);
+
+               return bytes;
+       }
+}
+
+PUBLIC int uds_write(message *dev_m_in, message *dev_m_out)
+{
+       int rc;
+       int bytes;
+       int minor;
+       int peer;
+       message fs_m_in, fs_m_out;
+
+#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->IO_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, TASK_REPLY, dev_m_in->IO_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->IO_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);
+
+       if (bytes == -1) {
+
+               uds_set_reply(dev_m_out, TASK_REPLY, 
+                               uds_fd_table[minor].endpoint, 
+                               uds_fd_table[minor].io_gr,
+                               errno);
+
+               return errno;
+
+       } else {
+
+               uds_set_reply(dev_m_out, TASK_REPLY, 
+                               uds_fd_table[minor].endpoint, 
+                               uds_fd_table[minor].io_gr,
+                               bytes);
+
+               return bytes;
+       }
+}
+
+PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out)
+{
+       int rc, i;
+       int minor;
+       struct sockaddr_un addr;
+
+#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->IO_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, TASK_REPLY, dev_m_in->IO_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() */
+                       return do_connect(dev_m_in, dev_m_out);
+
+               case NWIOSUDSACCEPT:
+
+                       /* accept an incoming connection -- accept() */
+                       return do_accept(dev_m_in, dev_m_out);
+
+               case NWIOSUDSBLOG:
+
+                       /* set the backlog_size and put the socket into the
+                        * listening state -- listen()
+                        */
+                       return do_listen(dev_m_in, dev_m_out);
+
+               case NWIOSUDSTYPE:
+
+                       /* set the type for this socket (i.e. 
+                        * SOCK_STREAM, SOCK_DGRAM, etc) -- socket()
+                        */
+                       return do_socket(dev_m_in, dev_m_out);
+
+               case NWIOSUDSADDR:
+
+                       /* set the address for this socket -- bind() */
+                       return do_bind(dev_m_in, dev_m_out);
+
+               case NWIOGUDSADDR:
+
+                       /* get the address for this socket -- getsockname() */
+                       return do_getsockname(dev_m_in, dev_m_out);
+
+               case NWIOGUDSPADDR:
+
+                       /* get the address for the peer -- getpeername() */
+                       return do_getpeername(dev_m_in, dev_m_out);
+
+               case NWIOSUDSSHUT:
+
+                       /* shutdown a socket for reading, writing, or 
+                        * both -- shutdown()
+                        */
+                       return do_shutdown(dev_m_in, dev_m_out);
+
+               case NWIOSUDSPAIR:
+
+                       /* connect two sockets -- socketpair() */
+                       return do_socketpair(dev_m_in, dev_m_out);
+
+               case NWIOGUDSSOTYPE:
+
+                       /* get socket type -- getsockopt(SO_TYPE) */
+                       return do_getsockopt_sotype(dev_m_in, dev_m_out);
+
+               case NWIOGUDSPEERCRED:
+
+                       /* get peer endpoint -- getsockopt(SO_PEERCRED) */
+                       return do_getsockopt_peercred(dev_m_in, dev_m_out);
+
+               case NWIOSUDSTADDR:
+
+                       /* set target address -- sendto() */
+                       return do_sendto(dev_m_in, dev_m_out);
+
+               case NWIOGUDSFADDR:
+
+                       /* get from address -- recvfrom() */
+                       return do_recvfrom(dev_m_in, dev_m_out);
+
+               case NWIOGUDSSNDBUF:
+
+                       /* get the send buffer size -- getsockopt(SO_SNDBUF) */
+                       return do_getsockopt_sndbuf(dev_m_in, dev_m_out);
+
+               case NWIOSUDSSNDBUF:
+
+                       /* set the send buffer size -- setsockopt(SO_SNDBUF) */
+                       return do_setsockopt_sndbuf(dev_m_in, dev_m_out);
+
+               case NWIOGUDSRCVBUF:
+
+                       /* get the send buffer size -- getsockopt(SO_SNDBUF) */
+                       return do_getsockopt_rcvbuf(dev_m_in, dev_m_out);
+
+               case NWIOSUDSRCVBUF:
+
+                       /* set the send buffer size -- setsockopt(SO_SNDBUF) */
+                       return do_setsockopt_rcvbuf(dev_m_in, dev_m_out);
+
+               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.
+                        */
+                       uds_fd_table[minor].syscall_done = 1;
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                                       dev_m_in->IO_ENDPT, 
+                                       (cp_grant_id_t) dev_m_in->IO_GRANT,
+                                       EBADIOCTL);
+
+                       return EBADIOCTL;
+       }
+}
+
+PUBLIC int uds_status(message *dev_m_in, message *dev_m_out)
+{
+       int i, bytes;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] uds_status() call_count=%d\n", uds_minor(dev_m_in),
+                                                       ++call_count);
+       printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, dev_m_in->POSITION);
+#endif
+
+       for (i = 0; i < NR_FDS; i++) {
+
+               if (uds_fd_table[i].status_updated == 1) {
+
+                       /* clear the status_updated flag */
+                       uds_fd_table[i].status_updated = 0;
+                       uds_fd_table[i].selecting = 0;
+
+                       /* prepare the response */
+                       dev_m_out->m_type = DEV_IO_READY;
+                       dev_m_out->DEV_MINOR = i;
+                       dev_m_out->DEV_SEL_OPS = uds_fd_table[i].sel_ops_out;
+
+                       return uds_fd_table[i].sel_ops_out;
+               }
+
+               if (uds_fd_table[i].ready_to_revive == 1) {
+
+                       /* clear the ready to revive flag */
+                       uds_fd_table[i].ready_to_revive = 0;
+
+                       switch (uds_fd_table[i].suspended) {
+
+                               case UDS_SUSPENDED_READ:
+
+                                       bytes = uds_perform_read(i, 
+                                               dev_m_in->m_source,
+                                               uds_fd_table[i].io_gr_size,
+                                               0);
+
+                                       if (bytes == -1) {
+
+                                               uds_set_reply(dev_m_out,
+                                               DEV_REVIVE, 
+                                               uds_fd_table[i].endpoint,
+                                               uds_fd_table[i].io_gr,
+                                               errno);
+
+                                               return errno;
+
+                                       } else if (bytes == SUSPEND) {
+
+                                               dev_m_out->m_type =
+                                                       DEV_NO_STATUS;
+
+                                               return OK;
+
+                                       } else  {
+
+                                               uds_fd_table[i].suspended =
+                                                       UDS_NOT_SUSPENDED;
+
+                                               uds_set_reply(dev_m_out,
+                                               DEV_REVIVE, 
+                                               uds_fd_table[i].endpoint,
+                                               uds_fd_table[i].io_gr,
+                                               bytes);
+
+                                               return bytes;
+                                       }
+
+                               case UDS_SUSPENDED_WRITE:
+
+                                       bytes = uds_perform_write(i,
+                                               dev_m_in->m_source, 
+                                               uds_fd_table[i].io_gr_size,
+                                               0);
+
+                                       if (bytes == -1) {
+
+                                               uds_set_reply(dev_m_out,
+                                               DEV_REVIVE, 
+                                               uds_fd_table[i].endpoint,
+                                               uds_fd_table[i].io_gr,
+                                               errno);
+
+                                               return errno;
+
+                                       } else if (bytes == SUSPEND) {
+
+                                               dev_m_out->m_type =
+                                                       DEV_NO_STATUS;
+
+                                               return OK;
+
+                                       } else  {
+
+                                               uds_fd_table[i].suspended =
+                                                       UDS_NOT_SUSPENDED;
+
+                                               uds_set_reply(dev_m_out, 
+                                               DEV_REVIVE, 
+                                               uds_fd_table[i].endpoint,
+                                               uds_fd_table[i].io_gr,
+                                               bytes);
+
+                                               return bytes;
+                                       }
+
+                               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.
+                                        */
+
+                                       uds_fd_table[i].suspended = 
+                                                       UDS_NOT_SUSPENDED;
+
+                                       uds_set_reply(dev_m_out,
+                                               DEV_REVIVE, 
+                                               uds_fd_table[i].endpoint,
+                                               uds_fd_table[i].io_gr,
+                                               OK);
+
+                                       return OK;
+
+                               default:
+                                       continue;
+                       }
+
+               }
+       }
+
+       dev_m_out->m_type = DEV_NO_STATUS;
+       return OK;
+}
+
+PUBLIC int uds_cancel(message *dev_m_in, message *dev_m_out)
+{
+       int i, j;
+       int minor;
+
+#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->IO_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, TASK_REPLY, dev_m_in->IO_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->IO_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, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, EINTR);
+
+       return EINTR;
+}
+
index 6a1ca24ade5e79798c3fd3a46b3374b39134b74c..225cd35acd4f968fd3205e745aa34b218ba6e673 100644 (file)
@@ -15,6 +15,7 @@
 #include <minix/const.h>
 #include <minix/type.h>
 #include <minix/dmap.h>
+#include <minix/vfsif.h>
 #include <limits.h>
 #include <errno.h>
 #include <minix/syslib.h>
index 9b4eeeb8e85923e11b9de230be59197e0a3cba46..76338599b30dd371be1518641ab8e1de92f00a74 100644 (file)
 /* The following variables are used for returning results to the caller. */
 EXTERN int err_code;           /* temporary storage for error number */
 
-EXTERN _PROTOTYPE (int (*fs_call_vec[]), (void) ); /* fs call table */
-
-EXTERN message fs_m_in;
-EXTERN message fs_m_out;
+EXTERN _PROTOTYPE (int (*fs_call_vec[]), (message *fs_m_in, message *fs_m_out) ); /* fs call table */
+EXTERN _PROTOTYPE (int (*dev_call_vec[]), (message *fs_m_in, message *fs_m_out) ); /* dev call table */
 
 EXTERN uid_t caller_uid;
 EXTERN gid_t caller_gid;
index 9f22b60e9b53e7b392c76138ff61e7d83d28ba36..09755c5e4260a161b59d5e49573a32e17927e0e4 100644 (file)
@@ -4,8 +4,13 @@
 
 #define VERBOSE                   0    /* display diagnostics */
 
+#include <net/ioctl.h>
+
 #include <ansi.h>
 #include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
 #include <limits.h>
 #include <errno.h>
 #include <signal.h>
@@ -13,6 +18,7 @@
 
 #include <minix/callnr.h>
 #include <minix/config.h>
+#include <minix/dmap.h>
 #include <minix/type.h>
 #include <minix/const.h>
 #include <minix/com.h>
index bbb799c5131df1ed4c0b4b4566d22534b99eb487..a2b42e8b6e81a54a4212daef6bf3cddfb3750082 100644 (file)
@@ -26,7 +26,7 @@ FORWARD _PROTOTYPE( void unhash_inode, (struct inode * const node)            );
 /*===========================================================================*
  *                             fs_putnode                                   *
  *===========================================================================*/
-PUBLIC int fs_putnode()
+PUBLIC int fs_putnode(message *fs_m_in, message *fs_m_out)
 {
 /* Find the inode specified by the request message and decrease its counter.*/
 
@@ -35,15 +35,15 @@ PUBLIC int fs_putnode()
   dev_t dev;
   ino_t inum;
   
-  rip = find_inode( (ino_t) fs_m_in.REQ_INODE_NR);
+  rip = find_inode( (ino_t) fs_m_in->REQ_INODE_NR);
 
   if(!rip) {
          printf("%s:%d put_inode: inode #%ld dev: %d not found\n", __FILE__,
-                __LINE__, fs_m_in.REQ_INODE_NR, (dev_t) fs_m_in.REQ_DEV);
+                __LINE__, fs_m_in->REQ_INODE_NR, (dev_t) fs_m_in->REQ_DEV);
          panic("fs_putnode failed");
   }
 
-  count = fs_m_in.REQ_COUNT;
+  count = fs_m_in->REQ_COUNT;
   if (count <= 0) {
        printf("%s:%d put_inode: bad value for count: %d\n", __FILE__,
               __LINE__, count);
index d6b9ba9ed7ae2583c54cd31777ae059b58523b4f..4a5e901cb5d96d065579598246bc64b555cfa576 100644 (file)
@@ -6,18 +6,18 @@
 /*===========================================================================*
  *                             fs_ftrunc                                    *
  *===========================================================================*/
-PUBLIC int fs_ftrunc(void)
+PUBLIC int fs_ftrunc(message *fs_m_in, message *fs_m_out)
 {
   struct inode *rip;
   off_t start, end;
   ino_t inumb;
   
-  inumb = (ino_t) fs_m_in.REQ_INODE_NR;
+  inumb = (ino_t) fs_m_in->REQ_INODE_NR;
 
   if( (rip = find_inode(inumb)) == NULL) return(EINVAL);
 
-  start = fs_m_in.REQ_TRC_START_LO;
-  end = fs_m_in.REQ_TRC_END_LO;
+  start = fs_m_in->REQ_TRC_START_LO;
+  end = fs_m_in->REQ_TRC_END_LO;
 
   return truncate_inode(rip, start);
 }
index d3c1da514d330c90307a8e72a70d3eee4104684e..ae5210b95c868c53fd6e4884784b1a5571332f96 100644 (file)
@@ -6,6 +6,7 @@
 #include <minix/vfsif.h>
 #include "buf.h"
 #include "inode.h"
+#include "uds.h"
 
 FORWARD _PROTOTYPE(void get_work, (message *m_in)                      );
 
@@ -23,7 +24,9 @@ PUBLIC int main(int argc, char *argv[])
  * three major activities: getting new work, processing the work, and
  * sending the reply. The loop never terminates, unless a panic occurs.
  */
-  int error, ind;
+  int ind;
+  message pfs_m_in;
+  message pfs_m_out;
 
   /* SEF local startup. */
   env_setargs(argc, argv);
@@ -33,31 +36,36 @@ PUBLIC int main(int argc, char *argv[])
        endpoint_t src;
 
        /* Wait for request message. */
-       get_work(&fs_m_in);
-       
-       src = fs_m_in.m_source;
-       error = OK;
+       get_work(&pfs_m_in);
+
+       src = pfs_m_in.m_source;
        caller_uid = INVAL_UID; /* To trap errors */
        caller_gid = INVAL_GID;
-       req_nr = fs_m_in.m_type;
-
-       if (req_nr < VFS_BASE) {
-               fs_m_in.m_type += VFS_BASE;
-               req_nr = fs_m_in.m_type;
-               printf("PFS: bad request (no VFS_BASE) %d\n", req_nr);
-       }
-       ind = req_nr - VFS_BASE;
-
-       if (ind < 0 || ind >= NREQS) {
-               printf("pfs: bad request %d\n", req_nr); 
-               error = EINVAL; 
+       req_nr = pfs_m_in.m_type;
+
+       if (IS_DEV_RQ(req_nr)) {
+               ind = req_nr - DEV_RQ_BASE;
+               if (ind < 0 || ind >= DEV_CALL_VEC_SIZE) {
+                       printf("pfs: bad DEV request %d\n", req_nr);
+                       pfs_m_out.m_type = EINVAL;
+               } else {
+                       (*dev_call_vec[ind])(&pfs_m_in, &pfs_m_out);
+               }
+       } else if (IS_VFS_RQ(req_nr)) {
+               ind = req_nr - VFS_BASE;
+               if (ind < 0 || ind >= FS_CALL_VEC_SIZE) {
+                       printf("pfs: bad FS request %d\n", req_nr);
+                       pfs_m_out.m_type = EINVAL;
+               } else {
+                       pfs_m_out.m_type =
+                               (*fs_call_vec[ind])(&pfs_m_in, &pfs_m_out);
+               }
        } else {
-               error = (*fs_call_vec[ind])();
+               printf("pfs: bad request %d\n", req_nr);
+               pfs_m_out.m_type = EINVAL;
        }
 
-       fs_m_out.m_type = error; 
-       reply(src, &fs_m_out);
-      
+       reply(src, &pfs_m_out);
   }
   return(OK);
 }
@@ -98,10 +106,13 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
   }
        
   init_inode_cache();
+  uds_init();
 
   SELF_E = getprocnr();
   buf_pool();
 
+  driver_announce();
+
   return(OK);
 }
 
@@ -122,12 +133,13 @@ PRIVATE void sef_cb_signal_handler(int signo)
 PRIVATE void get_work(m_in)
 message *m_in;                         /* pointer to message */
 {
-  int r, srcok = 0;
+  int r, srcok = 0, status;
   endpoint_t src;
 
   do {
-       if ((r = sef_receive(ANY, m_in)) != OK)         /* wait for message */
-               panic("sef_receive failed: %d", r);
+       /* wait for a message */
+       if ((r = sef_receive_status(ANY, m_in, &status)) != OK)
+               panic("sef_receive_status failed: %d", r);
        src = m_in->m_source;
 
        if(src == VFS_PROC_NR) {
@@ -148,4 +160,3 @@ message *m_out;                             /* report result */
   if (OK != send(who, m_out))    /* send the message */
        printf("PFS(%d) was unable to send reply\n", SELF_E);
 }
-
index e460113ac5f3752875611da5aee7e00bc65c15f3..dc8da9e6ec26c52051dbd5dd2f97c3af83bb0b1a 100644 (file)
@@ -4,7 +4,7 @@
 /*===========================================================================*
  *                             fs_sync                                      *
  *===========================================================================*/
-PUBLIC int fs_sync()
+PUBLIC int fs_sync(message *fs_m_in, message *fs_m_out)
 {
 /* Perform the sync() system call.  No-op on this FS. */
 
index ca512bb3f3819235eae010965a11452edb7cb44f..4abf5b1cf4334fcdbb4b1b1023a2677e16095507 100644 (file)
@@ -8,17 +8,17 @@
 /*===========================================================================*
  *                             fs_newnode                                   *
  *===========================================================================*/
-PUBLIC int fs_newnode()
+PUBLIC int fs_newnode(message *fs_m_in, message *fs_m_out)
 {
   register int r = OK;
   mode_t bits;
   struct inode *rip;
   dev_t dev;
 
-  caller_uid = (uid_t) fs_m_in.REQ_UID;
-  caller_gid = (gid_t) fs_m_in.REQ_GID;
-  bits = (mode_t) fs_m_in.REQ_MODE;
-  dev = (dev_t) fs_m_in.REQ_DEV;
+  caller_uid = (uid_t) fs_m_in->REQ_UID;
+  caller_gid = (gid_t) fs_m_in->REQ_GID;
+  bits = (mode_t) fs_m_in->REQ_MODE;
+  dev = (dev_t) fs_m_in->REQ_DEV;
 
   /* Try to allocate the inode */
   if( (rip = alloc_inode(dev, bits) ) == NULL) return(err_code);
@@ -40,12 +40,12 @@ PUBLIC int fs_newnode()
        free_inode(rip);
   } else {
        /* Fill in the fields of the response message */
-       fs_m_out.RES_INODE_NR = rip->i_num;
-       fs_m_out.RES_MODE = rip->i_mode;
-       fs_m_out.RES_FILE_SIZE_LO = rip->i_size;
-       fs_m_out.RES_UID = rip->i_uid;
-       fs_m_out.RES_GID = rip->i_gid;
-       fs_m_out.RES_DEV = dev;
+       fs_m_out->RES_INODE_NR = rip->i_num;
+       fs_m_out->RES_MODE = rip->i_mode;
+       fs_m_out->RES_FILE_SIZE_LO = rip->i_size;
+       fs_m_out->RES_UID = rip->i_uid;
+       fs_m_out->RES_GID = rip->i_gid;
+       fs_m_out->RES_DEV = dev;
   }
 
   return(r);
index b0b7578c816886e6c3153f5a4397ccfd152009b7..6e8300d10a5d0291ee3d09a33b0b1b7dba8e1ae7 100644 (file)
@@ -6,10 +6,11 @@
 /* Structs used in prototypes must be declared as such first. */
 struct buf;
 struct inode;
+struct sockaddr_un;
 
 /* buffer.c */
 _PROTOTYPE( struct buf *get_block, (dev_t dev, ino_t inum)             );
-_PROTOTYPE( void put_block, (dev_t dev, ino_t inum)                            );
+_PROTOTYPE( void put_block, (dev_t dev, ino_t inum)                    );
 
 /* cache.c */
 _PROTOTYPE( void buf_pool, (void)                                      );
@@ -19,7 +20,7 @@ _PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t mode)               );
 _PROTOTYPE( void dup_inode, (struct inode *ip)                         );
 _PROTOTYPE( struct inode *find_inode, (ino_t numb)                     );
 _PROTOTYPE( void free_inode, (struct inode *rip)                       );
-_PROTOTYPE( int fs_putnode, (void)                                     );
+_PROTOTYPE( int fs_putnode, (message *fs_m_in, message *fs_m_out)      );
 _PROTOTYPE( void init_inode_cache, (void)                              );
 _PROTOTYPE( struct inode *get_inode, (dev_t dev, ino_t numb)           );
 _PROTOTYPE( void put_inode, (struct inode *rip)                                );
@@ -27,31 +28,71 @@ _PROTOTYPE( void update_times, (struct inode *rip)                  );
 _PROTOTYPE( void wipe_inode, (struct inode *rip)                       );
 
 /* link.c */
-_PROTOTYPE( int fs_ftrunc, (void)                                      );
-_PROTOTYPE( int truncate_inode, (struct inode *rip, off_t newsize)                             );
+_PROTOTYPE( int fs_ftrunc, (message *fs_m_in, message *fs_m_out)       );
+_PROTOTYPE( int truncate_inode, (struct inode *rip, off_t newsize)     );
 
 
 /* main.c */
-_PROTOTYPE( void reply, (endpoint_t who, message *m_out)                       );
+_PROTOTYPE( void reply, (endpoint_t who, message *m_out)               );
 
 /* misc.c */
-_PROTOTYPE( int fs_sync, (void)                                                );
+_PROTOTYPE( int fs_sync, (message *fs_m_in, message *fs_m_out)         );
 
 /* open.c */
-_PROTOTYPE( int fs_newnode, (void)                                     );
+_PROTOTYPE( int fs_newnode, (message *fs_m_in, message *fs_m_out)      );
 
 /* read.c */
-_PROTOTYPE( int fs_readwrite, (void)                                   );
+_PROTOTYPE( int fs_readwrite, (message *fs_m_in, message *fs_m_out)    );
 
 /* utility.c */
 _PROTOTYPE( time_t clock_time, (void)                                  );
-_PROTOTYPE( int no_sys, (void)                                         );
+_PROTOTYPE( int no_sys, (message *pfs_m_in, message *pfs_m_out)                );
 
 /* stadir.c */
-_PROTOTYPE( int fs_stat, (void)                                                );
+_PROTOTYPE( int fs_stat, (message *fs_m_in, message *fs_m_out)         );
 
 /* super.c */
 _PROTOTYPE( bit_t alloc_bit, (void)                                    );
 _PROTOTYPE( void free_bit, (bit_t bit_returned)                                );
 
+/* dev_uds.c */
+_PROTOTYPE( int uds_open, (message *dev_m_in, message *dev_m_out)      );
+_PROTOTYPE( int uds_close, (message *dev_m_in, message *dev_m_out)     );
+_PROTOTYPE( int uds_read, (message *dev_m_in, message *dev_m_out)      );
+_PROTOTYPE( int uds_write, (message *dev_m_in, message *dev_m_out)     );
+_PROTOTYPE( int uds_ioctl, (message *dev_m_in, message *dev_m_out)     );
+_PROTOTYPE( int uds_select, (message *dev_m_in, message *dev_m_out)    );
+_PROTOTYPE( int uds_status, (message *dev_m_in, message *dev_m_out)    );
+_PROTOTYPE( int uds_cancel, (message *dev_m_in, message *dev_m_out)    );
+
+/* uds.c */
+_PROTOTYPE( void uds_init, (void)                                      );
+_PROTOTYPE( int do_accept, (message *dev_m_in, message *dev_m_out)     );
+_PROTOTYPE( int do_connect, (message *dev_m_in, message *dev_m_out)    );
+_PROTOTYPE( int do_listen, (message *dev_m_in, message *dev_m_out)     );
+_PROTOTYPE( int do_socket, (message *dev_m_in, message *dev_m_out)     );
+_PROTOTYPE( int do_bind, (message *dev_m_in, message *dev_m_out)       );
+_PROTOTYPE( int do_getsockname, (message *dev_m_in, message *dev_m_out)        );
+_PROTOTYPE( int do_getpeername, (message *dev_m_in, message *dev_m_out)        );
+_PROTOTYPE( int do_shutdown, (message *dev_m_in, message *dev_m_out)   );
+_PROTOTYPE( int do_socketpair, (message *dev_m_in, message *dev_m_out) );
+_PROTOTYPE( int do_getsockopt_sotype,
+                               (message *dev_m_in, message *dev_m_out) );
+_PROTOTYPE( int do_getsockopt_peercred,
+                               (message *dev_m_in, message *dev_m_out) );
+_PROTOTYPE( int do_getsockopt_sndbuf,
+                               (message *dev_m_in, message *dev_m_out) );
+_PROTOTYPE( int do_setsockopt_sndbuf,
+                               (message *dev_m_in, message *dev_m_out) );
+_PROTOTYPE( int do_getsockopt_rcvbuf,
+                               (message *dev_m_in, message *dev_m_out) );
+_PROTOTYPE( int do_setsockopt_rcvbuf,
+                               (message *dev_m_in, message *dev_m_out) );
+_PROTOTYPE( int do_sendto, (message *dev_m_in, message *dev_m_out)     );
+_PROTOTYPE( int do_recvfrom, (message *dev_m_in, message *dev_m_out)   );
+_PROTOTYPE( int perform_connection,
+                               (message *dev_m_in, message *dev_m_out, 
+                               struct sockaddr_un *addr, int minorx, 
+                               int minory)                             );
+
 #endif
index be3c19b2a654ae57986f8f56d045bd0169720916..3a6579f0a8cae61f042a493a57a00d9ff9a84d22 100644 (file)
@@ -7,7 +7,7 @@
 /*===========================================================================*
  *                             fs_readwrite                                 *
  *===========================================================================*/
-PUBLIC int fs_readwrite(void)
+PUBLIC int fs_readwrite(message *fs_m_in, message *fs_m_out)
 {
   int r, rw_flag;
   struct buf *bp;
@@ -20,7 +20,7 @@ PUBLIC int fs_readwrite(void)
 
   r = OK;
   cum_io = 0;
-  inumb = (ino_t) fs_m_in.REQ_INODE_NR;
+  inumb = (ino_t) fs_m_in->REQ_INODE_NR;
 
   /* Find the inode referred */
   if ((rip = find_inode(inumb)) == NULL) return(EINVAL);
@@ -30,10 +30,10 @@ PUBLIC int fs_readwrite(void)
   f_size = rip->i_size;
   
   /* Get the values from the request message */ 
-  rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
-  gid = (cp_grant_id_t) fs_m_in.REQ_GRANT;
-  position = fs_m_in.REQ_SEEK_POS_LO;
-  nrbytes = (unsigned) fs_m_in.REQ_NBYTES;
+  rw_flag = (fs_m_in->m_type == REQ_READ ? READING : WRITING);
+  gid = (cp_grant_id_t) fs_m_in->REQ_GRANT;
+  position = fs_m_in->REQ_SEEK_POS_LO;
+  nrbytes = (unsigned) fs_m_in->REQ_NBYTES;
 
   /* We can't read beyond the max file position */
   if (nrbytes > MAX_FILE_POS) return(EFBIG);
@@ -64,7 +64,7 @@ PUBLIC int fs_readwrite(void)
        cum_io += nrbytes;
   }
 
-  fs_m_out.RES_SEEK_POS_LO = position; /* It might change later and the VFS
+  fs_m_out->RES_SEEK_POS_LO = position; /* It might change later and the VFS
                                           has to know this value */
   
   /* On write, update file size and access time. */
@@ -81,7 +81,7 @@ PUBLIC int fs_readwrite(void)
   bp->b_bytes = position;
   if (rw_flag == READING) rip->i_update |= ATIME;
   if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
-  fs_m_out.RES_NBYTES = (size_t) cum_io;
+  fs_m_out->RES_NBYTES = (size_t) cum_io;
   put_inode(rip);
   put_block(rip->i_dev, rip->i_num);
 
index 2b0e496611d1b883021734ef03626401c2765c94..707301a07760d04d44ee43a76e407f06ab40bb72 100644 (file)
@@ -47,14 +47,14 @@ PRIVATE int stat_inode(
 /*===========================================================================*
  *                             fs_stat                                      *
  *===========================================================================*/
-PUBLIC int fs_stat()
+PUBLIC int fs_stat(message *fs_m_in, message *fs_m_out)
 {
   register int r;              /* return value */
   register struct inode *rip;  /* target inode */
 
-  if( (rip = find_inode(fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL);
+  if( (rip = find_inode(fs_m_in->REQ_INODE_NR)) == NULL) return(EINVAL);
   get_inode(rip->i_dev, rip->i_num);   /* mark inode in use */  
-  r = stat_inode(rip, fs_m_in.m_source, (cp_grant_id_t) fs_m_in.REQ_GRANT);
+  r = stat_inode(rip, fs_m_in->m_source, (cp_grant_id_t) fs_m_in->REQ_GRANT);
   put_inode(rip);                      /* release the inode */
   return(r);
 }
index 110d02250c9ba423cc597b0e91486a2c7d653fb8..95e5c5a404699a3ebe35a513e1b9d9ba5b36a0dd 100644 (file)
@@ -8,8 +8,12 @@
 #include "fs.h"
 #include "inode.h"
 #include "buf.h"
+#include "uds.h"
+
+/* File System Handlers (pfs) */
+PUBLIC _PROTOTYPE (int (*fs_call_vec[]),
+                               (message *fs_m_in, message *fs_m_out) ) = {
 
-PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = {
         no_sys,             /* 0   not used */
         no_sys,             /* 1   */
         fs_putnode,         /* 2   */
@@ -42,6 +46,37 @@ PUBLIC _PROTOTYPE (int (*fs_call_vec[]), (void) ) = {
         fs_newnode,        /* 29  */
         no_sys,                    /* 30  */
         no_sys,                    /* 31  */
-               no_sys,             /* 32 */
+       no_sys,             /* 32 */
 };
 
+/* Device Handlers (/dev/uds) */
+PUBLIC _PROTOTYPE (int (*dev_call_vec[]),
+                               (message *dev_m_in, message *dev_m_out) ) = {
+
+        uds_cancel,         /* 0   */
+        no_sys,             /* 1   */
+        no_sys,             /* 2   */
+        no_sys,             /* 3   */
+        no_sys,             /* 4   */
+        no_sys,             /* 5   */
+       uds_open,           /* 6   */
+        uds_close,          /* 7   */
+        no_sys,             /* 8   */
+        no_sys,             /* 9   */
+        no_sys,             /* 10  */
+        no_sys,             /* 11  */
+        uds_select,         /* 12  */
+        uds_status,         /* 13  */
+        uds_open,           /* 14  */
+        no_sys,             /* 15  */
+       no_sys,             /* 16  */
+        no_sys,             /* 17  */
+        no_sys,                    /* 18  */
+        no_sys,                    /* 19  */
+        uds_read,          /* 20  */
+        uds_write,          /* 21  */
+        no_sys,             /* 22  */
+        no_sys,             /* 23  */
+        uds_ioctl,          /* 24  */
+        no_sys,             /* 25  */
+};
diff --git a/servers/pfs/uds.c b/servers/pfs/uds.c
new file mode 100644 (file)
index 0000000..3188cad
--- /dev/null
@@ -0,0 +1,1354 @@
+/*
+ * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL)
+ * This code handles ioctl(2) commands to implement the socket API.
+ * Some helper functions are also present.
+ *
+ * The entry points into this file are...
+ *
+ *   uds_init:               initialize the descriptor table.
+ *   do_accept:              handles the      accept(2) syscall.
+ *   do_connect:             handles the     connect(2) syscall.
+ *   do_listen:              handles the      listen(2) syscall.
+ *   do_socket:              handles the      socket(2) syscall.
+ *   do_bind:                handles the        bind(2) syscall.
+ *   do_getsockname:         handles the getsockname(2) syscall.
+ *   do_getpeername:         handles the getpeername(2) syscall.
+ *   do_shutdown:            handles the    shutdown(2) syscall.
+ *   do_socketpair:          handles the  socketpair(2) syscall.
+ *   do_getsockopt_sotype:   handles the  getsockopt(2) syscall.
+ *   do_getsockopt_peercred: handles the  getsockopt(2) syscall.
+ *   do_getsockopt_sndbuf:   handles the  getsockopt(2) syscall.
+ *   do_setsockopt_sndbuf:   handles the  setsockopt(2) syscall.
+ *   do_getsockopt_rcvbuf:   handles the  getsockopt(2) syscall.
+ *   do_setsockopt_rcvbuf:   handles the  setsockopt(2) syscall.
+ *   do_sendto:              handles the      sendto(2) syscall.
+ *   do_recvfrom:            handles the    recvfrom(2) syscall.
+ *   perform_connection:     performs the connection of two descriptors.
+ *
+ * Also see...
+ *
+ *   table.c, dev_uds.c, uds.h
+ */
+
+#define DEBUG 0
+
+#include "inc.h"
+#include "const.h"
+#include "glo.h"
+#include "uds.h"
+
+/* File Descriptor Table */
+uds_fd_t uds_fd_table[NR_FDS];
+
+/* initialize the descriptor table */
+PUBLIC void uds_init(void)
+{
+       /*
+        * Setting everything to NULL implicitly sets the 
+        * state to UDS_FREE.
+        */
+       memset(uds_fd_table, '\0', sizeof(uds_fd_t) * NR_FDS);
+}
+
+PUBLIC int perform_connection(message *dev_m_in, message *dev_m_out, 
+                       struct sockaddr_un *addr, int minorx, int minory)
+{
+       /* there are several places were a connection is established. */
+       /* accept(2), connect(2), uds_status(2), socketpair(2)        */
+       /* This is a helper function to make sure it is done in the   */
+       /* same way in each place with the same validation checks.    */
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] perform_connection() call_count=%d\n", 
+                                       uds_minor(dev_m_in), ++call_count);
+#endif
+
+       /* only connection oriented types are acceptable and only like 
+        * types can connect to each other
+        */
+       if ((uds_fd_table[minorx].type != SOCK_SEQPACKET && 
+               uds_fd_table[minorx].type != SOCK_STREAM) ||
+               uds_fd_table[minorx].type != uds_fd_table[minory].type) {
+
+               /* sockets are not in a valid state */
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       /* connect the pair of sockets */
+       uds_fd_table[minorx].peer = minory;
+       uds_fd_table[minory].peer = minorx;
+
+       /* Set the address of both sockets */
+       memcpy(&(uds_fd_table[minorx].addr), addr, sizeof(struct sockaddr_un));
+       memcpy(&(uds_fd_table[minory].addr), addr, sizeof(struct sockaddr_un));
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+
+PUBLIC int do_accept(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int minorparent; /* minor number of parent (server) */
+       int minorpeer;
+       int rc, i;
+       struct sockaddr_un addr;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_accept() call_count=%d\n", 
+                                       uds_minor(dev_m_in), ++call_count);
+#endif
+
+       /* Somewhat weird logic is used in this function, so here's an 
+        * overview... The minor number is the server's client socket 
+        * (the socket to be returned by accept()). The data waiting 
+        * for us in the IO Grant is the address that the server is 
+        * listening on. This function uses the address to find the 
+        * server's descriptor. From there we can perform the 
+        * connection or suspend and wait for a connect().
+        */
+
+       minor = uds_minor(dev_m_in);
+
+       if (uds_fd_table[minor].type != -1) {
+
+               /* this IOCTL must be called on a 'fresh' socket */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                        (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       /* Get the server's address */
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un),
+               D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       /* locate server socket */
+       rc = -1; /* to trap error */
+
+       for (i = 0; i < NR_FDS; i++) {
+
+               if (uds_fd_table[i].addr.sun_family == AF_UNIX &&
+                               !strncmp(addr.sun_path, 
+                               uds_fd_table[i].addr.sun_path,
+                               UNIX_PATH_MAX)) {
+
+                       rc = 0;
+                       break;
+               }
+       }
+
+       if (rc == -1) {
+
+               /* there is no server listening on addr. Maybe someone 
+                * screwed up the ioctl()?
+                */
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, 
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       minorparent = i; /* parent */
+
+       /* we are the parent's child */
+       uds_fd_table[minorparent].child = minor;
+
+       /* the peer has the same type as the parent. we need to be that 
+        * type too.
+        */
+       uds_fd_table[minor].type = uds_fd_table[minorparent].type;
+
+       /* locate peer to accept in the parent's backlog */
+       minorpeer = -1; /* to trap error */
+       for (i = 0; i < uds_fd_table[minorparent].backlog_size; i++) {
+               if (uds_fd_table[minorparent].backlog[i] != -1) {
+                       minorpeer = uds_fd_table[minorparent].backlog[i];
+                       uds_fd_table[minorparent].backlog[i] = -1;
+                       rc = 0;
+                       break;
+               }
+       }
+
+       if (minorpeer == -1) {
+
+#if DEBUG == 1
+               printf("(uds) [%d] {do_accept} suspend\n", minor);
+#endif
+
+               /* there are no peers in the backlog, suspend and wait 
+                * for some to show up
+                */
+               uds_fd_table[minor].suspended = UDS_SUSPENDED_ACCEPT;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, SUSPEND);
+
+               return SUSPEND;
+       }
+
+#if DEBUG == 1
+       printf("(uds) [%d] connecting to %d -- parent is %d\n", minor, 
+                                               minorpeer, minorparent);
+#endif
+
+       rc = perform_connection(dev_m_in, dev_m_out, &addr, minor, minorpeer);
+       if (rc != OK) {
+#if DEBUG == 1
+               printf("(uds) [%d] {do_accept} connection not performed\n",
+                                                               minor);
+#endif
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, errno);
+
+               return errno;
+       }
+
+       uds_fd_table[minorparent].child = -1;
+
+       /* if peer is blocked on connect() revive peer */
+       if (uds_fd_table[minorpeer].suspended) {
+#if DEBUG == 1
+               printf("(uds) [%d] {do_accept} revive %d", minor, minorpeer);
+#endif
+               uds_fd_table[minorpeer].ready_to_revive = 1;
+               notify(dev_m_in->m_source);
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, 
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+PUBLIC int do_connect(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       struct sockaddr_un addr;
+       int rc, i, j;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_connect() call_count=%d\n", uds_minor(dev_m_in),
+                                                               ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       /* only connection oriented sockets can connect */
+       if (uds_fd_table[minor].type != SOCK_STREAM &&
+                       uds_fd_table[minor].type != SOCK_SEQPACKET) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       if (uds_fd_table[minor].peer != -1) {
+
+               /* socket is already connected */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, EISCONN);
+
+               return EISCONN;
+       }
+
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+                               (vir_bytes) 0, (vir_bytes) &addr, 
+                               sizeof(struct sockaddr_un), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       /* look for a socket of the same type that is listening on the 
+        * address we want to connect to
+        */
+       for (i = 0; i < NR_FDS; i++) {
+
+               if (uds_fd_table[minor].type == uds_fd_table[i].type &&
+                       uds_fd_table[i].listening &&
+                       uds_fd_table[i].addr.sun_family == AF_UNIX &&
+                       !strncmp(addr.sun_path, uds_fd_table[i].addr.sun_path,
+                       UNIX_PATH_MAX)) {
+
+                       if (uds_fd_table[i].child != -1) {
+
+                               /* the server is blocked on accept(2) --
+                                * perform connection to the child
+                                */
+
+                               rc = perform_connection(dev_m_in, dev_m_out,
+                                       &addr, minor, uds_fd_table[i].child);
+
+                               if (rc == OK) {
+
+                                       uds_fd_table[i].child = -1;
+
+#if DEBUG == 1
+                       printf("(uds) [%d] {do_connect} revive %d", minor, i);
+#endif
+
+                                       /* wake the parent (server) */
+                                       uds_fd_table[i].ready_to_revive = 1;
+                                       notify(dev_m_in->m_source);
+
+                                       uds_fd_table[minor].syscall_done = 1;
+
+                                       uds_set_reply(dev_m_out, TASK_REPLY,
+                                               dev_m_in->IO_ENDPT,
+                                       (cp_grant_id_t) dev_m_in->IO_GRANT,
+                                               OK);
+
+                                       return OK;
+                               } else {
+
+                                       uds_fd_table[minor].syscall_done = 1;
+
+                                       uds_set_reply(dev_m_out, TASK_REPLY,
+                                               dev_m_in->IO_ENDPT,
+                                       (cp_grant_id_t) dev_m_in->IO_GRANT,
+                                               rc);
+
+                                       return rc;
+                               }
+
+                       } else {
+
+#if DEBUG == 1
+                               printf("(uds) [%d] adding to %d's backlog\n",
+                                                               minor, i);
+#endif
+
+                               /* tell the server were waiting to be served */
+
+                               /* look for a free slot in the backlog */
+                               rc = -1; /* to trap error */
+                               for (j = 0; j < uds_fd_table[i].backlog_size;
+                                       j++) {
+
+                                       if (uds_fd_table[i].backlog[j] == -1) {
+
+                                               uds_fd_table[i].backlog[j] =
+                                                       minor;
+
+                                               rc = 0;
+                                               break;
+                                       }
+                               }
+
+                               if (rc == -1) {
+
+                                       /* backlog is full */
+                                       break;
+                               }
+
+                               /* see if the server is blocked on select() */
+                               if (uds_fd_table[i].selecting == 1) {
+
+                                       /* if the server wants to know 
+                                        * about data ready to read and 
+                                        * it doesn't know about it 
+                                        * already, then let the server
+                                        * know we have data for it.
+                                        */
+                                       if ((uds_fd_table[i].sel_ops_in & 
+                                               SEL_RD) && 
+                                               !(uds_fd_table[i].sel_ops_out &
+                                               SEL_RD)) {
+
+                                               uds_fd_table[i].sel_ops_out |=
+                                                       SEL_RD;
+
+                                               uds_fd_table[i].status_updated
+                                                       = 1;
+
+                                               notify(
+                                               uds_fd_table[i].select_proc
+                                               );
+                                       }
+                               }
+
+                               /* we found our server */
+                               uds_fd_table[minor].peer = i;
+
+                               /* set the address */
+                               memcpy(&(uds_fd_table[minor].addr), &addr,
+                                       sizeof(struct sockaddr_un));
+
+                               break;
+                       }
+               }
+       }
+
+       if (uds_fd_table[minor].peer == -1) {
+
+               /* could not find another open socket listening on the 
+                * specified address with room in the backlog
+                */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, ECONNREFUSED);
+
+               return ECONNREFUSED;
+       }
+
+#if DEBUG == 1
+       printf("(uds) [%d] {do_connect} suspend", minor);
+#endif
+
+       /* suspend until the server side completes the connection with accept()
+        */
+
+       uds_fd_table[minor].suspended = UDS_SUSPENDED_CONNECT;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, SUSPEND);
+
+       return SUSPEND;
+}
+
+PUBLIC int do_listen(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int rc;
+       int backlog_size;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_listen() call_count=%d\n", uds_minor(dev_m_in),
+                                                       ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       /* ensure the socket has a type and is bound */
+       if (uds_fd_table[minor].type == -1 ||
+               uds_fd_table[minor].addr.sun_family != AF_UNIX) {
+
+               /* probably trying to call listen() before bind() */
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       /* the two supported types for listen(2) are SOCK_STREAM and 
+        * SOCK_SEQPACKET
+        */
+       if (uds_fd_table[minor].type != SOCK_STREAM &&
+                       uds_fd_table[minor].type != SOCK_SEQPACKET) {
+
+               /* probably trying to call listen() with a SOCK_DGRAM */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, 
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, EOPNOTSUPP);
+
+               return EOPNOTSUPP;
+       }
+
+       /* The POSIX standard doesn't say what to do if listen() has 
+        * already been called. Well, there isn't an errno. we silently 
+        * let it happen, but if listen() has already been called, we 
+        * don't allow the backlog to shrink
+        */
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &backlog_size, sizeof(int), 
+               D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       if (uds_fd_table[minor].listening == 0) {
+
+               /* See if backlog_size is between 0 and UDS_SOMAXCONN */
+               if (backlog_size >= 0 || backlog_size < UDS_SOMAXCONN) {
+
+                       /* use the user provided backlog_size */
+                       uds_fd_table[minor].backlog_size = backlog_size;
+
+               } else {
+
+                       /* the user gave an invalid size, use 
+                        * UDS_SOMAXCONN instead
+                        */
+                       uds_fd_table[minor].backlog_size = UDS_SOMAXCONN;
+               }
+       } else {
+
+               /* See if the user is trying to expand the backlog_size */
+               if (backlog_size > uds_fd_table[minor].backlog_size &&
+                       backlog_size < UDS_SOMAXCONN) {
+
+                       /* expand backlog_size */
+                       uds_fd_table[minor].backlog_size = backlog_size;
+               }
+
+               /* Don't let the user shrink the backlog_size (we might 
+                * have clients waiting in those slots
+                */
+       }
+
+       /* perform listen(2) */
+       uds_fd_table[minor].listening = 1;
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+PUBLIC int do_socket(message *dev_m_in, message *dev_m_out)
+{
+       int rc;
+       int minor;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_socket() call_count=%d\n", uds_minor(dev_m_in),
+                                                       ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       /* see if this socket already has a type */
+       if (uds_fd_table[minor].type != -1) {
+
+               /* socket type can only be set once */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       /* get the requested type */
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type),
+               sizeof(int), D);
+
+       if (rc != OK) {
+
+               /* something went wrong and we couldn't get the type */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       /* validate the type */
+       switch (uds_fd_table[minor].type) {
+               case SOCK_STREAM:
+               case SOCK_DGRAM:
+               case SOCK_SEQPACKET:
+
+                       /* the type is one of the 3 valid socket types */
+                       uds_fd_table[minor].syscall_done = 1;
+
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, 
+                               OK);
+
+                       return OK;
+
+               default:
+
+                       /* if the type isn't one of the 3 valid socket 
+                        * types, then it must be invalid.
+                        */
+
+                       /* set the type back to '-1' (no type set) */
+                       uds_fd_table[minor].type = -1;
+
+                       uds_fd_table[minor].syscall_done = 1;
+
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT,
+                               EINVAL);
+
+                       return EINVAL;
+       }
+}
+
+PUBLIC int do_bind(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       struct sockaddr_un addr;
+       int rc, i;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_bind() call_count=%d\n", uds_minor(dev_m_in),
+                                                       ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       if ((uds_fd_table[minor].type == -1) ||
+               (uds_fd_table[minor].addr.sun_family == AF_UNIX &&
+               uds_fd_table[minor].type != SOCK_DGRAM)) {
+
+               /* the type hasn't been set by do_socket() yet OR attempting
+                * to re-bind() a non-SOCK_DGRAM socket
+                */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un), 
+               D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       /* do some basic sanity checks on the address */
+       if (addr.sun_family != AF_UNIX || addr.sun_path[0] == '\0') {
+
+               /* bad address */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       /* make sure the address isn't already in use by another socket. */
+       for (i = 0; i < NR_FDS; i++) {
+               if ((uds_fd_table[i].addr.sun_family == AF_UNIX) &&
+                       !strncmp(addr.sun_path, 
+                       uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) {
+
+                       /* another socket is bound to this sun_path */
+                       uds_fd_table[minor].syscall_done = 1;
+
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT,
+                               EADDRINUSE);
+
+                       return EADDRINUSE;
+               }
+       }
+
+       /* looks good, perform the bind() */
+       memcpy(&(uds_fd_table[minor].addr), &addr, sizeof(struct sockaddr_un));
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+PUBLIC int do_getsockname(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int rc;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_getsockname() call_count=%d\n",
+                                       uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       /* Unconditionally send the address we have assigned to this socket.
+        * The POSIX standard doesn't say what to do if the address 
+        * hasn't been set. If the address isn't currently set, then 
+        * the user will get NULL bytes. Note: libc depends on this 
+        * behavior.
+        */
+       rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].addr), 
+               sizeof(struct sockaddr_un), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+PUBLIC int do_getpeername(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int rc;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_getpeername() call_count=%d\n",
+                               uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       /* check that the socket is connected with a valid peer */
+       if (uds_fd_table[minor].peer != -1) {
+               int peer_minor;
+
+               peer_minor = uds_fd_table[minor].peer;
+
+               /* copy the address from the peer */
+               rc = sys_safecopyto(VFS_PROC_NR,
+                       (cp_grant_id_t) dev_m_in->IO_GRANT, (vir_bytes) 0,
+                       (vir_bytes) &(uds_fd_table[peer_minor].addr),
+                       sizeof(struct sockaddr_un), D);
+
+               if (rc != OK) {
+
+                       uds_fd_table[minor].syscall_done = 1;
+
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+                       return EIO;
+               }
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+               return OK;
+       } else {
+
+               int err;
+
+               if (uds_fd_table[minor].err == ECONNRESET) {
+                       err = ECONNRESET;
+                       uds_fd_table[minor].err = 0;
+               } else {
+                       err = ENOTCONN;
+               }
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, err);
+
+               return err;
+       }
+}
+
+PUBLIC int do_shutdown(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int rc, how;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_shutdown() call_count=%d\n",
+                                       uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       if (uds_fd_table[minor].type != SOCK_STREAM &&
+                       uds_fd_table[minor].type != SOCK_SEQPACKET) {
+
+               /* socket must be a connection oriented socket */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       if (uds_fd_table[minor].peer == -1) {
+
+               int err;
+
+               if (uds_fd_table[minor].err == ECONNRESET) {
+                       err = ECONNRESET;
+               } else {
+                       err = ENOTCONN;
+               }
+
+               /* shutdown(2) is only valid for connected sockets */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, err);
+
+               return err;
+       }
+
+       /* get the 'how' parameter from the process */
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+                       (vir_bytes) 0, (vir_bytes) &how, sizeof(int), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       switch (how) {
+               case SHUT_RD:
+                       /* take away read permission */
+                       uds_fd_table[minor].mode =
+                               uds_fd_table[minor].mode ^ S_IRUSR;
+                       break;
+
+               case SHUT_WR:
+                       /* take away write permission */
+                       uds_fd_table[minor].mode = 
+                               uds_fd_table[minor].mode ^ S_IWUSR;
+                       break;
+
+               case SHUT_RDWR:
+                       /* completely shutdown */
+                       uds_fd_table[minor].mode = 0;
+                       break;
+
+               default:
+
+                       /* the 'how' parameter is invalid */
+                       uds_fd_table[minor].syscall_done = 1;
+
+                       uds_set_reply(dev_m_out, TASK_REPLY,
+                               dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+                       return EINVAL;
+       }
+
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+PUBLIC int do_socketpair(message *dev_m_in, message *dev_m_out)
+{
+       int rc;
+       dev_t minorin;
+       int minorx, minory;
+       struct sockaddr_un addr;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_socketpair() call_count=%d\n",
+                               uds_minor(dev_m_in), ++call_count);
+#endif
+
+       /* first ioctl param is the first socket */
+       minorx = uds_minor(dev_m_in);
+
+       /* third ioctl param is the minor number of the second socket */
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+                       (vir_bytes) 0, (vir_bytes) &minorin, sizeof(dev_t), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minorx].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       minory = (minor(minorin) & BYTE);
+
+       /* security check - both sockets must have the same endpoint (owner) */
+       if (uds_fd_table[minorx].endpoint != uds_fd_table[minory].endpoint) {
+
+               /* we won't allow you to magically connect your socket to
+                * someone elses socket
+                */
+               uds_fd_table[minorx].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EPERM);
+
+               return EPERM;
+       }
+
+       addr.sun_family = AF_UNIX;
+       addr.sun_path[0] = 'X';
+       addr.sun_path[1] = '\0';
+
+       uds_fd_table[minorx].syscall_done = 1;
+       return perform_connection(dev_m_in, dev_m_out, &addr, minorx, minory);
+}
+
+PUBLIC int do_getsockopt_sotype(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int rc;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_getsockopt_sotype() call_count=%d\n",
+                               uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       if (uds_fd_table[minor].type == -1) {
+
+               /* the type hasn't been set yet. instead of returning an
+                * invalid type, we fail with EINVAL
+                */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].type), 
+               sizeof(int), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+PUBLIC int do_getsockopt_peercred(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int peer_minor;
+       int rc;
+       struct ucred cred;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_getsockopt_peercred() call_count=%d\n",
+                                       uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       if (uds_fd_table[minor].peer == -1) {
+
+               int err;
+
+               if (uds_fd_table[minor].err == ECONNRESET) {
+                       err = ECONNRESET;
+                       uds_fd_table[minor].err = 0;
+               } else {
+                       err = ENOTCONN;
+               }
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, err);
+
+               return err;
+       }
+
+       peer_minor = uds_fd_table[minor].peer;
+
+       /* obtain the peer's credentials */
+       rc = getnucred(uds_fd_table[peer_minor].owner, &cred);
+       if (rc == -1) {
+
+               /* likely error: invalid endpoint / proc doesn't exist */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, errno);
+
+               return errno;
+       }
+
+       rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &cred, sizeof(struct ucred), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+int do_getsockopt_sndbuf(message *dev_m_in, message *dev_m_out) 
+{
+       int minor;
+       int rc;
+       size_t sndbuf = PIPE_BUF;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_getsockopt_sndbuf() call_count=%d\n",
+                               uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &(sndbuf), 
+               sizeof(size_t), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+int do_setsockopt_sndbuf(message *dev_m_in, message *dev_m_out) 
+{
+       int minor;
+       int rc;
+       size_t sndbuf;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n",
+                               uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+                               (vir_bytes) 0, (vir_bytes) &sndbuf, 
+                               sizeof(size_t), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       if (sndbuf > PIPE_BUF) {
+
+               /* The send buffer is limited to 32K at the moment. */
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, ENOSYS);
+
+               return ENOSYS;
+       }
+
+       /* There is no way to reduce the send buffer, do we have to
+        * let this call fail for smaller buffers?
+        */
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+int do_getsockopt_rcvbuf(message *dev_m_in, message *dev_m_out) 
+{
+       int minor;
+       int rc;
+       size_t rcvbuf = PIPE_BUF;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_getsockopt_rcvbuf() call_count=%d\n",
+                               uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &(rcvbuf), 
+               sizeof(size_t), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+int do_setsockopt_rcvbuf(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int rc;
+       size_t rcvbuf;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_setsockopt_rcvbuf() call_count=%d\n",
+                               uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+                               (vir_bytes) 0, (vir_bytes) &rcvbuf, 
+                               sizeof(size_t), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       if (rcvbuf > PIPE_BUF) {
+
+               /* The send buffer is limited to 32K at the moment. */
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, ENOSYS);
+
+               return ENOSYS;
+       }
+
+       /* There is no way to reduce the send buffer, do we have to
+        * let this call fail for smaller buffers?
+        */
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+
+PUBLIC int do_sendto(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int rc;
+       struct sockaddr_un addr;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_sendto() call_count=%d\n", uds_minor(dev_m_in),
+                                                       ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       if (uds_fd_table[minor].type != SOCK_DGRAM) {
+
+               /* This IOCTL is only for SOCK_DGRAM sockets */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &addr, sizeof(struct sockaddr_un),
+               D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       /* do some basic sanity checks on the address */
+       if (addr.sun_family != AF_UNIX || addr.sun_path[0] == '\0') {
+
+               /* bad address */
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
+
+               return EINVAL;
+       }
+
+       memcpy(&(uds_fd_table[minor].target), &addr,
+                                       sizeof(struct sockaddr_un));
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
+
+PUBLIC int do_recvfrom(message *dev_m_in, message *dev_m_out)
+{
+       int minor;
+       int rc;
+
+#if DEBUG == 1
+       static int call_count = 0;
+       printf("(uds) [%d] do_recvfrom() call_count=%d\n",
+                                       uds_minor(dev_m_in), ++call_count);
+#endif
+
+       minor = uds_minor(dev_m_in);
+
+       rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT,
+               (vir_bytes) 0, (vir_bytes) &(uds_fd_table[minor].source), 
+               sizeof(struct sockaddr_un), D);
+
+       if (rc != OK) {
+
+               uds_fd_table[minor].syscall_done = 1;
+
+               uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, EIO);
+
+               return EIO;
+       }
+
+       uds_fd_table[minor].syscall_done = 1;
+
+       uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT,
+                               (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
+
+       return OK;
+}
diff --git a/servers/pfs/uds.h b/servers/pfs/uds.h
new file mode 100644 (file)
index 0000000..3af2d57
--- /dev/null
@@ -0,0 +1,227 @@
+#ifndef __PFS_UDS_H__
+#define __PFS_UDS_H__
+
+/*
+ * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL)
+ *
+ * Also See...
+ *
+ *   dev_uds.c, table.c, uds.c
+ */
+
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <minix/endpoint.h>
+
+/* max connection backlog for incoming connections */
+#define UDS_SOMAXCONN 64
+
+/* UDS FD state Flags */
+#define UDS_CONNECTING  0x10
+
+/*
+ * Internal State Information for a socket descriptor.
+ */
+struct uds_fd {
+
+/* Flags */
+
+       enum UDS_STATE {
+               /* This file descriptor is UDS_FREE and can be allocated. */
+               UDS_FREE  = 0,
+
+               /* OR it is UDS_INUSE and can't be allocated. */
+               UDS_INUSE = 1
+
+       /* state is set to UDS_INUSE in uds_open(). state is Set to 
+        * UDS_FREE in uds_init() and uds_close(). state should be 
+        * checked prior to all operations.
+        */
+       } state;
+
+/* Owner Info */
+
+       /* Socket Owner */
+       endpoint_t owner;
+
+       /* endpoint for suspend/resume */
+       endpoint_t endpoint;
+
+/* Pipe Housekeeping */
+
+       /* inode number on PFS -- each descriptor is backed by 1
+        * PIPE which is allocated in uds_open() and freed in
+        * uds_close(). Data is sent/written to a peer's PIPE.
+        * Data is recv/read from this PIPE.
+        */
+       ino_t inode_nr;
+
+
+       /* position in the PIPE where the data starts */
+       off_t pos;
+
+       /* size of data in the PIPE */
+       size_t size;
+
+       /* control read/write, set by uds_open() and shutdown(2).
+        * Can be set to S_IRUSR|S_IWUSR, S_IRUSR, S_IWUSR, or 0
+        * for read and write, read only, write only, or neither.
+        * default is S_IRUSR|S_IWUSR.
+        */
+       mode_t mode;
+
+/* Socket Info */
+
+
+       /* socket type - SOCK_STREAM, SOCK_DGRAM, or SOCK_SEQPACKET
+        * Set by uds_ioctl(NWIOSUDSTYPE). It defaults to -1 in
+        * uds_open(). Any action on a socket with type -1 besides
+        * uds_ioctl(NWIOSUDSTYPE) and uds_close() will result in
+        * an error.
+        */
+       int type;
+
+       /* queue of pending connections for server sockets.
+        * connect(2) inserts and accept(2) removes from the queue
+        */
+       int backlog[UDS_SOMAXCONN];
+
+       /* requested connection backlog size. Set by listen(2)
+        * Bounds (0 <= backlog_size <= UDS_SOMAXCONN)
+        * Defaults to UDS_SOMAXCONN which is defined above.
+        */
+       unsigned char backlog_size;
+
+       /* index of peer in uds_fd_table for connected sockets.
+        * -1 is used to mean no peer. Assumptions: peer != -1 means 
+        * connected.
+        */
+       int peer;
+
+       /* index of child (client sd returned by accept(2))
+        * -1 is used to mean no child.
+        */
+       int child;
+
+       /* address -- the address the socket is bound to.
+        * Assumptions: addr.sun_family == AF_UNIX means its bound.
+        */
+       struct sockaddr_un addr;
+
+       /* target -- where DGRAMs are sent to on the next uds_write(). */
+       struct sockaddr_un target;
+
+       /* source -- address where DGRAMs are from. used to fill in the
+        * from address in recvfrom(2) and recvmsg(2).
+        */
+       struct sockaddr_un source;
+
+       /* Flag (1 or 0) - listening for incoming connections.
+        * Default to 0. Set to 1 by do_listen()
+        */
+       int listening;
+
+       /* Holds an errno. This is set when a connected socket is
+        * closed and we need to pass ECONNRESET on to a suspended
+        * peer.
+        */
+       int err;
+
+/* Suspend/Revive Housekeeping */
+
+       
+       /* SUSPEND State Flags */
+       enum UDS_SUSPENDED {
+
+               /* Socket isn't blocked. */
+               UDS_NOT_SUSPENDED     = 0,
+
+               /* Socket is blocked on read(2) waiting for data to read. */
+               UDS_SUSPENDED_READ    = 1,
+
+               /* Socket is blocked on write(2) for space to write data. */
+               UDS_SUSPENDED_WRITE   = 2,
+
+               /* Socket is blocked on connect(2) waiting for the server. */
+               UDS_SUSPENDED_CONNECT = 4,
+
+               /* Socket is blocked on accept(2) waiting for clients. */
+               UDS_SUSPENDED_ACCEPT  = 8
+       } suspended;
+
+       /* Flag (1 or 0) - thing socket was waiting for is ready.
+        * If 1, then uds_status() will attempt the operation that
+        * the socket was blocked on.
+        */
+       int ready_to_revive;
+
+       /* i/o grant, saved for later use by suspended procs */
+       cp_grant_id_t io_gr;
+
+       /* is of i/o grant, saved for later use by suspended procs */
+       size_t io_gr_size;
+
+       /* Save the call number so that uds_cancel() can unwind the
+        * call properly.
+        */
+       int call_nr;
+
+       /* Save the IOCTL so uds_cancel() knows what got cancelled. */
+       int ioctl;
+
+       /* Flag (1 or 0) - the system call completed.
+        * A doc I read said DEV_CANCEL might be called even though
+        * the operation is finished. We use this variable to
+        * determine if we should rollback the changes or not.
+        */
+       int syscall_done;
+
+/* select() */
+
+       /* Flag (1 or 0) - the process blocked on select(2). When
+        * selecting is 1 and I/O happens on this socket, then
+        * select_proc should be notified.
+        */
+       int selecting;
+
+       /* when a select is in progress, we notify() this endpoint
+        * of new data.
+        */
+       endpoint_t select_proc;
+
+       /* Options (SEL_RD, SEL_WR, SEL_ERR) that are requested. */
+       int sel_ops_in;
+
+       /* Options that are available for this socket. */
+       int sel_ops_out;
+
+       /* Flag (1 or 0) to be set to one before calling notify().
+        * uds_status() will use the flag to locate this descriptor.
+        */
+       int status_updated;
+};
+
+typedef struct uds_fd uds_fd_t;
+
+/* File Descriptor Table -- Defined in uds.c */
+EXTERN uds_fd_t uds_fd_table[NR_FDS];
+
+/*
+ * Take message m and get the index in uds_fd_table.
+ */
+#define uds_minor(m)   (minor((dev_t) m->DEVICE) & BYTE)
+
+/*
+ * Fill in a reply message.
+ */
+#define uds_set_reply(msg,type,endpoint,io_gr,status)  \
+       do {                                            \
+               msg->m_type = type;                     \
+               msg->REP_ENDPT = endpoint;              \
+               msg->REP_IO_GRANT = io_gr;              \
+               msg->REP_STATUS = status;               \
+       } while (0)
+
+
+#endif
index 7c329615443cb5b70d0c015e4d8ba6475624baa1..b4bd955f1a73d2f359b91e741325cd6fdc8934fd 100644 (file)
@@ -4,10 +4,10 @@
 /*===========================================================================*
  *                             no_sys                                       *
  *===========================================================================*/
-PUBLIC int no_sys()
+PUBLIC int no_sys(message *pfs_m_in, message *pfs_m_out)
 {
 /* Somebody has used an illegal system call number */
-  printf("no_sys: invalid call %d\n", req_nr);
+  printf("no_sys: invalid call 0x%x to pfs\n", req_nr);
   return(EINVAL);
 }