From 40d8a050625ba040739338acb22d8b21ee4798ee Mon Sep 17 00:00:00 2001 From: Matheus Date: Mon, 3 Jun 2024 21:53:46 -0300 Subject: [PATCH] sock: MSG_PEEK and other fixes --- kernel-src/include/kernel/abi.h | 2 ++ kernel-src/include/kernel/sock.h | 1 + kernel-src/io/net/localsocket.c | 18 ++++++++++++------ kernel-src/io/net/udp.c | 21 ++++++++++++++------- kernel-src/sys/syscalls/accept.c | 2 +- kernel-src/sys/syscalls/read.c | 5 +++++ kernel-src/sys/syscalls/recvmsg.c | 12 +++++++++--- kernel-src/sys/syscalls/socket.c | 8 ++++---- kernel-src/sys/syscalls/write.c | 6 ++++++ 9 files changed, 54 insertions(+), 21 deletions(-) diff --git a/kernel-src/include/kernel/abi.h b/kernel-src/include/kernel/abi.h index 851db41a..f07f0716 100644 --- a/kernel-src/include/kernel/abi.h +++ b/kernel-src/include/kernel/abi.h @@ -88,6 +88,8 @@ typedef struct { #define SOCK_DGRAM 2 #define SOCK_RAW 3 +#define MSG_PEEK 2 + #define SO_BROADCAST 6 #define SO_BINDTODEVICE 25 diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index a1cb4880..02057cee 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -28,6 +28,7 @@ typedef struct { }; } sockaddr_t; +#define SOCKET_RECV_FLAGS_PEEK 0x8000000000000000l typedef struct socketops_t { int (*bind)(socket_t *socket, sockaddr_t *addr); int (*send)(socket_t *socket, sockaddr_t *addr, void *buffer, size_t count, uintmax_t flags, size_t *sendcount); diff --git a/kernel-src/io/net/localsocket.c b/kernel-src/io/net/localsocket.c index 818edeab..f637f742 100644 --- a/kernel-src/io/net/localsocket.c +++ b/kernel-src/io/net/localsocket.c @@ -211,6 +211,9 @@ static int localsock_send(socket_t *socket, sockaddr_t *addr, void *buffer, size localsocket_t *peer = pair->client == localsocket ? pair->server : pair->client; if (peer == NULL) { + if (_cpu()->thread->proc) + signal_signalproc(_cpu()->thread->proc, SIGPIPE); + error = EPIPE; goto leave; } @@ -277,12 +280,15 @@ static int localsock_recv(socket_t *socket, sockaddr_t *addr, void *buffer, size goto leave; } - *recvcount = ringbuffer_read(&localsocket->ringbuffer, buffer, count); - localsocket_t *peer = pair->client == localsocket ? pair->server : pair->client; - - // signal that there is space to write for any threads blocked on this socket - if (peer && *recvcount) - poll_event(&peer->socket.pollheader, POLLOUT); + if (flags & SOCKET_RECV_FLAGS_PEEK) { + *recvcount = ringbuffer_peek(&localsocket->ringbuffer, buffer, 0, count); + } else { + *recvcount = ringbuffer_read(&localsocket->ringbuffer, buffer, count); + localsocket_t *peer = pair->client == localsocket ? pair->server : pair->client; + // signal that there is space to write for any threads blocked on this socket + if (peer && *recvcount) + poll_event(&peer->socket.pollheader, POLLOUT); + } leave: if (pair) diff --git a/kernel-src/io/net/udp.c b/kernel-src/io/net/udp.c index 092f8120..530bcd0e 100644 --- a/kernel-src/io/net/udp.c +++ b/kernel-src/io/net/udp.c @@ -120,7 +120,7 @@ void udp_process(netdev_t *netdev, void *buffer, uint32_t peer) { if (freespace >= needed) { __assert(ringbuffer_write(&socket->ringbuffer, &header, sizeof(header)) == sizeof(header)); __assert(ringbuffer_write(&socket->ringbuffer, writebuffer, header.length) == header.length); - poll_event(&socket->socket.pollheader, POLLOUT); + poll_event(&socket->socket.pollheader, POLLIN); } spinlock_release(&socket->ringbufferlock); __atomic_sub_fetch(&socket->packetsprocessing, 1, __ATOMIC_SEQ_CST); @@ -250,16 +250,23 @@ static int udp_recv(socket_t *socket, sockaddr_t *addr, void *buffer, size_t cou bool intstate = interrupt_set(false); spinlock_acquire(&udpsocket->ringbufferlock); + size_t copycount; dataheader_t header; - __assert(ringbuffer_read(&udpsocket->ringbuffer, &header, sizeof(header)) == sizeof(header)); + if (flags & SOCKET_RECV_FLAGS_PEEK) { + __assert(ringbuffer_peek(&udpsocket->ringbuffer, &header, 0, sizeof(header)) == sizeof(header)); + copycount = min(header.length, count); - size_t copycount = min(header.length, count); - __assert(ringbuffer_read(&udpsocket->ringbuffer, buffer, copycount) == copycount); + __assert(ringbuffer_peek(&udpsocket->ringbuffer, &buffer, sizeof(header), copycount) == copycount); + } else { + __assert(ringbuffer_read(&udpsocket->ringbuffer, &header, sizeof(header)) == sizeof(header)); - // truncate the rest if the buffer wasn't big enough to handle everything - if (header.length > count) - ringbuffer_truncate(&udpsocket->ringbuffer, header.length - copycount); + copycount = min(header.length, count); + __assert(ringbuffer_read(&udpsocket->ringbuffer, buffer, copycount) == copycount); + // truncate the rest if the buffer wasn't big enough to handle everything + if (header.length > count) + ringbuffer_truncate(&udpsocket->ringbuffer, header.length - copycount); + } spinlock_release(&udpsocket->ringbufferlock); interrupt_set(intstate); diff --git a/kernel-src/sys/syscalls/accept.c b/kernel-src/sys/syscalls/accept.c index bc84be07..9f3f09b5 100644 --- a/kernel-src/sys/syscalls/accept.c +++ b/kernel-src/sys/syscalls/accept.c @@ -3,7 +3,7 @@ #include #include -syscallret_t syscall_accept(context_t *, int oldfd, abisockaddr_t *abisockaddr, size_t *addrlen, int acceptflags) { +syscallret_t syscall_accept(context_t *, int oldfd, abisockaddr_t *abisockaddr, int *addrlen, int acceptflags) { syscallret_t ret = { .ret = -1 }; diff --git a/kernel-src/sys/syscalls/read.c b/kernel-src/sys/syscalls/read.c index f63d3faa..d672585e 100644 --- a/kernel-src/sys/syscalls/read.c +++ b/kernel-src/sys/syscalls/read.c @@ -23,6 +23,11 @@ syscallret_t syscall_read(context_t *context, int fd, void *buffer, size_t size) goto cleanup; } + if (size == 0) { + ret.ret = 0; + ret.errno = 0; + goto cleanup; + } size_t bytesread; uintmax_t offset = file->offset; ret.errno = vfs_read(file->vnode, kernelbuff, size, file->offset, &bytesread, fileflagstovnodeflags(file->flags)); diff --git a/kernel-src/sys/syscalls/recvmsg.c b/kernel-src/sys/syscalls/recvmsg.c index 213e6d33..0ef464e2 100644 --- a/kernel-src/sys/syscalls/recvmsg.c +++ b/kernel-src/sys/syscalls/recvmsg.c @@ -6,9 +6,13 @@ #include #include +#define KNOWN_FLAGS (MSG_PEEK) + syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) { - __assert(flags == 0); - syscallret_t ret; + __assert((flags & ~KNOWN_FLAGS) == 0); + syscallret_t ret = { + .ret = -1 + }; msghdr_t msghdr; ret.errno = sock_copymsghdr(&msghdr, umsghdr); @@ -37,8 +41,10 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) sockaddr_t sockaddr; socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); size_t recvcount; - ret.errno = socket->ops->recv(socket, &sockaddr, buffer, buffersize, fileflagstovnodeflags(file->flags), &recvcount); + ret.errno = socket->ops->recv(socket, &sockaddr, buffer, buffersize, fileflagstovnodeflags(file->flags) | ((flags & MSG_PEEK) ? SOCKET_RECV_FLAGS_PEEK : 0), &recvcount); ret.ret = ret.errno ? -1 : recvcount; + if (ret.errno) + goto cleanup; uintmax_t iovoffset = 0; for (int i = 0; i < msghdr.iovcount; ++i) { diff --git a/kernel-src/sys/syscalls/socket.c b/kernel-src/sys/syscalls/socket.c index 445a5d45..3f5967b8 100644 --- a/kernel-src/sys/syscalls/socket.c +++ b/kernel-src/sys/syscalls/socket.c @@ -12,10 +12,10 @@ syscallret_t syscall_socket(context_t *, int domain, int type, int protocol) { switch (domain) { case AF_INET: - if (type != SOCK_DGRAM) - break; - - socktype = SOCKET_TYPE_UDP; + if (type == SOCK_STREAM) + socktype = SOCKET_TYPE_TCP; + if (type == SOCK_DGRAM) + socktype = SOCKET_TYPE_UDP; break; case AF_LOCAL: socktype = SOCKET_TYPE_LOCAL; diff --git a/kernel-src/sys/syscalls/write.c b/kernel-src/sys/syscalls/write.c index fa090ab1..784a5dde 100644 --- a/kernel-src/sys/syscalls/write.c +++ b/kernel-src/sys/syscalls/write.c @@ -21,6 +21,12 @@ syscallret_t syscall_write(context_t *context, int fd, void *buffer, size_t size goto cleanup; } + if (size == 0) { + ret.ret = 0; + ret.errno = 0; + goto cleanup; + } + // TODO safe memcpy memcpy(kernelbuff, buffer, size);