diff --git a/servers/pfs/Makefile b/servers/pfs/Makefile index 9e84d3929..c36260425 100644 --- a/servers/pfs/Makefile +++ b/servers/pfs/Makefile @@ -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= diff --git a/servers/pfs/const.h b/servers/pfs/const.h index 25c5bc83a..443c61f40 100644 --- a/servers/pfs/const.h +++ b/servers/pfs/const.h @@ -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<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; +} + diff --git a/servers/pfs/fs.h b/servers/pfs/fs.h index 6a1ca24ad..225cd35ac 100644 --- a/servers/pfs/fs.h +++ b/servers/pfs/fs.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/servers/pfs/glo.h b/servers/pfs/glo.h index 9b4eeeb8e..76338599b 100644 --- a/servers/pfs/glo.h +++ b/servers/pfs/glo.h @@ -12,10 +12,8 @@ /* 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; diff --git a/servers/pfs/inc.h b/servers/pfs/inc.h index 9f22b60e9..09755c5e4 100644 --- a/servers/pfs/inc.h +++ b/servers/pfs/inc.h @@ -4,8 +4,13 @@ #define VERBOSE 0 /* display diagnostics */ +#include + #include #include +#include +#include +#include #include #include #include @@ -13,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/servers/pfs/inode.c b/servers/pfs/inode.c index bbb799c51..a2b42e8b6 100644 --- a/servers/pfs/inode.c +++ b/servers/pfs/inode.c @@ -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); diff --git a/servers/pfs/link.c b/servers/pfs/link.c index d6b9ba9ed..4a5e901cb 100644 --- a/servers/pfs/link.c +++ b/servers/pfs/link.c @@ -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); } diff --git a/servers/pfs/main.c b/servers/pfs/main.c index d3c1da514..ae5210b95 100644 --- a/servers/pfs/main.c +++ b/servers/pfs/main.c @@ -6,6 +6,7 @@ #include #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; + req_nr = pfs_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; + 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); } - diff --git a/servers/pfs/misc.c b/servers/pfs/misc.c index e460113ac..dc8da9e6e 100644 --- a/servers/pfs/misc.c +++ b/servers/pfs/misc.c @@ -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. */ diff --git a/servers/pfs/open.c b/servers/pfs/open.c index ca512bb3f..4abf5b1cf 100644 --- a/servers/pfs/open.c +++ b/servers/pfs/open.c @@ -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); diff --git a/servers/pfs/proto.h b/servers/pfs/proto.h index b0b7578c8..6e8300d10 100644 --- a/servers/pfs/proto.h +++ b/servers/pfs/proto.h @@ -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 diff --git a/servers/pfs/read.c b/servers/pfs/read.c index be3c19b2a..3a6579f0a 100644 --- a/servers/pfs/read.c +++ b/servers/pfs/read.c @@ -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); diff --git a/servers/pfs/stadir.c b/servers/pfs/stadir.c index 2b0e49661..707301a07 100644 --- a/servers/pfs/stadir.c +++ b/servers/pfs/stadir.c @@ -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); } diff --git a/servers/pfs/table.c b/servers/pfs/table.c index 110d02250..95e5c5a40 100644 --- a/servers/pfs/table.c +++ b/servers/pfs/table.c @@ -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 index 000000000..3188cad88 --- /dev/null +++ b/servers/pfs/uds.c @@ -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 index 000000000..3af2d57e5 --- /dev/null +++ b/servers/pfs/uds.h @@ -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 +#include + +#include + +/* 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 diff --git a/servers/pfs/utility.c b/servers/pfs/utility.c index 7c3296154..b4bd955f1 100644 --- a/servers/pfs/utility.c +++ b/servers/pfs/utility.c @@ -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); }