From f46d85fe6da5354db619a4240fb8ecc51d211254 Mon Sep 17 00:00:00 2001 From: Matheus Date: Tue, 7 Jul 2026 16:49:21 -0300 Subject: [PATCH] socket: fix close shutdown properly --- kernel-src/fs/file.c | 6 ------ kernel-src/fs/sockfs.c | 4 +++- kernel-src/include/kernel/sock.h | 22 ++++++++++++++++++++ kernel-src/sys/syscalls/accept.c | 29 +++++++++++---------------- kernel-src/sys/syscalls/bind.c | 19 ++++++------------ kernel-src/sys/syscalls/connect.c | 22 ++++++++------------ kernel-src/sys/syscalls/getpeername.c | 19 ++++++------------ kernel-src/sys/syscalls/getsockname.c | 19 ++++++------------ kernel-src/sys/syscalls/getsockopt.c | 17 +++++----------- kernel-src/sys/syscalls/listen.c | 17 +++++----------- kernel-src/sys/syscalls/recvmsg.c | 23 ++++++++------------- kernel-src/sys/syscalls/sendmsg.c | 27 ++++++++++--------------- kernel-src/sys/syscalls/setsockopt.c | 17 +++++----------- kernel-src/sys/syscalls/shutdown.c | 18 +++++------------ recipes/astral | 2 +- 15 files changed, 103 insertions(+), 158 deletions(-) diff --git a/kernel-src/fs/file.c b/kernel-src/fs/file.c index c3e02fd4..d847d2ff 100644 --- a/kernel-src/fs/file.c +++ b/kernel-src/fs/file.c @@ -4,7 +4,6 @@ #include #include #include -#include static scache_t *filecache; #define FILE_HOLD(f) __atomic_add_fetch(&(f)->refcount, 1, __ATOMIC_SEQ_CST) @@ -180,11 +179,6 @@ int fd_close(int fd) { MUTEX_RELEASE(&proc->fdmutex); if (file) { - if (file->vnode && file->vnode->type == V_TYPE_SOCKET) { - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); - socket->ops->shutdown(socket, SOCKET_SHUTDOWN_RW); - } - FILE_RELEASE(file); } else { diff --git a/kernel-src/fs/sockfs.c b/kernel-src/fs/sockfs.c index ede220e5..b8b31a31 100644 --- a/kernel-src/fs/sockfs.c +++ b/kernel-src/fs/sockfs.c @@ -22,7 +22,9 @@ int sockfs_open(vnode_t **node, int flags, cred_t *cred) { } int sockfs_close(vnode_t *node, int flags, cred_t *cred) { - return ENOSYS; // not needed + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); + + return socket->ops->shutdown ? socket->ops->shutdown(socket, SOCKET_SHUTDOWN_RW) : 0; } int sockfs_read(vnode_t *node, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, size_t *bytes_read, cred_t *cred) { diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index 2516593e..c5c1d291 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -3,11 +3,13 @@ #include #include +#include #include #include #include #include #include +#include #define SOCKET_STATE_UNBOUND 0 #define SOCKET_STATE_BOUND 1 @@ -92,6 +94,26 @@ typedef struct { #define SOCKET_TYPE_LOCAL_SEQPACKET 3 #define SOCKFS_SOCKET_FROM_NODE(nodep) (((socketnode_t *)(nodep))->socket) +static inline int sockfd_get(int fd, vnode_t **vnodep, int *fileflags) { + file_t *file = fd_get(fd); + if (file == NULL) + return EBADF; + + if (file->vnode->type != V_TYPE_SOCKET) { + fd_release(file); + return ENOTSOCK; + } + + vnode_t *vnode = file->vnode; + VOP_HOLD(vnode); + if (fileflags) + *fileflags = file->flags; + fd_release(file); + + *vnodep = vnode; + return 0; +} + static inline bool socket_nonblocking(socket_t *socket, uintmax_t flags) { return socket->nonblocking || (flags & V_FFLAGS_NONBLOCKING); } diff --git a/kernel-src/sys/syscalls/accept.c b/kernel-src/sys/syscalls/accept.c index 9caae2fe..50480897 100644 --- a/kernel-src/sys/syscalls/accept.c +++ b/kernel-src/sys/syscalls/accept.c @@ -15,18 +15,13 @@ syscallret_t syscall_accept(context_t *, int oldfd, abisockaddr_t *abisockaddr, return ret; } - file_t *oldfile = fd_get(oldfd); - if (oldfile == NULL) { - ret.errno = EBADF; + vnode_t *servernode; + int fileflags; + ret.errno = sockfd_get(oldfd, &servernode, &fileflags); + if (ret.errno) return ret; - } - if (oldfile->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } - - socket_t *server = SOCKFS_SOCKET_FROM_NODE(oldfile->vnode); + socket_t *server = SOCKFS_SOCKET_FROM_NODE(servernode); if (server->ops->accept == NULL) { ret.errno = ENOTSUP; @@ -39,18 +34,18 @@ syscallret_t syscall_accept(context_t *, int oldfd, abisockaddr_t *abisockaddr, goto cleanup; } - vnode_t *vnode; - ret.errno = sockfs_newsocket(&vnode, client); + vnode_t *clientnode; + ret.errno = sockfs_newsocket(&clientnode, client); if (ret.errno) { client->ops->destroy(client); goto cleanup; } sockaddr_t addr = {0}; - ret.errno = server->ops->accept(server, client, &addr, fileflagstovnodeflags(oldfile->flags)); + ret.errno = server->ops->accept(server, client, &addr, fileflagstovnodeflags(fileflags)); if (ret.errno) { // socket gets deleted by node cleanup - VOP_RELEASE(vnode); + VOP_RELEASE(clientnode); goto cleanup; } @@ -60,11 +55,11 @@ syscallret_t syscall_accept(context_t *, int oldfd, abisockaddr_t *abisockaddr, ret.errno = fd_new(acceptflags & O_CLOEXEC, &newfile, &newfd); if (ret.errno) { // socket gets deleted by node cleanup - VOP_RELEASE(vnode); + VOP_RELEASE(clientnode); goto cleanup; } - newfile->vnode = vnode; + newfile->vnode = clientnode; newfile->flags = FILE_READ | FILE_WRITE | (acceptflags & (O_NONBLOCK)); newfile->offset = 0; newfile->mode = 0777; @@ -88,7 +83,7 @@ syscallret_t syscall_accept(context_t *, int oldfd, abisockaddr_t *abisockaddr, ret.ret = newfd; cleanup: - fd_release(oldfile); + VOP_RELEASE(servernode); return ret; } diff --git a/kernel-src/sys/syscalls/bind.c b/kernel-src/sys/syscalls/bind.c index 02b3437a..1970a01b 100644 --- a/kernel-src/sys/syscalls/bind.c +++ b/kernel-src/sys/syscalls/bind.c @@ -24,16 +24,10 @@ syscallret_t syscall_bind(context_t *, int fd, void *uaddr, size_t addrlen) { return ret; } - file_t *file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; + vnode_t *vnode = NULL; + ret.errno = sockfd_get(fd, &vnode, NULL); + if (ret.errno) goto cleanup; - } - - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } ret.errno = usercopy_fromuser(addr, uaddr, addrlen); if (ret.errno) @@ -44,15 +38,14 @@ syscallret_t syscall_bind(context_t *, int fd, void *uaddr, size_t addrlen) { if (ret.errno) goto cleanup; - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); ret.errno = socket->ops->bind(socket, &sockaddr, ¤t_thread()->proc->cred); ret.ret = ret.errno ? -1 : 0; cleanup: - if (file) - fd_release(file); - + if (vnode) + VOP_RELEASE(vnode); free(addr); return ret; } diff --git a/kernel-src/sys/syscalls/connect.c b/kernel-src/sys/syscalls/connect.c index ade1be7f..66773231 100644 --- a/kernel-src/sys/syscalls/connect.c +++ b/kernel-src/sys/syscalls/connect.c @@ -25,16 +25,11 @@ syscallret_t syscall_connect(context_t *, int fd, abisockaddr_t *uaddr, size_t a return ret; } - file_t *file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; + vnode_t *vnode = NULL; + int fileflags; + ret.errno = sockfd_get(fd, &vnode, &fileflags); + if (ret.errno) goto cleanup; - } - - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } ret.errno = usercopy_fromuser(addr, uaddr, addrlen); if (ret.errno) @@ -45,15 +40,14 @@ syscallret_t syscall_connect(context_t *, int fd, abisockaddr_t *uaddr, size_t a if (ret.errno) goto cleanup; - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); - ret.errno = socket->ops->connect ? socket->ops->connect(socket, &sockaddr, fileflagstovnodeflags(file->flags), ¤t_thread()->proc->cred) : EOPNOTSUPP; + ret.errno = socket->ops->connect ? socket->ops->connect(socket, &sockaddr, fileflagstovnodeflags(fileflags), ¤t_thread()->proc->cred) : EOPNOTSUPP; ret.ret = ret.errno ? -1 : 0; cleanup: - if (file) - fd_release(file); - + if (vnode) + VOP_RELEASE(vnode); free(addr); return ret; } diff --git a/kernel-src/sys/syscalls/getpeername.c b/kernel-src/sys/syscalls/getpeername.c index 2e127e4d..b3943e62 100644 --- a/kernel-src/sys/syscalls/getpeername.c +++ b/kernel-src/sys/syscalls/getpeername.c @@ -11,19 +11,13 @@ syscallret_t syscall_getpeername(context_t *, int fd, void *uaddr, int *uaddrlen if (ret.errno) return ret; - file_t *file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; - goto cleanup; - } - - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } + vnode_t *vnode; + ret.errno = sockfd_get(fd, &vnode, NULL); + if (ret.errno) + return ret; sockaddr_t sockaddr; - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); ret.errno = socket->ops->getpeername(socket, &sockaddr); if (ret.errno) @@ -39,8 +33,7 @@ syscallret_t syscall_getpeername(context_t *, int fd, void *uaddr, int *uaddrlen ret.ret = ret.errno ? -1 : 0; cleanup: - if (file) - fd_release(file); + VOP_RELEASE(vnode); return ret; } diff --git a/kernel-src/sys/syscalls/getsockname.c b/kernel-src/sys/syscalls/getsockname.c index 4d084a92..56d2f459 100644 --- a/kernel-src/sys/syscalls/getsockname.c +++ b/kernel-src/sys/syscalls/getsockname.c @@ -11,19 +11,13 @@ syscallret_t syscall_getsockname(context_t *, int fd, void *uaddr, int *uaddrlen if (ret.errno) return ret; - file_t *file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; - goto cleanup; - } - - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } + vnode_t *vnode; + ret.errno = sockfd_get(fd, &vnode, NULL); + if (ret.errno) + return ret; sockaddr_t sockaddr; - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); ret.errno = socket->ops->getname(socket, &sockaddr); if (ret.errno) @@ -42,8 +36,7 @@ syscallret_t syscall_getsockname(context_t *, int fd, void *uaddr, int *uaddrlen ret.ret = 0; cleanup: - if (file) - fd_release(file); + VOP_RELEASE(vnode); return ret; } diff --git a/kernel-src/sys/syscalls/getsockopt.c b/kernel-src/sys/syscalls/getsockopt.c index 8f0ca35d..57242059 100644 --- a/kernel-src/sys/syscalls/getsockopt.c +++ b/kernel-src/sys/syscalls/getsockopt.c @@ -14,18 +14,12 @@ syscallret_t syscall_getsockopt(context_t *, int fd, int level, int optname, voi return ret; } - file_t *file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; + vnode_t *vnode; + ret.errno = sockfd_get(fd, &vnode, NULL); + if (ret.errno) return ret; - } - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } - - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); MUTEX_ACQUIRE(&socket->mutex); if (level == SOL_SOCKET) { @@ -59,9 +53,8 @@ syscallret_t syscall_getsockopt(context_t *, int fd, int level, int optname, voi MUTEX_RELEASE(&socket->mutex); - cleanup: ret.ret = ret.errno ? -1 : 0; - fd_release(file); + VOP_RELEASE(vnode); return ret; } diff --git a/kernel-src/sys/syscalls/listen.c b/kernel-src/sys/syscalls/listen.c index 9165deac..5e94e606 100644 --- a/kernel-src/sys/syscalls/listen.c +++ b/kernel-src/sys/syscalls/listen.c @@ -7,24 +7,17 @@ syscallret_t syscall_listen(context_t *, int fd, int backlog) { .ret = -1 }; - file_t *file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; + vnode_t *vnode; + ret.errno = sockfd_get(fd, &vnode, NULL); + if (ret.errno) return ret; - } - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } - - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); ret.errno = socket->ops->listen ? socket->ops->listen(socket, backlog) : EOPNOTSUPP; ret.ret = ret.errno ? -1 : 0; - cleanup: - fd_release(file); + VOP_RELEASE(vnode); return ret; } diff --git a/kernel-src/sys/syscalls/recvmsg.c b/kernel-src/sys/syscalls/recvmsg.c index 97903375..70e522fa 100644 --- a/kernel-src/sys/syscalls/recvmsg.c +++ b/kernel-src/sys/syscalls/recvmsg.c @@ -21,7 +21,6 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) if (ret.errno) return ret; - file_t *file = NULL; size_t buffersize = iovec_size(msghdr.iov, msghdr.iovcount); if (buffersize == 0) { sock_freemsghdr(&msghdr); @@ -36,19 +35,14 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) return ret; } - file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; + vnode_t *vnode = NULL; + int fileflags; + ret.errno = sockfd_get(fd, &vnode, &fileflags); + if (ret.errno) goto cleanup; - } - - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } sockaddr_t sockaddr; - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); uintmax_t recvflags = 0; if (flags & MSG_PEEK) @@ -68,7 +62,7 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) .addr = &sockaddr, .iovec_iterator = &iovec_iterator, .count = buffersize, - .flags = fileflagstovnodeflags(file->flags) | recvflags, + .flags = fileflagstovnodeflags(fileflags) | recvflags, .donecount = 0, .ctrl = msghdr.msgctrl, .ctrllen = msghdr.ctrllen, @@ -120,9 +114,8 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) ret.ret = ret.errno ? -1 : desc.donecount; cleanup: - if (file) - fd_release(file); - + if (vnode) + VOP_RELEASE(vnode); sock_freemsghdr(&msghdr); return ret; } diff --git a/kernel-src/sys/syscalls/sendmsg.c b/kernel-src/sys/syscalls/sendmsg.c index b0323798..7c7475ab 100644 --- a/kernel-src/sys/syscalls/sendmsg.c +++ b/kernel-src/sys/syscalls/sendmsg.c @@ -6,7 +6,9 @@ #include syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) { - syscallret_t ret; + syscallret_t ret = { + .ret = -1 + }; if (flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL)) printf("sendmsg: unknown %x\n", flags); @@ -16,7 +18,6 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) if (ret.errno) return ret; - file_t *file = NULL; size_t buffersize = iovec_size(msghdr.iov, msghdr.iovcount); if (buffersize == 0) { sock_freemsghdr(&msghdr); @@ -31,16 +32,11 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) return ret; } - file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; - goto cleanup; - } - - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; + vnode_t *vnode = NULL; + int fileflags; + ret.errno = sockfd_get(fd, &vnode, &fileflags); + if (ret.errno) goto cleanup; - } sockaddr_t sockaddr; if (msghdr.addr) { @@ -49,7 +45,7 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) goto cleanup; } - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); int sendflags = 0; @@ -64,7 +60,7 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) .addr = msghdr.addr ? &sockaddr : NULL, .iovec_iterator = &iovec_iterator, .count = buffersize, - .flags = fileflagstovnodeflags(file->flags) | sendflags, + .flags = fileflagstovnodeflags(fileflags) | sendflags, .donecount = 0, .ctrl = msghdr.msgctrl, .ctrllen = msghdr.ctrllen, @@ -77,9 +73,8 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) ret.ret = ret.errno ? -1 : desc.donecount; cleanup: - if (file) - fd_release(file); - + if (vnode) + VOP_RELEASE(vnode); sock_freemsghdr(&msghdr); return ret; } diff --git a/kernel-src/sys/syscalls/setsockopt.c b/kernel-src/sys/syscalls/setsockopt.c index 8e4c2de3..d9b09c0f 100644 --- a/kernel-src/sys/syscalls/setsockopt.c +++ b/kernel-src/sys/syscalls/setsockopt.c @@ -10,18 +10,12 @@ syscallret_t syscall_setsockopt(context_t *, int fd, int level, int optname, voi .ret = -1 }; - file_t *file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; + vnode_t *vnode; + ret.errno = sockfd_get(fd, &vnode, NULL); + if (ret.errno) return ret; - } - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } - - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); MUTEX_ACQUIRE(&socket->mutex); if (level == SOL_SOCKET) { @@ -65,10 +59,9 @@ syscallret_t syscall_setsockopt(context_t *, int fd, int level, int optname, voi MUTEX_RELEASE(&socket->mutex); - cleanup: ret.ret = ret.errno ? -1 : 0; - fd_release(file); + VOP_RELEASE(vnode); return ret; } diff --git a/kernel-src/sys/syscalls/shutdown.c b/kernel-src/sys/syscalls/shutdown.c index 337e5b17..6c8a1bca 100644 --- a/kernel-src/sys/syscalls/shutdown.c +++ b/kernel-src/sys/syscalls/shutdown.c @@ -20,24 +20,16 @@ syscallret_t syscall_shutdown(context_t *, int fd, int how) { ++how; // convert to internal meaning - file_t *file = fd_get(fd); - if (file == NULL) { - ret.errno = EBADF; + vnode_t *vnode; + ret.errno = sockfd_get(fd, &vnode, NULL); + if (ret.errno) return ret; - } - if (file->vnode->type != V_TYPE_SOCKET) { - ret.errno = ENOTSOCK; - goto cleanup; - } - - socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(vnode); ret.errno = socket->ops->shutdown(socket, how); ret.ret = ret.errno ? -1 : 0; - cleanup: - - fd_release(file); + VOP_RELEASE(vnode); return ret; } diff --git a/recipes/astral b/recipes/astral index e50b66dc..2bd868f3 100644 --- a/recipes/astral +++ b/recipes/astral @@ -1,5 +1,5 @@ name=astral -revision=22 +revision=23 from_source=astral imagedeps="build-essential nasm" hostdeps="xgcc xbinutils limine"