summaryrefslogtreecommitdiff
path: root/Kernel/Syscalls
diff options
context:
space:
mode:
authorGunnar Beutner <gbeutner@serenityos.org>2021-05-16 19:56:11 +0200
committerAndreas Kling <kling@serenityos.org>2021-05-17 13:32:19 +0200
commit89956cb0d66f24bfcee312dcd35f78b5dbc9e1b9 (patch)
treedd7f38132b4cb91410271b4948cdfe99d28778d0 /Kernel/Syscalls
parent529f605ac801a541b1206ce06d497f8835ca7412 (diff)
downloadserenity-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')
-rw-r--r--Kernel/Syscalls/socket.cpp18
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(&params, 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);