From 9a6eccc590450b695289c8066dca99e1eabf223c Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Tue, 22 Oct 2024 13:27:15 -0600 Subject: [PATCH] LibWebView+LibCore: Move IPCProcess into WebView::Process Ladybird's HelperProcess.cpp was the only user of the IPCProcess class. Moving the helper class from LibCore allows for some more interesting LibIPC changes in the upcoming commits. --- Ladybird/HelperProcess.cpp | 12 +-- Userland/Libraries/LibCore/Process.cpp | 100 ------------------ Userland/Libraries/LibCore/Process.h | 42 -------- .../Libraries/LibWebView/ChromeProcess.cpp | 6 +- Userland/Libraries/LibWebView/Process.cpp | 99 +++++++++++++++++ Userland/Libraries/LibWebView/Process.h | 36 +++++++ 6 files changed, 144 insertions(+), 151 deletions(-) diff --git a/Ladybird/HelperProcess.cpp b/Ladybird/HelperProcess.cpp index ced86e92be9..c1791981c64 100644 --- a/Ladybird/HelperProcess.cpp +++ b/Ladybird/HelperProcess.cpp @@ -42,15 +42,15 @@ static ErrorOr> launch_server_process( options.executable = path; } - auto result = Core::IPCProcess::spawn(move(options), forward(client_arguments)...); + auto result = WebView::Process::spawn(process_type, move(options), forward(client_arguments)...); if (!result.is_error()) { - auto process = result.release_value(); + auto&& [process, client] = result.release_value(); - if constexpr (requires { process.client->set_pid(pid_t {}); }) - process.client->set_pid(process.process.pid()); + if constexpr (requires { client->set_pid(pid_t {}); }) + client->set_pid(process.pid()); - WebView::Application::the().add_child_process(WebView::Process { process_type, process.client, move(process.process) }); + WebView::Application::the().add_child_process(move(process)); if (chrome_options.profile_helper_process == process_type) { dbgln(); @@ -59,7 +59,7 @@ static ErrorOr> launch_server_process( dbgln(); } - return move(process.client); + return move(client); } if (i == candidate_server_paths.size() - 1) { diff --git a/Userland/Libraries/LibCore/Process.cpp b/Userland/Libraries/LibCore/Process.cpp index ff92db822d4..f8efdc6abf8 100644 --- a/Userland/Libraries/LibCore/Process.cpp +++ b/Userland/Libraries/LibCore/Process.cpp @@ -14,9 +14,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -363,101 +360,4 @@ ErrorOr Process::wait_for_termination() return exited_with_code_0; } -ErrorOr IPCProcess::spawn_and_connect_to_process(ProcessSpawnOptions const& options) -{ - int socket_fds[2] {}; - TRY(System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); - - ArmedScopeGuard guard_fd_0 { [&] { MUST(System::close(socket_fds[0])); } }; - ArmedScopeGuard guard_fd_1 { [&] { MUST(System::close(socket_fds[1])); } }; - - auto& file_actions = const_cast(options).file_actions; - file_actions.append(FileAction::CloseFile { socket_fds[0] }); - - auto takeover_string = MUST(String::formatted("{}:{}", options.name, socket_fds[1])); - TRY(Environment::set("SOCKET_TAKEOVER"sv, takeover_string, Environment::Overwrite::Yes)); - - auto process = TRY(Process::spawn(options)); - - auto ipc_socket = TRY(LocalSocket::adopt_fd(socket_fds[0])); - guard_fd_0.disarm(); - TRY(ipc_socket->set_blocking(true)); - - return ProcessAndIPCSocket { move(process), move(ipc_socket) }; -} - -ErrorOr> IPCProcess::get_process_pid(StringView process_name, StringView pid_path) -{ - if (System::stat(pid_path).is_error()) - return OptionalNone {}; - - Optional pid; - { - auto pid_file = File::open(pid_path, File::OpenMode::Read); - if (pid_file.is_error()) { - warnln("Could not open {} PID file '{}': {}", process_name, pid_path, pid_file.error()); - return pid_file.release_error(); - } - - auto contents = pid_file.value()->read_until_eof(); - if (contents.is_error()) { - warnln("Could not read {} PID file '{}': {}", process_name, pid_path, contents.error()); - return contents.release_error(); - } - - pid = StringView { contents.value() }.to_number(); - } - - if (!pid.has_value()) { - warnln("{} PID file '{}' exists, but with an invalid PID", process_name, pid_path); - TRY(System::unlink(pid_path)); - return OptionalNone {}; - } - if (kill(*pid, 0) < 0) { - warnln("{} PID file '{}' exists with PID {}, but process cannot be found", process_name, pid_path, *pid); - TRY(System::unlink(pid_path)); - return OptionalNone {}; - } - - return pid; -} - -// This is heavily based on how SystemServer's Service creates its socket. -ErrorOr IPCProcess::create_ipc_socket(ByteString const& socket_path) -{ - if (!System::stat(socket_path).is_error()) - TRY(System::unlink(socket_path)); - -#ifdef SOCK_NONBLOCK - auto socket_fd = TRY(System::socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)); -#else - auto socket_fd = TRY(System::socket(AF_LOCAL, SOCK_STREAM, 0)); - - int option = 1; - TRY(System::ioctl(socket_fd, FIONBIO, &option)); - TRY(System::fcntl(socket_fd, F_SETFD, FD_CLOEXEC)); -#endif - -#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_GNU_HURD) - TRY(System::fchmod(socket_fd, 0600)); -#endif - - auto socket_address = SocketAddress::local(socket_path); - auto socket_address_un = socket_address.to_sockaddr_un().release_value(); - - TRY(System::bind(socket_fd, reinterpret_cast(&socket_address_un), sizeof(socket_address_un))); - TRY(System::listen(socket_fd, 16)); - - return socket_fd; -} - -ErrorOr IPCProcess::paths_for_process(StringView process_name) -{ - auto runtime_directory = TRY(StandardPaths::runtime_directory()); - auto socket_path = ByteString::formatted("{}/{}.socket", runtime_directory, process_name); - auto pid_path = ByteString::formatted("{}/{}.pid", runtime_directory, process_name); - - return ProcessPaths { move(socket_path), move(pid_path) }; -} - } diff --git a/Userland/Libraries/LibCore/Process.h b/Userland/Libraries/LibCore/Process.h index 7b1474ed86d..144aab88274 100644 --- a/Userland/Libraries/LibCore/Process.h +++ b/Userland/Libraries/LibCore/Process.h @@ -13,7 +13,6 @@ #include #include #include -#include namespace Core { @@ -45,8 +44,6 @@ struct ProcessSpawnOptions { Vector file_actions {}; }; -class IPCProcess; - class Process { AK_MAKE_NONCOPYABLE(Process); @@ -102,8 +99,6 @@ public: ErrorOr wait_for_termination(); private: - friend IPCProcess; - Process(pid_t pid) : m_pid(pid) , m_should_disown(true) @@ -114,41 +109,4 @@ private: bool m_should_disown; }; -class IPCProcess { -public: - template - struct ProcessAndIPCClient { - Process process; - NonnullRefPtr client; - }; - - template - static ErrorOr> spawn(ProcessSpawnOptions const& options, ClientArguments&&... client_arguments) - { - auto [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)... })); - - return ProcessAndIPCClient { move(process), move(client) }; - } - - struct ProcessPaths { - ByteString socket_path; - ByteString pid_path; - }; - static ErrorOr paths_for_process(StringView process_name); - static ErrorOr> get_process_pid(StringView process_name, StringView pid_path); - static ErrorOr create_ipc_socket(ByteString const& socket_path); - - pid_t pid() const { return m_process.pid(); } - -private: - struct ProcessAndIPCSocket { - Process process; - NonnullOwnPtr m_ipc_socket; - }; - static ErrorOr spawn_and_connect_to_process(ProcessSpawnOptions const& options); - - Process m_process; -}; - } diff --git a/Userland/Libraries/LibWebView/ChromeProcess.cpp b/Userland/Libraries/LibWebView/ChromeProcess.cpp index c02101fa427..9a34091bb02 100644 --- a/Userland/Libraries/LibWebView/ChromeProcess.cpp +++ b/Userland/Libraries/LibWebView/ChromeProcess.cpp @@ -29,9 +29,9 @@ ErrorOr ChromeProcess::connect(Vector ChromeProcess::connect_as_client(ByteString const& socket_path, Ve ErrorOr ChromeProcess::connect_as_server(ByteString const& socket_path) { - auto socket_fd = TRY(Core::IPCProcess::create_ipc_socket(socket_path)); + 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)); diff --git a/Userland/Libraries/LibWebView/Process.cpp b/Userland/Libraries/LibWebView/Process.cpp index 49ff8480d73..d59a3193140 100644 --- a/Userland/Libraries/LibWebView/Process.cpp +++ b/Userland/Libraries/LibWebView/Process.cpp @@ -4,7 +4,9 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include +#include #include namespace WebView { @@ -22,4 +24,101 @@ Process::~Process() m_connection->shutdown(); } +ErrorOr Process::spawn_and_connect_to_process(Core::ProcessSpawnOptions const& options) +{ + int socket_fds[2] {}; + TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); + + ArmedScopeGuard guard_fd_0 { [&] { MUST(Core::System::close(socket_fds[0])); } }; + ArmedScopeGuard guard_fd_1 { [&] { MUST(Core::System::close(socket_fds[1])); } }; + + auto& file_actions = const_cast(options).file_actions; + file_actions.append(Core::FileAction::CloseFile { socket_fds[0] }); + + auto takeover_string = MUST(String::formatted("{}:{}", options.name, socket_fds[1])); + TRY(Core::Environment::set("SOCKET_TAKEOVER"sv, takeover_string, Core::Environment::Overwrite::Yes)); + + auto process = TRY(Core::Process::spawn(options)); + + auto ipc_socket = TRY(Core::LocalSocket::adopt_fd(socket_fds[0])); + guard_fd_0.disarm(); + TRY(ipc_socket->set_blocking(true)); + + return ProcessAndIPCSocket { move(process), move(ipc_socket) }; +} + +ErrorOr> Process::get_process_pid(StringView process_name, StringView pid_path) +{ + if (Core::System::stat(pid_path).is_error()) + return OptionalNone {}; + + Optional pid; + { + auto pid_file = Core::File::open(pid_path, Core::File::OpenMode::Read); + if (pid_file.is_error()) { + warnln("Could not open {} PID file '{}': {}", process_name, pid_path, pid_file.error()); + return pid_file.release_error(); + } + + auto contents = pid_file.value()->read_until_eof(); + if (contents.is_error()) { + warnln("Could not read {} PID file '{}': {}", process_name, pid_path, contents.error()); + return contents.release_error(); + } + + pid = StringView { contents.value() }.to_number(); + } + + if (!pid.has_value()) { + warnln("{} PID file '{}' exists, but with an invalid PID", process_name, pid_path); + TRY(Core::System::unlink(pid_path)); + return OptionalNone {}; + } + if (kill(*pid, 0) < 0) { + warnln("{} PID file '{}' exists with PID {}, but process cannot be found", process_name, pid_path, *pid); + TRY(Core::System::unlink(pid_path)); + return OptionalNone {}; + } + + return pid; +} + +// This is heavily based on how SystemServer's Service creates its socket. +ErrorOr Process::create_ipc_socket(ByteString const& socket_path) +{ + if (!Core::System::stat(socket_path).is_error()) + TRY(Core::System::unlink(socket_path)); + +#ifdef SOCK_NONBLOCK + auto socket_fd = TRY(Core::System::socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0)); +#else + auto socket_fd = TRY(Core::System::socket(AF_LOCAL, SOCK_STREAM, 0)); + + int option = 1; + TRY(Core::System::ioctl(socket_fd, FIONBIO, &option)); + TRY(Core::System::fcntl(socket_fd, F_SETFD, FD_CLOEXEC)); +#endif + +#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_GNU_HURD) + TRY(Core::System::fchmod(socket_fd, 0600)); +#endif + + auto socket_address = Core::SocketAddress::local(socket_path); + auto socket_address_un = socket_address.to_sockaddr_un().release_value(); + + TRY(Core::System::bind(socket_fd, reinterpret_cast(&socket_address_un), sizeof(socket_address_un))); + TRY(Core::System::listen(socket_fd, 16)); + + return socket_fd; +} + +ErrorOr Process::paths_for_process(StringView process_name) +{ + auto runtime_directory = TRY(Core::StandardPaths::runtime_directory()); + auto socket_path = ByteString::formatted("{}/{}.socket", runtime_directory, process_name); + auto pid_path = ByteString::formatted("{}/{}.pid", runtime_directory, process_name); + + return ProcessPaths { move(socket_path), move(pid_path) }; +} + } diff --git a/Userland/Libraries/LibWebView/Process.h b/Userland/Libraries/LibWebView/Process.h index ae9346c7dd0..7254a1a5379 100644 --- a/Userland/Libraries/LibWebView/Process.h +++ b/Userland/Libraries/LibWebView/Process.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -22,6 +23,12 @@ public: Process(ProcessType type, RefPtr connection, Core::Process process); ~Process(); + template + struct ProcessAndClient; + + template + static ErrorOr> spawn(ProcessType type, Core::ProcessSpawnOptions const& options, ClientArguments&&... client_arguments); + ProcessType type() const { return m_type; } Optional const& title() const { return m_title; } void set_title(Optional title) { m_title = move(title); } @@ -36,11 +43,40 @@ public: pid_t pid() const { return m_process.pid(); } + struct ProcessPaths { + ByteString socket_path; + ByteString pid_path; + }; + static ErrorOr paths_for_process(StringView process_name); + static ErrorOr> get_process_pid(StringView process_name, StringView pid_path); + static ErrorOr create_ipc_socket(ByteString const& socket_path); + private: + struct ProcessAndIPCSocket { + Core::Process process; + NonnullOwnPtr socket; + }; + static ErrorOr spawn_and_connect_to_process(Core::ProcessSpawnOptions const& options); + Core::Process m_process; ProcessType m_type; Optional m_title; WeakPtr m_connection; }; +template +struct Process::ProcessAndClient { + Process process; + NonnullRefPtr client; +}; + +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)... })); + + return ProcessAndClient { Process { type, client, move(core_process) }, client }; +} + }