Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibIPC: Port to Windows #2643

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions Libraries/LibIPC/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ set(SOURCES
Connection.cpp
Decoder.cpp
Encoder.cpp
Message.cpp
)

if (UNIX)
list(APPEND SOURCES TransportSocket.cpp)
list(APPEND SOURCES
File.cpp
Message.cpp
TransportSocket.cpp)
else()
list(APPEND SOURCES
FileWindows.cpp
MessageWindows.cpp
TransportSocketWindows.cpp)
endif()

serenity_lib(LibIPC ipc)
Expand Down
45 changes: 18 additions & 27 deletions Libraries/LibIPC/Concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,54 +27,45 @@ namespace IPC::Concepts {

namespace Detail {

// Cannot use SpecializationOf with these templates because they have non-type parameters. See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1985r3.pdf
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the order of declarations, which makes the diff unreadable. This is a diff that shows changes of substance (without reordering or inline removing).

template<typename T>
constexpr inline bool IsHashMap = false;
template<typename K, typename V, typename KeyTraits, typename ValueTraits, bool IsOrdered>
constexpr inline bool IsHashMap<HashMap<K, V, KeyTraits, ValueTraits, IsOrdered>> = true;
constexpr bool IsArray = false;
template<typename T, size_t N>
constexpr bool IsArray<Array<T, N>> = true;

template<typename T>
constexpr inline bool IsOptional = false;
constexpr bool IsVector = false;
template<typename T, size_t inline_capacity>
constexpr bool IsVector<Vector<T, inline_capacity>> = true;

template<typename T>
constexpr inline bool IsOptional<Optional<T>> = true;
constexpr bool IsHashMap = false;
template<typename K, typename V, typename KeyTraits, typename ValueTraits, bool IsOrdered>
constexpr bool IsHashMap<HashMap<K, V, KeyTraits, ValueTraits, IsOrdered>> = true;

template<typename T>
constexpr inline bool IsSharedSingleProducerCircularQueue = false;
constexpr bool IsSharedSingleProducerCircularQueue = false;
template<typename T, size_t Size>
constexpr inline bool IsSharedSingleProducerCircularQueue<Core::SharedSingleProducerCircularQueue<T, Size>> = true;
constexpr bool IsSharedSingleProducerCircularQueue<Core::SharedSingleProducerCircularQueue<T, Size>> = true;

template<typename T>
constexpr inline bool IsVariant = false;
template<typename... Ts>
constexpr inline bool IsVariant<Variant<Ts...>> = true;
}

template<typename T>
constexpr inline bool IsVector = false;
template<typename T>
constexpr inline bool IsVector<Vector<T>> = true;
concept Array = Detail::IsArray<T>;

template<typename T>
constexpr inline bool IsArray = false;
template<typename T, size_t N>
constexpr inline bool IsArray<Array<T, N>> = true;

}
concept Vector = Detail::IsVector<T>;

template<typename T>
concept HashMap = Detail::IsHashMap<T>;

template<typename T>
concept Optional = Detail::IsOptional<T>;

template<typename T>
concept SharedSingleProducerCircularQueue = Detail::IsSharedSingleProducerCircularQueue<T>;

template<typename T>
concept Variant = Detail::IsVariant<T>;
concept Optional = SpecializationOf<T, AK::Optional>;

template<typename T>
concept Vector = Detail::IsVector<T>;

