LibCore+LibIPC+Everywhere: Return Stream::LocalSocket from LocalServer

This change unfortunately cannot be atomically made without a single
commit changing everything.

Most of the important changes are in LibIPC/Connection.cpp,
LibIPC/ServerConnection.cpp and LibCore/LocalServer.cpp.

The notable changes are:
- IPCCompiler now generates the decode and decode_message functions such
  that they take a Core::Stream::LocalSocket instead of the socket fd.
- IPC::Decoder now uses the receive_fd method of LocalSocket instead of
  doing system calls directly on the fd.
- IPC::ConnectionBase and related classes now use the Stream API
  functions.
- IPC::ServerConnection no longer constructs the socket itself; instead,
  a convenience macro, IPC_CLIENT_CONNECTION, is used in place of
  C_OBJECT and will generate a static try_create factory function for
  the ServerConnection subclass. The subclass is now responsible for
  passing the socket constructed in this function to its
  ServerConnection base; the socket is passed as the first argument to
  the constructor (as a NonnullOwnPtr<Core::Stream::LocalServer>) before
  any other arguments.
- The functionality regarding taking over sockets from SystemServer has
  been moved to LibIPC/SystemServerTakeover.cpp. The Core::LocalSocket
  implementation of this functionality hasn't been deleted due to my
  intention of removing this class in the near future and to reduce
  noise on this (already quite noisy) PR.
This commit is contained in:
sin-ack 2022-01-14 13:12:49 +00:00 committed by Ali Mohammad Pur
parent 4cad0dd74c
commit 2e1bbcb0fa
Notes: sideshowbarker 2024-07-17 20:52:19 +09:00
94 changed files with 378 additions and 252 deletions

View File

