From f54287ca6de376b1c8398a6b41df73f52c014313 Mon Sep 17 00:00:00 2001 From: frlp Date: Mon, 15 Jun 2026 12:01:25 +0000 Subject: [PATCH 1/5] tests: add e2e test for accept4 syscall --- tests/e2e/accept4/expected.txt | 1 + tests/e2e/accept4/test.sh | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/e2e/accept4/expected.txt create mode 100644 tests/e2e/accept4/test.sh diff --git a/tests/e2e/accept4/expected.txt b/tests/e2e/accept4/expected.txt new file mode 100644 index 0000000000..fc269290ce --- /dev/null +++ b/tests/e2e/accept4/expected.txt @@ -0,0 +1 @@ +accept4 ok \ No newline at end of file diff --git a/tests/e2e/accept4/test.sh b/tests/e2e/accept4/test.sh new file mode 100644 index 0000000000..99e018ff6e --- /dev/null +++ b/tests/e2e/accept4/test.sh @@ -0,0 +1,21 @@ +python3 -c " +import socket, ctypes, ctypes.util, threading, time + +libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) +s = socket.socket() +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +s.bind(('127.0.0.1', 19999)) +s.listen(1) + +def connect(): + time.sleep(0.3) + c = socket.socket() + c.connect(('127.0.0.1', 19999)) + +threading.Thread(target=connect).start() + +args = (ctypes.c_ulong * 4)(s.fileno(), 0, 0, 0) +result = libc.syscall(102, 18, args) +err = ctypes.get_errno() +print('accept4 ok' if result > 0 else 'accept4 failed errno=' + str(err)) +" From cd88e9b7c33cf99680cff11a9bc78c4f470ccb91 Mon Sep 17 00:00:00 2001 From: frlp Date: Mon, 15 Jun 2026 12:12:20 +0000 Subject: [PATCH 2/5] fs/sock.c: implement accept4 via accept + fcntl --- fs/sock.c | 15 ++++++++++++++- fs/sock.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/fs/sock.c b/fs/sock.c index 4c62f1c485..4e52065b54 100644 --- a/fs/sock.c +++ b/fs/sock.c @@ -450,6 +450,19 @@ int_t sys_accept(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr) { return client_f; } +int_t sys_accept4(fd_t sock_fd, addr_t sockaddr_addr, + addr_t sockaddr_len_addr, int_t flags) { + fd_t client = sys_accept(sock_fd, sockaddr_addr, sockaddr_len_addr); + if (client < 0) + return client; + if (flags & SOCK_NONBLOCK_) + sys_fcntl(client, F_SETFL_, O_NONBLOCK_); + if (flags & SOCK_CLOEXEC_) + sys_fcntl(client, F_SETFD_, 1); + return client; +} + + static void copy_unix_name(char *sockaddr, dword_t *sockaddr_len, struct fd *sock) { struct sockaddr_ *fake_addr = (void *) sockaddr; fake_addr->family = PF_LOCAL_; @@ -1214,7 +1227,7 @@ static struct socket_call { {(syscall_t) sys_getsockopt, 5}, {(syscall_t) sys_sendmsg, 3}, {(syscall_t) sys_recvmsg, 3}, - {NULL}, // accept4 + {(syscall_t) sys_accept4, 4}, {NULL}, // recvmmsg {(syscall_t) sys_sendmmsg, 4}, }; diff --git a/fs/sock.h b/fs/sock.h index ce40ca5d6a..2df3064ea0 100644 --- a/fs/sock.h +++ b/fs/sock.h @@ -16,6 +16,7 @@ int_t sys_bind(fd_t sock_fd, addr_t sockaddr_addr, uint_t sockaddr_len); int_t sys_connect(fd_t sock_fd, addr_t sockaddr_addr, uint_t sockaddr_len); int_t sys_listen(fd_t sock_fd, int_t backlog); int_t sys_accept(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr); +int_t sys_accept4(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr, int_t flags); int_t sys_getsockname(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr); int_t sys_getpeername(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr); int_t sys_socketpair(dword_t domain, dword_t type, dword_t protocol, addr_t sockets_addr); From ae2d076ed8810d301c15d1c3d401d3ddeac55fa4 Mon Sep 17 00:00:00 2001 From: frlp Date: Mon, 15 Jun 2026 16:45:37 +0000 Subject: [PATCH 3/5] fs/fd.h: move fcntl defines from fd.c to header --- fs/fd.c | 15 --------------- fs/fd.h | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/fs/fd.c b/fs/fd.c index 6bc39f5918..fbaf02c90e 100644 --- a/fs/fd.c +++ b/fs/fd.c @@ -226,21 +226,6 @@ void fdtable_do_cloexec(struct fdtable *table) { unlock(&table->lock); } -#define F_DUPFD_ 0 -#define F_GETFD_ 1 -#define F_SETFD_ 2 -#define F_GETFL_ 3 -#define F_SETFL_ 4 - -#define F_GETLK_ 5 -#define F_SETLK_ 6 -#define F_SETLKW_ 7 -#define F_GETLK64_ 12 -#define F_SETLK64_ 13 -#define F_SETLKW64_ 14 - -#define F_DUPFD_CLOEXEC_ 1030 - dword_t sys_dup(fd_t f) { STRACE("dup(%d)", f); struct fd *fd = f_get(f); diff --git a/fs/fd.h b/fs/fd.h index 4bd1f18353..b67a7f84c4 100644 --- a/fs/fd.h +++ b/fs/fd.h @@ -124,6 +124,21 @@ struct dir_entry { char name[NAME_MAX + 1]; }; +#define F_DUPFD_ 0 +#define F_GETFD_ 1 +#define F_SETFD_ 2 +#define F_GETFL_ 3 +#define F_SETFL_ 4 + +#define F_GETLK_ 5 +#define F_SETLK_ 6 +#define F_SETLKW_ 7 +#define F_GETLK64_ 12 +#define F_SETLK64_ 13 +#define F_SETLKW64_ 14 + +#define F_DUPFD_CLOEXEC_ 1030 + #define LSEEK_SET 0 #define LSEEK_CUR 1 #define LSEEK_END 2 From d98d15d236c46bcd54c9b57e9c0327a628974123 Mon Sep 17 00:00:00 2001 From: frlp Date: Mon, 15 Jun 2026 23:19:38 +0000 Subject: [PATCH 4/5] fs/sock.c: return EINVAL for unknown flags in accept4 --- fs/sock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/sock.c b/fs/sock.c index 4e52065b54..28375d4fad 100644 --- a/fs/sock.c +++ b/fs/sock.c @@ -450,8 +450,9 @@ int_t sys_accept(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr) { return client_f; } -int_t sys_accept4(fd_t sock_fd, addr_t sockaddr_addr, - addr_t sockaddr_len_addr, int_t flags) { +int_t sys_accept4(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr, int_t flags) { + if (flags & ~(SOCK_NONBLOCK_ | SOCK_CLOEXEC_)) + return _EINVAL; fd_t client = sys_accept(sock_fd, sockaddr_addr, sockaddr_len_addr); if (client < 0) return client; From c4918c985b73b82514d0ab50708c3bb12d2c6a49 Mon Sep 17 00:00:00 2001 From: frlp Date: Mon, 15 Jun 2026 23:34:33 +0000 Subject: [PATCH 5/5] fs/sock.c: preserve existing flags when setting O_NONBLOCK in accept4 --- fs/sock.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/sock.c b/fs/sock.c index 28375d4fad..809c2d2e58 100644 --- a/fs/sock.c +++ b/fs/sock.c @@ -456,14 +456,15 @@ int_t sys_accept4(fd_t sock_fd, addr_t sockaddr_addr, addr_t sockaddr_len_addr, fd_t client = sys_accept(sock_fd, sockaddr_addr, sockaddr_len_addr); if (client < 0) return client; - if (flags & SOCK_NONBLOCK_) - sys_fcntl(client, F_SETFL_, O_NONBLOCK_); + if (flags & SOCK_NONBLOCK_) { + int_t old = sys_fcntl(client, F_GETFL_, 0); + sys_fcntl(client, F_SETFL_, old | O_NONBLOCK_); + } if (flags & SOCK_CLOEXEC_) sys_fcntl(client, F_SETFD_, 1); return client; } - static void copy_unix_name(char *sockaddr, dword_t *sockaddr_len, struct fd *sock) { struct sockaddr_ *fake_addr = (void *) sockaddr; fake_addr->family = PF_LOCAL_;