UDS: clean up source code
- move VFS calls to a separate source file; - solve a few subtle bugs, mostly in error handling; - simplify debug reporting code; - make a few definitions more independent; - restyle to something closer to KNF. Change-Id: I7b0537adfccac8b92b5cc3e78dac9f5ce3c79f03
This commit is contained in:
parent
b003ed0929
commit
1e07186caf
@ -1,6 +1,6 @@
|
|||||||
# Makefile for the UNIX Domain Sockets driver (UDS)
|
# Makefile for the UNIX Domain Sockets driver (UDS)
|
||||||
PROG= uds
|
PROG= uds
|
||||||
SRCS= uds.c ioc_uds.c
|
SRCS= uds.c ioc_uds.c vfs_uds.c
|
||||||
|
|
||||||
DPADD+= ${LIBCHARDRIVER} ${LIBSYS}
|
DPADD+= ${LIBCHARDRIVER} ${LIBSYS}
|
||||||
LDADD+= -lchardriver -lsys
|
LDADD+= -lchardriver -lsys
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -50,32 +50,23 @@ uds_open(devminor_t UNUSED(orig_minor), int access,
|
|||||||
endpoint_t user_endpt)
|
endpoint_t user_endpt)
|
||||||
{
|
{
|
||||||
devminor_t minor;
|
devminor_t minor;
|
||||||
int i;
|
|
||||||
char *buf;
|
char *buf;
|
||||||
|
int i;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_open() from %d\n", user_endpt));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [-] uds_open() call_count=%d\n", ++call_count);
|
|
||||||
printf("Endpoint: 0x%x\n", user_endpt);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a slot in the descriptor table for the new descriptor.
|
* Find a slot in the descriptor table for the new descriptor.
|
||||||
* The index of the descriptor in the table will be returned.
|
* The index of the descriptor in the table will be returned.
|
||||||
* Subsequent calls to read/write/close/ioctl/etc will use this
|
* Subsequent calls to read/write/close/ioctl/etc will use this
|
||||||
* minor number. The minor number must be different from the
|
* minor number. The minor number must be different from the
|
||||||
* the /dev/uds device's minor number (currently 0).
|
* the /dev/uds device's minor number (0).
|
||||||
*/
|
*/
|
||||||
minor = -1; /* to trap error */
|
for (minor = 1; minor < NR_FDS; minor++)
|
||||||
|
if (uds_fd_table[minor].state == UDS_FREE)
|
||||||
for (i = 1; i < NR_FDS; i++) {
|
|
||||||
if (uds_fd_table[i].state == UDS_FREE) {
|
|
||||||
minor = i;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minor == -1)
|
if (minor == NR_FDS)
|
||||||
return ENFILE;
|
return ENFILE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -84,69 +75,40 @@ uds_open(devminor_t UNUSED(orig_minor), int access,
|
|||||||
* in use. We use mmap instead of malloc to allow the memory to be
|
* in use. We use mmap instead of malloc to allow the memory to be
|
||||||
* actually freed later.
|
* actually freed later.
|
||||||
*/
|
*/
|
||||||
if ((buf = minix_mmap(NULL, PIPE_BUF, PROT_READ | PROT_WRITE,
|
if ((buf = minix_mmap(NULL, UDS_BUF, PROT_READ | PROT_WRITE,
|
||||||
MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED)
|
MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
/* mark this one as 'in use' so that it doesn't get assigned to
|
/*
|
||||||
* another socket
|
* Allocate the socket, and set its initial parameters.
|
||||||
*/
|
*/
|
||||||
uds_fd_table[minor].state = UDS_INUSE;
|
uds_fd_table[minor].state = UDS_INUSE;
|
||||||
|
|
||||||
/* set the socket owner */
|
|
||||||
uds_fd_table[minor].owner = user_endpt;
|
uds_fd_table[minor].owner = user_endpt;
|
||||||
|
|
||||||
/* setup select(2) framework */
|
|
||||||
uds_fd_table[minor].sel_endpt = NONE;
|
uds_fd_table[minor].sel_endpt = NONE;
|
||||||
uds_fd_table[minor].sel_ops = 0;
|
uds_fd_table[minor].sel_ops = 0;
|
||||||
uds_fd_table[minor].buf = buf;
|
uds_fd_table[minor].buf = buf;
|
||||||
uds_fd_table[minor].pos = 0;
|
uds_fd_table[minor].pos = 0;
|
||||||
|
|
||||||
/* the PIPE is initially empty */
|
|
||||||
uds_fd_table[minor].size = 0;
|
uds_fd_table[minor].size = 0;
|
||||||
|
uds_fd_table[minor].mode = UDS_R | UDS_W;
|
||||||
/* 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 = R_BIT | W_BIT;
|
|
||||||
|
|
||||||
/* In libc socket(2) sets this to the actual value later with the
|
|
||||||
* NWIOSUDSTYPE ioctl().
|
|
||||||
*/
|
|
||||||
uds_fd_table[minor].type = -1;
|
uds_fd_table[minor].type = -1;
|
||||||
|
|
||||||
/* Clear the backlog by setting each entry to -1 */
|
for (i = 0; i < UDS_SOMAXCONN; i++)
|
||||||
for (i = 0; i < UDS_SOMAXCONN; i++) {
|
|
||||||
/* initially no connections are pending */
|
|
||||||
uds_fd_table[minor].backlog[i] = -1;
|
uds_fd_table[minor].backlog[i] = -1;
|
||||||
}
|
|
||||||
|
|
||||||
memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct
|
|
||||||
ancillary));
|
|
||||||
for (i = 0; i < OPEN_MAX; i++) {
|
|
||||||
uds_fd_table[minor].ancillary_data.fds[i] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* default the size to UDS_SOMAXCONN */
|
|
||||||
uds_fd_table[minor].backlog_size = UDS_SOMAXCONN;
|
uds_fd_table[minor].backlog_size = UDS_SOMAXCONN;
|
||||||
|
|
||||||
/* the socket isn't listening for incoming connections until
|
memset(&uds_fd_table[minor].ancillary_data, '\0',
|
||||||
* listen(2) is called
|
sizeof(struct ancillary));
|
||||||
*/
|
for (i = 0; i < OPEN_MAX; i++)
|
||||||
|
uds_fd_table[minor].ancillary_data.fds[i] = -1;
|
||||||
|
|
||||||
uds_fd_table[minor].listening = 0;
|
uds_fd_table[minor].listening = 0;
|
||||||
|
|
||||||
/* initially the socket is not connected to a peer */
|
|
||||||
uds_fd_table[minor].peer = -1;
|
uds_fd_table[minor].peer = -1;
|
||||||
|
|
||||||
/* there isn't a child waiting to be accept(2)'d */
|
|
||||||
uds_fd_table[minor].child = -1;
|
uds_fd_table[minor].child = -1;
|
||||||
|
|
||||||
/* initially the socket is not bound or listening on an address */
|
memset(&uds_fd_table[minor].addr, '\0', sizeof(struct sockaddr_un));
|
||||||
memset(&(uds_fd_table[minor].addr), '\0', sizeof(struct sockaddr_un));
|
memset(&uds_fd_table[minor].source, '\0', sizeof(struct sockaddr_un));
|
||||||
memset(&(uds_fd_table[minor].source), '\0', sizeof(struct sockaddr_un));
|
memset(&uds_fd_table[minor].target, '\0', sizeof(struct sockaddr_un));
|
||||||
memset(&(uds_fd_table[minor].target), '\0', sizeof(struct sockaddr_un));
|
|
||||||
|
|
||||||
/* Initially the socket isn't suspended. */
|
|
||||||
uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;
|
uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;
|
||||||
|
|
||||||
return CDEV_CLONED | minor;
|
return CDEV_CLONED | minor;
|
||||||
@ -157,41 +119,32 @@ uds_close(devminor_t minor)
|
|||||||
{
|
{
|
||||||
int peer;
|
int peer;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_close(%d)\n", minor));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [%d] uds_close() call_count=%d\n", minor, ++call_count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
||||||
|
|
||||||
if (uds_fd_table[minor].state != UDS_INUSE) {
|
if (uds_fd_table[minor].state != UDS_INUSE)
|
||||||
/* attempted to close a socket that hasn't been opened --
|
|
||||||
* something is very wrong :(
|
|
||||||
*/
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
/* if the socket is connected, disconnect it */
|
/* If the socket is connected, disconnect it. */
|
||||||
if (uds_fd_table[minor].peer != -1) {
|
if (uds_fd_table[minor].peer != -1) {
|
||||||
peer = uds_fd_table[minor].peer;
|
peer = uds_fd_table[minor].peer;
|
||||||
|
|
||||||
/* set peer of this peer to -1 */
|
|
||||||
uds_fd_table[peer].peer = -1;
|
uds_fd_table[peer].peer = -1;
|
||||||
|
|
||||||
/* error to pass to peer */
|
/* The error to pass to the peer. */
|
||||||
uds_fd_table[peer].err = ECONNRESET;
|
uds_fd_table[peer].err = ECONNRESET;
|
||||||
|
|
||||||
/* if peer was blocked on I/O revive peer */
|
/* If the peer was blocked on I/O, revive it. */
|
||||||
if (uds_fd_table[peer].suspended != UDS_NOT_SUSPENDED)
|
if (uds_fd_table[peer].suspended != UDS_NOT_SUSPENDED)
|
||||||
uds_unsuspend(peer);
|
uds_unsuspend(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
|
if (uds_fd_table[minor].ancillary_data.nfiledes > 0)
|
||||||
uds_clear_fds(minor, &uds_fd_table[minor].ancillary_data);
|
uds_clear_fds(minor, &uds_fd_table[minor].ancillary_data);
|
||||||
}
|
|
||||||
|
|
||||||
/* Release the memory for the ring buffer. */
|
/* Release the memory for the ring buffer. */
|
||||||
minix_munmap(uds_fd_table[minor].buf, PIPE_BUF);
|
minix_munmap(uds_fd_table[minor].buf, UDS_BUF);
|
||||||
|
|
||||||
/* Set the socket back to its original UDS_FREE state. */
|
/* Set the socket back to its original UDS_FREE state. */
|
||||||
memset(&uds_fd_table[minor], '\0', sizeof(uds_fd_t));
|
memset(&uds_fd_table[minor], '\0', sizeof(uds_fd_t));
|
||||||
@ -211,33 +164,25 @@ uds_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
|
|||||||
unsigned int ready_ops;
|
unsigned int ready_ops;
|
||||||
int i, bytes, watch;
|
int i, bytes, watch;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_select(%d)\n", minor));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [%d] uds_select() call_count=%d\n", minor, ++call_count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
||||||
|
|
||||||
if (uds_fd_table[minor].state != UDS_INUSE) {
|
if (uds_fd_table[minor].state != UDS_INUSE)
|
||||||
/* attempted to select on a socket that hasn't been opened --
|
|
||||||
* something is very wrong :(
|
|
||||||
*/
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
watch = (ops & CDEV_NOTIFY);
|
watch = (ops & CDEV_NOTIFY);
|
||||||
ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
|
ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
|
||||||
|
|
||||||
ready_ops = 0;
|
ready_ops = 0;
|
||||||
|
|
||||||
/* check if there is data available to read */
|
/* Check if there is data available to read. */
|
||||||
if (ops & CDEV_OP_RD) {
|
if (ops & CDEV_OP_RD) {
|
||||||
bytes = uds_perform_read(minor, NONE, GRANT_INVALID, 1, 1);
|
bytes = uds_perform_read(minor, NONE, GRANT_INVALID, 1, 1);
|
||||||
if (bytes > 0) {
|
if (bytes > 0) {
|
||||||
/* there is data in the pipe for us to read */
|
ready_ops |= CDEV_OP_RD; /* data available */
|
||||||
ready_ops |= CDEV_OP_RD;
|
|
||||||
} else if (uds_fd_table[minor].listening == 1) {
|
} else if (uds_fd_table[minor].listening == 1) {
|
||||||
/* check for pending connections */
|
/* Check for pending connections. */
|
||||||
for (i = 0; i < uds_fd_table[minor].backlog_size; i++)
|
for (i = 0; i < uds_fd_table[minor].backlog_size; i++)
|
||||||
{
|
{
|
||||||
if (uds_fd_table[minor].backlog[i] != -1) {
|
if (uds_fd_table[minor].backlog[i] != -1) {
|
||||||
@ -246,22 +191,19 @@ uds_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (bytes != SUSPEND) {
|
} else if (bytes != SUSPEND) {
|
||||||
ready_ops |= CDEV_OP_RD;
|
ready_ops |= CDEV_OP_RD; /* error */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if we can write without blocking */
|
/* Check if we can write without blocking. */
|
||||||
if (ops & CDEV_OP_WR) {
|
if (ops & CDEV_OP_WR) {
|
||||||
bytes = uds_perform_write(minor, NONE, GRANT_INVALID, 1, 1);
|
bytes = uds_perform_write(minor, NONE, GRANT_INVALID, 1, 1);
|
||||||
if (bytes != 0 && bytes != SUSPEND) {
|
if (bytes != 0 && bytes != SUSPEND)
|
||||||
/* There is room to write or there is an error
|
|
||||||
* condition.
|
|
||||||
*/
|
|
||||||
ready_ops |= CDEV_OP_WR;
|
ready_ops |= CDEV_OP_WR;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If not all requested ops were ready, and the caller requests to be
|
/*
|
||||||
|
* If not all requested ops were ready, and the caller requests to be
|
||||||
* notified about changes, we add the remaining ops to the saved set.
|
* notified about changes, we add the remaining ops to the saved set.
|
||||||
*/
|
*/
|
||||||
ops &= ~ready_ops;
|
ops &= ~ready_ops;
|
||||||
@ -280,64 +222,50 @@ uds_perform_read(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant,
|
|||||||
size_t pos, subsize;
|
size_t pos, subsize;
|
||||||
int r, peer;
|
int r, peer;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_perform_read(%d)\n", minor));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [%d] uds_perform_read() call_count=%d\n", minor,
|
|
||||||
++call_count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
peer = uds_fd_table[minor].peer;
|
peer = uds_fd_table[minor].peer;
|
||||||
|
|
||||||
/* skip reads and writes of 0 (or less!) bytes */
|
/* Skip reads of zero bytes. */
|
||||||
if (size <= 0) {
|
if (size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
/* check if we are allowed to read */
|
/* Check if the socket isn't shut down for reads. */
|
||||||
if (!(uds_fd_table[minor].mode & R_BIT)) {
|
if (!(uds_fd_table[minor].mode & UDS_R))
|
||||||
/* socket is shutdown for reading */
|
|
||||||
return EPIPE;
|
return EPIPE;
|
||||||
}
|
|
||||||
|
|
||||||
if (uds_fd_table[minor].size == 0) {
|
if (uds_fd_table[minor].size == 0) {
|
||||||
if (peer == -1) {
|
if (peer == -1) {
|
||||||
/* We're not connected. That's only a problem when this
|
/*
|
||||||
* socket is connection oriented. */
|
* We're not connected. That's only a problem when this
|
||||||
|
* socket is connection oriented.
|
||||||
|
*/
|
||||||
if (uds_fd_table[minor].type == SOCK_STREAM ||
|
if (uds_fd_table[minor].type == SOCK_STREAM ||
|
||||||
uds_fd_table[minor].type == SOCK_SEQPACKET) {
|
uds_fd_table[minor].type == SOCK_SEQPACKET) {
|
||||||
if (uds_fd_table[minor].err == ECONNRESET) {
|
if (uds_fd_table[minor].err == ECONNRESET) {
|
||||||
if (!pretend)
|
if (!pretend)
|
||||||
uds_fd_table[minor].err = 0;
|
uds_fd_table[minor].err = 0;
|
||||||
return ECONNRESET;
|
return ECONNRESET;
|
||||||
} else {
|
} else
|
||||||
return ENOTCONN;
|
return ENOTCONN;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if process is reading from a closed pipe */
|
/* Check if process is reading from a closed pipe. */
|
||||||
if (peer != -1 && !(uds_fd_table[peer].mode & W_BIT) &&
|
if (peer != -1 && !(uds_fd_table[peer].mode & UDS_W) &&
|
||||||
uds_fd_table[minor].size == 0) {
|
uds_fd_table[minor].size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (pretend) {
|
if (pretend)
|
||||||
return SUSPEND;
|
return SUSPEND;
|
||||||
}
|
|
||||||
|
|
||||||
/* maybe a process is blocked waiting to write? if
|
|
||||||
* needed revive the writer
|
|
||||||
*/
|
|
||||||
if (peer != -1 &&
|
if (peer != -1 &&
|
||||||
uds_fd_table[peer].suspended == UDS_SUSPENDED_WRITE)
|
uds_fd_table[peer].suspended == UDS_SUSPENDED_WRITE)
|
||||||
uds_unsuspend(peer);
|
panic("writer blocked on empty socket");
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: suspending read request on %d\n", minor));
|
||||||
printf("(uds) [%d] suspending read request\n", minor);
|
|
||||||
#endif
|
/* Process is reading from an empty pipe. Suspend it. */
|
||||||
/* Process is reading from an empty pipe,
|
|
||||||
* suspend it so some bytes can be written
|
|
||||||
*/
|
|
||||||
return EDONTREPLY;
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +279,7 @@ uds_perform_read(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant,
|
|||||||
/* Get the data from the tail of the ring buffer. */
|
/* Get the data from the tail of the ring buffer. */
|
||||||
pos = uds_fd_table[minor].pos;
|
pos = uds_fd_table[minor].pos;
|
||||||
|
|
||||||
subsize = PIPE_BUF - pos;
|
subsize = UDS_BUF - pos;
|
||||||
if (subsize > size)
|
if (subsize > size)
|
||||||
subsize = size;
|
subsize = size;
|
||||||
|
|
||||||
@ -367,35 +295,27 @@ uds_perform_read(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Advance the buffer tail. */
|
/* Advance the buffer tail. */
|
||||||
uds_fd_table[minor].pos = (pos + size) % PIPE_BUF;
|
uds_fd_table[minor].pos = (pos + size) % UDS_BUF;
|
||||||
uds_fd_table[minor].size -= size;
|
uds_fd_table[minor].size -= size;
|
||||||
|
|
||||||
/* if we have 0 unread bytes, move the data pointer back to the
|
/* Reset position if the buffer is empty (it may save a copy call). */
|
||||||
* start of the buffer
|
if (uds_fd_table[minor].size == 0)
|
||||||
*/
|
|
||||||
if (uds_fd_table[minor].size == 0) {
|
|
||||||
uds_fd_table[minor].pos = 0;
|
uds_fd_table[minor].pos = 0;
|
||||||
}
|
|
||||||
|
|
||||||
/* maybe a big write was waiting for us to read some data, if
|
/* See if we can wake up a blocked writer. */
|
||||||
* needed revive the writer
|
|
||||||
*/
|
|
||||||
if (peer != -1 && uds_fd_table[peer].suspended == UDS_SUSPENDED_WRITE)
|
if (peer != -1 && uds_fd_table[peer].suspended == UDS_SUSPENDED_WRITE)
|
||||||
uds_unsuspend(peer);
|
uds_unsuspend(peer);
|
||||||
|
|
||||||
/* see if peer is blocked on select() and a write is possible (from
|
/* See if we can satisfy an ongoing select. */
|
||||||
* peer to minor); if the peer wants to know about write being possible
|
|
||||||
* and it doesn't know about it already, then let the peer know.
|
|
||||||
*/
|
|
||||||
if (peer != -1 && (uds_fd_table[peer].sel_ops & CDEV_OP_WR) &&
|
if (peer != -1 && (uds_fd_table[peer].sel_ops & CDEV_OP_WR) &&
|
||||||
size > 0) {
|
uds_fd_table[minor].size < UDS_BUF) {
|
||||||
/* a write on peer is possible now */
|
/* A write on the peer is possible now. */
|
||||||
chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer,
|
chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer,
|
||||||
CDEV_OP_WR);
|
CDEV_OP_WR);
|
||||||
uds_fd_table[peer].sel_ops &= ~CDEV_OP_WR;
|
uds_fd_table[peer].sel_ops &= ~CDEV_OP_WR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return size; /* return number of bytes read */
|
return size; /* number of bytes read */
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
@ -405,120 +325,104 @@ uds_perform_write(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant,
|
|||||||
size_t subsize, pos;
|
size_t subsize, pos;
|
||||||
int i, r, peer;
|
int i, r, peer;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_perform_write(%d)\n", minor));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [%d] uds_perform_write() call_count=%d\n", minor,
|
|
||||||
++call_count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Skip writes of zero bytes. */
|
/* Skip writes of zero bytes. */
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* check if we are allowed to write */
|
/* Check if the socket isn't shut down for writes. */
|
||||||
if (!(uds_fd_table[minor].mode & W_BIT)) {
|
if (!(uds_fd_table[minor].mode & UDS_W))
|
||||||
/* socket is shutdown for writing */
|
|
||||||
return EPIPE;
|
return EPIPE;
|
||||||
}
|
|
||||||
|
|
||||||
if (size > PIPE_BUF) {
|
/* We cannot handle input beyond the buffer size. */
|
||||||
/* message is too big to ever write to the PIPE */
|
if (size > UDS_BUF)
|
||||||
return EMSGSIZE;
|
return EMSGSIZE;
|
||||||
}
|
|
||||||
|
|
||||||
if (uds_fd_table[minor].type == SOCK_STREAM ||
|
if (uds_fd_table[minor].type == SOCK_STREAM ||
|
||||||
uds_fd_table[minor].type == SOCK_SEQPACKET) {
|
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 we're writing to a connection-oriented socket,
|
||||||
|
* then it needs a peer to write to.
|
||||||
*/
|
*/
|
||||||
if (uds_fd_table[minor].peer == -1) {
|
peer = uds_fd_table[minor].peer;
|
||||||
if (uds_fd_table[minor].err == ECONNRESET) {
|
|
||||||
|
|
||||||
uds_fd_table[minor].err = 0;
|
if (peer == -1) {
|
||||||
|
if (uds_fd_table[minor].err == ECONNRESET) {
|
||||||
|
if (!pretend)
|
||||||
|
uds_fd_table[minor].err = 0;
|
||||||
return ECONNRESET;
|
return ECONNRESET;
|
||||||
} else {
|
} else
|
||||||
return ENOTCONN;
|
return ENOTCONN;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
peer = uds_fd_table[minor].peer;
|
|
||||||
}
|
}
|
||||||
} else /* uds_fd_table[minor].type == SOCK_DGRAM */ {
|
} else /* uds_fd_table[minor].type == SOCK_DGRAM */ {
|
||||||
peer = -1;
|
peer = -1;
|
||||||
|
|
||||||
/* locate the "peer" we want to write to */
|
/* Locate the "peer" we want to write to. */
|
||||||
for (i = 0; i < NR_FDS; i++) {
|
for (i = 0; i < NR_FDS; i++) {
|
||||||
|
/*
|
||||||
/* look for a SOCK_DGRAM socket that is bound on
|
* Look for a SOCK_DGRAM socket that is bound on
|
||||||
* the target address
|
* the target address.
|
||||||
*/
|
*/
|
||||||
if (uds_fd_table[i].type == SOCK_DGRAM &&
|
if (uds_fd_table[i].type == SOCK_DGRAM &&
|
||||||
uds_fd_table[i].addr.sun_family == AF_UNIX &&
|
uds_fd_table[i].addr.sun_family == AF_UNIX &&
|
||||||
!strncmp(uds_fd_table[minor].target.sun_path,
|
!strncmp(uds_fd_table[minor].target.sun_path,
|
||||||
uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) {
|
uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) {
|
||||||
|
|
||||||
peer = i;
|
peer = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (peer == -1) {
|
||||||
|
if (pretend)
|
||||||
|
return SUSPEND;
|
||||||
|
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peer == -1) {
|
/* Check if we write to a closed pipe. */
|
||||||
if (pretend)
|
if (!(uds_fd_table[peer].mode & UDS_R))
|
||||||
return SUSPEND;
|
|
||||||
|
|
||||||
return ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if we write to a closed pipe */
|
|
||||||
if (!(uds_fd_table[peer].mode & R_BIT)) {
|
|
||||||
return EPIPE;
|
return EPIPE;
|
||||||
}
|
|
||||||
|
|
||||||
/* we have to preserve the boundary for DGRAM. if there's
|
/*
|
||||||
* already a packet waiting, discard it silently and pretend
|
* We have to preserve the boundary for DGRAM. If there's already a
|
||||||
* it was written.
|
* packet waiting, discard it silently and pretend it was written.
|
||||||
*/
|
*/
|
||||||
if(uds_fd_table[minor].type == SOCK_DGRAM &&
|
if (uds_fd_table[minor].type == SOCK_DGRAM &&
|
||||||
uds_fd_table[peer].size > 0) {
|
uds_fd_table[peer].size > 0)
|
||||||
return size;
|
return size;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the ring buffer is already full, and if the SEQPACKET
|
* Check if the ring buffer is already full, and if the SEQPACKET
|
||||||
* message wouldn't write to an empty buffer.
|
* message wouldn't write to an empty buffer.
|
||||||
*/
|
*/
|
||||||
if (uds_fd_table[peer].size == PIPE_BUF ||
|
if (uds_fd_table[peer].size == UDS_BUF ||
|
||||||
(uds_fd_table[minor].type == SOCK_SEQPACKET &&
|
(uds_fd_table[minor].type == SOCK_SEQPACKET &&
|
||||||
uds_fd_table[peer].size > 0)) {
|
uds_fd_table[peer].size > 0)) {
|
||||||
if (pretend) {
|
if (pretend)
|
||||||
return SUSPEND;
|
return SUSPEND;
|
||||||
}
|
|
||||||
|
|
||||||
/* if needed revive the reader */
|
|
||||||
if (uds_fd_table[peer].suspended == UDS_SUSPENDED_READ)
|
if (uds_fd_table[peer].suspended == UDS_SUSPENDED_READ)
|
||||||
uds_unsuspend(peer);
|
panic("reader blocked on full socket");
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: suspending write request on %d\n", minor));
|
||||||
printf("(uds) [%d] suspending write request\n", minor);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Process is reading from an empty pipe,
|
/* Process is reading from an empty pipe. Suspend it. */
|
||||||
* suspend it so some bytes can be written
|
|
||||||
*/
|
|
||||||
return EDONTREPLY;
|
return EDONTREPLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* How much can we add to the ring buffer? */
|
/* How much can we add to the ring buffer? */
|
||||||
if (size > PIPE_BUF - uds_fd_table[peer].size)
|
if (size > UDS_BUF - uds_fd_table[peer].size)
|
||||||
size = PIPE_BUF - uds_fd_table[peer].size;
|
size = UDS_BUF - uds_fd_table[peer].size;
|
||||||
|
|
||||||
if (pretend)
|
if (pretend)
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
/* Put the data at the head of the ring buffer. */
|
/* Put the data at the head of the ring buffer. */
|
||||||
pos = (uds_fd_table[peer].pos + uds_fd_table[peer].size) % PIPE_BUF;
|
pos = (uds_fd_table[peer].pos + uds_fd_table[peer].size) % UDS_BUF;
|
||||||
|
|
||||||
subsize = PIPE_BUF - pos;
|
subsize = UDS_BUF - pos;
|
||||||
if (subsize > size)
|
if (subsize > size)
|
||||||
subsize = size;
|
subsize = size;
|
||||||
|
|
||||||
@ -535,28 +439,25 @@ uds_perform_write(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant,
|
|||||||
/* Advance the buffer head. */
|
/* Advance the buffer head. */
|
||||||
uds_fd_table[peer].size += size;
|
uds_fd_table[peer].size += size;
|
||||||
|
|
||||||
/* fill in the source address to be returned by recvfrom & recvmsg */
|
/* Fill in the source address to be returned by recvfrom, recvmsg. */
|
||||||
if (uds_fd_table[minor].type == SOCK_DGRAM) {
|
if (uds_fd_table[minor].type == SOCK_DGRAM)
|
||||||
memcpy(&uds_fd_table[peer].source, &uds_fd_table[minor].addr,
|
memcpy(&uds_fd_table[peer].source, &uds_fd_table[minor].addr,
|
||||||
sizeof(struct sockaddr_un));
|
sizeof(struct sockaddr_un));
|
||||||
}
|
|
||||||
|
|
||||||
/* revive peer that was waiting for us to write */
|
/* See if we can wake up a blocked reader. */
|
||||||
if (uds_fd_table[peer].suspended == UDS_SUSPENDED_READ)
|
if (uds_fd_table[peer].suspended == UDS_SUSPENDED_READ)
|
||||||
uds_unsuspend(peer);
|
uds_unsuspend(peer);
|
||||||
|
|
||||||
/* see if peer is blocked on select(); if the peer wants to know about
|
/* See if we can satisfy an ongoing select. */
|
||||||
* data ready to read and it doesn't know about it already, then let
|
if ((uds_fd_table[peer].sel_ops & CDEV_OP_RD) &&
|
||||||
* the peer know we have data for it.
|
uds_fd_table[peer].size > 0) {
|
||||||
*/
|
/* A read on the peer is possible now. */
|
||||||
if ((uds_fd_table[peer].sel_ops & CDEV_OP_RD) && size > 0) {
|
|
||||||
/* a read on peer is possible now */
|
|
||||||
chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer,
|
chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer,
|
||||||
CDEV_OP_RD);
|
CDEV_OP_RD);
|
||||||
uds_fd_table[peer].sel_ops &= ~CDEV_OP_RD;
|
uds_fd_table[peer].sel_ops &= ~CDEV_OP_RD;
|
||||||
}
|
}
|
||||||
|
|
||||||
return size; /* return number of bytes written */
|
return size; /* number of bytes written */
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
@ -565,19 +466,12 @@ uds_read(devminor_t minor, u64_t position, endpoint_t endpt,
|
|||||||
{
|
{
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_read(%d)\n", minor));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [%d] uds_read() call_count=%d\n", minor, ++call_count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
||||||
|
|
||||||
if (uds_fd_table[minor].state != UDS_INUSE) {
|
if (uds_fd_table[minor].state != UDS_INUSE)
|
||||||
/* attempted to read from a socket that hasn't been opened --
|
|
||||||
* something is very wrong :(
|
|
||||||
*/
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
rc = uds_perform_read(minor, endpt, grant, size, 0);
|
rc = uds_perform_read(minor, endpt, grant, size, 0);
|
||||||
|
|
||||||
@ -606,19 +500,12 @@ uds_write(devminor_t minor, u64_t position, endpoint_t endpt,
|
|||||||
{
|
{
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_write(%d)\n", minor));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [%d] uds_write() call_count=%d\n", minor, ++call_count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
||||||
|
|
||||||
if (uds_fd_table[minor].state != UDS_INUSE) {
|
if (uds_fd_table[minor].state != UDS_INUSE)
|
||||||
/* attempted to write to a socket that hasn't been opened --
|
|
||||||
* something is very wrong :(
|
|
||||||
*/
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
rc = uds_perform_write(minor, endpt, grant, size, 0);
|
rc = uds_perform_write(minor, endpt, grant, size, 0);
|
||||||
|
|
||||||
@ -647,24 +534,17 @@ uds_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_ioctl(%d, %lu)\n", minor, request));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [%d] uds_ioctl() call_count=%d\n", minor, ++call_count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
if (minor < 0 || minor >= NR_FDS) return ENXIO;
|
||||||
|
|
||||||
if (uds_fd_table[minor].state != UDS_INUSE) {
|
if (uds_fd_table[minor].state != UDS_INUSE)
|
||||||
/* attempted to perform I/O control on a socket that hasn't
|
|
||||||
* been opened -- something is very wrong :(
|
|
||||||
*/
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
/* update the owner endpoint */
|
/* Update the owner endpoint. */
|
||||||
uds_fd_table[minor].owner = user_endpt;
|
uds_fd_table[minor].owner = user_endpt;
|
||||||
|
|
||||||
/* let the UDS subsystem handle the actual request */
|
/* Let the UDS ioctl subsystem handle the actual request. */
|
||||||
rc = uds_do_ioctl(minor, request, endpt, grant);
|
rc = uds_do_ioctl(minor, request, endpt, grant);
|
||||||
|
|
||||||
/* If the call couldn't complete, suspend the caller. */
|
/* If the call couldn't complete, suspend the caller. */
|
||||||
@ -699,7 +579,7 @@ uds_unsuspend(devminor_t minor)
|
|||||||
switch (fdp->suspended) {
|
switch (fdp->suspended) {
|
||||||
case UDS_SUSPENDED_READ:
|
case UDS_SUSPENDED_READ:
|
||||||
r = uds_perform_read(minor, fdp->susp_endpt, fdp->susp_grant,
|
r = uds_perform_read(minor, fdp->susp_endpt, fdp->susp_grant,
|
||||||
fdp->susp_size, 0);
|
fdp->susp_size, 0);
|
||||||
|
|
||||||
if (r == EDONTREPLY)
|
if (r == EDONTREPLY)
|
||||||
return;
|
return;
|
||||||
@ -708,7 +588,7 @@ uds_unsuspend(devminor_t minor)
|
|||||||
|
|
||||||
case UDS_SUSPENDED_WRITE:
|
case UDS_SUSPENDED_WRITE:
|
||||||
r = uds_perform_write(minor, fdp->susp_endpt, fdp->susp_grant,
|
r = uds_perform_write(minor, fdp->susp_endpt, fdp->susp_grant,
|
||||||
fdp->susp_size, 0);
|
fdp->susp_size, 0);
|
||||||
|
|
||||||
if (r == EDONTREPLY)
|
if (r == EDONTREPLY)
|
||||||
return;
|
return;
|
||||||
@ -717,7 +597,8 @@ uds_unsuspend(devminor_t minor)
|
|||||||
|
|
||||||
case UDS_SUSPENDED_CONNECT:
|
case UDS_SUSPENDED_CONNECT:
|
||||||
case UDS_SUSPENDED_ACCEPT:
|
case UDS_SUSPENDED_ACCEPT:
|
||||||
/* In both cases, the caller already set up the connection.
|
/*
|
||||||
|
* In both cases, the caller already set up the connection.
|
||||||
* The only thing to do here is unblock.
|
* The only thing to do here is unblock.
|
||||||
*/
|
*/
|
||||||
r = OK;
|
r = OK;
|
||||||
@ -739,10 +620,7 @@ uds_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
|||||||
uds_fd_t *fdp;
|
uds_fd_t *fdp;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
#if DEBUG == 1
|
dprintf(("UDS: uds_cancel(%d)\n", minor));
|
||||||
static int call_count = 0;
|
|
||||||
printf("(uds) [%d] uds_cancel() call_count=%d\n", minor, ++call_count);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (minor < 0 || minor >= NR_FDS) return EDONTREPLY;
|
if (minor < 0 || minor >= NR_FDS) return EDONTREPLY;
|
||||||
|
|
||||||
@ -755,48 +633,41 @@ uds_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
|||||||
|
|
||||||
/* Make sure the cancel request is for a request we're hanging on. */
|
/* Make sure the cancel request is for a request we're hanging on. */
|
||||||
if (fdp->suspended == UDS_NOT_SUSPENDED || fdp->susp_endpt != endpt ||
|
if (fdp->suspended == UDS_NOT_SUSPENDED || fdp->susp_endpt != endpt ||
|
||||||
fdp->susp_id != id) {
|
fdp->susp_id != id)
|
||||||
return EDONTREPLY; /* this happens. */
|
return EDONTREPLY; /* this happens. */
|
||||||
}
|
|
||||||
|
|
||||||
/* The system call was cancelled, so the socket is not suspended
|
/*
|
||||||
|
* The system call was cancelled, so the socket is not suspended
|
||||||
* anymore.
|
* anymore.
|
||||||
*/
|
*/
|
||||||
switch (fdp->suspended) {
|
switch (fdp->suspended) {
|
||||||
case UDS_SUSPENDED_ACCEPT: /* accept() */
|
case UDS_SUSPENDED_ACCEPT: /* accept() */
|
||||||
/* partial accept() only changes
|
/* A partial accept() only sets the server's child. */
|
||||||
* uds_fd_table[minorparent].child
|
for (i = 0; i < NR_FDS; i++)
|
||||||
*/
|
if (uds_fd_table[i].child == minor)
|
||||||
for (i = 0; i < NR_FDS; i++) {
|
|
||||||
if (uds_fd_table[i].child == minor) {
|
|
||||||
uds_fd_table[i].child = -1;
|
uds_fd_table[i].child = -1;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UDS_SUSPENDED_CONNECT: /* connect() */
|
case UDS_SUSPENDED_CONNECT: /* connect() */
|
||||||
/* partial connect() sets addr and adds minor to server backlog
|
/*
|
||||||
|
* A partial connect() sets the address and adds the minor to
|
||||||
|
* the server backlog.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 0; i < NR_FDS; i++) {
|
for (i = 0; i < NR_FDS; i++) {
|
||||||
/* find a socket that is in use. */
|
|
||||||
if (uds_fd_table[i].state != UDS_INUSE)
|
if (uds_fd_table[i].state != UDS_INUSE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* see if minor is in the backlog */
|
/* Remove the minor from the backlog of any server. */
|
||||||
for (j = 0; j < uds_fd_table[i].backlog_size; j++) {
|
for (j = 0; j < uds_fd_table[i].backlog_size; j++) {
|
||||||
if (uds_fd_table[i].backlog[j] == minor) {
|
if (uds_fd_table[i].backlog[j] == minor)
|
||||||
|
|
||||||
/* remove from backlog */
|
|
||||||
uds_fd_table[i].backlog[j] = -1;
|
uds_fd_table[i].backlog[j] = -1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear the address */
|
/* Clear the address. */
|
||||||
memset(&(uds_fd_table[minor].addr), '\0',
|
memset(&uds_fd_table[minor].addr, '\0',
|
||||||
sizeof(struct sockaddr_un));
|
sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -16,9 +16,18 @@
|
|||||||
/* Connection backlog size for incoming connections. */
|
/* Connection backlog size for incoming connections. */
|
||||||
#define UDS_SOMAXCONN 64
|
#define UDS_SOMAXCONN 64
|
||||||
|
|
||||||
|
/* Maximum UDS socket buffer size. */
|
||||||
|
#define UDS_BUF PIPE_BUF
|
||||||
|
|
||||||
/* Output debugging information? */
|
/* Output debugging information? */
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#define dprintf(x) printf x
|
||||||
|
#else
|
||||||
|
#define dprintf(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void* filp_id_t;
|
typedef void* filp_id_t;
|
||||||
|
|
||||||
/* ancillary data to be sent */
|
/* ancillary data to be sent */
|
||||||
@ -29,6 +38,9 @@ struct ancillary {
|
|||||||
struct uucred cred;
|
struct uucred cred;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define UDS_R 0x1
|
||||||
|
#define UDS_W 0x2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal State Information for a socket descriptor.
|
* Internal State Information for a socket descriptor.
|
||||||
*/
|
*/
|
||||||
@ -61,9 +73,9 @@ struct uds_fd {
|
|||||||
size_t size; /* size of used part of ring buffer */
|
size_t size; /* size of used part of ring buffer */
|
||||||
|
|
||||||
/* control read/write, set by uds_open() and shutdown(2).
|
/* control read/write, set by uds_open() and shutdown(2).
|
||||||
* Can be set to R_BIT|W_BIT, R_BIT, W_BIT, or 0
|
* Can be set to UDS_R|UDS_W, UDS_R, UDS_W, or 0
|
||||||
* for read and write, read only, write only, or neither.
|
* for read and write, read only, write only, or neither.
|
||||||
* default is R_BIT|W_BIT.
|
* default is UDS_R|UDS_W.
|
||||||
*/
|
*/
|
||||||
int mode;
|
int mode;
|
||||||
|
|
||||||
@ -179,12 +191,20 @@ EXTERN uds_fd_t uds_fd_table[NR_FDS];
|
|||||||
|
|
||||||
/* Function prototypes. */
|
/* Function prototypes. */
|
||||||
|
|
||||||
/* dev_uds.c */
|
/* ioc_uds.c */
|
||||||
void uds_unsuspend(devminor_t minor);
|
|
||||||
|
|
||||||
/* uds.c */
|
|
||||||
int uds_clear_fds(devminor_t minor, struct ancillary *data);
|
int uds_clear_fds(devminor_t minor, struct ancillary *data);
|
||||||
int uds_do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
|
int uds_do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
|
||||||
cp_grant_id_t grant);
|
cp_grant_id_t grant);
|
||||||
|
|
||||||
|
/* uds.c */
|
||||||
|
void uds_unsuspend(devminor_t minor);
|
||||||
|
|
||||||
|
/* vfs_uds.c */
|
||||||
|
int vfs_check_perms(endpoint_t ep, struct sockaddr_un *addr);
|
||||||
|
int vfs_verify_fd(endpoint_t ep, int fd, filp_id_t *filp);
|
||||||
|
int vfs_set_filp(filp_id_t sfilp);
|
||||||
|
int vfs_copy_filp(endpoint_t to_ep, filp_id_t cfilp);
|
||||||
|
int vfs_put_filp(filp_id_t pfilp);
|
||||||
|
int vfs_cancel_fd(endpoint_t ep, int fd);
|
||||||
|
|
||||||
#endif /* !__UDS_UDS_H */
|
#endif /* !__UDS_UDS_H */
|
||||||
|
168
drivers/uds/vfs_uds.c
Normal file
168
drivers/uds/vfs_uds.c
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL)
|
||||||
|
* This code provides communication stubs for backcalls to VFS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uds.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the permissions of a socket file.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vfs_check_perms(endpoint_t ep, struct sockaddr_un *addr)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
message m;
|
||||||
|
cp_grant_id_t grant_id;
|
||||||
|
|
||||||
|
dprintf(("UDS: vfs_check_perms(%d)\n", ep));
|
||||||
|
|
||||||
|
grant_id = cpf_grant_direct(VFS_PROC_NR, (vir_bytes) addr->sun_path,
|
||||||
|
UNIX_PATH_MAX, CPF_READ | CPF_WRITE);
|
||||||
|
|
||||||
|
/* Ask VFS to verify the permissions. */
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
|
||||||
|
m.m_type = VFS_UDS_CHECK_PERMS;
|
||||||
|
m.VFS_UDS_ENDPT = ep;
|
||||||
|
m.VFS_UDS_GRANT = grant_id;
|
||||||
|
m.VFS_UDS_COUNT = UNIX_PATH_MAX;
|
||||||
|
|
||||||
|
if ((rc = sendrec(VFS_PROC_NR, &m)) != OK)
|
||||||
|
panic("error sending to VFS: %d\n", rc);
|
||||||
|
|
||||||
|
cpf_revoke(grant_id);
|
||||||
|
|
||||||
|
dprintf(("UDS: VFS reply => %d, \"%s\"\n", m.m_type,
|
||||||
|
addr->sun_path));
|
||||||
|
|
||||||
|
return m.m_type; /* reply code: OK, ELOOP, etc. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify whether the given file descriptor is valid for the given process, and
|
||||||
|
* obtain a filp object identifier upon success.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vfs_verify_fd(endpoint_t ep, int fd, filp_id_t *filp)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
message m;
|
||||||
|
|
||||||
|
dprintf(("UDS: vfs_verify_fd(%d, %d)\n", ep, fd));
|
||||||
|
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
|
||||||
|
m.m_type = VFS_UDS_VERIFY_FD;
|
||||||
|
m.VFS_UDS_ENDPT = ep;
|
||||||
|
m.VFS_UDS_FD = fd;
|
||||||
|
|
||||||
|
if ((rc = sendrec(VFS_PROC_NR, &m)) != OK)
|
||||||
|
panic("error sending to VFS: %d\n", rc);
|
||||||
|
|
||||||
|
dprintf(("UDS: VFS reply => %d, %p\n", m.m_type, m.VFS_UDS_FILP));
|
||||||
|
|
||||||
|
if (m.m_type != OK)
|
||||||
|
return m.m_type;
|
||||||
|
|
||||||
|
*filp = m.VFS_UDS_FILP;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark a filp object as in flight, that is, in use by UDS.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vfs_set_filp(filp_id_t sfilp)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
message m;
|
||||||
|
|
||||||
|
dprintf(("UDS: set_filp(%p)\n", sfilp));
|
||||||
|
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
|
||||||
|
m.m_type = VFS_UDS_SET_FILP;
|
||||||
|
m.VFS_UDS_FILP = sfilp;
|
||||||
|
|
||||||
|
if ((rc = sendrec(VFS_PROC_NR, &m)) != OK)
|
||||||
|
panic("error sending to VFS: %d\n", rc);
|
||||||
|
|
||||||
|
dprintf(("UDS: VFS reply => %d\n", m.m_type));
|
||||||
|
|
||||||
|
return m.m_type; /* reply code: OK, ELOOP, etc. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy a filp object into a process, yielding a file descriptor.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vfs_copy_filp(endpoint_t to_ep, filp_id_t cfilp)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
message m;
|
||||||
|
|
||||||
|
dprintf(("UDS: vfs_copy_filp(%d, %p)\n", to_ep, cfilp));
|
||||||
|
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
|
||||||
|
m.m_type = VFS_UDS_COPY_FILP;
|
||||||
|
m.VFS_UDS_ENDPT = to_ep;
|
||||||
|
m.VFS_UDS_FILP = cfilp;
|
||||||
|
|
||||||
|
if ((rc = sendrec(VFS_PROC_NR, &m)) != OK)
|
||||||
|
panic("error sending to VFS: %d\n", rc);
|
||||||
|
|
||||||
|
dprintf(("UDS: VFS reply => %d\n", m.m_type));
|
||||||
|
|
||||||
|
return m.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark a filp object as no longer in flight.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vfs_put_filp(filp_id_t pfilp)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
message m;
|
||||||
|
|
||||||
|
dprintf(("UDS: vfs_put_filp(%p)\n", pfilp));
|
||||||
|
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
|
||||||
|
m.m_type = VFS_UDS_PUT_FILP;
|
||||||
|
m.VFS_UDS_FILP = pfilp;
|
||||||
|
|
||||||
|
if ((rc = sendrec(VFS_PROC_NR, &m)) != OK)
|
||||||
|
panic("error sending to VFS: %d\n", rc);
|
||||||
|
|
||||||
|
dprintf(("UDS: VFS reply => %d\n", m.m_type));
|
||||||
|
|
||||||
|
return m.m_type; /* reply code: OK, ELOOP, etc. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Undo creation of a file descriptor in a process.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vfs_cancel_fd(endpoint_t ep, int fd)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
message m;
|
||||||
|
|
||||||
|
dprintf(("UDS: vfs_cancel_fd(%d,%d)\n", ep, fd));
|
||||||
|
|
||||||
|
memset(&m, '\0', sizeof(message));
|
||||||
|
|
||||||
|
m.m_type = VFS_UDS_CANCEL_FD;
|
||||||
|
m.VFS_UDS_ENDPT = ep;
|
||||||
|
m.VFS_UDS_FD = fd;
|
||||||
|
|
||||||
|
if ((rc = sendrec(VFS_PROC_NR, &m)) != OK)
|
||||||
|
panic("error sending to VFS: %d\n", rc);
|
||||||
|
|
||||||
|
dprintf(("UDS: VFS reply => %d\n", m.m_type));
|
||||||
|
|
||||||
|
return m.m_type; /* reply code: OK, ELOOP, etc. */
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user