@ -368,9 +368,9 @@ public:
static i32 static_message_id() { return (int)MessageID::@message.pascal_name@; }
virtual const char* message_name() const override { return "@endpoint.name@::@message.pascal_name@"; }
static OwnPtr<@message.pascal_name@> decode(InputMemoryStream& stream, [[maybe_unused]] int sockfd)
static OwnPtr<@message.pascal_name@> decode(InputMemoryStream& stream, Core::Stream::LocalSocket& socket)
{
IPC::Decoder decoder { stream, sockfd };
IPC::Decoder decoder { stream, socket };
)~~~");
for (auto& parameter : parameters) {
@ -632,7 +632,7 @@ public:
static u32 static_magic() { return @endpoint.magic@; }
static OwnPtr<IPC::Message> decode_message(ReadonlyBytes buffer, [[maybe_unused]] int sockfd)
static OwnPtr<IPC::Message> decode_message(ReadonlyBytes buffer, [[maybe_unused]] Core::Stream::LocalSocket& socket)
{
InputMemoryStream stream { buffer };
u32 message_endpoint_magic = 0;
@ -685,7 +685,7 @@ public:
message_generator.append(R"~~~(
case (int)Messages::@endpoint.name@::MessageID::@message.pascal_name@:
message = Messages::@endpoint.name@::@message.pascal_name@::decode(stream, sockfd);
message = Messages::@endpoint.name@::@message.pascal_name@::decode(stream, socket);
break;
)~~~");
};

View File

@ -300,8 +300,8 @@ TEST_CASE(local_socket_read)
auto local_server = Core::LocalServer::construct();
EXPECT(local_server->listen("/tmp/test-socket"));
local_server->on_accept = [&](NonnullRefPtr<Core::LocalSocket> server_socket) {
EXPECT(server_socket->write(sent_data));
local_server->on_accept = [&](NonnullOwnPtr<Core::Stream::LocalSocket> server_socket) {
EXPECT(!server_socket->write(sent_data.bytes()).is_error());
event_loop.quit(0);
event_loop.pump();
@ -346,14 +346,17 @@ TEST_CASE(local_socket_write)
auto local_server = Core::LocalServer::construct();
EXPECT(local_server->listen("/tmp/test-socket"));
local_server->on_accept = [&](NonnullRefPtr<Core::LocalSocket> server_socket) {
local_server->on_accept = [&](NonnullOwnPtr<Core::Stream::LocalSocket> server_socket) {
// NOTE: For some reason LocalServer gives us a nonblocking socket..?
server_socket->set_blocking(true);
MUST(server_socket->set_blocking(true));
auto receive_buffer = server_socket->read_all();
EXPECT(!server_socket->error());
auto pending_bytes = MUST(server_socket->pending_bytes());
auto receive_buffer = ByteBuffer::create_uninitialized(pending_bytes).release_value();
auto maybe_nread = server_socket->read(receive_buffer);
EXPECT(!maybe_nread.is_error());
EXPECT(maybe_nread.value() == sent_data.length());
StringView received_data { receive_buffer.bytes() };
StringView received_data { receive_buffer.data(), maybe_nread.value() };
EXPECT_EQ(sent_data, received_data);
event_loop.quit(0);

View File

@ -41,14 +41,15 @@ public:
{ 0, TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/audio-volume-zero.png")) },
{ 0, TRY(Gfx::Bitmap::try_load_from_file("/res/icons/16x16/audio-volume-muted.png")) }
};
NonnullRefPtr<AudioWidget> audio_widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AudioWidget(move(volume_level_bitmaps))));
auto audio_client = TRY(Audio::ClientConnection::try_create());
NonnullRefPtr<AudioWidget> audio_widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AudioWidget(move(audio_client), move(volume_level_bitmaps))));
TRY(audio_widget->try_initialize_graphical_elements());
return audio_widget;
}
private:
AudioWidget(Vector<VolumeBitmapPair, 5> volume_level_bitmaps)
: m_audio_client(Audio::ClientConnection::construct())
AudioWidget(NonnullRefPtr<Audio::ClientConnection> audio_client, Vector<VolumeBitmapPair, 5> volume_level_bitmaps)
: m_audio_client(move(audio_client))
, m_volume_level_bitmaps(move(volume_level_bitmaps))
, m_show_percent(Config::read_bool("AudioApplet", "Applet", "ShowPercent", false))
{

View File

@ -169,7 +169,7 @@ void ViewWidget::load_from_file(const String& path)
auto& mapped_file = *file_or_error.value();
// Spawn a new ImageDecoder service process and connect to it.
auto client = ImageDecoderClient::Client::construct();
auto client = ImageDecoderClient::Client::try_create().release_value_but_fixme_should_propagate_errors();
auto decoded_image_or_error = client->decode_image(mapped_file.bytes());
if (!decoded_image_or_error.has_value()) {

View File

@ -27,7 +27,7 @@ AudioPlayerLoop::AudioPlayerLoop(TrackManager& track_manager, bool& need_to_writ
, m_need_to_write_wav(need_to_write_wav)
, m_wav_writer(wav_writer)
{
m_audio_client = Audio::ClientConnection::construct();
m_audio_client = Audio::ClientConnection::try_create().release_value_but_fixme_should_propagate_errors();
m_audio_client->on_finish_playing_buffer = [this](int buffer_id) {
(void)buffer_id;
enqueue_audio();

View File

@ -56,7 +56,7 @@ void Image::paint_into(GUI::Painter& painter, Gfx::IntRect const& dest_rect) con
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Image::try_decode_bitmap(ReadonlyBytes bitmap_data)
{
// Spawn a new ImageDecoder service process and connect to it.
auto client = ImageDecoderClient::Client::construct();
auto client = TRY(ImageDecoderClient::Client::try_create());
// FIXME: Find a way to avoid the memory copying here.
auto maybe_decoded_image = client->decode_image(bitmap_data);

View File

@ -31,8 +31,8 @@ class ServerConnection
friend class ServerConnectionWrapper;
public:
ServerConnection(StringView socket, const String& project_path)
: IPC::ServerConnection<LanguageClientEndpoint, LanguageServerEndpoint>(*this, socket)
ServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, const String& project_path)
: IPC::ServerConnection<LanguageClientEndpoint, LanguageServerEndpoint>(*this, move(socket))
{
m_project_path = project_path;
async_greet(m_project_path);
@ -159,7 +159,7 @@ ServerConnectionWrapper& ServerConnectionWrapper::get_or_create(const String& pr
if (wrapper)
return *wrapper;
auto connection_wrapper_ptr = make<ServerConnectionWrapper>(LanguageServerType::language_name(), [project_path]() { return LanguageServerType::construct(project_path); });
auto connection_wrapper_ptr = make<ServerConnectionWrapper>(LanguageServerType::language_name(), [project_path]() { return LanguageServerType::try_create(project_path).release_value_but_fixme_should_propagate_errors(); });
auto& connection_wrapper = *connection_wrapper_ptr;
ServerConnectionInstances::set_instance_for_language(LanguageServerType::language_name(), move(connection_wrapper_ptr));
return connection_wrapper;

View File

@ -12,19 +12,19 @@
#include <DevTools/HackStudio/LanguageServers/LanguageServerEndpoint.h>
#include <LibIPC/ServerConnection.h>
#define LANGUAGE_CLIENT(language_name_, socket_name) \
namespace language_name_ { \
class ServerConnection final : public HackStudio::ServerConnection { \
C_OBJECT(ServerConnection) \
public: \
static const char* language_name() { return #language_name_; } \
\
private: \
ServerConnection(const String& project_path) \
: HackStudio::ServerConnection("/tmp/portal/language/" #socket_name, project_path) \
{ \
} \
}; \
#define LANGUAGE_CLIENT(language_name_, socket_name) \
namespace language_name_ { \
class ServerConnection final : public HackStudio::ServerConnection { \
IPC_CLIENT_CONNECTION(ServerConnection, "/tmp/portal/language" #socket_name) \
public: \
static const char* language_name() { return #language_name_; } \
\
private: \
ServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, const String& project_path) \
: HackStudio::ServerConnection(move(socket), project_path) \
{ \
} \
}; \
}
namespace LanguageClients {

View File

@ -14,7 +14,7 @@ namespace LanguageServers {
static HashMap<int, RefPtr<ClientConnection>> s_connections;
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ClientConnection<LanguageClientEndpoint, LanguageServerEndpoint>(*this, move(socket), 1)
{
s_connections.set(1, *this);

View File

@ -20,7 +20,7 @@ namespace LanguageServers {
class ClientConnection : public IPC::ClientConnection<LanguageClientEndpoint, LanguageServerEndpoint> {
public:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>);
~ClientConnection() override;
virtual void die() override;

View File

@ -15,7 +15,7 @@ class ClientConnection final : public LanguageServers::ClientConnection {
C_OBJECT(ClientConnection);
private:
ClientConnection(NonnullRefPtr<Core::LocalSocket> socket)
ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: LanguageServers::ClientConnection(move(socket))
{
m_autocomplete_engine = make<CppComprehensionEngine>(m_filedb);

View File

@ -16,7 +16,7 @@ class ClientConnection final : public LanguageServers::ClientConnection {
C_OBJECT(ClientConnection);
private:
ClientConnection(NonnullRefPtr<Core::LocalSocket> socket)
ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: LanguageServers::ClientConnection(move(socket))
{
m_autocomplete_engine = make<ShellComprehensionEngine>(m_filedb);

View File

@ -15,14 +15,14 @@ namespace Inspector {
class InspectorServerClient final
: public IPC::ServerConnection<InspectorClientEndpoint, InspectorServerEndpoint>
, public InspectorClientEndpoint {
C_OBJECT(InspectorServerClient);
IPC_CLIENT_CONNECTION(InspectorServerClient, "/tmp/portal/inspector")
public:
virtual ~InspectorServerClient() override = default;
private:
InspectorServerClient()
: IPC::ServerConnection<InspectorClientEndpoint, InspectorServerEndpoint>(*this, "/tmp/portal/inspector")
InspectorServerClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<InspectorClientEndpoint, InspectorServerEndpoint>(*this, move(socket))
{
}
};

View File

@ -24,7 +24,7 @@ RemoteProcess::RemoteProcess(pid_t pid)
, m_object_graph_model(RemoteObjectGraphModel::create(*this))
{
s_the = this;
m_client = InspectorServerClient::construct();
m_client = InspectorServerClient::try_create().release_value_but_fixme_should_propagate_errors();
}
void RemoteProcess::handle_identify_response(const JsonObject& response)

View File

@ -14,8 +14,8 @@ namespace Audio {
// Real-time audio may be improved with a lower value.
static timespec g_enqueue_wait_time { 0, 10'000'000 };
ClientConnection::ClientConnection()
: IPC::ServerConnection<AudioClientEndpoint, AudioServerEndpoint>(*this, "/tmp/portal/audio")
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<AudioClientEndpoint, AudioServerEndpoint>(*this, move(socket))
{
}

View File

@ -17,7 +17,7 @@ class Buffer;
class ClientConnection final
: public IPC::ServerConnection<AudioClientEndpoint, AudioServerEndpoint>
, public AudioClientEndpoint {
C_OBJECT(ClientConnection)
IPC_CLIENT_CONNECTION(ClientConnection, "/tmp/portal/audio")
public:
void enqueue(Buffer const&);
bool try_enqueue(Buffer const&);
@ -29,7 +29,7 @@ public:
Function<void(double volume)> on_client_volume_change;
private:
ClientConnection();
ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual void finished_playing_buffer(i32) override;
virtual void main_mix_muted_state_changed(bool) override;

View File

@ -15,7 +15,7 @@ Client& Client::the()
{
if (!s_the || !s_the->is_open()) {
VERIFY(Core::EventLoop::has_been_instantiated());
s_the = Client::construct();
s_the = Client::try_create().release_value_but_fixme_should_propagate_errors();
}
return *s_the;
}

View File

@ -18,7 +18,7 @@ namespace Config {
class Client final
: public IPC::ServerConnection<ConfigClientEndpoint, ConfigServerEndpoint>
, public ConfigClientEndpoint {
C_OBJECT(Client);
IPC_CLIENT_CONNECTION(Client, "/tmp/portal/config")
public:
void pledge_domains(Vector<String> const&);
@ -39,8 +39,8 @@ public:
static Client& the();
private:
explicit Client()
: IPC::ServerConnection<ConfigClientEndpoint, ConfigServerEndpoint>(*this, "/tmp/portal/config")
explicit Client(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<ConfigClientEndpoint, ConfigServerEndpoint>(*this, move(socket))
{
}

View File

@ -7,6 +7,7 @@
#include <LibCore/LocalServer.h>
#include <LibCore/LocalSocket.h>
#include <LibCore/Notifier.h>
#include <LibCore/Stream.h>
#include <LibCore/System.h>
#include <fcntl.h>
#include <stdio.h>
@ -80,8 +81,13 @@ void LocalServer::setup_notifier()
m_notifier = Notifier::construct(m_fd, Notifier::Event::Read, this);
m_notifier->on_ready_to_read = [this] {
if (on_accept) {
if (auto client_socket = accept())
on_accept(client_socket.release_nonnull());
auto maybe_client_socket = accept();
if (maybe_client_socket.is_error()) {
dbgln("LocalServer::on_ready_to_read: Error accepting a connection: {} (FIXME: should propagate!)", maybe_client_socket.error());
return;
}
on_accept(maybe_client_socket.release_value());
}
};
}
@ -134,7 +140,7 @@ bool LocalServer::listen(const String& address)
return true;
}
RefPtr<LocalSocket> LocalServer::accept()
ErrorOr<NonnullOwnPtr<Stream::LocalSocket>> LocalServer::accept()
{
VERIFY(m_listening);
sockaddr_un un;
@ -145,8 +151,7 @@ RefPtr<LocalSocket> LocalServer::accept()
int accepted_fd = ::accept(m_fd, (sockaddr*)&un, &un_size);
#endif
if (accepted_fd < 0) {
perror("accept");
return nullptr;
return Error::from_syscall("accept", -errno);
}
#ifdef AK_OS_MACOS
@ -155,7 +160,7 @@ RefPtr<LocalSocket> LocalServer::accept()
(void)fcntl(accepted_fd, F_SETFD, FD_CLOEXEC);
#endif
return LocalSocket::construct(accepted_fd);
return Stream::LocalSocket::adopt_fd(accepted_fd);
}
}

View File

@ -8,6 +8,7 @@
#include <LibCore/Notifier.h>
#include <LibCore/Object.h>
#include <LibCore/Stream.h>
namespace Core {
@ -20,9 +21,9 @@ public:
bool is_listening() const { return m_listening; }
bool listen(const String& address);
RefPtr<LocalSocket> accept();
ErrorOr<NonnullOwnPtr<Stream::LocalSocket>> accept();
Function<void(NonnullRefPtr<Core::LocalSocket>)> on_accept;
Function<void(NonnullOwnPtr<Stream::LocalSocket>)> on_accept;
private:
explicit LocalServer(Object* parent = nullptr);

View File

@ -36,17 +36,17 @@ auto Launcher::Details::from_details_str(const String& details_str) -> NonnullRe
class LaunchServerConnection final
: public IPC::ServerConnection<LaunchClientEndpoint, LaunchServerEndpoint>
, public LaunchClientEndpoint {
C_OBJECT(LaunchServerConnection)
IPC_CLIENT_CONNECTION(LaunchServerConnection, "/tmp/portal/launch")
private:
LaunchServerConnection()
: IPC::ServerConnection<LaunchClientEndpoint, LaunchServerEndpoint>(*this, "/tmp/portal/launch")
LaunchServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<LaunchClientEndpoint, LaunchServerEndpoint>(*this, move(socket))
{
}
};
static LaunchServerConnection& connection()
{
static auto connection = LaunchServerConnection::construct();
static auto connection = LaunchServerConnection::try_create().release_value_but_fixme_should_propagate_errors();
return connection;
}

View File

@ -20,7 +20,7 @@ static RefPtr<Client> s_the = nullptr;
Client& Client::the()
{
if (!s_the || !s_the->is_open())
s_the = Client::construct();
s_the = Client::try_create().release_value_but_fixme_should_propagate_errors();
return *s_the;
}

View File

@ -24,7 +24,7 @@ struct Result {
class Client final
: public IPC::ServerConnection<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>
, public FileSystemAccessClientEndpoint {
C_OBJECT(Client)
IPC_CLIENT_CONNECTION(Client, "/tmp/portal/filesystemaccess")
public:
Result request_file_read_only_approved(i32 parent_window_id, String const& path);
@ -38,8 +38,8 @@ protected:
void die() override;
private:
explicit Client()
: IPC::ServerConnection<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>(*this, "/tmp/portal/filesystemaccess")
explicit Client(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>(*this, move(socket))
{
}

View File

@ -16,11 +16,11 @@ namespace GUI {
class ClipboardServerConnection final
: public IPC::ServerConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>
, public ClipboardClientEndpoint {
C_OBJECT(ClipboardServerConnection);
IPC_CLIENT_CONNECTION(ClipboardServerConnection, "/tmp/portal/clipboard")
private:
ClipboardServerConnection()
: IPC::ServerConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>(*this, "/tmp/portal/clipboard")
ClipboardServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>(*this, move(socket))
{
}
@ -30,7 +30,7 @@ private:
}
};
static ClipboardServerConnection* s_connection;
static RefPtr<ClipboardServerConnection> s_connection;
static ClipboardServerConnection& connection()
{
@ -39,7 +39,7 @@ static ClipboardServerConnection& connection()
void Clipboard::initialize(Badge<Application>)
{
s_connection = &ClipboardServerConnection::construct().leak_ref();
s_connection = ClipboardServerConnection::try_create().release_value_but_fixme_should_propagate_errors();
}
Clipboard& Clipboard::the()

View File

@ -14,7 +14,7 @@ namespace GUI {
class NotificationServerConnection final
: public IPC::ServerConnection<NotificationClientEndpoint, NotificationServerEndpoint>
, public NotificationClientEndpoint {
C_OBJECT(NotificationServerConnection)
IPC_CLIENT_CONNECTION(NotificationServerConnection, "/tmp/portal/notify")
friend class Notification;
@ -25,8 +25,8 @@ public:
}
private:
explicit NotificationServerConnection(Notification* notification)
: IPC::ServerConnection<NotificationClientEndpoint, NotificationServerEndpoint>(*this, "/tmp/portal/notify")
explicit NotificationServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, Notification* notification)
: IPC::ServerConnection<NotificationClientEndpoint, NotificationServerEndpoint>(*this, move(socket))
, m_notification(notification)
{
}
@ -45,7 +45,7 @@ void Notification::show()
{
VERIFY(!m_shown && !m_destroyed);
auto icon = m_icon ? m_icon->to_shareable_bitmap() : Gfx::ShareableBitmap();
m_connection = NotificationServerConnection::construct(this);
m_connection = NotificationServerConnection::try_create(this).release_value_but_fixme_should_propagate_errors();
m_connection->show_notification(m_text, m_title, icon);
m_shown = true;
}

View File

@ -12,9 +12,9 @@ namespace GUI {
WindowManagerServerConnection& WindowManagerServerConnection::the()
{
static WindowManagerServerConnection* s_connection = nullptr;
static RefPtr<WindowManagerServerConnection> s_connection = nullptr;
if (!s_connection)
s_connection = new WindowManagerServerConnection;
s_connection = WindowManagerServerConnection::try_create().release_value_but_fixme_should_propagate_errors();
return *s_connection;
}

View File

@ -16,13 +16,14 @@ namespace GUI {
class WindowManagerServerConnection final
: public IPC::ServerConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint>
, public WindowManagerClientEndpoint {
C_OBJECT(WindowManagerServerConnection)
IPC_CLIENT_CONNECTION(WindowManagerServerConnection, "/tmp/portal/wm")
public:
static WindowManagerServerConnection& the();
private:
WindowManagerServerConnection()
: IPC::ServerConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint>(*this, "/tmp/portal/wm")
WindowManagerServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint>(*this, move(socket))
{
}

View File

@ -28,9 +28,9 @@ namespace GUI {
WindowServerConnection& WindowServerConnection::the()
{
static WindowServerConnection* s_connection = nullptr;
static RefPtr<WindowServerConnection> s_connection = nullptr;
if (!s_connection)
s_connection = new WindowServerConnection;
s_connection = WindowServerConnection::try_create().release_value_but_fixme_should_propagate_errors();
return *s_connection;
}
@ -40,8 +40,8 @@ static void set_system_theme_from_anonymous_buffer(Core::AnonymousBuffer buffer)
Application::the()->set_system_palette(buffer);
}
WindowServerConnection::WindowServerConnection()
: IPC::ServerConnection<WindowClientEndpoint, WindowServerEndpoint>(*this, "/tmp/portal/window")
WindowServerConnection::WindowServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<WindowClientEndpoint, WindowServerEndpoint>(*this, move(socket))
{
// NOTE: WindowServer automatically sends a "fast_greet" message to us when we connect.
// All we have to do is wait for it to arrive. This avoids a round-trip during application startup.

View File

@ -16,13 +16,13 @@ namespace GUI {
class WindowServerConnection final
: public IPC::ServerConnection<WindowClientEndpoint, WindowServerEndpoint>
, public WindowClientEndpoint {
C_OBJECT(WindowServerConnection)
IPC_CLIENT_CONNECTION(WindowServerConnection, "/tmp/portal/window")
public:
static WindowServerConnection& the();
i32 expose_client_id() { return m_client_id; }
private:
WindowServerConnection();
WindowServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual void fast_greet(Vector<Gfx::IntRect> const&, u32, u32, u32, Core::AnonymousBuffer const&, String const&, String const&, i32) override;
virtual void paint(i32, Gfx::IntSize const&, Vector<Gfx::IntRect> const&) override;

View File

@ -4,6 +4,7 @@ set(SOURCES
Encoder.cpp
Message.cpp
Stub.cpp
SystemServerTakeover.cpp
)
serenity_lib(LibIPC ipc)

View File

@ -24,12 +24,12 @@ public:
using ServerStub = typename ServerEndpoint::Stub;
using IPCProxy = typename ClientEndpoint::template Proxy<ServerEndpoint>;
ClientConnection(ServerStub& stub, NonnullRefPtr<Core::LocalSocket> socket, int client_id)
ClientConnection(ServerStub& stub, NonnullOwnPtr<Core::Stream::LocalSocket> socket, int client_id)
: IPC::Connection<ServerEndpoint, ClientEndpoint>(stub, move(socket))
, ClientEndpoint::template Proxy<ServerEndpoint>(*this, {})
, m_client_id(client_id)
{
VERIFY(this->socket().is_connected());
VERIFY(this->socket().is_open());
this->socket().on_ready_to_read = [this] {
// FIXME: Do something about errors.
(void)this->drain_messages_from_peer();

View File

@ -11,10 +11,9 @@
namespace IPC {
ConnectionBase::ConnectionBase(IPC::Stub& local_stub, NonnullRefPtr<Core::LocalSocket> socket, u32 local_endpoint_magic)
ConnectionBase::ConnectionBase(IPC::Stub& local_stub, NonnullOwnPtr<Core::Stream::LocalSocket> socket, u32 local_endpoint_magic)
: m_local_stub(local_stub)
, m_socket(move(socket))
, m_notifier(Core::Notifier::construct(m_socket->fd(), Core::Notifier::Read, this))
, m_local_endpoint_magic(local_endpoint_magic)
{
m_responsiveness_timer = Core::Timer::create_single_shot(3000, [this] { may_have_become_unresponsive(); });
@ -42,7 +41,7 @@ ErrorOr<void> ConnectionBase::post_message(MessageBuffer buffer)
#ifdef __serenity__
for (auto& fd : buffer.fds) {
if (auto result = Core::System::sendfd(m_socket->fd(), fd.value()); result.is_error()) {
if (auto result = m_socket->send_fd(fd.value()); result.is_error()) {
dbgln("{}", result.error());
shutdown();
return result;
@ -53,23 +52,29 @@ ErrorOr<void> ConnectionBase::post_message(MessageBuffer buffer)
warnln("fd passing is not supported on this platform, sorry :(");
#endif
size_t total_nwritten = 0;
while (total_nwritten < buffer.data.size()) {
auto nwritten = write(m_socket->fd(), buffer.data.data() + total_nwritten, buffer.data.size() - total_nwritten);
if (nwritten < 0) {
switch (errno) {
case EPIPE:
shutdown();
return Error::from_string_literal("IPC::Connection::post_message: Disconnected from peer"sv);
case EAGAIN:
shutdown();
return Error::from_string_literal("IPC::Connection::post_message: Peer buffer overflowed"sv);
default:
shutdown();
return Error::from_syscall("IPC::Connection::post_message write"sv, -errno);
ReadonlyBytes bytes_to_write { buffer.data.span() };
while (!bytes_to_write.is_empty()) {
auto maybe_nwritten = m_socket->write(bytes_to_write);
if (maybe_nwritten.is_error()) {
auto error = maybe_nwritten.release_error();
if (error.is_errno()) {
switch (error.code()) {
case EPIPE:
shutdown();
return Error::from_string_literal("IPC::Connection::post_message: Disconnected from peer"sv);
case EAGAIN:
shutdown();
return Error::from_string_literal("IPC::Connection::post_message: Peer buffer overflowed"sv);
default:
shutdown();
return Error::from_syscall("IPC::Connection::post_message write"sv, -error.code());
}
} else {
return error;
}
}
total_nwritten += nwritten;
bytes_to_write = bytes_to_write.slice(maybe_nwritten.value());
}
m_responsiveness_timer->start();
@ -78,7 +83,6 @@ ErrorOr<void> ConnectionBase::post_message(MessageBuffer buffer)
void ConnectionBase::shutdown()
{
m_notifier->close();
m_socket->close();
die();
}
@ -99,21 +103,14 @@ void ConnectionBase::handle_messages()
void ConnectionBase::wait_for_socket_to_become_readable()
{
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(m_socket->fd(), &read_fds);
for (;;) {
if (auto rc = select(m_socket->fd() + 1, &read_fds, nullptr, nullptr, nullptr); rc < 0) {
if (errno == EINTR)
continue;
perror("wait_for_specific_endpoint_message: select");
VERIFY_NOT_REACHED();
} else {
VERIFY(rc > 0);
VERIFY(FD_ISSET(m_socket->fd(), &read_fds));
break;
}
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());
}
ErrorOr<Vector<u8>> ConnectionBase::read_as_much_as_possible_from_socket_without_blocking()
@ -125,15 +122,21 @@ ErrorOr<Vector<u8>> ConnectionBase::read_as_much_as_possible_from_socket_without
m_unprocessed_bytes.clear();
}
u8 buffer[4096];
while (m_socket->is_open()) {
u8 buffer[4096];
ssize_t nread = recv(m_socket->fd(), buffer, sizeof(buffer), MSG_DONTWAIT);
if (nread < 0) {
if (errno == EAGAIN)
auto maybe_nread = m_socket->read_without_waiting({ buffer, 4096 });
if (maybe_nread.is_error()) {
auto error = maybe_nread.release_error();
if (error.is_syscall() && error.code() == EAGAIN) {
break;
perror("recv");
exit(1);
}
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 nread = maybe_nread.release_value();
if (nread == 0) {
if (bytes.is_empty()) {
deferred_invoke([this] { shutdown(); });
@ -141,6 +144,7 @@ ErrorOr<Vector<u8>> ConnectionBase::read_as_much_as_possible_from_socket_without
}
break;
}
bytes.append(buffer, nread);
}

View File

@ -11,8 +11,8 @@
#include <AK/Try.h>
#include <LibCore/Event.h>
#include <LibCore/EventLoop.h>
#include <LibCore/LocalSocket.h>
#include <LibCore/Notifier.h>
#include <LibCore/Stream.h>
#include <LibCore/Timer.h>
#include <LibIPC/Forward.h>
#include <LibIPC/Message.h>
@ -39,9 +39,9 @@ public:
virtual void die() { }
protected:
explicit ConnectionBase(IPC::Stub&, NonnullRefPtr<Core::LocalSocket>, u32 local_endpoint_magic);
explicit ConnectionBase(IPC::Stub&, NonnullOwnPtr<Core::Stream::LocalSocket>, u32 local_endpoint_magic);
Core::LocalSocket& socket() { return *m_socket; }
Core::Stream::LocalSocket& socket() { return *m_socket; }
virtual void may_have_become_unresponsive() { }
virtual void did_become_responsive() { }
@ -57,10 +57,9 @@ protected:
IPC::Stub& m_local_stub;
NonnullRefPtr<Core::LocalSocket> m_socket;
NonnullOwnPtr<Core::Stream::LocalSocket> m_socket;
RefPtr<Core::Timer> m_responsiveness_timer;
RefPtr<Core::Notifier> m_notifier;
NonnullOwnPtrVector<Message> m_unprocessed_messages;
ByteBuffer m_unprocessed_bytes;
@ -70,10 +69,10 @@ protected:
template<typename LocalEndpoint, typename PeerEndpoint>
class Connection : public ConnectionBase {
public:
Connection(IPC::Stub& local_stub, NonnullRefPtr<Core::LocalSocket> socket)
Connection(IPC::Stub& local_stub, NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: ConnectionBase(local_stub, move(socket), LocalEndpoint::static_magic())
{
m_notifier->on_ready_to_read = [this] {
m_socket->on_ready_to_read = [this] {
NonnullRefPtr protect = *this;
// FIXME: Do something about errors.
(void)drain_messages_from_peer();
@ -122,9 +121,9 @@ protected:
break;
index += sizeof(message_size);
auto remaining_bytes = ReadonlyBytes { bytes.data() + index, message_size };
if (auto message = LocalEndpoint::decode_message(remaining_bytes, m_socket->fd())) {
if (auto message = LocalEndpoint::decode_message(remaining_bytes, *m_socket)) {
m_unprocessed_messages.append(message.release_nonnull());
} else if (auto message = PeerEndpoint::decode_message(remaining_bytes, m_socket->fd())) {
} else if (auto message = PeerEndpoint::decode_message(remaining_bytes, *m_socket)) {
m_unprocessed_messages.append(message.release_nonnull());
} else {
dbgln("Failed to parse a message");

View File

@ -162,14 +162,9 @@ ErrorOr<void> Decoder::decode(Dictionary& dictionary)
ErrorOr<void> Decoder::decode([[maybe_unused]] File& file)
{
#ifdef __serenity__
int fd = TRY(Core::System::recvfd(m_sockfd, O_CLOEXEC));
int fd = TRY(m_socket.receive_fd(O_CLOEXEC));
file = File(fd, File::ConstructWithReceivedFileDescriptor);
return {};
#else
[[maybe_unused]] auto fd = m_sockfd;
return Error::from_string_literal("File descriptor passing not supported on this platform");
#endif
}
ErrorOr<void> decode(Decoder& decoder, Core::AnonymousBuffer& buffer)

View File

@ -11,6 +11,7 @@
#include <AK/NumericLimits.h>
#include <AK/StdLibExtras.h>
#include <AK/String.h>
#include <LibCore/Stream.h>
#include <LibIPC/Forward.h>
#include <LibIPC/Message.h>
@ -25,9 +26,9 @@ inline ErrorOr<void> decode(Decoder&, T&)
class Decoder {
public:
Decoder(InputMemoryStream& stream, int sockfd)
Decoder(InputMemoryStream& stream, Core::Stream::LocalSocket& socket)
: m_stream(stream)
, m_sockfd(sockfd)
, m_socket(socket)
{
}
@ -115,7 +116,7 @@ public:
private:
InputMemoryStream& m_stream;
int m_sockfd { -1 };
Core::Stream::LocalSocket& m_socket;
};
}

View File

@ -6,10 +6,24 @@
#pragma once
#include <LibCore/Stream.h>
#include <LibIPC/Connection.h>
namespace IPC {
#define IPC_CLIENT_CONNECTION(klass, socket_path) \
C_OBJECT_ABSTRACT(klass) \
public: \
template<typename Klass = klass, class... Args> \
static ErrorOr<NonnullRefPtr<klass>> try_create(Args&&... args) \
{ \
auto socket = TRY(Core::Stream::LocalSocket::connect(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>(args)...)); \
}
template<typename ClientEndpoint, typename ServerEndpoint>
class ServerConnection : public IPC::Connection<ClientEndpoint, ServerEndpoint>
, public ClientEndpoint::Stub
@ -18,19 +32,10 @@ public:
using ClientStub = typename ClientEndpoint::Stub;
using IPCProxy = typename ServerEndpoint::template Proxy<ClientEndpoint>;
ServerConnection(ClientStub& local_endpoint, StringView address)
: Connection<ClientEndpoint, ServerEndpoint>(local_endpoint, Core::LocalSocket::construct())
ServerConnection(ClientStub& local_endpoint, NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: Connection<ClientEndpoint, ServerEndpoint>(local_endpoint, move(socket))
, ServerEndpoint::template Proxy<ClientEndpoint>(*this, {})
{
// We want to rate-limit our clients
this->socket().set_blocking(true);
if (!this->socket().connect(Core::SocketAddress::local(address))) {
perror("connect");
VERIFY_NOT_REACHED();
}
VERIFY(this->socket().is_connected());
}
virtual void die() override

View File

@ -6,14 +6,16 @@
#pragma once
#include <LibCore/System.h>
#include <LibIPC/ClientConnection.h>
#include <LibIPC/SystemServerTakeover.h>
namespace IPC {
template<typename ClientConnectionType>
ErrorOr<NonnullRefPtr<ClientConnectionType>> take_over_accepted_client_from_system_server()
{
auto socket = TRY(Core::LocalSocket::take_over_accepted_socket_from_system_server());
auto socket = TRY(take_over_accepted_socket_from_system_server());
return IPC::new_client_connection<ClientConnectionType>(move(socket));
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2022, sin-ack <sin-ack@protonmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "SystemServerTakeover.h"
#include <LibCore/System.h>
HashMap<String, int> s_overtaken_sockets {};
bool s_overtaken_sockets_parsed { false };
void parse_sockets_from_system_server()
{
VERIFY(!s_overtaken_sockets_parsed);
constexpr auto socket_takeover = "SOCKET_TAKEOVER";
const char* sockets = getenv(socket_takeover);
if (!sockets) {
s_overtaken_sockets_parsed = true;
return;
}
for (auto& socket : StringView(sockets).split_view(' ')) {
auto params = socket.split_view(':');
s_overtaken_sockets.set(params[0].to_string(), strtol(params[1].to_string().characters(), nullptr, 10));
}
s_overtaken_sockets_parsed = true;
// We wouldn't want our children to think we're passing
// them a socket either, so unset the env variable.
unsetenv(socket_takeover);
}
ErrorOr<NonnullOwnPtr<Core::Stream::LocalSocket>> take_over_accepted_socket_from_system_server(String const& socket_path)
{
if (!s_overtaken_sockets_parsed)
parse_sockets_from_system_server();
int fd;
if (socket_path.is_null()) {
// We want the first (and only) socket.
VERIFY(s_overtaken_sockets.size() == 1);
fd = s_overtaken_sockets.begin()->value;
} else {
auto it = s_overtaken_sockets.find(socket_path);
if (it == s_overtaken_sockets.end())
return Error::from_string_literal("Non-existent socket requested"sv);
fd = it->value;
}
// Sanity check: it has to be a socket.
auto stat = TRY(Core::System::fstat(fd));
if (!S_ISSOCK(stat.st_mode))
return Error::from_string_literal("The fd we got from SystemServer is not a socket"sv);
auto socket = TRY(Core::Stream::LocalSocket::adopt_fd(fd));
// It had to be !CLOEXEC for obvious reasons, but we
// don't need it to be !CLOEXEC anymore, so set the
// CLOEXEC flag now.
TRY(socket->set_close_on_exec(true));
return socket;
}

View File

@ -0,0 +1,12 @@
/*
* Copyright (c) 2022, sin-ack <sin-ack@protonmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibCore/Stream.h>
void parse_sockets_from_system_server();
ErrorOr<NonnullOwnPtr<Core::Stream::LocalSocket>> take_over_accepted_socket_from_system_server(String const& socket_path = {});

View File

@ -9,8 +9,8 @@
namespace ImageDecoderClient {
Client::Client()
: IPC::ServerConnection<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>(*this, "/tmp/portal/image")
Client::Client(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>(*this, move(socket))
{
}

View File

@ -27,7 +27,7 @@ struct DecodedImage {
class Client final
: public IPC::ServerConnection<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>
, public ImageDecoderClientEndpoint {
C_OBJECT(Client);
IPC_CLIENT_CONNECTION(Client, "/tmp/portal/image");
public:
Optional<DecodedImage> decode_image(ReadonlyBytes);
@ -35,7 +35,7 @@ public:
Function<void()> on_death;
private:
Client();
Client(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual void die() override;
};

View File

@ -10,8 +10,8 @@
namespace Protocol {
RequestClient::RequestClient()
: IPC::ServerConnection<RequestClientEndpoint, RequestServerEndpoint>(*this, "/tmp/portal/request")
RequestClient::RequestClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<RequestClientEndpoint, RequestServerEndpoint>(*this, move(socket))
{
}

View File

@ -18,7 +18,7 @@ class Request;
class RequestClient final
: public IPC::ServerConnection<RequestClientEndpoint, RequestServerEndpoint>
, public RequestClientEndpoint {
C_OBJECT(RequestClient);
IPC_CLIENT_CONNECTION(RequestClient, "/tmp/portal/request")
public:
template<typename RequestHashMapTraits = Traits<String>>
@ -30,7 +30,7 @@ public:
bool set_certificate(Badge<Request>, Request&, String, String);
private:
RequestClient();
RequestClient(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual void request_progress(i32, Optional<u32> const&, u32) override;
virtual void request_finished(i32, bool, u32) override;

View File

@ -9,8 +9,8 @@
namespace Protocol {
WebSocketClient::WebSocketClient()
: IPC::ServerConnection<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, "/tmp/portal/websocket")
WebSocketClient::WebSocketClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket))
{
}

View File

@ -18,7 +18,7 @@ class WebSocket;
class WebSocketClient final
: public IPC::ServerConnection<WebSocketClientEndpoint, WebSocketServerEndpoint>
, public WebSocketClientEndpoint {
C_OBJECT(WebSocketClient);
IPC_CLIENT_CONNECTION(WebSocketClient, "/tmp/portal/websocket")
public:
RefPtr<WebSocket> connect(const URL&, const String& origin = {}, const Vector<String>& protocols = {}, const Vector<String>& extensions = {}, const HashMap<String, String>& request_headers = {});
@ -29,7 +29,7 @@ public:
bool set_certificate(Badge<WebSocket>, WebSocket&, String, String);
private:
WebSocketClient();
WebSocketClient(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual void connected(i32) override;
virtual void received(i32, bool, ByteBuffer const&) override;

View File

@ -15,7 +15,7 @@ namespace SQL {
class SQLClient
: public IPC::ServerConnection<SQLClientEndpoint, SQLServerEndpoint>
, public SQLClientEndpoint {
C_OBJECT(SQLClient);
IPC_CLIENT_CONNECTION(SQLClient, "/tmp/portal/sql")
virtual ~SQLClient();
Function<void(int, String const&)> on_connected;
@ -27,8 +27,8 @@ class SQLClient
Function<void(int, int)> on_results_exhausted;
private:
SQLClient()
: IPC::ServerConnection<SQLClientEndpoint, SQLServerEndpoint>(*this, "/tmp/portal/sql")
SQLClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<SQLClientEndpoint, SQLServerEndpoint>(*this, move(socket))
{
}

View File

@ -29,14 +29,20 @@ namespace Web::HTML {
WebSocketClientManager& WebSocketClientManager::the()
{
static WebSocketClientManager* s_the;
static RefPtr<WebSocketClientManager> s_the;
if (!s_the)
s_the = &WebSocketClientManager::construct().leak_ref();
s_the = WebSocketClientManager::try_create().release_value_but_fixme_should_propagate_errors();
return *s_the;
}
WebSocketClientManager::WebSocketClientManager()
: m_websocket_client(Protocol::WebSocketClient::construct())
ErrorOr<NonnullRefPtr<WebSocketClientManager>> WebSocketClientManager::try_create()
{
auto websocket_client = TRY(Protocol::WebSocketClient::try_create());
return adopt_nonnull_ref_or_enomem(new (nothrow) WebSocketClientManager(move(websocket_client)));
}
WebSocketClientManager::WebSocketClientManager(NonnullRefPtr<Protocol::WebSocketClient> websocket_client)
: m_websocket_client(move(websocket_client))
{
}

View File

@ -31,14 +31,16 @@ class WebSocket;
namespace Web::HTML {
class WebSocketClientManager : public Core::Object {
C_OBJECT(WebSocketClientManager)
C_OBJECT_ABSTRACT(WebSocketClientManager)
public:
static WebSocketClientManager& the();
RefPtr<Protocol::WebSocket> connect(const AK::URL&);
private:
WebSocketClientManager();
static ErrorOr<NonnullRefPtr<WebSocketClientManager>> try_create();
WebSocketClientManager(NonnullRefPtr<Protocol::WebSocketClient>);
RefPtr<Protocol::WebSocketClient> m_websocket_client;
};

View File

@ -12,7 +12,7 @@ ImageDecoderClient::Client& image_decoder_client()
{
static RefPtr<ImageDecoderClient::Client> image_decoder_client;
if (!image_decoder_client) {
image_decoder_client = ImageDecoderClient::Client::construct();
image_decoder_client = ImageDecoderClient::Client::try_create().release_value_but_fixme_should_propagate_errors();
image_decoder_client->on_death = [&] {
image_decoder_client = nullptr;
};

View File

@ -21,14 +21,21 @@ namespace Web {
ResourceLoader& ResourceLoader::the()
{
static ResourceLoader* s_the;
static RefPtr<ResourceLoader> s_the;
if (!s_the)
s_the = &ResourceLoader::construct().leak_ref();
s_the = ResourceLoader::try_create().release_value_but_fixme_should_propagate_errors();
return *s_the;
}
ResourceLoader::ResourceLoader()
: m_protocol_client(Protocol::RequestClient::construct())
ErrorOr<NonnullRefPtr<ResourceLoader>> ResourceLoader::try_create()
{
auto protocol_client = TRY(Protocol::RequestClient::try_create());
return adopt_nonnull_ref_or_enomem(new (nothrow) ResourceLoader(move(protocol_client)));
}
ResourceLoader::ResourceLoader(NonnullRefPtr<Protocol::RequestClient> protocol_client)
: m_protocol_client(move(protocol_client))
, m_user_agent(default_user_agent)
{
}

View File

@ -27,7 +27,7 @@ namespace Web {
constexpr auto default_user_agent = "Mozilla/4.0 (SerenityOS; " CPU_STRING ") LibWeb+LibJS (Not KHTML, nor Gecko) LibWeb";
class ResourceLoader : public Core::Object {
C_OBJECT(ResourceLoader)
C_OBJECT_ABSTRACT(ResourceLoader)
public:
static ResourceLoader& the();
@ -52,7 +52,9 @@ public:
void clear_cache();
private:
ResourceLoader();
ResourceLoader(NonnullRefPtr<Protocol::RequestClient> protocol_client);
static ErrorOr<NonnullRefPtr<ResourceLoader>> try_create();
static bool is_port_blocked(int port);
int m_pending_loads { 0 };

View File

@ -62,7 +62,7 @@ void OutOfProcessWebView::create_client()
{
m_client_state = {};
m_client_state.client = WebContentClient::construct(*this);
m_client_state.client = WebContentClient::try_create(*this).release_value_but_fixme_should_propagate_errors();
m_client_state.client->on_web_content_process_crash = [this] {
deferred_invoke([this] {
handle_web_content_process_crash();

View File

@ -11,8 +11,8 @@
namespace Web {
WebContentClient::WebContentClient(OutOfProcessWebView& view)
: IPC::ServerConnection<WebContentClientEndpoint, WebContentServerEndpoint>(*this, "/tmp/portal/webcontent")
WebContentClient::WebContentClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket, OutOfProcessWebView& view)
: IPC::ServerConnection<WebContentClientEndpoint, WebContentServerEndpoint>(*this, move(socket))
, m_view(view)
{
}

View File

@ -19,13 +19,13 @@ class OutOfProcessWebView;
class WebContentClient final
: public IPC::ServerConnection<WebContentClientEndpoint, WebContentServerEndpoint>
, public WebContentClientEndpoint {
C_OBJECT(WebContentClient);
IPC_CLIENT_CONNECTION(WebContentClient, "/tmp/portal/webcontent");
public:
Function<void()> on_web_content_process_crash;
private:
WebContentClient(OutOfProcessWebView&);
WebContentClient(NonnullOwnPtr<Core::Stream::LocalSocket>, OutOfProcessWebView&);
virtual void die() override;

View File

@ -22,7 +22,7 @@ void ClientConnection::for_each(Function<void(ClientConnection&)> callback)
callback(connection);
}
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id, Mixer& mixer)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> client_socket, int client_id, Mixer& mixer)
: IPC::ClientConnection<AudioClientEndpoint, AudioServerEndpoint>(*this, move(client_socket), client_id)
, m_mixer(mixer)
{

View File

@ -35,7 +35,7 @@ public:
static void for_each(Function<void(ClientConnection&)>);
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id, Mixer& mixer);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id, Mixer& mixer);
virtual Messages::AudioServer::GetMainMixVolumeResponse get_main_mix_volume() override;
virtual void set_main_mix_volume(double) override;

View File

@ -25,7 +25,7 @@ ErrorOr<int> serenity_main(Main::Arguments)
auto server = TRY(Core::LocalServer::try_create());
TRY(server->take_over_from_system_server());
server->on_accept = [&](NonnullRefPtr<Core::LocalSocket> client_socket) {
server->on_accept = [&](NonnullOwnPtr<Core::Stream::LocalSocket> client_socket) {
static int s_next_client_id = 0;
int client_id = ++s_next_client_id;
(void)IPC::new_client_connection<AudioServer::ClientConnection>(move(client_socket), client_id, *mixer);

View File

@ -19,7 +19,7 @@ void ClientConnection::for_each_client(Function<void(ClientConnection&)> callbac
}
}
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, int client_id)
: IPC::ClientConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>(*this, move(socket), client_id)
{
s_connections.set(client_id, *this);

View File

@ -27,7 +27,7 @@ public:
void notify_about_clipboard_change();
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id);
virtual Messages::ClipboardServer::GetClipboardDataResponse get_clipboard_data() override;
virtual void set_clipboard_data(Core::AnonymousBuffer const&, String const&, IPC::Dictionary const&) override;

View File

@ -74,7 +74,7 @@ static Core::ConfigFile& ensure_domain_config(String const& domain)
return *config;
}
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> client_socket, int client_id)
: IPC::ClientConnection<ConfigClientEndpoint, ConfigServerEndpoint>(*this, move(client_socket), client_id)
, m_sync_timer(Core::Timer::create_single_shot(s_disk_sync_delay_ms, [this]() { sync_dirty_domains_to_disk(); }))
{

View File

@ -23,7 +23,7 @@ public:
bool is_monitoring_domain(String const& domain) const { return m_monitored_domains.contains(domain); }
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id);
virtual void pledge_domains(Vector<String> const&) override;
virtual void monitor_domain(String const&) override;

View File

@ -20,7 +20,7 @@ namespace FileSystemAccessServer {
static HashMap<int, NonnullRefPtr<ClientConnection>> s_connections;
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ClientConnection<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>(*this, move(socket), 1)
{
s_connections.set(1, *this);
@ -72,7 +72,7 @@ void ClientConnection::request_file_handler(i32 window_server_client_id, i32 par
else if (has_flag(requested_access, Core::OpenMode::WriteOnly))
access_string = "write to";
auto pid = this->socket().peer_pid();
auto pid = this->socket().peer_pid().release_value_but_fixme_should_propagate_errors();
auto exe_link = LexicalPath("/proc").append(String::number(pid)).append("exe").string();
auto exe_path = Core::File::real_path_for(exe_link);

View File

@ -25,7 +25,7 @@ public:
virtual void die() override;
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual void request_file_read_only_approved(i32, i32, String const&) override;
virtual void request_file(i32, i32, String const&, Core::OpenMode const&) override;

View File

@ -12,7 +12,7 @@
namespace ImageDecoder {
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ClientConnection<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>(*this, move(socket), 1)
{
}

View File

@ -25,7 +25,7 @@ public:
virtual void die() override;
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual Messages::ImageDecoderServer::DecodeImageResponse decode_image(Core::AnonymousBuffer const&) override;
};

View File

@ -12,7 +12,7 @@ namespace InspectorServer {
static HashMap<int, RefPtr<ClientConnection>> s_connections;
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, int client_id)
: IPC::ClientConnection<InspectorClientEndpoint, InspectorServerEndpoint>(*this, move(socket), client_id)
{
s_connections.set(client_id, *this);

View File

@ -23,7 +23,7 @@ public:
virtual void die() override;
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id);
virtual Messages::InspectorServer::GetAllObjectsResponse get_all_objects(pid_t) override;
virtual Messages::InspectorServer::SetInspectedObjectResponse set_inspected_object(pid_t, u64 object_id) override;

View File

@ -16,14 +16,17 @@ InspectableProcess* InspectableProcess::from_pid(pid_t pid)
return g_processes.get(pid).value_or(nullptr);
}
InspectableProcess::InspectableProcess(pid_t pid, NonnullRefPtr<Core::LocalSocket> socket)
InspectableProcess::InspectableProcess(pid_t pid, NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: m_pid(pid)
, m_socket(move(socket))
{
m_socket->set_blocking(true);
// FIXME: Propagate errors
MUST(m_socket->set_blocking(true));
m_socket->on_ready_to_read = [this] {
[[maybe_unused]] auto buffer = m_socket->read(1);
if (m_socket->eof()) {
char c;
[[maybe_unused]] auto buffer = m_socket->read({ &c, 1 });
if (m_socket->is_eof()) {
g_processes.remove(m_pid);
return;
}
@ -36,46 +39,51 @@ InspectableProcess::~InspectableProcess()
String InspectableProcess::wait_for_response()
{
if (m_socket->eof()) {
if (m_socket->is_eof()) {
dbgln("InspectableProcess disconnected: PID {}", m_pid);
m_socket->close();
return {};
}
u32 length {};
auto nread = m_socket->read((u8*)&length, sizeof(length));
auto nread = m_socket->read({ (u8*)&length, sizeof(length) }).release_value_but_fixme_should_propagate_errors();
if (nread != sizeof(length)) {
dbgln("InspectableProcess got malformed data: PID {}", m_pid);
m_socket->close();
return {};
}
ByteBuffer data;
size_t remaining_bytes = length;
auto data_buffer = ByteBuffer::create_uninitialized(length).release_value();
auto remaining_data_buffer = data_buffer.bytes();
while (remaining_bytes) {
auto packet = m_socket->read(remaining_bytes);
if (packet.size() == 0)
break;
if (auto result = data.try_append(packet.data(), packet.size()); result.is_error()) {
dbgln("Failed to append {} bytes to data buffer: {}", packet.size(), result.error());
while (!remaining_data_buffer.is_empty()) {
auto maybe_nread = m_socket->read(remaining_data_buffer);
if (maybe_nread.is_error()) {
dbgln("InspectableProcess::wait_for_response: Failed to read data: {}", maybe_nread.error());
break;
}
remaining_bytes -= packet.size();
auto nread = maybe_nread.release_value();
if (nread == 0)
break;
remaining_data_buffer = remaining_data_buffer.slice(nread);
}
VERIFY(data.size() == length);
VERIFY(data_buffer.size() == length);
dbgln("Got data size {} and read that many bytes", length);
return String::copy(data);
return String::copy(data_buffer);
}
void InspectableProcess::send_request(JsonObject const& request)
{
auto serialized = request.to_string();
u32 length = serialized.length();
m_socket->write((u8 const*)&length, sizeof(length));
m_socket->write(serialized);
// FIXME: Propagate errors
MUST(m_socket->write({ (u8 const*)&length, sizeof(length) }));
MUST(m_socket->write(serialized.bytes()));
}
}

View File

@ -6,13 +6,13 @@
#pragma once
#include <LibCore/LocalSocket.h>
#include <LibCore/Stream.h>
namespace InspectorServer {
class InspectableProcess {
public:
InspectableProcess(pid_t, NonnullRefPtr<Core::LocalSocket>);
InspectableProcess(pid_t, NonnullOwnPtr<Core::Stream::LocalSocket>);
~InspectableProcess();
void send_request(JsonObject const& request);
@ -22,7 +22,7 @@ public:
private:
pid_t m_pid { 0 };
NonnullRefPtr<Core::LocalSocket> m_socket;
NonnullOwnPtr<Core::Stream::LocalSocket> m_socket;
};
extern HashMap<pid_t, NonnullOwnPtr<InspectorServer::InspectableProcess>> g_processes;

View File

@ -25,7 +25,7 @@ ErrorOr<int> serenity_main(Main::Arguments)
TRY(inspectables_server->take_over_from_system_server("/tmp/portal/inspectables"));
inspectables_server->on_accept = [&](auto client_socket) {
auto pid = client_socket->peer_pid();
auto pid = client_socket->peer_pid().release_value_but_fixme_should_propagate_errors();
InspectorServer::g_processes.set(pid, make<InspectorServer::InspectableProcess>(pid, move(client_socket)));
};

View File

@ -13,7 +13,7 @@
namespace LaunchServer {
static HashMap<int, RefPtr<ClientConnection>> s_connections;
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> client_socket, int client_id)
: IPC::ClientConnection<LaunchClientEndpoint, LaunchServerEndpoint>(*this, move(client_socket), client_id)
{
s_connections.set(client_id, *this);

View File

@ -20,7 +20,7 @@ public:
virtual void die() override;
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id);
virtual Messages::LaunchServer::OpenUrlResponse open_url(URL const&, String const&) override;
virtual Messages::LaunchServer::GetHandlersForUrlResponse get_handlers_for_url(URL const&) override;

View File

@ -13,7 +13,7 @@ namespace LookupServer {
static HashMap<int, RefPtr<ClientConnection>> s_connections;
ClientConnection::ClientConnection(AK::NonnullRefPtr<Core::LocalSocket> socket, int client_id)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, int client_id)
: IPC::ClientConnection<LookupClientEndpoint, LookupServerEndpoint>(*this, move(socket), client_id)
{
s_connections.set(client_id, *this);

View File

@ -23,7 +23,7 @@ public:
virtual void die() override;
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id);
virtual Messages::LookupServer::LookupNameResponse lookup_name(String const&) override;
virtual Messages::LookupServer::LookupAddressResponse lookup_address(String const&) override;

View File

@ -13,7 +13,7 @@ namespace NotificationServer {
static HashMap<int, RefPtr<ClientConnection>> s_connections;
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> client_socket, int client_id)
: IPC::ClientConnection<NotificationClientEndpoint, NotificationServerEndpoint>(*this, move(client_socket), client_id)
{
s_connections.set(client_id, *this);

View File

@ -23,7 +23,7 @@ public:
virtual void die() override;
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id);
virtual void show_notification(String const&, String const&, Gfx::ShareableBitmap const&) override;
virtual void close_notification() override;

View File

@ -15,7 +15,7 @@ namespace RequestServer {
static HashMap<int, RefPtr<ClientConnection>> s_connections;
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ClientConnection<RequestClientEndpoint, RequestServerEndpoint>(*this, move(socket), 1)
{
s_connections.set(1, *this);

View File

@ -29,7 +29,7 @@ public:
void did_request_certificates(Badge<Request>, Request&);
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual Messages::RequestServer::IsSupportedProtocolResponse is_supported_protocol(String const&) override;
virtual Messages::RequestServer::StartRequestResponse start_request(String const&, URL const&, IPC::Dictionary const&, ByteBuffer const&) override;

View File

@ -23,7 +23,7 @@ RefPtr<ClientConnection> ClientConnection::client_connection_for(int client_id)
return nullptr;
}
ClientConnection::ClientConnection(AK::NonnullRefPtr<Core::LocalSocket> socket, int client_id)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket, int client_id)
: IPC::ClientConnection<SQLClientEndpoint, SQLServerEndpoint>(*this, move(socket), client_id)
{
s_connections.set(client_id, *this);

View File

@ -25,7 +25,7 @@ public:
static RefPtr<ClientConnection> client_connection_for(int client_id);
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id);
virtual Messages::SQLServer::ConnectResponse connect(String const&) override;
virtual Messages::SQLServer::SqlStatementResponse sql_statement(int, String const&) override;

View File

@ -15,7 +15,7 @@
class ClipboardServerConnection final
: public IPC::ServerConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>
, public ClipboardClientEndpoint {
C_OBJECT(ClipboardServerConnection);
IPC_CLIENT_CONNECTION(ClipboardServerConnection, "/tmp/portal/clipboard")
public:
Function<void()> on_data_changed;
@ -23,8 +23,8 @@ public:
void set_bitmap(Gfx::Bitmap const& bitmap);
private:
ClipboardServerConnection()
: IPC::ServerConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>(*this, "/tmp/portal/clipboard")
ClipboardServerConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ServerConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>(*this, move(socket))
{
}
virtual void clipboard_data_changed(String const&) override

View File

@ -29,7 +29,7 @@
namespace WebContent {
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ClientConnection<WebContentClientEndpoint, WebContentServerEndpoint>(*this, move(socket), 1)
, m_page_host(PageHost::create(*this))
{

View File

@ -32,7 +32,7 @@ public:
void initialize_js_console(Badge<PageHost>);
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>);
Web::Page& page();
const Web::Page& page() const;

View File

@ -13,7 +13,7 @@ namespace WebSocket {
static HashMap<int, RefPtr<ClientConnection>> s_connections;
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: IPC::ClientConnection<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket), 1)
{
s_connections.set(1, *this);

View File

@ -24,7 +24,7 @@ public:
virtual void die() override;
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual Messages::WebSocketServer::ConnectResponse connect(URL const&, String const&, Vector<String> const&, Vector<String> const&, IPC::Dictionary const&) override;
virtual Messages::WebSocketServer::ReadyStateResponse ready_state(i32) override;

View File

@ -45,7 +45,7 @@ ClientConnection* ClientConnection::from_client_id(int client_id)
return (*it).value.ptr();
}
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
ClientConnection::ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> client_socket, int client_id)
: IPC::ClientConnection<WindowClientEndpoint, WindowServerEndpoint>(*this, move(client_socket), client_id)
{
if (!s_connections)

View File

@ -81,7 +81,7 @@ public:
void notify_display_link(Badge<Compositor>);
private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
explicit ClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket>, int client_id);
// ^ClientConnection
virtual void die() override;

View File

@ -13,7 +13,7 @@ namespace WindowServer {
HashMap<int, NonnullRefPtr<WMClientConnection>> WMClientConnection::s_connections {};
WMClientConnection::WMClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
WMClientConnection::WMClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> client_socket, int client_id)
: IPC::ClientConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint>(*this, move(client_socket), client_id)
{
s_connections.set(client_id, *this);

View File

@ -36,7 +36,7 @@ public:
int window_id() const { return m_window_id; }
private:
explicit WMClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id);
explicit WMClientConnection(NonnullOwnPtr<Core::Stream::LocalSocket> client_socket, int client_id);
// ^ClientConnection
virtual void die() override;

View File

@ -32,7 +32,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
Core::EventLoop loop;
auto audio_client = Audio::ClientConnection::construct();
auto audio_client = TRY(Audio::ClientConnection::try_create());
auto maybe_loader = Audio::Loader::create(path);
if (maybe_loader.is_error()) {
warnln("Failed to load audio file: {}", maybe_loader.error().description);

View File

@ -29,7 +29,7 @@ enum AudioVariable : u32 {
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
Core::EventLoop loop;
auto audio_client = Audio::ClientConnection::construct();
auto audio_client = TRY(Audio::ClientConnection::try_create());
String command = String::empty();
Vector<StringView> command_arguments;

View File

@ -188,7 +188,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
}
Core::EventLoop loop;
auto protocol_client = Protocol::RequestClient::construct();
auto protocol_client = TRY(Protocol::RequestClient::try_create());
auto request = protocol_client->start_request(method, url, request_headers, data ? StringView { data }.bytes() : ReadonlyBytes {});
if (!request) {

View File

@ -71,7 +71,7 @@ public:
m_editor->set_prompt(prompt_for_level(open_indents));
};
m_sql_client = SQL::SQLClient::construct();
m_sql_client = SQL::SQLClient::try_create().release_value_but_fixme_should_propagate_errors();
m_sql_client->on_connected = [this](int connection_id, String const& connected_to_database) {
outln("Connected to \033[33;1m{}\033[0m", connected_to_database);

View File

@ -40,9 +40,15 @@ int main(int argc, char** argv)
}
Core::EventLoop loop;
auto maybe_websocket_client = Protocol::WebSocketClient::try_create();
if (maybe_websocket_client.is_error()) {
warnln("Failed to connect to the websocket server: {}\n", maybe_websocket_client.error());
}
auto websocket_client = maybe_websocket_client.release_value();
RefPtr<Line::Editor> editor = Line::Editor::construct();
bool should_quit = false;
auto websocket_client = Protocol::WebSocketClient::construct();
auto socket = websocket_client->connect(url, origin);
if (!socket) {
warnln("Failed to start socket for '{}'\n", url);