diff --git a/kernel-src/fs/file.c b/kernel-src/fs/file.c index 53ed06e8..93156256 100644 --- a/kernel-src/fs/file.c +++ b/kernel-src/fs/file.c @@ -196,7 +196,7 @@ int fd_clone(proc_t *targproc) { return error; } -int fd_insert(file_t *file, int *fdp) { +int fd_insert(file_t *file, int *fdp, int flags) { proc_t *proc = current_thread()->proc; int err = 0; MUTEX_ACQUIRE(&proc->fdmutex); @@ -210,7 +210,7 @@ int fd_insert(file_t *file, int *fdp) { } proc->fd[fd].file = file; - proc->fd[fd].flags = 0; + proc->fd[fd].flags = flags; FILE_HOLD(file); *fdp = fd; diff --git a/kernel-src/include/kernel/abi.h b/kernel-src/include/kernel/abi.h index 2d9fad18..290442de 100644 --- a/kernel-src/include/kernel/abi.h +++ b/kernel-src/include/kernel/abi.h @@ -89,6 +89,7 @@ typedef struct { #define SOCK_DGRAM 2 #define SOCK_RAW 3 +#define MSG_CMSG_CLOEXEC 0x40000000 #define MSG_CTRUNC 0x8 #define MSG_PEEK 2 #define MSG_WAITALL 0x100 diff --git a/kernel-src/include/kernel/file.h b/kernel-src/include/kernel/file.h index e1c03c34..6d71e5ad 100644 --- a/kernel-src/include/kernel/file.h +++ b/kernel-src/include/kernel/file.h @@ -28,7 +28,7 @@ int fd_dup(int oldfd, int newfd, bool exact, int flags, int *ret); int fd_clone(proc_t *proc); int fd_setflags(int fd, int flags); int fd_getflags(int fd, int *flags); -int fd_insert(file_t *file, int *fdp); +int fd_insert(file_t *file, int *fdp, int flags); #define FILE_LOCK(x) MUTEX_ACQUIRE(&(x)->mutex) #define FILE_UNLOCK(x) MUTEX_RELEASE(&(x)->mutex) diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index f70b2bf5..7cc67e02 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -51,6 +51,7 @@ typedef struct { #define SOCKET_RECV_FLAGS_PEEK 0x8000000000000000l #define SOCKET_RECV_FLAGS_WAITALL 0x4000000000000000l #define SOCKET_RECV_FLAGS_CTRLTRUNCATED 0x2000000000000000l +#define SOCKET_RECV_FLAGS_CLOEXEC_CTRL 0x1000000000000000l #define SOCKET_SEND_FLAGS_NOSIGNAL 0x8000000000000000l typedef struct socketops_t { diff --git a/kernel-src/io/net/localsocket.c b/kernel-src/io/net/localsocket.c index d705ba65..a68a0384 100644 --- a/kernel-src/io/net/localsocket.c +++ b/kernel-src/io/net/localsocket.c @@ -71,11 +71,14 @@ static int datapoll(localsocket_t *local, localsocket_t *peer, int events) { int revents = 0; // data to read? - if ((events & POLLIN) && RINGBUFFER_DATACOUNT(&local->ringbuffer)) + if ((events & POLLIN) && (RINGBUFFER_DATACOUNT(&local->ringbuffer) || (peer->socket.shutdown & SOCKET_SHUTDOWN_WRITE))) revents |= POLLIN; + // XXX is this the correct behaviour? + if ((events & POLLOUT) && (peer->socket.shutdown & SOCKET_SHUTDOWN_READ)) + revents |= POLLHUP; // space to write? - if ((events & POLLOUT) && RINGBUFFER_DATACOUNT(&peer->ringbuffer) != SOCKET_BUFFER) + else if ((events & POLLOUT) && RINGBUFFER_DATACOUNT(&peer->ringbuffer) != SOCKET_BUFFER) revents |= POLLOUT; return revents; @@ -177,7 +180,7 @@ static int sendctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, size_t datas if (ctrl == NULL) { // if there is no control data, there is no need to add a barrier // increase the bytes in the current section - peer->bytesremaining[peer->barrierwrite] += datasent; + peer->bytesremaining[peer->barrierwrite % BARRIER_SIZE] += datasent; return 0; } @@ -233,9 +236,10 @@ static int sendctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, size_t datas // create a new barrier secion __assert(peer->barrierwrite != peer->barriercurrent + BARRIER_SIZE); - peer->barrierwrite++; + peer->filesremaining[peer->barrierwrite % BARRIER_SIZE] = fdcount; peer->bytesremaining[peer->barrierwrite % BARRIER_SIZE] = datasent; + ++peer->barrierwrite; } ctrl = SOCK_CTRL_NEXT(ctrl); @@ -244,7 +248,7 @@ static int sendctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, size_t datas return error; } -static int recvctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, bool *truncated, size_t *receivedlen) { +static int recvctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, bool *truncated, size_t *receivedlen, uintmax_t flags) { localsocket_t *localsocket = (localsocket_t *)socket; int error = 0; *receivedlen = 0; @@ -258,7 +262,7 @@ static int recvctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, bool *trunca // - number fds that fit in the data of the control // - files in the current section // - files actually in the ringbuffer - size_t actualcount = min(min((len - sizeof(sockctrl_t)) / sizeof(int), filecount), localsocket->filesremaining[localsocket->barriercurrent]); + size_t actualcount = min(min((len - sizeof(sockctrl_t)) / sizeof(int), filecount), localsocket->filesremaining[localsocket->barriercurrent % BARRIER_SIZE]); if (actualcount == 0) goto discard; @@ -269,8 +273,7 @@ static int recvctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, bool *trunca // read the file pointers and insert them into the process fd table file_t *file; __assert(ringbuffer_read(&localsocket->fds, &file, sizeof(file_t *)) == sizeof(file_t *)); - - if (fd_insert(file, &fds[donecount])) { + if (fd_insert(file, &fds[donecount], (flags & SOCKET_RECV_FLAGS_CLOEXEC_CTRL) ? O_CLOEXEC : 0)) { fd_release(file); break; } @@ -286,7 +289,7 @@ static int recvctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, bool *trunca memcpy(ctrl->data, fds, donecount * sizeof(int)); // prepare for discarding the rest later - localsocket->filesremaining[localsocket->barriercurrent] -= donecount; + localsocket->filesremaining[localsocket->barriercurrent % BARRIER_SIZE] -= donecount; *receivedlen += ctrl->length; } @@ -294,14 +297,14 @@ static int recvctrl(socket_t *socket, sockctrl_t *ctrl, size_t len, bool *trunca discard: // discard the rest file_t *file = NULL; - for (int i = 0; i < localsocket->filesremaining[localsocket->barriercurrent]; ++i) { + for (int i = 0; i < localsocket->filesremaining[localsocket->barriercurrent % BARRIER_SIZE]; ++i) { ringbuffer_read(&localsocket->fds, &file, sizeof(file_t *)); fd_release(file); } *truncated = file != NULL; - localsocket->filesremaining[localsocket->barriercurrent] = 0; + localsocket->filesremaining[localsocket->barriercurrent % BARRIER_SIZE] = 0; return error; } @@ -447,7 +450,7 @@ static int localsock_recv(socket_t *socket, sockdesc_t *sockdesc) { // receive control data bool truncated; - error = recvctrl(socket, sockdesc->ctrl, sockdesc->ctrllen, &truncated, &sockdesc->ctrldone); + error = recvctrl(socket, sockdesc->ctrl, sockdesc->ctrllen, &truncated, &sockdesc->ctrldone, flags); if (error) goto leave; @@ -458,7 +461,7 @@ static int localsock_recv(socket_t *socket, sockdesc_t *sockdesc) { // check for a barrier from control data if (localsocket->bytesremaining[localsocket->barriercurrent % BARRIER_SIZE]) { - recvcount = min(recvcount, localsocket->bytesremaining[localsocket->barriercurrent]); + recvcount = min(recvcount, localsocket->bytesremaining[localsocket->barriercurrent % BARRIER_SIZE]); // check if we should step forward from that barrier localsocket->bytesremaining[localsocket->barriercurrent % BARRIER_SIZE] -= recvcount; diff --git a/kernel-src/sys/syscalls/recvmsg.c b/kernel-src/sys/syscalls/recvmsg.c index 9d53787a..af88443c 100644 --- a/kernel-src/sys/syscalls/recvmsg.c +++ b/kernel-src/sys/syscalls/recvmsg.c @@ -6,7 +6,7 @@ #include #include -#define KNOWN_FLAGS (MSG_PEEK | MSG_WAITALL) +#define KNOWN_FLAGS (MSG_PEEK | MSG_WAITALL | MSG_CMSG_CLOEXEC) syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) { __assert((flags & ~KNOWN_FLAGS) == 0); @@ -55,6 +55,9 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) if (flags & MSG_WAITALL) recvflags |= SOCKET_RECV_FLAGS_WAITALL; + if (flags & MSG_CMSG_CLOEXEC) + recvflags |= SOCKET_RECV_FLAGS_CLOEXEC_CTRL; + iovec_iterator_t iovec_iterator; sockdesc_t desc = { .addr = &sockaddr,