From b1e87c57e9d044bd8202bb28cf059d76ed818830 Mon Sep 17 00:00:00 2001 From: Matheus Date: Sat, 8 Feb 2025 20:24:43 -0300 Subject: [PATCH] syscalls: shutdown --- kernel-src/arch/x86-64/syscall.asm | 4 +- kernel-src/arch/x86-64/syscalllog.c | 8 ++- kernel-src/include/kernel/sock.h | 6 ++ kernel-src/io/net/localsocket.c | 46 +++++++++++- kernel-src/io/net/tcp.c | 8 ++- kernel-src/io/net/udp.c | 26 ++++++- patches/mlibc/jinx-working-patch.patch | 98 +++++++++++++++++++++++++- 7 files changed, 183 insertions(+), 13 deletions(-) diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index 5b683dfd..7418b416 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -91,6 +91,7 @@ extern syscall_sigsuspend extern syscall_sigtimedwait extern syscall_sigpending extern syscall_killthread +extern syscall_shutdown syscalltab: dq syscall_print dq syscall_mmap @@ -184,7 +185,8 @@ dq syscall_sigsuspend dq syscall_sigtimedwait dq syscall_sigpending dq syscall_killthread -syscallcount equ 92 +dq syscall_shutdown +syscallcount equ 93 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index 54c90d66..20ffc9ac 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -5,7 +5,7 @@ #ifdef SYSCALL_LOGGING -#define SYSCALL_COUNT 92 +#define SYSCALL_COUNT 93 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -100,7 +100,8 @@ static char *name[] = { "sigsuspend", "sigtimedwait", "sigpending", - "killthread" + "killthread", + "shutdown" }; static char *args[] = { @@ -195,7 +196,8 @@ static char *args[] = { "sigset %p", // sigsuspend "sigset %p info %p, timespec %p", // sigtimedwait "sigset %p\n", // sigpending - "pid %d tid %d signal %d" // killthread + "pid %d tid %d signal %d", // killthread + "how %d" // shutdown }; #endif diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index 7cc67e02..d38e645a 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -13,6 +13,10 @@ #define SOCKET_STATE_CONNECTED 2 #define SOCKET_STATE_LISTENING 3 +#define SOCKET_SHUTDOWN_READ 1 +#define SOCKET_SHUTDOWN_WRITE 2 +#define SOCKET_SHUTDOWN_RW 3 + typedef struct { struct socketops_t *ops; mutex_t mutex; @@ -21,6 +25,7 @@ typedef struct { netdev_t *netdev; pollheader_t pollheader; int type; + int shutdown; } socket_t; typedef struct { @@ -67,6 +72,7 @@ typedef struct socketops_t { size_t (*datacount)(socket_t *socket); void (*destroy)(socket_t *socket); int (*setopt)(socket_t *socket, int optname, void *buffer, size_t len, cred_t *cred); + int (*shutdown)(socket_t *socket, int how); } socketops_t; typedef struct { diff --git a/kernel-src/io/net/localsocket.c b/kernel-src/io/net/localsocket.c index a68a0384..0a73dcdc 100644 --- a/kernel-src/io/net/localsocket.c +++ b/kernel-src/io/net/localsocket.c @@ -13,7 +13,7 @@ struct localpair_t; struct binding_t; typedef struct { - socket_t socket; + socket_t socket; // shutdown state is shared with pair ringbuffer_t ringbuffer; // shared with pair // client/connected server struct localpair_t *pair; @@ -1003,6 +1003,47 @@ static int localsock_getpeername(socket_t *socket, sockaddr_t *addr) { return 0; } +static int localsock_shutdown(socket_t *socket, int how) { + localsocket_t *localsocket = (localsocket_t *)socket; + MUTEX_ACQUIRE(&socket->mutex); + int error; + + localpair_t *pair = localsocket->pair; + // socket not connected + if (pair == NULL) { + error = ENOTCONN; + goto leave; + } + + MUTEX_ACQUIRE(&pair->mutex); + + localsocket_t *peer = localsocket->pair->client == localsocket ? localsocket->pair->server : localsocket->pair->client; + + socket->shutdown |= how; + + int poll_events = 0; + + // XXX is this the correct behaviour? + if (how & SOCKET_SHUTDOWN_READ) + poll_events |= POLLHUP; + + if (how & SOCKET_SHUTDOWN_WRITE) + poll_events |= POLLIN; + + if (peer) + poll_event(&peer->socket.pollheader, poll_events); + + error = 0; + + leave: + if (pair) + MUTEX_RELEASE(&pair->mutex); + + MUTEX_RELEASE(&socket->mutex); + return error; + +} + static socketops_t socketops = { .bind = localsock_bind, .listen = localsock_listen, @@ -1014,7 +1055,8 @@ static socketops_t socketops = { .poll = localsock_poll, .datacount = localsocket_datacount, .getname = localsock_getname, - .getpeername = localsock_getpeername + .getpeername = localsock_getpeername, + .shutdown = localsock_shutdown }; socket_t *localsock_createsocket() { diff --git a/kernel-src/io/net/tcp.c b/kernel-src/io/net/tcp.c index 859a2a8c..168f25aa 100644 --- a/kernel-src/io/net/tcp.c +++ b/kernel-src/io/net/tcp.c @@ -1832,6 +1832,11 @@ static int tcp_setopt(socket_t *socket, int optname, void *buffer, size_t len, c return 0; } +static int tcp_shutdown(socket_t *socket, int how) { + printf("tcp: shutdown is not implemented\n"); + return ENOSYS; +} + static socketops_t socketops = { .bind = tcp_bind, .send = tcp_send, @@ -1844,7 +1849,8 @@ static socketops_t socketops = { .destroy = tcp_destroy, .getname = tcp_getname, .getpeername = tcp_getpeername, - .setopt = tcp_setopt + .setopt = tcp_setopt, + .shutdown = tcp_shutdown }; socket_t *tcp_createsocket() { diff --git a/kernel-src/io/net/udp.c b/kernel-src/io/net/udp.c index 7460f62a..eaf0cfb7 100644 --- a/kernel-src/io/net/udp.c +++ b/kernel-src/io/net/udp.c @@ -109,7 +109,7 @@ void udp_process(netdev_t *netdev, void *buffer, uint32_t peer) { spinlock_release(&portlock); - if (socket == NULL) // drop packet if no socket listening on port + if (socket == NULL || (socket->socket.shutdown & SOCKET_SHUTDOWN_READ)) // drop packet if no socket listening on port or its not accepting incoming data return; dataheader_t header = { @@ -185,7 +185,14 @@ static int udp_send(socket_t *socket, sockdesc_t *sockdesc) { int e; MUTEX_ACQUIRE(&socket->mutex); - if (sockdesc->addr == NULL && socket->state != SOCKET_STATE_CONNECTED) { + if (socket->shutdown & SOCKET_SHUTDOWN_WRITE) { + // XXX should SIGPIPE be sent in this case? + e = 0; + sockdesc->donecount = 0; + return 0; + } + + if (sockdesc->addr == NULL) { e = ENOTCONN; goto cleanup; } @@ -337,6 +344,18 @@ static int udp_poll(socket_t *socket, polldata_t *data, int events) { return revents; } +static int udp_shutdown(socket_t *socket, int how) { + if (how > SOCKET_SHUTDOWN_RW) + return EINVAL; + + MUTEX_ACQUIRE(&socket->mutex); + + socket->shutdown |= how; + + MUTEX_RELEASE(&socket->mutex); + return 0; +} + static socketops_t socketops = { .bind = udp_bind, .send = udp_send, @@ -344,7 +363,8 @@ static socketops_t socketops = { .destroy = udp_destroy, .poll = udp_poll, .getname = udp_getname, - .getpeername = udp_getpeername + .getpeername = udp_getpeername, + .shutdown = udp_shutdown }; socket_t *udp_createsocket() { diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch index 845bb068..995be358 100644 --- a/patches/mlibc/jinx-working-patch.patch +++ b/patches/mlibc/jinx-working-patch.patch @@ -12,6 +12,18 @@ index 87bc25f..d7370d0 100644 #define IPPROTO_IP 0 #define IPPROTO_HOPOPTS 0 #define IPPROTO_ICMP 1 +diff --git mlibc-clean/meson.build mlibc-workdir/meson.build +index 39796b5..7d671fc 100644 +--- mlibc-clean/meson.build ++++ mlibc-workdir/meson.build +@@ -268,6 +268,7 @@ elif host_machine.system() == 'astral' + libc_include_dirs += include_directories('sysdeps/astral/include') + internal_conf.set10('MLIBC_MAP_DSO_SEGMENTS', true) + internal_conf.set10('MLIBC_MAP_FILE_WINDOWS', true) ++ internal_conf.set10('MLIBC_MMAP_ALLOCATE_DSO', true) + subdir('sysdeps/astral') + else + error('No sysdeps defined for OS: ' + host_machine.system()) diff --git mlibc-clean/options/ansi/generic/environment.cpp mlibc-workdir/options/ansi/generic/environment.cpp index 5625592..36b42ee 100644 --- mlibc-clean/options/ansi/generic/environment.cpp @@ -111,8 +123,21 @@ index 9219ef0..1ff679c 100644 #if __MLIBC_POSIX_OPTION #include #endif +diff --git mlibc-clean/sysdeps/astral/generic/astral.cpp mlibc-workdir/sysdeps/astral/generic/astral.cpp +index d5ba7b2..a86353f 100644 +--- mlibc-clean/sysdeps/astral/generic/astral.cpp ++++ mlibc-workdir/sysdeps/astral/generic/astral.cpp +@@ -4,7 +4,7 @@ + + #ifndef MLIBC_BUILDING_RTLD + +-int syscall_archctl(int func, void *arg) { ++int arch_ctl(int func, void *arg) { + long ret; + long error = syscall(SYSCALL_ARCHCTL, &ret, func, (uint64_t)arg); + if(error) diff --git mlibc-clean/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp -index 2a504ab..61c3bf0 100644 +index 2a504ab..3c46318 100644 --- mlibc-clean/sysdeps/astral/generic/generic.cpp +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp @@ -31,6 +31,12 @@ namespace mlibc { @@ -128,7 +153,19 @@ index 2a504ab..61c3bf0 100644 int sys_getsockopt(int fd, int layer, int number, void *__restrict buffer, socklen_t *__restrict size) { (void)size; -@@ -161,7 +167,18 @@ namespace mlibc { +@@ -40,6 +46,11 @@ namespace mlibc { + return 0; + } + ++ int sys_shutdown(int sockfd, int how) { ++ long ret; ++ return syscall(SYSCALL_SHUTDOWN, &ret, sockfd, how); ++ } ++ + int sys_tgkill(int pid, int tid, int sig) { + long ret; + return syscall(SYSCALL_KILLTHREAD, &ret, pid, tid, sig); +@@ -161,7 +172,18 @@ namespace mlibc { *bytes_written = writec; return error; } @@ -148,7 +185,7 @@ index 2a504ab..61c3bf0 100644 #ifndef MLIBC_BUILDING_RTLD typedef struct { -@@ -487,6 +504,12 @@ namespace mlibc { +@@ -487,6 +509,12 @@ namespace mlibc { return ret; } @@ -161,3 +198,58 @@ index 2a504ab..61c3bf0 100644 #ifndef MLIBC_BUILDING_RTLD [[noreturn]] void sys_thread_exit() { +@@ -882,7 +910,7 @@ namespace mlibc { + + int sys_tcb_set(void *pointer) { + long r; +- return syscall(SYSCALL_ARCHCTL, &r, ARCH_CTL_FSBASE, (uint64_t)pointer); ++ return syscall(SYSCALL_ARCHCTL, &r, ARCH_CTL_SET_FSBASE, (uint64_t)pointer); + } + + #define FUTEX_WAIT 0 +diff --git mlibc-clean/sysdeps/astral/include/astral/archctl.h mlibc-workdir/sysdeps/astral/include/astral/archctl.h +index d738e02..7e4f2a1 100644 +--- mlibc-clean/sysdeps/astral/include/astral/archctl.h ++++ mlibc-workdir/sysdeps/astral/include/astral/archctl.h +@@ -1,8 +1,10 @@ + #ifndef _ASTRAL_ARCHCTL_H + #define _ASTRAL_ARCHCTL_H + +-#define ARCH_CTL_GSBASE 0 +-#define ARCH_CTL_FSBASE 1 ++#define ARCH_CTL_SET_GSBASE 0 ++#define ARCH_CTL_SET_FSBASE 1 ++#define ARCH_CTL_GET_GSBASE 2 ++#define ARCH_CTL_GET_FSBASE 3 + + #ifdef __cplusplus + extern "C" { +diff --git mlibc-clean/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h +index 5f42d62..852f9ff 100644 +--- mlibc-clean/sysdeps/astral/include/astral/syscall.h ++++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h +@@ -96,6 +96,7 @@ + #define SYSCALL_SIGTIMEDWAIT 89 + #define SYSCALL_SIGPENDING 90 + #define SYSCALL_KILLTHREAD 91 ++#define SYSCALL_SHUTDOWN 92 + + #ifndef __MLIBC_ABI_ONLY + +diff --git mlibc-clean/sysdeps/astral/meson.build mlibc-workdir/sysdeps/astral/meson.build +index a5ede46..e198d2e 100644 +--- mlibc-clean/sysdeps/astral/meson.build ++++ mlibc-workdir/sysdeps/astral/meson.build +@@ -63,6 +63,12 @@ if not no_headers + subdir: 'abi-bits', + follow_symlinks: true, + ) ++ install_headers( ++ 'include/astral/syscall.h', ++ 'include/astral/archctl.h', ++ subdir: 'astral', ++ follow_symlinks: true, ++ ) + endif + + if not headers_only