1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 17:17:45 +00:00

Kernel+LibC: Implement the socketpair() syscall

This commit is contained in:
Gunnar Beutner 2021-04-28 12:39:12 +02:00 committed by Andreas Kling
parent c841012f56
commit aa792062cb
11 changed files with 100 additions and 91 deletions

View file

@ -120,6 +120,7 @@ namespace Kernel {
S(beep) \
S(getsockname) \
S(getpeername) \
S(socketpair) \
S(sched_setparam) \
S(sched_getparam) \
S(fchown) \
@ -293,6 +294,13 @@ struct SC_getpeername_params {
socklen_t* addrlen;
};
struct SC_socketpair_params {
int domain;
int type;
int protocol;
int* sv;
};
struct SC_futex_params {
u32* userspace_address;
int futex_op;

View file

@ -36,6 +36,31 @@ KResultOr<NonnullRefPtr<Socket>> LocalSocket::create(int type)
return adopt_ref(*new LocalSocket(type));
}
KResultOr<SocketPair> LocalSocket::create_connected_pair(int type)
{
auto socket = adopt_ref(*new LocalSocket(type));
auto description1_result = FileDescription::create(*socket);
if (description1_result.is_error())
return description1_result.error();
socket->m_address.sun_family = AF_LOCAL;
memcpy(socket->m_address.sun_path, "[socketpair]", 13);
auto& process = *Process::current();
socket->m_acceptor = { process.pid().value(), process.uid(), process.gid() };
socket->set_connected(true);
socket->set_connect_side_role(Role::Connected);
socket->m_role = Role::Accepted;
auto description2_result = FileDescription::create(*socket);
if (description2_result.is_error())
return description2_result.error();
return SocketPair { description1_result.release_value(), description2_result.release_value() };
}
LocalSocket::LocalSocket(int type)
: Socket(AF_LOCAL, type, 0)
{

View file

@ -14,12 +14,18 @@ namespace Kernel {
class FileDescription;
struct SocketPair {
NonnullRefPtr<FileDescription> description1;
NonnullRefPtr<FileDescription> description2;
};
class LocalSocket final : public Socket
, public InlineLinkedListNode<LocalSocket> {
friend class InlineLinkedListNode<LocalSocket>;
public:
static KResultOr<NonnullRefPtr<Socket>> create(int type);
static KResultOr<SocketPair> create_connected_pair(int type);
virtual ~LocalSocket() override;
KResult sendfd(const FileDescription& socket_description, FileDescription& passing_description);

View file

@ -355,6 +355,7 @@ public:
KResultOr<int> sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*>);
KResultOr<int> sys$getsockname(Userspace<const Syscall::SC_getsockname_params*>);
KResultOr<int> sys$getpeername(Userspace<const Syscall::SC_getpeername_params*>);
KResultOr<int> sys$socketpair(Userspace<const Syscall::SC_socketpair_params*>);
KResultOr<int> sys$sched_setparam(pid_t pid, Userspace<const struct sched_param*>);
KResultOr<int> sys$sched_getparam(pid_t pid, Userspace<struct sched_param*>);
KResultOr<int> sys$create_thread(void* (*)(void*), Userspace<const Syscall::SC_create_thread_params*>);
@ -529,6 +530,8 @@ private:
void clear_futex_queues_on_exec();
void setup_socket_fd(int fd, NonnullRefPtr<FileDescription> description, int type);
inline PerformanceEventBuffer* current_perf_events_buffer()
{
return g_profiling_all_threads ? g_global_perf_events : m_perf_event_buffer.ptr();

View file

@ -20,6 +20,18 @@ namespace Kernel {
REQUIRE_PROMISE(unix); \
} while (0)
void Process::setup_socket_fd(int fd, NonnullRefPtr<FileDescription> description, int type)
{
description->set_readable(true);
description->set_writable(true);
unsigned flags = 0;
if (type & SOCK_CLOEXEC)
flags |= FD_CLOEXEC;
if (type & SOCK_NONBLOCK)
description->set_blocking(false);
m_fds[fd].set(*description, flags);
}
KResultOr<int> Process::sys$socket(int domain, int type, int protocol)
{
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(domain);
@ -35,14 +47,7 @@ KResultOr<int> Process::sys$socket(int domain, int type, int protocol)
auto description_result = FileDescription::create(*result.value());
if (description_result.is_error())
return description_result.error();
description_result.value()->set_readable(true);
description_result.value()->set_writable(true);
unsigned flags = 0;
if (type & SOCK_CLOEXEC)
flags |= FD_CLOEXEC;
if (type & SOCK_NONBLOCK)
description_result.value()->set_blocking(false);
m_fds[fd].set(description_result.release_value(), flags);
setup_socket_fd(fd, description_result.value(), type);
return fd;
}
@ -362,4 +367,41 @@ KResultOr<int> Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_pa
return socket.setsockopt(params.level, params.option, user_value, params.value_size);
}
KResultOr<int> Process::sys$socketpair(Userspace<const Syscall::SC_socketpair_params*> user_params)
{
Syscall::SC_socketpair_params params;
if (!copy_from_user(&params, user_params))
return EFAULT;
if (params.domain != AF_LOCAL)
return EINVAL;
if (params.protocol != 0 && params.protocol != PF_LOCAL)
return EINVAL;
auto result = LocalSocket::create_connected_pair(params.type & SOCK_TYPE_MASK);
if (result.is_error())
return result.error();
auto pair = result.value();
int fds[2];
fds[0] = alloc_fd();
if (fds[0] < 0)
return ENFILE;
setup_socket_fd(fds[0], pair.description1, params.type);
fds[1] = alloc_fd();
if (fds[1] < 0) {
// FIXME: This leaks fds[0]
return ENFILE;
}
setup_socket_fd(fds[1], pair.description2, params.type);
if (!copy_to_user(params.sv, fds, sizeof(fds))) {
// FIXME: This leaks both file descriptors
return EFAULT;
}
return KSuccess;
}
}