mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 04:07:45 +00:00
Kernel+LibC+UserspaceEmulator: Mostly add recvmsg(), sendmsg()
The implementation only supports a single iovec for now. Some might say having more than one iovec is the main point of recvmsg() and sendmsg(), but I'm interested in the control message bits.
This commit is contained in:
parent
19f2203b53
commit
b36a2d6686
9 changed files with 158 additions and 79 deletions
|
@ -130,8 +130,8 @@ namespace Kernel {
|
|||
S(fchmod) \
|
||||
S(symlink) \
|
||||
S(shbuf_seal) \
|
||||
S(sendto) \
|
||||
S(recvfrom) \
|
||||
S(sendmsg) \
|
||||
S(recvmsg) \
|
||||
S(getsockopt) \
|
||||
S(setsockopt) \
|
||||
S(create_thread) \
|
||||
|
@ -284,22 +284,6 @@ struct SC_clock_nanosleep_params {
|
|||
struct timespec* remaining_sleep;
|
||||
};
|
||||
|
||||
struct SC_sendto_params {
|
||||
int sockfd;
|
||||
ImmutableBufferArgument<void, size_t> data;
|
||||
int flags;
|
||||
const sockaddr* addr;
|
||||
socklen_t addr_length;
|
||||
};
|
||||
|
||||
struct SC_recvfrom_params {
|
||||
int sockfd;
|
||||
MutableBufferArgument<void, size_t> buffer;
|
||||
int flags;
|
||||
sockaddr* addr;
|
||||
socklen_t* addr_length;
|
||||
};
|
||||
|
||||
struct SC_getsockopt_params {
|
||||
int sockfd;
|
||||
int level;
|
||||
|
|
|
@ -290,8 +290,8 @@ public:
|
|||
int sys$accept(int sockfd, Userspace<sockaddr*>, Userspace<socklen_t*>);
|
||||
int sys$connect(int sockfd, Userspace<const sockaddr*>, socklen_t);
|
||||
int sys$shutdown(int sockfd, int how);
|
||||
ssize_t sys$sendto(Userspace<const Syscall::SC_sendto_params*>);
|
||||
ssize_t sys$recvfrom(Userspace<const Syscall::SC_recvfrom_params*>);
|
||||
ssize_t sys$sendmsg(int sockfd, Userspace<const struct msghdr*>, int flags);
|
||||
ssize_t sys$recvmsg(int sockfd, Userspace<struct msghdr*>, int flags);
|
||||
int sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*>);
|
||||
int sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*>);
|
||||
int sys$getsockname(Userspace<const Syscall::SC_getsockname_params*>);
|
||||
|
|
|
@ -76,6 +76,12 @@ template<typename T>
|
|||
return copy_from_user(dest, src.unsafe_userspace_ptr(), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline bool copy_from_user(T* dest, Userspace<T*> src)
|
||||
{
|
||||
return copy_from_user(dest, src.unsafe_userspace_ptr(), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline bool copy_to_user(Userspace<T*> dest, const T* src)
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <Kernel/Net/IPv4Socket.h>
|
||||
#include <Kernel/Net/LocalSocket.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/UnixTypes.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
@ -176,18 +177,24 @@ int Process::sys$shutdown(int sockfd, int how)
|
|||
return socket.shutdown(how);
|
||||
}
|
||||
|
||||
ssize_t Process::sys$sendto(Userspace<const Syscall::SC_sendto_params*> user_params)
|
||||
ssize_t Process::sys$sendmsg(int sockfd, Userspace<const struct msghdr*> user_msg, int flags)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
Syscall::SC_sendto_params params;
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
struct msghdr msg;
|
||||
if (!copy_from_user(&msg, user_msg))
|
||||
return -EFAULT;
|
||||
|
||||
int flags = params.flags;
|
||||
Userspace<const sockaddr*> addr((FlatPtr)params.addr);
|
||||
socklen_t addr_length = params.addr_length;
|
||||
if (msg.msg_iovlen != 1)
|
||||
return -ENOTSUP; // FIXME: Support this :)
|
||||
Vector<iovec, 1> iovs;
|
||||
iovs.resize(msg.msg_iovlen);
|
||||
if (!copy_n_from_user(iovs.data(), msg.msg_iov, msg.msg_iovlen))
|
||||
return -EFAULT;
|
||||
|
||||
auto description = file_description(params.sockfd);
|
||||
Userspace<const sockaddr*> user_addr((FlatPtr)msg.msg_name);
|
||||
socklen_t addr_length = msg.msg_namelen;
|
||||
|
||||
auto description = file_description(sockfd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
if (!description->is_socket())
|
||||
|
@ -196,32 +203,36 @@ ssize_t Process::sys$sendto(Userspace<const Syscall::SC_sendto_params*> user_par
|
|||
if (socket.is_shut_down_for_writing())
|
||||
return -EPIPE;
|
||||
SmapDisabler disabler;
|
||||
auto data_buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>((const u8*)params.data.data), params.data.size);
|
||||
auto data_buffer = UserOrKernelBuffer::for_user_buffer((u8*)iovs[0].iov_base, iovs[0].iov_len);
|
||||
if (!data_buffer.has_value())
|
||||
return -EFAULT;
|
||||
auto result = socket.sendto(*description, data_buffer.value(), params.data.size, flags, addr, addr_length);
|
||||
auto result = socket.sendto(*description, data_buffer.value(), iovs[0].iov_len, flags, user_addr, addr_length);
|
||||
if (result.is_error())
|
||||
return result.error();
|
||||
return result.value();
|
||||
}
|
||||
|
||||
ssize_t Process::sys$recvfrom(Userspace<const Syscall::SC_recvfrom_params*> user_params)
|
||||
ssize_t Process::sys$recvmsg(int sockfd, Userspace<struct msghdr*> user_msg, int flags)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
|
||||
Syscall::SC_recvfrom_params params;
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
struct msghdr msg;
|
||||
if (!copy_from_user(&msg, user_msg))
|
||||
return -EFAULT;
|
||||
|
||||
int flags = params.flags;
|
||||
Userspace<sockaddr*> user_addr((FlatPtr)params.addr);
|
||||
Userspace<socklen_t*> user_addr_length((FlatPtr)params.addr_length);
|
||||
if (msg.msg_iovlen != 1)
|
||||
return -ENOTSUP; // FIXME: Support this :)
|
||||
Vector<iovec, 1> iovs;
|
||||
iovs.resize(msg.msg_iovlen);
|
||||
if (!copy_n_from_user(iovs.data(), msg.msg_iov, msg.msg_iovlen))
|
||||
return -EFAULT;
|
||||
|
||||
Userspace<sockaddr*> user_addr((FlatPtr)msg.msg_name);
|
||||
Userspace<socklen_t*> user_addr_length(msg.msg_name ? (FlatPtr)&user_msg.unsafe_userspace_ptr()->msg_namelen : 0);
|
||||
|
||||
SmapDisabler disabler;
|
||||
if (!user_addr_length && user_addr)
|
||||
return -EINVAL;
|
||||
|
||||
auto description = file_description(params.sockfd);
|
||||
auto description = file_description(sockfd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
if (!description->is_socket())
|
||||
|
@ -235,15 +246,26 @@ ssize_t Process::sys$recvfrom(Userspace<const Syscall::SC_recvfrom_params*> user
|
|||
if (flags & MSG_DONTWAIT)
|
||||
description->set_blocking(false);
|
||||
|
||||
auto data_buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>((const u8*)params.buffer.data), params.buffer.size);
|
||||
auto data_buffer = UserOrKernelBuffer::for_user_buffer((u8*)iovs[0].iov_base, iovs[0].iov_len);
|
||||
if (!data_buffer.has_value())
|
||||
return -EFAULT;
|
||||
auto result = socket.recvfrom(*description, data_buffer.value(), params.buffer.size, flags, user_addr, user_addr_length);
|
||||
auto result = socket.recvfrom(*description, data_buffer.value(), iovs[0].iov_len, flags, user_addr, user_addr_length);
|
||||
if (flags & MSG_DONTWAIT)
|
||||
description->set_blocking(original_blocking);
|
||||
|
||||
if (result.is_error())
|
||||
return result.error();
|
||||
|
||||
int msg_flags = 0;
|
||||
|
||||
if (result.value() > iovs[0].iov_len) {
|
||||
ASSERT(socket.type() != SOCK_STREAM);
|
||||
msg_flags |= MSG_TRUNC;
|
||||
}
|
||||
|
||||
if (!copy_to_user(&user_msg.unsafe_userspace_ptr()->msg_flags, &msg_flags))
|
||||
return -EFAULT;
|
||||
|
||||
return result.value();
|
||||
}
|
||||
|
||||
|
|
|
@ -457,6 +457,7 @@ struct pollfd {
|
|||
#define SHUT_WR 2
|
||||
#define SHUT_RDWR 3
|
||||
|
||||
#define MSG_TRUNC 0x1
|
||||
#define MSG_DONTWAIT 0x40
|
||||
|
||||
#define SOL_SOCKET 1
|
||||
|
@ -552,6 +553,16 @@ struct iovec {
|
|||
size_t iov_len;
|
||||
};
|
||||
|
||||
struct msghdr {
|
||||
void* msg_name;
|
||||
socklen_t msg_namelen;
|
||||
struct iovec* msg_iov;
|
||||
int msg_iovlen;
|
||||
void* msg_control;
|
||||
socklen_t msg_controllen;
|
||||
int msg_flags;
|
||||
};
|
||||
|
||||
struct sched_param {
|
||||
int sched_priority;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue