mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 18:27:42 +00:00
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.
This commit is contained in:
parent
529f605ac8
commit
89956cb0d6
7 changed files with 49 additions and 18 deletions
|
@ -99,7 +99,7 @@ namespace Kernel {
|
||||||
S(chmod) \
|
S(chmod) \
|
||||||
S(socket) \
|
S(socket) \
|
||||||
S(bind) \
|
S(bind) \
|
||||||
S(accept) \
|
S(accept4) \
|
||||||
S(listen) \
|
S(listen) \
|
||||||
S(connect) \
|
S(connect) \
|
||||||
S(link) \
|
S(link) \
|
||||||
|
@ -269,6 +269,13 @@ struct SC_clock_nanosleep_params {
|
||||||
struct timespec* remaining_sleep;
|
struct timespec* remaining_sleep;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SC_accept4_params {
|
||||||
|
int sockfd;
|
||||||
|
sockaddr* addr;
|
||||||
|
socklen_t* addrlen;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
struct SC_getsockopt_params {
|
struct SC_getsockopt_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int level;
|
int level;
|
||||||
|
|
|
@ -364,7 +364,7 @@ public:
|
||||||
KResultOr<int> sys$socket(int domain, int type, int protocol);
|
KResultOr<int> sys$socket(int domain, int type, int protocol);
|
||||||
KResultOr<int> sys$bind(int sockfd, Userspace<const sockaddr*> addr, socklen_t);
|
KResultOr<int> sys$bind(int sockfd, Userspace<const sockaddr*> addr, socklen_t);
|
||||||
KResultOr<int> sys$listen(int sockfd, int backlog);
|
KResultOr<int> sys$listen(int sockfd, int backlog);
|
||||||
KResultOr<int> sys$accept(int sockfd, Userspace<sockaddr*>, Userspace<socklen_t*>);
|
KResultOr<int> sys$accept4(Userspace<const Syscall::SC_accept4_params*>);
|
||||||
KResultOr<int> sys$connect(int sockfd, Userspace<const sockaddr*>, socklen_t);
|
KResultOr<int> sys$connect(int sockfd, Userspace<const sockaddr*>, socklen_t);
|
||||||
KResultOr<int> sys$shutdown(int sockfd, int how);
|
KResultOr<int> sys$shutdown(int sockfd, int how);
|
||||||
KResultOr<ssize_t> sys$sendmsg(int sockfd, Userspace<const struct msghdr*>, int flags);
|
KResultOr<ssize_t> sys$sendmsg(int sockfd, Userspace<const struct msghdr*>, int flags);
|
||||||
|
|
|
@ -79,10 +79,19 @@ KResultOr<int> Process::sys$listen(int sockfd, int backlog)
|
||||||
return socket.listen(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);
|
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;
|
socklen_t address_size = 0;
|
||||||
if (user_address && !copy_from_user(&address_size, static_ptr_cast<const socklen_t*>(user_address_size)))
|
if (user_address && !copy_from_user(&address_size, static_ptr_cast<const socklen_t*>(user_address_size)))
|
||||||
return EFAULT;
|
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_readable(true);
|
||||||
accepted_socket_description_result.value()->set_writable(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.
|
// NOTE: Moving this state to Completed is what causes connect() to unblock on the client side.
|
||||||
accepted_socket->set_setup_state(Socket::SetupState::Completed);
|
accepted_socket->set_setup_state(Socket::SetupState::Completed);
|
||||||
|
|
|
@ -137,7 +137,7 @@ private:
|
||||||
int virt$getpeername(FlatPtr);
|
int virt$getpeername(FlatPtr);
|
||||||
int virt$select(FlatPtr);
|
int virt$select(FlatPtr);
|
||||||
int virt$get_stack_bounds(FlatPtr, FlatPtr);
|
int virt$get_stack_bounds(FlatPtr, FlatPtr);
|
||||||
int virt$accept(int sockfd, FlatPtr address, FlatPtr address_length);
|
int virt$accept4(FlatPtr);
|
||||||
int virt$bind(int sockfd, FlatPtr address, socklen_t address_length);
|
int virt$bind(int sockfd, FlatPtr address, socklen_t address_length);
|
||||||
int virt$recvmsg(int sockfd, FlatPtr msg_addr, int flags);
|
int virt$recvmsg(int sockfd, FlatPtr msg_addr, int flags);
|
||||||
int virt$sendmsg(int sockfd, FlatPtr msg_addr, int flags);
|
int virt$sendmsg(int sockfd, FlatPtr msg_addr, int flags);
|
||||||
|
|
|
@ -168,8 +168,8 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
|
||||||
return virt$fchmod(arg1, arg2);
|
return virt$fchmod(arg1, arg2);
|
||||||
case SC_fchown:
|
case SC_fchown:
|
||||||
return virt$fchown(arg1, arg2, arg3);
|
return virt$fchown(arg1, arg2, arg3);
|
||||||
case SC_accept:
|
case SC_accept4:
|
||||||
return virt$accept(arg1, arg2, arg3);
|
return virt$accept4(arg1);
|
||||||
case SC_setsockopt:
|
case SC_setsockopt:
|
||||||
return virt$setsockopt(arg1);
|
return virt$setsockopt(arg1);
|
||||||
case SC_getsockname:
|
case SC_getsockname:
|
||||||
|
@ -452,17 +452,20 @@ mode_t Emulator::virt$umask(mode_t mask)
|
||||||
return syscall(SC_umask, mask);
|
return syscall(SC_umask, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Emulator::virt$accept(int sockfd, FlatPtr address, FlatPtr address_length)
|
int Emulator::virt$accept4(FlatPtr params_addr)
|
||||||
{
|
{
|
||||||
socklen_t host_address_length = 0;
|
Syscall::SC_accept4_params params;
|
||||||
mmu().copy_from_vm(&host_address_length, address_length, sizeof(host_address_length));
|
mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
|
||||||
auto host_buffer = ByteBuffer::create_zeroed(host_address_length);
|
sockaddr_storage addr = {};
|
||||||
int rc = syscall(SC_accept, sockfd, host_buffer.data(), &host_address_length);
|
socklen_t addrlen;
|
||||||
if (rc < 0)
|
mmu().copy_from_vm(&addrlen, (FlatPtr)params.addrlen, sizeof(socklen_t));
|
||||||
return rc;
|
VERIFY(addrlen <= sizeof(addr));
|
||||||
mmu().copy_to_vm(address, host_buffer.data(), min((socklen_t)host_buffer.size(), host_address_length));
|
int rc = accept4(params.sockfd, (sockaddr*)&addr, &addrlen, params.flags);
|
||||||
mmu().copy_to_vm(address_length, &host_address_length, sizeof(host_address_length));
|
if (rc == 0) {
|
||||||
return rc;
|
mmu().copy_to_vm((FlatPtr)params.addr, &addr, addrlen);
|
||||||
|
mmu().copy_to_vm((FlatPtr)params.addrlen, &addrlen, sizeof(socklen_t));
|
||||||
|
}
|
||||||
|
return rc < 0 ? -errno : rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Emulator::virt$bind(int sockfd, FlatPtr address, socklen_t address_length)
|
int Emulator::virt$bind(int sockfd, FlatPtr address, socklen_t address_length)
|
||||||
|
|
|
@ -34,7 +34,13 @@ int listen(int sockfd, int backlog)
|
||||||
|
|
||||||
int accept(int sockfd, sockaddr* addr, socklen_t* addrlen)
|
int accept(int sockfd, sockaddr* addr, socklen_t* addrlen)
|
||||||
{
|
{
|
||||||
int rc = syscall(SC_accept, sockfd, addr, addrlen);
|
return accept4(sockfd, addr, addrlen, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int accept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags)
|
||||||
|
{
|
||||||
|
Syscall::SC_accept4_params params { sockfd, addr, addrlen, flags };
|
||||||
|
int rc = syscall(SC_accept4, ¶ms);
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,7 @@ int socket(int domain, int type, int protocol);
|
||||||
int bind(int sockfd, const struct sockaddr* addr, socklen_t);
|
int bind(int sockfd, const struct sockaddr* addr, socklen_t);
|
||||||
int listen(int sockfd, int backlog);
|
int listen(int sockfd, int backlog);
|
||||||
int accept(int sockfd, struct sockaddr*, socklen_t*);
|
int accept(int sockfd, struct sockaddr*, socklen_t*);
|
||||||
|
int accept4(int sockfd, struct sockaddr*, socklen_t*, int);
|
||||||
int connect(int sockfd, const struct sockaddr*, socklen_t);
|
int connect(int sockfd, const struct sockaddr*, socklen_t);
|
||||||
int shutdown(int sockfd, int how);
|
int shutdown(int sockfd, int how);
|
||||||
ssize_t send(int sockfd, const void*, size_t, int flags);
|
ssize_t send(int sockfd, const void*, size_t, int flags);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue