# 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=
#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)
#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
--- /dev/null
+/*
+ * 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;
+}
+
#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>
/* 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;
#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>
#include <minix/callnr.h>
#include <minix/config.h>
+#include <minix/dmap.h>
#include <minix/type.h>
#include <minix/const.h>
#include <minix/com.h>
/*===========================================================================*
* 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.*/
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);
/*===========================================================================*
* 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);
}
#include <minix/vfsif.h>
#include "buf.h"
#include "inode.h"
+#include "uds.h"
FORWARD _PROTOTYPE(void get_work, (message *m_in) );
* 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);
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);
}
}
init_inode_cache();
+ uds_init();
SELF_E = getprocnr();
buf_pool();
+ driver_announce();
+
return(OK);
}
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) {
if (OK != send(who, m_out)) /* send the message */
printf("PFS(%d) was unable to send reply\n", SELF_E);
}
-
/*===========================================================================*
* 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. */
/*===========================================================================*
* 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);
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);
/* 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) );
_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) );
_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
/*===========================================================================*
* 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;
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);
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);
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. */
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);
/*===========================================================================*
* 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);
}
#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 */
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 */
+};
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+#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
/*===========================================================================*
* 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);
}