diff --git a/Ladybird/AppKit/Application/Application.mm b/Ladybird/AppKit/Application/Application.mm index e3be7f7c5c6..ddae9b15834 100644 --- a/Ladybird/AppKit/Application/Application.mm +++ b/Ladybird/AppKit/Application/Application.mm @@ -134,7 +134,7 @@ static ErrorOr> launch_new_image_decod auto web_worker_paths = TRY(get_paths_for_helper_process("WebWorker"sv)); auto worker_client = TRY(launch_web_worker_process(web_worker_paths, *m_request_server_client)); - return worker_client->dup_socket(); + return worker_client->clone_transport(); } #pragma mark - NSApplication diff --git a/Ladybird/Headless/HeadlessWebView.cpp b/Ladybird/Headless/HeadlessWebView.cpp index 7ed43ba5c2b..aa8309598fe 100644 --- a/Ladybird/Headless/HeadlessWebView.cpp +++ b/Ladybird/Headless/HeadlessWebView.cpp @@ -33,7 +33,7 @@ HeadlessWebView::HeadlessWebView(Core::AnonymousBuffer theme, Gfx::IntSize viewp auto web_worker_paths = MUST(get_paths_for_helper_process("WebWorker"sv)); auto worker_client = MUST(launch_web_worker_process(web_worker_paths, Application::request_client())); - return worker_client->dup_socket(); + return worker_client->clone_transport(); }; } diff --git a/Ladybird/Qt/WebContentView.cpp b/Ladybird/Qt/WebContentView.cpp index df1afbd0dbd..c74eaf40bd3 100644 --- a/Ladybird/Qt/WebContentView.cpp +++ b/Ladybird/Qt/WebContentView.cpp @@ -135,7 +135,7 @@ WebContentView::WebContentView(QWidget* window, RefPtr(QApplication::instance())->request_server_client; auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)), *request_server_client)); - return worker_client->dup_socket(); + return worker_client->clone_transport(); }; m_select_dropdown = new QMenu("Select Dropdown", this); diff --git a/Ladybird/WebContent/main.cpp b/Ladybird/WebContent/main.cpp index a0ccf5328b1..e2ea6ef5df5 100644 --- a/Ladybird/WebContent/main.cpp +++ b/Ladybird/WebContent/main.cpp @@ -188,8 +188,10 @@ ErrorOr serenity_main(Main::Arguments arguments) if (maybe_autoplay_allowlist_error.is_error()) dbgln("Failed to load autoplay allowlist: {}", maybe_autoplay_allowlist_error.error()); + static_assert(IsSame, "Need to handle other IPC transports here"); + auto webcontent_socket = TRY(Core::take_over_socket_from_system_server("WebContent"sv)); - auto webcontent_client = TRY(WebContent::ConnectionFromClient::try_create(move(webcontent_socket))); + auto webcontent_client = TRY(WebContent::ConnectionFromClient::try_create(IPC::Transport(move(webcontent_socket)))); webcontent_client->on_image_decoder_connection = [&](auto& socket_file) { auto maybe_error = reinitialize_image_decoder(socket_file); @@ -250,10 +252,12 @@ static ErrorOr load_autoplay_allowlist(StringView config_path) ErrorOr initialize_resource_loader(int request_server_socket) { + static_assert(IsSame, "Need to handle other IPC transports here"); + auto socket = TRY(Core::LocalSocket::adopt_fd(request_server_socket)); TRY(socket->set_blocking(true)); - auto request_client = TRY(try_make_ref_counted(move(socket))); + auto request_client = TRY(try_make_ref_counted(IPC::Transport(move(socket)))); Web::ResourceLoader::initialize(move(request_client)); return {}; @@ -261,10 +265,11 @@ ErrorOr initialize_resource_loader(int request_server_socket) ErrorOr initialize_image_decoder(int image_decoder_socket) { + static_assert(IsSame, "Need to handle other IPC transports here"); auto socket = TRY(Core::LocalSocket::adopt_fd(image_decoder_socket)); TRY(socket->set_blocking(true)); - auto new_client = TRY(try_make_ref_counted(move(socket))); + auto new_client = TRY(try_make_ref_counted(IPC::Transport(move(socket)))); Web::Platform::ImageCodecPlugin::install(*new Ladybird::ImageCodecPlugin(move(new_client))); @@ -273,10 +278,12 @@ ErrorOr initialize_image_decoder(int image_decoder_socket) ErrorOr reinitialize_image_decoder(IPC::File const& image_decoder_socket) { + static_assert(IsSame, "Need to handle other IPC transports here"); + auto socket = TRY(Core::LocalSocket::adopt_fd(image_decoder_socket.take_fd())); TRY(socket->set_blocking(true)); - auto new_client = TRY(try_make_ref_counted(move(socket))); + auto new_client = TRY(try_make_ref_counted(IPC::Transport(move(socket)))); static_cast(Web::Platform::ImageCodecPlugin::the()).set_client(move(new_client)); diff --git a/Ladybird/WebWorker/main.cpp b/Ladybird/WebWorker/main.cpp index 7271f37948f..b0b9fb4f8e1 100644 --- a/Ladybird/WebWorker/main.cpp +++ b/Ladybird/WebWorker/main.cpp @@ -73,10 +73,12 @@ ErrorOr serenity_main(Main::Arguments arguments) static ErrorOr initialize_resource_loader(int request_server_socket) { + static_assert(IsSame, "Need to handle other IPC transports here"); + auto socket = TRY(Core::LocalSocket::adopt_fd(request_server_socket)); TRY(socket->set_blocking(true)); - auto request_client = TRY(try_make_ref_counted(move(socket))); + auto request_client = TRY(try_make_ref_counted(IPC::Transport(move(socket)))); Web::ResourceLoader::initialize(move(request_client)); return {}; diff --git a/Userland/Libraries/LibIPC/CMakeLists.txt b/Userland/Libraries/LibIPC/CMakeLists.txt index 7af0aa27752..114d0c482b0 100644 --- a/Userland/Libraries/LibIPC/CMakeLists.txt +++ b/Userland/Libraries/LibIPC/CMakeLists.txt @@ -5,5 +5,9 @@ set(SOURCES Message.cpp ) +if (UNIX) + list(APPEND SOURCES TransportSocket.cpp) +endif() + serenity_lib(LibIPC ipc) target_link_libraries(LibIPC PRIVATE LibCore LibURL LibThreading) diff --git a/Userland/Libraries/LibIPC/Connection.cpp b/Userland/Libraries/LibIPC/Connection.cpp index 2c52008bc80..18651c7972e 100644 --- a/Userland/Libraries/LibIPC/Connection.cpp +++ b/Userland/Libraries/LibIPC/Connection.cpp @@ -14,22 +14,19 @@ namespace IPC { -ConnectionBase::ConnectionBase(IPC::Stub& local_stub, NonnullOwnPtr socket, u32 local_endpoint_magic) +ConnectionBase::ConnectionBase(IPC::Stub& local_stub, Transport transport, u32 local_endpoint_magic) : m_local_stub(local_stub) - , m_socket(move(socket)) + , m_transport(move(transport)) , m_local_endpoint_magic(local_endpoint_magic) { - socklen_t socket_buffer_size = 128 * KiB; - (void)Core::System::setsockopt(m_socket->fd().value(), SOL_SOCKET, SO_SNDBUF, &socket_buffer_size, sizeof(socket_buffer_size)); - (void)Core::System::setsockopt(m_socket->fd().value(), SOL_SOCKET, SO_RCVBUF, &socket_buffer_size, sizeof(socket_buffer_size)); - m_responsiveness_timer = Core::Timer::create_single_shot(3000, [this] { may_have_become_unresponsive(); }); - m_socket->on_ready_to_read = [this] { + + m_transport.set_up_read_hook([this] { NonnullRefPtr protect = *this; // FIXME: Do something about errors. (void)drain_messages_from_peer(); handle_messages(); - }; + }); m_send_queue = adopt_ref(*new SendQueue); m_send_thread = Threading::Thread::construct([this, queue = m_send_queue]() -> intptr_t { @@ -46,7 +43,7 @@ ConnectionBase::ConnectionBase(IPC::Stub& local_stub, NonnullOwnPtrmessages.take_first(); queue->mutex.unlock(); - if (auto result = message.transfer_message(*m_socket); result.is_error()) { + if (auto result = message.transfer_message(m_transport); result.is_error()) { dbgln("ConnectionBase::send_thread: {}", result.error()); continue; } @@ -68,7 +65,7 @@ ConnectionBase::~ConnectionBase() bool ConnectionBase::is_open() const { - return m_socket->is_open(); + return m_transport.is_open(); } ErrorOr ConnectionBase::post_message(Message const& message) @@ -80,7 +77,7 @@ ErrorOr ConnectionBase::post_message(MessageBuffer buffer) { // NOTE: If this connection is being shut down, but has not yet been destroyed, // the socket will be closed. Don't try to send more messages. - if (!m_socket->is_open()) + if (!m_transport.is_open()) return Error::from_string_literal("Trying to post_message during IPC shutdown"); { @@ -95,7 +92,7 @@ ErrorOr ConnectionBase::post_message(MessageBuffer buffer) void ConnectionBase::shutdown() { - m_socket->close(); + m_transport.close(); die(); } @@ -125,19 +122,12 @@ void ConnectionBase::handle_messages() } } -void ConnectionBase::wait_for_socket_to_become_readable() +void ConnectionBase::wait_for_transport_to_become_readable() { - auto maybe_did_become_readable = m_socket->can_read_without_blocking(-1); - if (maybe_did_become_readable.is_error()) { - dbgln("ConnectionBase::wait_for_socket_to_become_readable: {}", maybe_did_become_readable.error()); - warnln("ConnectionBase::wait_for_socket_to_become_readable: {}", maybe_did_become_readable.error()); - VERIFY_NOT_REACHED(); - } - - VERIFY(maybe_did_become_readable.value()); + m_transport.wait_until_readable(); } -ErrorOr> ConnectionBase::read_as_much_as_possible_from_socket_without_blocking() +ErrorOr> ConnectionBase::read_as_much_as_possible_from_transport_without_blocking() { Vector bytes; @@ -146,9 +136,6 @@ ErrorOr> ConnectionBase::read_as_much_as_possible_from_socket_without m_unprocessed_bytes.clear(); } - u8 buffer[4096]; - Vector received_fds; - bool should_shut_down = false; auto schedule_shutdown = [this, &should_shut_down]() { should_shut_down = true; @@ -157,34 +144,11 @@ ErrorOr> ConnectionBase::read_as_much_as_possible_from_socket_without }); }; - while (m_socket->is_open()) { - auto maybe_bytes_read = m_socket->receive_message({ buffer, 4096 }, MSG_DONTWAIT, received_fds); - if (maybe_bytes_read.is_error()) { - auto error = maybe_bytes_read.release_error(); - if (error.is_syscall() && error.code() == EAGAIN) { - break; - } + auto&& [new_bytes, received_fds] = m_transport.read_as_much_as_possible_without_blocking(move(schedule_shutdown)); + bytes.append(new_bytes.data(), new_bytes.size()); - if (error.is_syscall() && error.code() == ECONNRESET) { - schedule_shutdown(); - break; - } - - dbgln("ConnectionBase::read_as_much_as_possible_from_socket_without_blocking: {}", error); - warnln("ConnectionBase::read_as_much_as_possible_from_socket_without_blocking: {}", error); - VERIFY_NOT_REACHED(); - } - - auto bytes_read = maybe_bytes_read.release_value(); - if (bytes_read.is_empty()) { - schedule_shutdown(); - break; - } - - bytes.append(bytes_read.data(), bytes_read.size()); - for (auto const& fd : received_fds) - m_unprocessed_fds.enqueue(IPC::File::adopt_fd(fd)); - } + for (auto const& fd : received_fds) + m_unprocessed_fds.enqueue(IPC::File::adopt_fd(fd)); if (!bytes.is_empty()) { m_responsiveness_timer->stop(); @@ -198,7 +162,7 @@ ErrorOr> ConnectionBase::read_as_much_as_possible_from_socket_without ErrorOr ConnectionBase::drain_messages_from_peer() { - auto bytes = TRY(read_as_much_as_possible_from_socket_without_blocking()); + auto bytes = TRY(read_as_much_as_possible_from_transport_without_blocking()); size_t index = 0; try_parse_messages(bytes, index); @@ -236,10 +200,10 @@ OwnPtr ConnectionBase::wait_for_specific_endpoint_message_impl(u32 return m_unprocessed_messages.take(i); } - if (!m_socket->is_open()) + if (!is_open()) break; - wait_for_socket_to_become_readable(); + wait_for_transport_to_become_readable(); if (drain_messages_from_peer().is_error()) break; } diff --git a/Userland/Libraries/LibIPC/Connection.h b/Userland/Libraries/LibIPC/Connection.h index 982c8038106..229227c7c14 100644 --- a/Userland/Libraries/LibIPC/Connection.h +++ b/Userland/Libraries/LibIPC/Connection.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -30,10 +31,10 @@ public: void shutdown(); virtual void die() { } - Core::LocalSocket& socket() { return *m_socket; } + Transport& transport() { return m_transport; } protected: - explicit ConnectionBase(IPC::Stub&, NonnullOwnPtr, u32 local_endpoint_magic); + explicit ConnectionBase(IPC::Stub&, Transport, u32 local_endpoint_magic); virtual void may_have_become_unresponsive() { } virtual void did_become_responsive() { } @@ -41,8 +42,8 @@ protected: virtual OwnPtr try_parse_message(ReadonlyBytes, Queue&) = 0; OwnPtr wait_for_specific_endpoint_message_impl(u32 endpoint_magic, int message_id); - void wait_for_socket_to_become_readable(); - ErrorOr> read_as_much_as_possible_from_socket_without_blocking(); + void wait_for_transport_to_become_readable(); + ErrorOr> read_as_much_as_possible_from_transport_without_blocking(); ErrorOr drain_messages_from_peer(); void try_parse_messages(Vector const& bytes, size_t& index); @@ -51,7 +52,7 @@ protected: IPC::Stub& m_local_stub; - NonnullOwnPtr m_socket; + Transport m_transport; RefPtr m_responsiveness_timer; @@ -75,8 +76,8 @@ protected: template class Connection : public ConnectionBase { public: - Connection(IPC::Stub& local_stub, NonnullOwnPtr socket) - : ConnectionBase(local_stub, move(socket), LocalEndpoint::static_magic()) + Connection(IPC::Stub& local_stub, Transport transport) + : ConnectionBase(local_stub, move(transport), LocalEndpoint::static_magic()) { } diff --git a/Userland/Libraries/LibIPC/ConnectionFromClient.h b/Userland/Libraries/LibIPC/ConnectionFromClient.h index 41477699af2..dffc6218d41 100644 --- a/Userland/Libraries/LibIPC/ConnectionFromClient.h +++ b/Userland/Libraries/LibIPC/ConnectionFromClient.h @@ -26,16 +26,16 @@ public: using ServerStub = typename ServerEndpoint::Stub; using IPCProxy = typename ClientEndpoint::template Proxy; - ConnectionFromClient(ServerStub& stub, NonnullOwnPtr socket, int client_id) - : IPC::Connection(stub, move(socket)) + ConnectionFromClient(ServerStub& stub, Transport transport, int client_id) + : IPC::Connection(stub, move(transport)) , ClientEndpoint::template Proxy(*this, {}) , m_client_id(client_id) { - VERIFY(this->socket().is_open()); - this->socket().on_ready_to_read = [this] { + this->transport().set_up_read_hook([this] { + NonnullRefPtr protect = *this; // FIXME: Do something about errors. (void)this->drain_messages_from_peer(); - }; + }); } virtual ~ConnectionFromClient() override = default; diff --git a/Userland/Libraries/LibIPC/ConnectionToServer.h b/Userland/Libraries/LibIPC/ConnectionToServer.h index fd6c6eb18e6..a45d18171fe 100644 --- a/Userland/Libraries/LibIPC/ConnectionToServer.h +++ b/Userland/Libraries/LibIPC/ConnectionToServer.h @@ -11,18 +11,18 @@ namespace IPC { -#define IPC_CLIENT_CONNECTION(klass, socket_path) \ - C_OBJECT_ABSTRACT(klass) \ -public: \ - template \ - static ErrorOr> try_create(Args&&... args) \ - { \ - auto parsed_socket_path = TRY(Core::SessionManagement::parse_path_with_sid(socket_path)); \ - auto socket = TRY(Core::LocalSocket::connect(move(parsed_socket_path))); \ - /* We want to rate-limit our clients */ \ - TRY(socket->set_blocking(true)); \ - \ - return adopt_nonnull_ref_or_enomem(new (nothrow) Klass(move(socket), forward(args)...)); \ +#define IPC_CLIENT_CONNECTION(klass, socket_path) \ + C_OBJECT_ABSTRACT(klass) \ +public: \ + template \ + static ErrorOr> try_create(Args&&... args) \ + { \ + auto parsed_socket_path = TRY(Core::SessionManagement::parse_path_with_sid(socket_path)); \ + auto socket = TRY(Core::LocalSocket::connect(move(parsed_socket_path))); \ + /* We want to rate-limit our clients */ \ + TRY(socket->set_blocking(true)); \ + \ + return adopt_nonnull_ref_or_enomem(new (nothrow) Klass(IPC::Transport(move(socket)), forward(args)...)); \ } template @@ -33,8 +33,8 @@ public: using ClientStub = typename ClientEndpoint::Stub; using IPCProxy = typename ServerEndpoint::template Proxy; - ConnectionToServer(ClientStub& local_endpoint, NonnullOwnPtr socket) - : Connection(local_endpoint, move(socket)) + ConnectionToServer(ClientStub& local_endpoint, Transport transport) + : Connection(local_endpoint, move(transport)) , ServerEndpoint::template Proxy(*this, {}) { } diff --git a/Userland/Libraries/LibIPC/Message.cpp b/Userland/Libraries/LibIPC/Message.cpp index fb699a68230..58778e6ae87 100644 --- a/Userland/Libraries/LibIPC/Message.cpp +++ b/Userland/Libraries/LibIPC/Message.cpp @@ -5,10 +5,7 @@ */ #include -#include -#include #include -#include namespace IPC { @@ -38,7 +35,7 @@ ErrorOr MessageBuffer::append_file_descriptor(int fd) return {}; } -ErrorOr MessageBuffer::transfer_message(Core::LocalSocket& socket) +ErrorOr MessageBuffer::transfer_message(Transport& transport) { Checked checked_message_size { m_data.size() }; checked_message_size -= sizeof(MessageSizeType); @@ -58,49 +55,7 @@ ErrorOr MessageBuffer::transfer_message(Core::LocalSocket& socket) } } - ReadonlyBytes bytes_to_write { m_data.span() }; - - while (!bytes_to_write.is_empty()) { - ErrorOr maybe_nwritten = 0; - if (num_fds_to_transfer > 0) { - maybe_nwritten = socket.send_message(bytes_to_write, 0, raw_fds); - if (!maybe_nwritten.is_error()) - num_fds_to_transfer = 0; - } else { - maybe_nwritten = socket.write_some(bytes_to_write); - } - - if (maybe_nwritten.is_error()) { - if (auto error = maybe_nwritten.release_error(); error.is_errno() && (error.code() == EAGAIN || error.code() == EWOULDBLOCK)) { - Vector pollfds; - if (pollfds.is_empty()) - pollfds.append({ .fd = socket.fd().value(), .events = POLLOUT, .revents = 0 }); - - ErrorOr result { 0 }; - do { - constexpr u32 POLL_TIMEOUT_MS = 100; - result = Core::System::poll(pollfds, POLL_TIMEOUT_MS); - } while (result.is_error() && result.error().code() == EINTR); - - if (!result.is_error() && result.value() != 0) - continue; - - switch (error.code()) { - case EPIPE: - return Error::from_string_literal("IPC::transfer_message: Disconnected from peer"); - case EAGAIN: - return Error::from_string_literal("IPC::transfer_message: Timed out waiting for socket to become writable"); - default: - return Error::from_syscall("IPC::transfer_message write"sv, -error.code()); - } - } else { - return error; - } - } - - bytes_to_write = bytes_to_write.slice(maybe_nwritten.value()); - } - + TRY(transport.transfer(m_data.span(), raw_fds)); return {}; } diff --git a/Userland/Libraries/LibIPC/Message.h b/Userland/Libraries/LibIPC/Message.h index 7e977cce3b1..413cb03dde9 100644 --- a/Userland/Libraries/LibIPC/Message.h +++ b/Userland/Libraries/LibIPC/Message.h @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace IPC { @@ -44,7 +45,7 @@ public: ErrorOr append_file_descriptor(int fd); - ErrorOr transfer_message(Core::LocalSocket& socket); + ErrorOr transfer_message(Transport& socket); private: Vector m_data; diff --git a/Userland/Libraries/LibIPC/MultiServer.h b/Userland/Libraries/LibIPC/MultiServer.h index edba6384eee..b40f8f138f9 100644 --- a/Userland/Libraries/LibIPC/MultiServer.h +++ b/Userland/Libraries/LibIPC/MultiServer.h @@ -37,7 +37,7 @@ private: m_server->on_accept = [&](auto client_socket) { auto client_id = ++m_next_client_id; - auto client = IPC::new_client_connection(move(client_socket), client_id); + auto client = IPC::new_client_connection(IPC::Transport(move(client_socket)), client_id); if (on_new_client) on_new_client(*client); }; diff --git a/Userland/Libraries/LibIPC/SingleServer.h b/Userland/Libraries/LibIPC/SingleServer.h index 8ca5340f9a2..b25289dbad7 100644 --- a/Userland/Libraries/LibIPC/SingleServer.h +++ b/Userland/Libraries/LibIPC/SingleServer.h @@ -16,7 +16,7 @@ template ErrorOr> take_over_accepted_client_from_system_server() { auto socket = TRY(Core::take_over_socket_from_system_server()); - return IPC::new_client_connection(move(socket)); + return IPC::new_client_connection(IPC::Transport(move(socket))); } } diff --git a/Userland/Libraries/LibIPC/Transport.h b/Userland/Libraries/LibIPC/Transport.h new file mode 100644 index 00000000000..fdc063fc056 --- /dev/null +++ b/Userland/Libraries/LibIPC/Transport.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#if !defined(AK_OS_WINDOWS) +# include +#endif + +namespace IPC { + +#if !defined(AK_OS_WINDOWS) +// Unix Domain Sockets +using Transport = TransportSocket; +#else +# error "LibIPC Transport has not been ported to this platform" +#endif + +} diff --git a/Userland/Libraries/LibIPC/TransportSocket.cpp b/Userland/Libraries/LibIPC/TransportSocket.cpp new file mode 100644 index 00000000000..c9e92880024 --- /dev/null +++ b/Userland/Libraries/LibIPC/TransportSocket.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace IPC { + +TransportSocket::TransportSocket(NonnullOwnPtr socket) + : m_socket(move(socket)) +{ + socklen_t socket_buffer_size = 128 * KiB; + (void)Core::System::setsockopt(m_socket->fd().value(), SOL_SOCKET, SO_SNDBUF, &socket_buffer_size, sizeof(socket_buffer_size)); + (void)Core::System::setsockopt(m_socket->fd().value(), SOL_SOCKET, SO_RCVBUF, &socket_buffer_size, sizeof(socket_buffer_size)); +} + +TransportSocket::~TransportSocket() = default; + +void TransportSocket::set_up_read_hook(Function hook) +{ + VERIFY(m_socket->is_open()); + m_socket->on_ready_to_read = move(hook); +} + +bool TransportSocket::is_open() const +{ + return m_socket->is_open(); +} + +void TransportSocket::close() +{ + m_socket->close(); +} + +void TransportSocket::wait_until_readable() +{ + auto maybe_did_become_readable = m_socket->can_read_without_blocking(-1); + if (maybe_did_become_readable.is_error()) { + dbgln("TransportSocket::wait_until_readable: {}", maybe_did_become_readable.error()); + warnln("TransportSocket::wait_until_readable: {}", maybe_did_become_readable.error()); + VERIFY_NOT_REACHED(); + } + + VERIFY(maybe_did_become_readable.value()); +} + +ErrorOr TransportSocket::transfer(ReadonlyBytes bytes_to_write, Vector const& unowned_fds) +{ + auto num_fds_to_transfer = unowned_fds.size(); + while (!bytes_to_write.is_empty()) { + ErrorOr maybe_nwritten = 0; + if (num_fds_to_transfer > 0) { + maybe_nwritten = m_socket->send_message(bytes_to_write, 0, unowned_fds); + if (!maybe_nwritten.is_error()) + num_fds_to_transfer = 0; + } else { + maybe_nwritten = m_socket->write_some(bytes_to_write); + } + + if (maybe_nwritten.is_error()) { + if (auto error = maybe_nwritten.release_error(); error.is_errno() && (error.code() == EAGAIN || error.code() == EWOULDBLOCK)) { + + // FIXME: Refactor this to pass the unwritten bytes back to the caller to send 'later' + // or next time the socket is writable + Vector pollfds; + if (pollfds.is_empty()) + pollfds.append({ .fd = m_socket->fd().value(), .events = POLLOUT, .revents = 0 }); + + ErrorOr result { 0 }; + do { + constexpr u32 POLL_TIMEOUT_MS = 100; + result = Core::System::poll(pollfds, POLL_TIMEOUT_MS); + } while (result.is_error() && result.error().code() == EINTR); + + if (!result.is_error() && result.value() != 0) + continue; + + switch (error.code()) { + case EPIPE: + return Error::from_string_literal("IPC::transfer_message: Disconnected from peer"); + case EAGAIN: + return Error::from_string_literal("IPC::transfer_message: Timed out waiting for socket to become writable"); + default: + return Error::from_syscall("IPC::transfer_message write"sv, -error.code()); + } + } else { + return error; + } + } + + bytes_to_write = bytes_to_write.slice(maybe_nwritten.value()); + } + return {}; +} + +TransportSocket::ReadResult TransportSocket::read_as_much_as_possible_without_blocking(Function schedule_shutdown) +{ + u8 buffer[4096]; + + ReadResult result; + auto received_fds = Vector {}; + auto& bytes = result.bytes; + + while (is_open()) { + auto maybe_bytes_read = m_socket->receive_message({ buffer, 4096 }, MSG_DONTWAIT, received_fds); + if (maybe_bytes_read.is_error()) { + auto error = maybe_bytes_read.release_error(); + if (error.is_syscall() && error.code() == EAGAIN) { + break; + } + + if (error.is_syscall() && error.code() == ECONNRESET) { + schedule_shutdown(); + break; + } + + dbgln("TransportSocket::read_as_much_as_possible_without_blocking: {}", error); + warnln("TransportSocket::read_as_much_as_possible_without_blocking: {}", error); + VERIFY_NOT_REACHED(); + } + + auto bytes_read = maybe_bytes_read.release_value(); + if (bytes_read.is_empty()) { + schedule_shutdown(); + break; + } + + bytes.append(bytes_read.data(), bytes_read.size()); + result.fds.append(received_fds.data(), received_fds.size()); + } + + return result; +} + +ErrorOr TransportSocket::release_underlying_transport_for_transfer() +{ + return m_socket->release_fd(); +} + +ErrorOr TransportSocket::clone_for_transfer() +{ + return IPC::File::clone_fd(m_socket->fd().value()); +} + +} diff --git a/Userland/Libraries/LibIPC/TransportSocket.h b/Userland/Libraries/LibIPC/TransportSocket.h new file mode 100644 index 00000000000..f533cc5922e --- /dev/null +++ b/Userland/Libraries/LibIPC/TransportSocket.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace IPC { + +class TransportSocket { + AK_MAKE_NONCOPYABLE(TransportSocket); + AK_MAKE_DEFAULT_MOVABLE(TransportSocket); + +public: + explicit TransportSocket(NonnullOwnPtr socket); + ~TransportSocket(); + + void set_up_read_hook(Function); + bool is_open() const; + void close(); + + void wait_until_readable(); + + ErrorOr transfer(ReadonlyBytes, Vector const& unowned_fds); + + struct [[nodiscard]] ReadResult { + Vector bytes; + Vector fds; + }; + ReadResult read_as_much_as_possible_without_blocking(Function schedule_shutdown); + + // Obnoxious name to make it clear that this is a dangerous operation. + ErrorOr release_underlying_transport_for_transfer(); + + ErrorOr clone_for_transfer(); + +private: + NonnullOwnPtr m_socket; +}; + +} diff --git a/Userland/Libraries/LibImageDecoderClient/Client.cpp b/Userland/Libraries/LibImageDecoderClient/Client.cpp index e6595edb777..28ccbab3dc4 100644 --- a/Userland/Libraries/LibImageDecoderClient/Client.cpp +++ b/Userland/Libraries/LibImageDecoderClient/Client.cpp @@ -9,8 +9,8 @@ namespace ImageDecoderClient { -Client::Client(NonnullOwnPtr socket) - : IPC::ConnectionToServer(*this, move(socket)) +Client::Client(IPC::Transport transport) + : IPC::ConnectionToServer(*this, move(transport)) { } diff --git a/Userland/Libraries/LibImageDecoderClient/Client.h b/Userland/Libraries/LibImageDecoderClient/Client.h index 044b3de5d5b..0a0e46f3f53 100644 --- a/Userland/Libraries/LibImageDecoderClient/Client.h +++ b/Userland/Libraries/LibImageDecoderClient/Client.h @@ -32,7 +32,7 @@ class Client final IPC_CLIENT_CONNECTION(Client, "/tmp/session/%sid/portal/image"sv); public: - Client(NonnullOwnPtr); + Client(IPC::Transport); NonnullRefPtr> decode_image(ReadonlyBytes, Function(DecodedImage&)> on_resolved, Function on_rejected, Optional ideal_size = {}, Optional mime_type = {}); diff --git a/Userland/Libraries/LibRequests/RequestClient.cpp b/Userland/Libraries/LibRequests/RequestClient.cpp index 515d0871ff9..67805af5d3b 100644 --- a/Userland/Libraries/LibRequests/RequestClient.cpp +++ b/Userland/Libraries/LibRequests/RequestClient.cpp @@ -9,8 +9,8 @@ namespace Requests { -RequestClient::RequestClient(NonnullOwnPtr socket) - : IPC::ConnectionToServer(*this, move(socket)) +RequestClient::RequestClient(IPC::Transport transport) + : IPC::ConnectionToServer(*this, move(transport)) { } diff --git a/Userland/Libraries/LibRequests/RequestClient.h b/Userland/Libraries/LibRequests/RequestClient.h index bbb5029bdab..ba85737da99 100644 --- a/Userland/Libraries/LibRequests/RequestClient.h +++ b/Userland/Libraries/LibRequests/RequestClient.h @@ -24,7 +24,7 @@ class RequestClient final IPC_CLIENT_CONNECTION(RequestClient, "/tmp/session/%sid/portal/request"sv) public: - explicit RequestClient(NonnullOwnPtr); + explicit RequestClient(IPC::Transport); virtual ~RequestClient() override; RefPtr start_request(ByteString const& method, URL::URL const&, HTTP::HeaderMap const& request_headers = {}, ReadonlyBytes request_body = {}, Core::ProxyData const& = {}); diff --git a/Userland/Libraries/LibWeb/HTML/MessagePort.cpp b/Userland/Libraries/LibWeb/HTML/MessagePort.cpp index 90ec66b0af2..d98205ad02c 100644 --- a/Userland/Libraries/LibWeb/HTML/MessagePort.cpp +++ b/Userland/Libraries/LibWeb/HTML/MessagePort.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,11 @@ void MessagePort::visit_edges(Cell::Visitor& visitor) visitor.visit(m_worker_event_target); } +bool MessagePort::is_entangled() const +{ + return m_transport.has_value(); +} + void MessagePort::set_worker_event_target(JS::NonnullGCPtr target) { m_worker_event_target = target; @@ -91,10 +97,14 @@ WebIDL::ExceptionOr MessagePort::transfer_steps(HTML::TransferDataHolder& m_remote_port->m_has_been_shipped = true; // 2. Set dataHolder.[[RemotePort]] to remotePort. - auto fd = MUST(m_socket->release_fd()); - m_socket = nullptr; - data_holder.fds.append(IPC::File::adopt_fd(fd)); - data_holder.data.append(IPC_FILE_TAG); + if constexpr (IsSame) { + auto fd = MUST(m_transport->release_underlying_transport_for_transfer()); + m_transport = {}; + data_holder.fds.append(IPC::File::adopt_fd(fd)); + data_holder.data.append(IPC_FILE_TAG); + } else { + VERIFY(false && "Don't know how to transfer IPC::Transport type"); + } } // 4. Otherwise, set dataHolder.[[RemotePort]] to null. @@ -118,12 +128,16 @@ WebIDL::ExceptionOr MessagePort::transfer_receiving_steps(HTML::TransferDa // (This will disentangle dataHolder.[[RemotePort]] from the original port that was transferred.) auto fd_tag = data_holder.data.take_first(); if (fd_tag == IPC_FILE_TAG) { - auto fd = data_holder.fds.take_first(); - m_socket = MUST(Core::LocalSocket::adopt_fd(fd.take_fd())); + if constexpr (IsSame) { + auto fd = data_holder.fds.take_first(); + m_transport = IPC::Transport(MUST(Core::LocalSocket::adopt_fd(fd.take_fd()))); - m_socket->on_ready_to_read = [strong_this = JS::make_handle(this)]() { - strong_this->read_from_socket(); - }; + m_transport->set_up_read_hook([strong_this = JS::make_handle(this)]() { + strong_this->read_from_transport(); + }); + } else { + VERIFY(false && "Don't know how to receive IPC::Transport type"); + } } else if (fd_tag != 0) { dbgln("Unexpected byte {:x} in MessagePort transfer data", fd_tag); VERIFY_NOT_REACHED(); @@ -138,7 +152,7 @@ void MessagePort::disentangle() m_remote_port->m_remote_port = nullptr; m_remote_port = nullptr; - m_socket = nullptr; + m_transport = {}; m_worker_event_target = nullptr; } @@ -160,6 +174,7 @@ void MessagePort::entangle_with(MessagePort& remote_port) remote_port.m_remote_port = this; m_remote_port = &remote_port; + // FIXME: Abstract such that we can entangle different transport types auto create_paired_sockets = []() -> Array, 2> { int fds[2] = {}; MUST(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)); @@ -174,16 +189,16 @@ void MessagePort::entangle_with(MessagePort& remote_port) }; auto sockets = create_paired_sockets(); - m_socket = move(sockets[0]); - m_remote_port->m_socket = move(sockets[1]); + m_transport = IPC::Transport(move(sockets[0])); + m_remote_port->m_transport = IPC::Transport(move(sockets[1])); - m_socket->on_ready_to_read = [strong_this = JS::make_handle(this)]() { - strong_this->read_from_socket(); - }; + m_transport->set_up_read_hook([strong_this = JS::make_handle(this)]() { + strong_this->read_from_transport(); + }); - m_remote_port->m_socket->on_ready_to_read = [remote_port = JS::make_handle(m_remote_port)]() { - remote_port->read_from_socket(); - }; + m_remote_port->m_transport->set_up_read_hook([remote_port = JS::make_handle(m_remote_port)]() { + remote_port->read_from_transport(); + }); } // https://html.spec.whatwg.org/multipage/web-messaging.html#dom-messageport-postmessage-options @@ -243,7 +258,7 @@ WebIDL::ExceptionOr MessagePort::message_port_post_message_steps(JS::GCPtr // 6. If targetPort is null, or if doomed is true, then return. // IMPLEMENTATION DEFINED: Actually check the socket here, not the target port. // If there's no target message port in the same realm, we still want to send the message over IPC - if (!m_socket || doomed) { + if (!m_transport.has_value() || doomed) { return {}; } @@ -253,13 +268,13 @@ WebIDL::ExceptionOr MessagePort::message_port_post_message_steps(JS::GCPtr return {}; } -ErrorOr MessagePort::send_message_on_socket(SerializedTransferRecord const& serialize_with_transfer_result) +ErrorOr MessagePort::send_message_on_transport(SerializedTransferRecord const& serialize_with_transfer_result) { IPC::MessageBuffer buffer; IPC::Encoder encoder(buffer); MUST(encoder.encode(serialize_with_transfer_result)); - TRY(buffer.transfer_message(*m_socket)); + TRY(buffer.transfer_message(*m_transport)); return {}; } @@ -267,9 +282,9 @@ void MessagePort::post_port_message(SerializedTransferRecord serialize_with_tran { // FIXME: Use the correct task source? queue_global_task(Task::Source::PostedMessage, relevant_global_object(*this), JS::create_heap_function(heap(), [this, serialize_with_transfer_result = move(serialize_with_transfer_result)]() mutable { - if (!m_socket || !m_socket->is_open()) + if (!m_transport.has_value() || !m_transport->is_open()) return; - if (auto result = send_message_on_socket(serialize_with_transfer_result); result.is_error()) { + if (auto result = send_message_on_transport(serialize_with_transfer_result); result.is_error()) { dbgln("Failed to post message: {}", result.error()); disentangle(); } @@ -320,18 +335,13 @@ ErrorOr MessagePort::parse_message() return ParseDecision::ParseNextMessage; } -void MessagePort::read_from_socket() +void MessagePort::read_from_transport() { - u8 buffer[4096] {}; - - Vector fds; - // FIXME: What if pending bytes is > 4096? Should we loop here? - auto maybe_bytes = m_socket->receive_message(buffer, MSG_NOSIGNAL, fds); - if (maybe_bytes.is_error()) { - dbgln("MessagePort::read_from_socket(): Failed to receive message: {}", maybe_bytes.error()); - return; - } - auto bytes = maybe_bytes.release_value(); + auto&& [bytes, fds] = m_transport->read_as_much_as_possible_without_blocking([this] { + queue_global_task(Task::Source::PostedMessage, relevant_global_object(*this), JS::create_heap_function(heap(), [this] { + this->close(); + })); + }); m_buffered_data.append(bytes.data(), bytes.size()); @@ -406,7 +416,7 @@ void MessagePort::start() if (!is_entangled()) return; - VERIFY(m_socket); + VERIFY(m_transport.has_value()); // TODO: The start() method steps are to enable this's port message queue, if it is not already enabled. } diff --git a/Userland/Libraries/LibWeb/HTML/MessagePort.h b/Userland/Libraries/LibWeb/HTML/MessagePort.h index 40c81b55695..a170219e717 100644 --- a/Userland/Libraries/LibWeb/HTML/MessagePort.h +++ b/Userland/Libraries/LibWeb/HTML/MessagePort.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -69,13 +70,13 @@ private: virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; - bool is_entangled() const { return static_cast(m_socket); } + bool is_entangled() const; WebIDL::ExceptionOr message_port_post_message_steps(JS::GCPtr target_port, JS::Value message, StructuredSerializeOptions const& options); void post_message_task_steps(SerializedTransferRecord&); void post_port_message(SerializedTransferRecord); - ErrorOr send_message_on_socket(SerializedTransferRecord const&); - void read_from_socket(); + ErrorOr send_message_on_transport(SerializedTransferRecord const&); + void read_from_transport(); enum class ParseDecision { NotEnoughData, @@ -89,7 +90,7 @@ private: // https://html.spec.whatwg.org/multipage/web-messaging.html#has-been-shipped bool m_has_been_shipped { false }; - OwnPtr m_socket; + Optional m_transport; enum class SocketState : u8 { Header, diff --git a/Userland/Libraries/LibWeb/HTML/WorkerAgent.cpp b/Userland/Libraries/LibWeb/HTML/WorkerAgent.cpp index b418787e565..bbb37555323 100644 --- a/Userland/Libraries/LibWeb/HTML/WorkerAgent.cpp +++ b/Userland/Libraries/LibWeb/HTML/WorkerAgent.cpp @@ -35,10 +35,14 @@ void WorkerAgent::initialize(JS::Realm& realm) // NOTE: This blocking IPC call may launch another process. // If spinning the event loop for this can cause other javascript to execute, we're in trouble. auto worker_socket_file = Bindings::host_defined_page(realm).client().request_worker_agent(); + auto worker_socket = MUST(Core::LocalSocket::adopt_fd(worker_socket_file.take_fd())); MUST(worker_socket->set_blocking(true)); + static_assert(IsSame, "Handle other IPC::Transport types here"); - m_worker_ipc = make_ref_counted(move(worker_socket)); + auto transport = IPC::Transport(move(worker_socket)); + + m_worker_ipc = make_ref_counted(move(transport)); m_worker_ipc->async_start_dedicated_worker(m_url, m_worker_options.type, m_worker_options.credentials, m_worker_options.name, move(data_holder), m_outside_settings->serialize()); } diff --git a/Userland/Libraries/LibWeb/Worker/WebWorkerClient.cpp b/Userland/Libraries/LibWeb/Worker/WebWorkerClient.cpp index e4cf5c743ef..2b501db7527 100644 --- a/Userland/Libraries/LibWeb/Worker/WebWorkerClient.cpp +++ b/Userland/Libraries/LibWeb/Worker/WebWorkerClient.cpp @@ -20,14 +20,14 @@ void WebWorkerClient::did_close_worker() on_worker_close(); } -WebWorkerClient::WebWorkerClient(NonnullOwnPtr socket) - : IPC::ConnectionToServer(*this, move(socket)) +WebWorkerClient::WebWorkerClient(IPC::Transport transport) + : IPC::ConnectionToServer(*this, move(transport)) { } -IPC::File WebWorkerClient::dup_socket() +IPC::File WebWorkerClient::clone_transport() { - return MUST(IPC::File::clone_fd(socket().fd().value())); + return MUST(m_transport.clone_for_transfer()); } } diff --git a/Userland/Libraries/LibWeb/Worker/WebWorkerClient.h b/Userland/Libraries/LibWeb/Worker/WebWorkerClient.h index 9600ce00965..540904e0bf9 100644 --- a/Userland/Libraries/LibWeb/Worker/WebWorkerClient.h +++ b/Userland/Libraries/LibWeb/Worker/WebWorkerClient.h @@ -19,13 +19,13 @@ class WebWorkerClient final IPC_CLIENT_CONNECTION(WebWorkerClient, "/tmp/session/%sid/portal/webworker"sv); public: - explicit WebWorkerClient(NonnullOwnPtr); + explicit WebWorkerClient(IPC::Transport); virtual void did_close_worker() override; Function on_worker_close; - IPC::File dup_socket(); + IPC::File clone_transport(); private: virtual void die() override; diff --git a/Userland/Libraries/LibWebView/ChromeProcess.cpp b/Userland/Libraries/LibWebView/ChromeProcess.cpp index 9a34091bb02..dac57631786 100644 --- a/Userland/Libraries/LibWebView/ChromeProcess.cpp +++ b/Userland/Libraries/LibWebView/ChromeProcess.cpp @@ -22,7 +22,7 @@ class UIProcessClient final C_OBJECT(UIProcessClient); private: - UIProcessClient(NonnullOwnPtr); + explicit UIProcessClient(IPC::Transport); }; ErrorOr ChromeProcess::connect(Vector const& raw_urls, NewWindow new_window) @@ -48,7 +48,8 @@ ErrorOr ChromeProcess::connect(Vector ChromeProcess::connect_as_client(ByteString const& socket_path, Vector const& raw_urls, NewWindow new_window) { auto socket = TRY(Core::LocalSocket::connect(socket_path)); - auto client = UIProcessClient::construct(move(socket)); + static_assert(IsSame, "Need to handle other IPC transports here"); + auto client = UIProcessClient::construct(IPC::Transport(move(socket))); if (new_window == NewWindow::Yes) { if (!client->send_sync_but_allow_failure(raw_urls)) @@ -63,10 +64,13 @@ ErrorOr ChromeProcess::connect_as_client(ByteString const& socket_path, Ve ErrorOr ChromeProcess::connect_as_server(ByteString const& socket_path) { + static_assert(IsSame, "Need to handle other IPC transports here"); + auto socket_fd = TRY(Process::create_ipc_socket(socket_path)); m_socket_path = socket_path; auto local_server = TRY(Core::LocalServer::try_create()); TRY(local_server->take_over_fd(socket_fd)); + m_server_connection = TRY(IPC::MultiServer::try_create(move(local_server))); m_server_connection->on_new_client = [this](auto& client) { @@ -95,13 +99,13 @@ ChromeProcess::~ChromeProcess() MUST(Core::System::unlink(m_socket_path)); } -UIProcessClient::UIProcessClient(NonnullOwnPtr socket) - : IPC::ConnectionToServer(*this, move(socket)) +UIProcessClient::UIProcessClient(IPC::Transport transport) + : IPC::ConnectionToServer(*this, move(transport)) { } -UIProcessConnectionFromClient::UIProcessConnectionFromClient(NonnullOwnPtr socket, int client_id) - : IPC::ConnectionFromClient(*this, move(socket), client_id) +UIProcessConnectionFromClient::UIProcessConnectionFromClient(IPC::Transport transport, int client_id) + : IPC::ConnectionFromClient(*this, move(transport), client_id) { s_connections.set(client_id, *this); } diff --git a/Userland/Libraries/LibWebView/ChromeProcess.h b/Userland/Libraries/LibWebView/ChromeProcess.h index 3a3b4adaefd..1fb5da57f50 100644 --- a/Userland/Libraries/LibWebView/ChromeProcess.h +++ b/Userland/Libraries/LibWebView/ChromeProcess.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -33,7 +32,7 @@ public: Function const&)> on_new_window; private: - UIProcessConnectionFromClient(NonnullOwnPtr, int client_id); + UIProcessConnectionFromClient(IPC::Transport, int client_id); virtual void create_new_tab(Vector const& urls) override; virtual void create_new_window(Vector const& urls) override; diff --git a/Userland/Libraries/LibWebView/Process.cpp b/Userland/Libraries/LibWebView/Process.cpp index d59a3193140..e5ba8ebd6d9 100644 --- a/Userland/Libraries/LibWebView/Process.cpp +++ b/Userland/Libraries/LibWebView/Process.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -24,8 +25,10 @@ Process::~Process() m_connection->shutdown(); } -ErrorOr Process::spawn_and_connect_to_process(Core::ProcessSpawnOptions const& options) +ErrorOr Process::spawn_and_connect_to_process(Core::ProcessSpawnOptions const& options) { + static_assert(IsSame, "Need to handle other IPC transports here"); + int socket_fds[2] {}; TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); @@ -44,7 +47,7 @@ ErrorOr Process::spawn_and_connect_to_process(Core guard_fd_0.disarm(); TRY(ipc_socket->set_blocking(true)); - return ProcessAndIPCSocket { move(process), move(ipc_socket) }; + return ProcessAndIPCTransport { move(process), IPC::Transport(move(ipc_socket)) }; } ErrorOr> Process::get_process_pid(StringView process_name, StringView pid_path) diff --git a/Userland/Libraries/LibWebView/Process.h b/Userland/Libraries/LibWebView/Process.h index 7254a1a5379..399f955fbcb 100644 --- a/Userland/Libraries/LibWebView/Process.h +++ b/Userland/Libraries/LibWebView/Process.h @@ -9,8 +9,8 @@ #include #include #include -#include #include +#include #include namespace WebView { @@ -52,11 +52,11 @@ public: static ErrorOr create_ipc_socket(ByteString const& socket_path); private: - struct ProcessAndIPCSocket { + struct ProcessAndIPCTransport { Core::Process process; - NonnullOwnPtr socket; + IPC::Transport transport; }; - static ErrorOr spawn_and_connect_to_process(Core::ProcessSpawnOptions const& options); + static ErrorOr spawn_and_connect_to_process(Core::ProcessSpawnOptions const& options); Core::Process m_process; ProcessType m_type; @@ -73,8 +73,8 @@ struct Process::ProcessAndClient { template ErrorOr> Process::spawn(ProcessType type, Core::ProcessSpawnOptions const& options, ClientArguments&&... client_arguments) { - auto [core_process, socket] = TRY(spawn_and_connect_to_process(options)); - auto client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) ClientType { move(socket), forward(client_arguments)... })); + auto [core_process, transport] = TRY(spawn_and_connect_to_process(options)); + auto client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) ClientType { move(transport), forward(client_arguments)... })); return ProcessAndClient { Process { type, client, move(core_process) }, client }; } diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index 0ad1723ce32..b447a074804 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -23,8 +23,8 @@ Optional WebContentClient::view_for_pid_and_page_id(pid_t p return {}; } -WebContentClient::WebContentClient(NonnullOwnPtr socket, ViewImplementation& view) - : IPC::ConnectionToServer(*this, move(socket)) +WebContentClient::WebContentClient(IPC::Transport transport, ViewImplementation& view) + : IPC::ConnectionToServer(*this, move(transport)) { s_clients.set(this); m_views.set(0, &view); diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h index c26373d4fe1..bb101687446 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.h +++ b/Userland/Libraries/LibWebView/WebContentClient.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,7 @@ public: static size_t client_count() { return s_clients.size(); } - WebContentClient(NonnullOwnPtr, ViewImplementation&); + WebContentClient(IPC::Transport, ViewImplementation&); ~WebContentClient(); void register_view(u64 page_id, ViewImplementation&); diff --git a/Userland/Services/ImageDecoder/ConnectionFromClient.cpp b/Userland/Services/ImageDecoder/ConnectionFromClient.cpp index a9218ea4519..164dc09ab6d 100644 --- a/Userland/Services/ImageDecoder/ConnectionFromClient.cpp +++ b/Userland/Services/ImageDecoder/ConnectionFromClient.cpp @@ -17,8 +17,8 @@ namespace ImageDecoder { static HashMap> s_connections; static IDAllocator s_client_ids; -ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr socket) - : IPC::ConnectionFromClient(*this, move(socket), s_client_ids.allocate()) +ConnectionFromClient::ConnectionFromClient(IPC::Transport transport) + : IPC::ConnectionFromClient(*this, move(transport), s_client_ids.allocate()) { s_connections.set(client_id(), *this); } @@ -55,7 +55,7 @@ ErrorOr ConnectionFromClient::connect_new_client() auto client_socket = client_socket_or_error.release_value(); // Note: A ref is stored in the static s_connections map - auto client = adopt_ref(*new ConnectionFromClient(move(client_socket))); + auto client = adopt_ref(*new ConnectionFromClient(IPC::Transport(move(client_socket)))); return IPC::File::adopt_fd(socket_fds[1]); } diff --git a/Userland/Services/ImageDecoder/ConnectionFromClient.h b/Userland/Services/ImageDecoder/ConnectionFromClient.h index 1f260a2593c..380a995363f 100644 --- a/Userland/Services/ImageDecoder/ConnectionFromClient.h +++ b/Userland/Services/ImageDecoder/ConnectionFromClient.h @@ -36,7 +36,7 @@ public: private: using Job = Threading::BackgroundAction; - explicit ConnectionFromClient(NonnullOwnPtr); + explicit ConnectionFromClient(IPC::Transport); virtual Messages::ImageDecoderServer::DecodeImageResponse decode_image(Core::AnonymousBuffer const&, Optional const& ideal_size, Optional const& mime_type) override; virtual void cancel_decoding(i64 image_id) override; diff --git a/Userland/Services/RequestServer/ConnectionFromClient.cpp b/Userland/Services/RequestServer/ConnectionFromClient.cpp index c8ef6ce7e4a..fb8823c18e1 100644 --- a/Userland/Services/RequestServer/ConnectionFromClient.cpp +++ b/Userland/Services/RequestServer/ConnectionFromClient.cpp @@ -175,8 +175,8 @@ int ConnectionFromClient::on_timeout_callback(void*, long timeout_ms, void* user return 0; } -ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr socket) - : IPC::ConnectionFromClient(*this, move(socket), s_client_ids.allocate()) +ConnectionFromClient::ConnectionFromClient(IPC::Transport transport) + : IPC::ConnectionFromClient(*this, move(transport), s_client_ids.allocate()) { s_connections.set(client_id(), *this); @@ -215,6 +215,8 @@ void ConnectionFromClient::die() Messages::RequestServer::ConnectNewClientResponse ConnectionFromClient::connect_new_client() { + static_assert(IsSame, "Need to handle other IPC transports here"); + int socket_fds[2] {}; if (auto err = Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds); err.is_error()) { dbgln("Failed to create client socketpair: {}", err.error()); @@ -230,7 +232,7 @@ Messages::RequestServer::ConnectNewClientResponse ConnectionFromClient::connect_ } auto client_socket = client_socket_or_error.release_value(); // Note: A ref is stored in the static s_connections map - auto client = adopt_ref(*new ConnectionFromClient(move(client_socket))); + auto client = adopt_ref(*new ConnectionFromClient(IPC::Transport(move(client_socket)))); return IPC::File::adopt_fd(socket_fds[1]); } diff --git a/Userland/Services/RequestServer/ConnectionFromClient.h b/Userland/Services/RequestServer/ConnectionFromClient.h index e18667d6e28..7846a379455 100644 --- a/Userland/Services/RequestServer/ConnectionFromClient.h +++ b/Userland/Services/RequestServer/ConnectionFromClient.h @@ -30,7 +30,7 @@ public: void did_request_certificates(Badge, Request&); private: - explicit ConnectionFromClient(NonnullOwnPtr); + explicit ConnectionFromClient(IPC::Transport); virtual Messages::RequestServer::ConnectNewClientResponse connect_new_client() override; virtual Messages::RequestServer::IsSupportedProtocolResponse is_supported_protocol(ByteString const&) override; diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index 5f313b0a31e..c3c15d02778 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -53,8 +53,8 @@ namespace WebContent { -ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr socket) - : IPC::ConnectionFromClient(*this, move(socket), 1) +ConnectionFromClient::ConnectionFromClient(IPC::Transport transport) + : IPC::ConnectionFromClient(*this, move(transport), 1) , m_page_host(PageHost::create(*this)) { m_input_event_queue_timer = Web::Platform::Timer::create_single_shot(0, [this] { process_next_input_event(); }); diff --git a/Userland/Services/WebContent/ConnectionFromClient.h b/Userland/Services/WebContent/ConnectionFromClient.h index 7a37a5e3498..9b00c77ac30 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.h +++ b/Userland/Services/WebContent/ConnectionFromClient.h @@ -42,15 +42,13 @@ public: void request_file(u64 page_id, Web::FileRequest); - Optional fd() { return socket().fd(); } - PageHost& page_host() { return *m_page_host; } PageHost const& page_host() const { return *m_page_host; } Function on_image_decoder_connection; private: - explicit ConnectionFromClient(NonnullOwnPtr); + explicit ConnectionFromClient(IPC::Transport); Optional page(u64 index, SourceLocation = SourceLocation::current()); Optional page(u64 index, SourceLocation = SourceLocation::current()) const; diff --git a/Userland/Services/WebContent/WebDriverConnection.cpp b/Userland/Services/WebContent/WebDriverConnection.cpp index e0a58f1cc60..7a06300c919 100644 --- a/Userland/Services/WebContent/WebDriverConnection.cpp +++ b/Userland/Services/WebContent/WebDriverConnection.cpp @@ -184,6 +184,8 @@ static bool fire_an_event(FlyString name, Optional target) ErrorOr> WebDriverConnection::connect(Web::PageClient& page_client, ByteString const& webdriver_ipc_path) { + static_assert(IsSame, "Need to handle other IPC transports here"); + dbgln_if(WEBDRIVER_DEBUG, "Trying to connect to {}", webdriver_ipc_path); auto socket = TRY(Core::LocalSocket::connect(webdriver_ipc_path)); @@ -191,11 +193,11 @@ ErrorOr> WebDriverConnection::connect(Web::Pa page_client.page().set_should_block_pop_ups(false); dbgln_if(WEBDRIVER_DEBUG, "Connected to WebDriver"); - return adopt_nonnull_ref_or_enomem(new (nothrow) WebDriverConnection(move(socket), page_client)); + return adopt_nonnull_ref_or_enomem(new (nothrow) WebDriverConnection(IPC::Transport(move(socket)), page_client)); } -WebDriverConnection::WebDriverConnection(NonnullOwnPtr socket, Web::PageClient& page_client) - : IPC::ConnectionToServer(*this, move(socket)) +WebDriverConnection::WebDriverConnection(IPC::Transport transport, Web::PageClient& page_client) + : IPC::ConnectionToServer(*this, move(transport)) { set_current_top_level_browsing_context(page_client.page().top_level_browsing_context()); } diff --git a/Userland/Services/WebContent/WebDriverConnection.h b/Userland/Services/WebContent/WebDriverConnection.h index 2d8592dda91..beef698ff97 100644 --- a/Userland/Services/WebContent/WebDriverConnection.h +++ b/Userland/Services/WebContent/WebDriverConnection.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,7 @@ public: void visit_edges(JS::Cell::Visitor&); private: - WebDriverConnection(NonnullOwnPtr socket, Web::PageClient& page_client); + WebDriverConnection(IPC::Transport transport, Web::PageClient& page_client); virtual void die() override { } diff --git a/Userland/Services/WebDriver/Session.cpp b/Userland/Services/WebDriver/Session.cpp index 1088c3e97d3..0a4086dda07 100644 --- a/Userland/Services/WebDriver/Session.cpp +++ b/Userland/Services/WebDriver/Session.cpp @@ -56,6 +56,8 @@ Session::~Session() ErrorOr> Session::create_server(NonnullRefPtr promise) { + static_assert(IsSame, "Need to handle other IPC transports here"); + dbgln("Listening for WebDriver connection on {}", *m_web_content_socket_path); (void)Core::System::unlink(*m_web_content_socket_path); @@ -64,7 +66,7 @@ ErrorOr> Session::create_server(NonnullRefPtrlisten(*m_web_content_socket_path); server->on_accept = [this, promise](auto client_socket) { - auto maybe_connection = adopt_nonnull_ref_or_enomem(new (nothrow) WebContentConnection(move(client_socket))); + auto maybe_connection = adopt_nonnull_ref_or_enomem(new (nothrow) WebContentConnection(IPC::Transport(move(client_socket)))); if (maybe_connection.is_error()) { promise->resolve(maybe_connection.release_error()); return; diff --git a/Userland/Services/WebDriver/WebContentConnection.cpp b/Userland/Services/WebDriver/WebContentConnection.cpp index 2d84edcc2d0..823252ab714 100644 --- a/Userland/Services/WebDriver/WebContentConnection.cpp +++ b/Userland/Services/WebDriver/WebContentConnection.cpp @@ -9,8 +9,8 @@ namespace WebDriver { -WebContentConnection::WebContentConnection(NonnullOwnPtr socket) - : IPC::ConnectionFromClient(*this, move(socket), 1) +WebContentConnection::WebContentConnection(IPC::Transport transport) + : IPC::ConnectionFromClient(*this, move(transport), 1) { } diff --git a/Userland/Services/WebDriver/WebContentConnection.h b/Userland/Services/WebDriver/WebContentConnection.h index 01b4b201fb0..cac9ce3fd1f 100644 --- a/Userland/Services/WebDriver/WebContentConnection.h +++ b/Userland/Services/WebDriver/WebContentConnection.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include @@ -18,7 +19,7 @@ class WebContentConnection : public IPC::ConnectionFromClient { C_OBJECT_ABSTRACT(WebContentConnection) public: - WebContentConnection(NonnullOwnPtr socket); + explicit WebContentConnection(IPC::Transport transport); Function on_close; Function on_script_executed; diff --git a/Userland/Services/WebWorker/ConnectionFromClient.cpp b/Userland/Services/WebWorker/ConnectionFromClient.cpp index 3ecaceb4f49..79aef848884 100644 --- a/Userland/Services/WebWorker/ConnectionFromClient.cpp +++ b/Userland/Services/WebWorker/ConnectionFromClient.cpp @@ -45,8 +45,8 @@ void ConnectionFromClient::request_file(Web::FileRequest request) handle_file_return(0, IPC::File::adopt_file(file.release_value()), request_id); } -ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr socket) - : IPC::ConnectionFromClient(*this, move(socket), 1) +ConnectionFromClient::ConnectionFromClient(IPC::Transport transport) + : IPC::ConnectionFromClient(*this, move(transport), 1) , m_page_host(PageHost::create(Web::Bindings::main_thread_vm(), *this)) { } diff --git a/Userland/Services/WebWorker/ConnectionFromClient.h b/Userland/Services/WebWorker/ConnectionFromClient.h index 3fa2f64aaf9..77aa66dea32 100644 --- a/Userland/Services/WebWorker/ConnectionFromClient.h +++ b/Userland/Services/WebWorker/ConnectionFromClient.h @@ -36,7 +36,7 @@ public: PageHost const& page_host() const { return *m_page_host; } private: - explicit ConnectionFromClient(NonnullOwnPtr); + explicit ConnectionFromClient(IPC::Transport); Web::Page& page(); Web::Page const& page() const;