template<typename T>
concept Array = Detail::IsArray<T>;
concept Variant = SpecializationOf<T, AK::Variant>;

}
2 changes: 1 addition & 1 deletion Libraries/LibIPC/Connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class ConnectionBase : public Core::EventReceiver {
RefPtr<Core::Timer> m_responsiveness_timer;

Vector<NonnullOwnPtr<Message>> m_unprocessed_messages;
Queue<IPC::File> m_unprocessed_fds;
Queue<IPC::File> m_unprocessed_fds; // unused on Windows
stasoid marked this conversation as resolved.
Show resolved Hide resolved
ByteBuffer m_unprocessed_bytes;

u32 m_local_endpoint_magic { 0 };
Expand Down
12 changes: 0 additions & 12 deletions Libraries/LibIPC/Decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <LibIPC/Decoder.h>
#include <LibIPC/File.h>
#include <LibURL/URL.h>
#include <fcntl.h>

namespace IPC {

Expand Down Expand Up @@ -118,17 +117,6 @@ ErrorOr<URL::Host> decode(Decoder& decoder)
return URL::Host { move(value) };
}

template<>
ErrorOr<File> decode(Decoder& decoder)
{
auto file = TRY(decoder.files().try_dequeue());
auto fd = file.fd();

auto fd_flags = TRY(Core::System::fcntl(fd, F_GETFD));
TRY(Core::System::fcntl(fd, F_SETFD, fd_flags | FD_CLOEXEC));
return file;
}

template<>
ErrorOr<Empty> decode(Decoder&)
{
Expand Down
36 changes: 36 additions & 0 deletions Libraries/LibIPC/File.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
* Copyright (c) 2021, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <LibIPC/Decoder.h>
#include <LibIPC/File.h>

namespace IPC {

// FIXME: IPC::Files transferred over the wire are always set O_CLOEXEC during decoding.
// Perhaps we should add an option to IPC::File to allow the receiver to decide whether to
// make it O_CLOEXEC or not. Or an attribute in the .ipc file?
stasoid marked this conversation as resolved.
Show resolved Hide resolved
ErrorOr<void> File::clear_close_on_exec()
{
auto fd_flags = TRY(Core::System::fcntl(m_fd, F_GETFD));
fd_flags &= ~FD_CLOEXEC;
TRY(Core::System::fcntl(m_fd, F_SETFD, fd_flags));
return {};
}

template<>
ErrorOr<File> decode(Decoder& decoder)
{
auto file = TRY(decoder.files().try_dequeue());
auto fd = file.fd();

auto fd_flags = TRY(Core::System::fcntl(fd, F_GETFD));
TRY(Core::System::fcntl(fd, F_SETFD, fd_flags | FD_CLOEXEC));
return file;
}

}
11 changes: 1 addition & 10 deletions Libraries/LibIPC/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,7 @@ class File {
return exchange(m_fd, -1);
}

// FIXME: IPC::Files transferred over the wire are always set O_CLOEXEC during decoding.
// Perhaps we should add an option to IPC::File to allow the receiver to decide whether to
// make it O_CLOEXEC or not. Or an attribute in the .ipc file?
ErrorOr<void> clear_close_on_exec()
{
auto fd_flags = TRY(Core::System::fcntl(m_fd, F_GETFD));
fd_flags &= ~FD_CLOEXEC;
TRY(Core::System::fcntl(m_fd, F_SETFD, fd_flags));
return {};
}
ErrorOr<void> clear_close_on_exec();

private:
explicit File(int fd)
Expand Down
42 changes: 42 additions & 0 deletions Libraries/LibIPC/FileWindows.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2024, stasoid <stasoid@yahoo.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <LibIPC/Decoder.h>
#include <LibIPC/File.h>

#include <AK/Windows.h>

namespace IPC {

ErrorOr<void> File::clear_close_on_exec()
{
if (!SetHandleInformation(Core::System::fd_to_handle(m_fd), HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
return Error::from_windows_error();
return {};
}

template<>
ErrorOr<File> decode(Decoder& decoder)
{
using namespace Core::System;
auto handle_type = TRY(decoder.decode<HandleType>());
intptr_t handle = 0;
if (handle_type == FileMappingHandle) {
TRY(decoder.decode_into(handle));
} else if (handle_type == SocketHandle) {
WSAPROTOCOL_INFO pi = {};
TRY(decoder.decode_into({ (u8*)&pi, sizeof(pi) }));
handle = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, &pi, 0, WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
stasoid marked this conversation as resolved.
Show resolved Hide resolved
if (handle == -1)
return Error::from_windows_error();
stasoid marked this conversation as resolved.
Show resolved Hide resolved
} else {
return Error::from_string_literal("Invalid handle type");
}
int fd = handle_to_fd(handle, handle_type);
return File::adopt_fd(fd);
}

}
9 changes: 6 additions & 3 deletions Libraries/LibIPC/Message.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
#include <AK/RefPtr.h>
#include <AK/Vector.h>
#include <LibCore/Forward.h>
#include <LibCore/System.h>
#include <LibIPC/Transport.h>
#include <unistd.h>

namespace IPC {

Expand All @@ -27,7 +27,7 @@ class AutoCloseFileDescriptor : public RefCounted<AutoCloseFileDescriptor> {
~AutoCloseFileDescriptor()
{
if (m_fd != -1)
close(m_fd);
(void)Core::System::close(m_fd);
stasoid marked this conversation as resolved.
Show resolved Hide resolved
}

int value() const { return m_fd; }
Expand All @@ -45,11 +45,14 @@ class MessageBuffer {

ErrorOr<void> append_file_descriptor(int fd);

ErrorOr<void> transfer_message(Transport& socket);
ErrorOr<void> transfer_message(Transport& transport);

private:
Vector<u8, 1024> m_data;
Vector<NonnullRefPtr<AutoCloseFileDescriptor>, 1> m_fds;
#ifdef AK_OS_WINDOWS
Vector<size_t> m_handle_offsets;
#endif
};

enum class ErrorCode : u32 {
Expand Down
70 changes: 70 additions & 0 deletions Libraries/LibIPC/MessageWindows.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
* Copyright (c) 2024, stasoid <stasoid@yahoo.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <LibIPC/Message.h>

#include <AK/Windows.h>

namespace IPC {

using MessageSizeType = u32;

MessageBuffer::MessageBuffer()
{
m_data.resize(sizeof(MessageSizeType));
}

ErrorOr<void> MessageBuffer::extend_data_capacity(size_t capacity)
{
TRY(m_data.try_ensure_capacity(m_data.size() + capacity));
return {};
}

ErrorOr<void> MessageBuffer::append_data(u8 const* values, size_t count)
{
TRY(m_data.try_append(values, count));
return {};
}

ErrorOr<void> MessageBuffer::append_file_descriptor(int fd)
{
using namespace Core::System;

HANDLE handle = fd_to_handle(fd);
if (handle == INVALID_HANDLE_VALUE)
return Error::from_string_literal("Invalid file descriptor");

m_fds.append(adopt_ref(*new AutoCloseFileDescriptor(fd)));
m_handle_offsets.append(m_data.size());

if (is_socket(fd)) {
HandleType type = SocketHandle;
m_data.append((u8*)&type, sizeof(type));
WSAPROTOCOL_INFO pi = {};
*(HANDLE*)&pi = handle;
// the handle will be duplicated and WSAPROTOCOL_INFO will be filled later in TransportSocketWindows::transfer
m_data.append((u8*)&pi, sizeof(pi));
} else {
HandleType type = FileMappingHandle;
m_data.append((u8*)&type, sizeof(type));
// the handle will be overwritten by a duplicate handle later in TransportSocketWindows::transfer
m_data.append((u8*)&handle, sizeof(handle));
}
return {};
}

ErrorOr<void> MessageBuffer::transfer_message(Transport& transport)
{
VERIFY(m_data.size() >= sizeof(MessageSizeType) && m_data.size() < NumericLimits<MessageSizeType>::max());
size_t message_size = m_data.size() - sizeof(MessageSizeType);
*(MessageSizeType*)m_data.data() = message_size;

TRY(transport.transfer(m_data.span(), m_handle_offsets));
return {};
}

}
4 changes: 3 additions & 1 deletion Libraries/LibIPC/Transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#if !defined(AK_OS_WINDOWS)
# include <LibIPC/TransportSocket.h>
#else
# include <LibIPC/TransportSocketWindows.h>
#endif

namespace IPC {
Expand All @@ -18,7 +20,7 @@ namespace IPC {
// Unix Domain Sockets
using Transport = TransportSocket;
#else
# error "LibIPC Transport has not been ported to this platform"
using Transport = TransportSocketWindows;
#endif

}
Loading
Loading