diff options
author | Gunnar Beutner <gbeutner@serenityos.org> | 2021-05-16 19:56:11 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-17 13:32:19 +0200 |
commit | 89956cb0d66f24bfcee312dcd35f78b5dbc9e1b9 (patch) | |
tree | dd7f38132b4cb91410271b4948cdfe99d28778d0 /Kernel/Syscalls/socket.cpp | |
parent | 529f605ac801a541b1206ce06d497f8835ca7412 (diff) | |
download | serenity-89956cb0d66f24bfcee312dcd35f78b5dbc9e1b9.zip |
Kernel+Userspace: Implement the accept4() system call
Unlike accept() the new accept4() system call lets the caller specify
flags for the newly accepted socket file descriptor, such as
SOCK_CLOEXEC and SOCK_NONBLOCK.
Diffstat (limited to 'Kernel/Syscalls/socket.cpp')
-rw-r--r-- | Kernel/Syscalls/socket.cpp | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/Kernel/Syscalls/socket.cpp b/Kernel/Syscalls/socket.cpp index 03288bb4d5..32f6c3e8cf 100644 --- a/Kernel/Syscalls/socket.cpp +++ b/Kernel/Syscalls/socket.cpp @@ -79,10 +79,19 @@ KResultOr<int> Process::sys$listen(int sockfd, int backlog) return socket.listen(backlog); } -KResultOr<int> Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_address, Userspace<socklen_t*> user_address_size) +KResultOr<int> Process::sys$accept4(Userspace<const Syscall::SC_accept4_params*> user_params) { REQUIRE_PROMISE(accept); + Syscall::SC_accept4_params params; + if (!copy_from_user(¶ms, user_params)) + return EFAULT; + + int accepting_socket_fd = params.sockfd; + Userspace<sockaddr*> user_address((FlatPtr)params.addr); + Userspace<socklen_t*> user_address_size((FlatPtr)params.addrlen); + int flags = params.flags; + socklen_t address_size = 0; if (user_address && !copy_from_user(&address_size, static_ptr_cast<const socklen_t*>(user_address_size))) return EFAULT; @@ -125,7 +134,12 @@ KResultOr<int> Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> accepted_socket_description_result.value()->set_readable(true); accepted_socket_description_result.value()->set_writable(true); - m_fds[accepted_socket_fd].set(accepted_socket_description_result.release_value(), 0); + if (flags & SOCK_NONBLOCK) + accepted_socket_description_result.value()->set_blocking(false); + int fd_flags = 0; + if (flags & SOCK_CLOEXEC) + fd_flags |= FD_CLOEXEC; + m_fds[accepted_socket_fd].set(accepted_socket_description_result.release_value(), fd_flags); // NOTE: Moving this state to Completed is what causes connect() to unblock on the client side. accepted_socket->set_setup_state(Socket::SetupState::Completed); |