1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:38:11 +00:00

Userland: Add try_* IPC handlers

This enables calling auto-generated IPC methods in a way that doesn't
crash the client if the peer disconnects.
This commit is contained in:
Gunnar Beutner 2021-05-03 16:51:42 +02:00 committed by Andreas Kling
parent 34cf5cf07f
commit 8a6db55e79
4 changed files with 62 additions and 27 deletions

View file

@ -247,6 +247,7 @@ int main(int argc, char** argv)
#pragma once #pragma once
#include <AK/MemoryStream.h> #include <AK/MemoryStream.h>
#include <AK/OwnPtr.h> #include <AK/OwnPtr.h>
#include <AK/Result.h>
#include <AK/URL.h> #include <AK/URL.h>
#include <AK/Utf8View.h> #include <AK/Utf8View.h>
#include <LibCore/AnonymousBuffer.h> #include <LibCore/AnonymousBuffer.h>
@ -496,7 +497,7 @@ public:
for (auto& message : endpoint.messages) { for (auto& message : endpoint.messages) {
auto message_generator = endpoint_generator.fork(); auto message_generator = endpoint_generator.fork();
auto do_implement_proxy = [&](String const& name, Vector<Parameter> const& parameters, bool is_synchronous) { auto do_implement_proxy = [&](String const& name, Vector<Parameter> const& parameters, bool is_synchronous, bool is_try) {
String return_type = "void"; String return_type = "void";
if (is_synchronous) { if (is_synchronous) {
if (message.outputs.size() == 1) if (message.outputs.size() == 1)
@ -504,14 +505,23 @@ public:
else if (!message.outputs.is_empty()) else if (!message.outputs.is_empty())
return_type = message_name(endpoint.name, message.name, true); return_type = message_name(endpoint.name, message.name, true);
} }
String inner_return_type = return_type;
if (is_try) {
StringBuilder builder;
builder.append("Result<");
builder.append(return_type);
builder.append(", IPC::ErrorCode>");
return_type = builder.to_string();
}
message_generator.set("message.name", message.name); message_generator.set("message.name", message.name);
message_generator.set("message.pascal_name", pascal_case(message.name)); message_generator.set("message.pascal_name", pascal_case(message.name));
message_generator.set("message.complex_return_type", return_type); message_generator.set("message.complex_return_type", return_type);
message_generator.set("async_prefix_maybe", is_synchronous ? "" : "async_"); message_generator.set("async_prefix_maybe", is_synchronous ? "" : "async_");
message_generator.set("try_prefix_maybe", is_try ? "try_" : "");
message_generator.set("handler_name", name); message_generator.set("handler_name", name);
message_generator.append(R"~~~( message_generator.append(R"~~~(
@message.complex_return_type@ @async_prefix_maybe@@handler_name@()~~~"); @message.complex_return_type@ @try_prefix_maybe@@async_prefix_maybe@@handler_name@()~~~");
for (size_t i = 0; i < parameters.size(); ++i) { for (size_t i = 0; i < parameters.size(); ++i) {
auto& parameter = parameters[i]; auto& parameter = parameters[i];
@ -525,18 +535,21 @@ public:
message_generator.append(") {"); message_generator.append(") {");
if (is_synchronous) { if (is_synchronous && !is_try) {
if (return_type != "void") { if (return_type != "void") {
message_generator.append(R"~~~( message_generator.append(R"~~~(
return )~~~"); return )~~~");
if (message.outputs.size() != 1) if (message.outputs.size() != 1)
message_generator.append(" move(*"); message_generator.append("move(*");
} else { } else {
message_generator.append(R"~~~( message_generator.append(R"~~~(
)~~~"); )~~~");
} }
message_generator.append("m_connection.template send_sync<Messages::@endpoint.name@::@message.pascal_name@>("); message_generator.append("m_connection.template send_sync<Messages::@endpoint.name@::@message.pascal_name@>(");
} else if (is_try) {
message_generator.append(R"~~~(
auto result = m_connection.template send_sync_but_allow_failure<Messages::@endpoint.name@::@message.pascal_name@>()~~~");
} else { } else {
message_generator.append(R"~~~( message_generator.append(R"~~~(
m_connection.post_message(Messages::@endpoint.name@::@message.pascal_name@ { )~~~"); m_connection.post_message(Messages::@endpoint.name@::@message.pascal_name@ { )~~~");
@ -554,7 +567,7 @@ public:
argument_generator.append(", "); argument_generator.append(", ");
} }
if (is_synchronous) { if (is_synchronous && !is_try) {
if (return_type != "void") { if (return_type != "void") {
message_generator.append(")"); message_generator.append(")");
} }
@ -566,20 +579,36 @@ public:
} else } else
message_generator.append(")"); message_generator.append(")");
message_generator.append(R"~~~(; message_generator.append(";");
} } else if (is_try) {
message_generator.append(R"~~~();
if (!result)
return IPC::ErrorCode::PeerDisconnected;
)~~~"); )~~~");
if (inner_return_type != "void") {
message_generator.append(R"~~~(
return move(*result);
)~~~");
} else {
message_generator.append(R"~~~(
return { };
)~~~");
}
} else { } else {
message_generator.append(R"~~~( }); message_generator.append(R"~~~( });
}
)~~~"); )~~~");
} }
message_generator.append(R"~~~(
}
)~~~");
}; };
do_implement_proxy(message.name, message.inputs, message.is_synchronous); do_implement_proxy(message.name, message.inputs, message.is_synchronous, false);
if (message.is_synchronous) if (message.is_synchronous) {
do_implement_proxy(message.name, message.inputs, false); do_implement_proxy(message.name, message.inputs, false, false);
do_implement_proxy(message.name, message.inputs, true, true);
}
} }
endpoint_generator.append(R"~~~( endpoint_generator.append(R"~~~(

View file

@ -59,8 +59,8 @@ static LaunchServerConnection& connection()
bool Launcher::add_allowed_url(const URL& url) bool Launcher::add_allowed_url(const URL& url)
{ {
auto response = connection().send_sync_but_allow_failure<Messages::LaunchServer::AddAllowedUrl>(url); auto response_or_error = connection().try_add_allowed_url(url);
if (!response) { if (response_or_error.is_error()) {
dbgln("Launcher::add_allowed_url: Failed"); dbgln("Launcher::add_allowed_url: Failed");
return false; return false;
} }
@ -69,8 +69,8 @@ bool Launcher::add_allowed_url(const URL& url)
bool Launcher::add_allowed_handler_with_any_url(const String& handler) bool Launcher::add_allowed_handler_with_any_url(const String& handler)
{ {
auto response = connection().send_sync_but_allow_failure<Messages::LaunchServer::AddAllowedHandlerWithAnyUrl>(handler); auto response_or_error = connection().try_add_allowed_handler_with_any_url(handler);
if (!response) { if (response_or_error.is_error()) {
dbgln("Launcher::add_allowed_handler_with_any_url: Failed"); dbgln("Launcher::add_allowed_handler_with_any_url: Failed");
return false; return false;
} }
@ -79,8 +79,8 @@ bool Launcher::add_allowed_handler_with_any_url(const String& handler)
bool Launcher::add_allowed_handler_with_only_specific_urls(const String& handler, const Vector<URL>& urls) bool Launcher::add_allowed_handler_with_only_specific_urls(const String& handler, const Vector<URL>& urls)
{ {
auto response = connection().send_sync_but_allow_failure<Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificUrls>(handler, urls); auto response_or_error = connection().try_add_allowed_handler_with_only_specific_urls(handler, urls);
if (!response) { if (response_or_error.is_error()) {
dbgln("Launcher::add_allowed_handler_with_only_specific_urls: Failed"); dbgln("Launcher::add_allowed_handler_with_only_specific_urls: Failed");
return false; return false;
} }
@ -89,8 +89,8 @@ bool Launcher::add_allowed_handler_with_only_specific_urls(const String& handler
bool Launcher::seal_allowlist() bool Launcher::seal_allowlist()
{ {
auto response = connection().send_sync_but_allow_failure<Messages::LaunchServer::SealAllowlist>(); auto response_or_error = connection().try_seal_allowlist();
if (!response) { if (response_or_error.is_error()) {
dbgln("Launcher::seal_allowlist: Failed"); dbgln("Launcher::seal_allowlist: Failed");
return false; return false;
} }

View file

@ -37,6 +37,10 @@ struct MessageBuffer {
Vector<RefPtr<AutoCloseFileDescriptor>> fds; Vector<RefPtr<AutoCloseFileDescriptor>> fds;
}; };
enum class ErrorCode : u32 {
PeerDisconnected
};
class Message { class Message {
public: public:
virtual ~Message(); virtual ~Message();

View file

@ -42,21 +42,23 @@ Optional<DecodedImage> Client::decode_image(const ByteBuffer& encoded_data)
} }
memcpy(encoded_buffer.data<void>(), encoded_data.data(), encoded_data.size()); memcpy(encoded_buffer.data<void>(), encoded_data.data(), encoded_data.size());
auto response = send_sync_but_allow_failure<Messages::ImageDecoderServer::DecodeImage>(move(encoded_buffer)); auto response_or_error = try_decode_image(move(encoded_buffer));
if (!response) { if (response_or_error.is_error()) {
dbgln("ImageDecoder died heroically"); dbgln("ImageDecoder died heroically");
return {}; return {};
} }
auto& response = response_or_error.value();
DecodedImage image; DecodedImage image;
image.is_animated = response->is_animated(); image.is_animated = response.is_animated();
image.loop_count = response->loop_count(); image.loop_count = response.loop_count();
image.frames.resize(response->bitmaps().size()); image.frames.resize(response.bitmaps().size());
for (size_t i = 0; i < image.frames.size(); ++i) { for (size_t i = 0; i < image.frames.size(); ++i) {
auto& frame = image.frames[i]; auto& frame = image.frames[i];
frame.bitmap = response->bitmaps()[i].bitmap(); frame.bitmap = response.bitmaps()[i].bitmap();
frame.duration = response->durations()[i]; frame.duration = response.durations()[i];
} }
return image; return image;
} }