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
Notes: sideshowbarker 2024-07-18 18:44:19 +09:00
4 changed files with 62 additions and 27 deletions

View file

@ -247,6 +247,7 @@ int main(int argc, char** argv)
#pragma once
#include <AK/MemoryStream.h>
#include <AK/OwnPtr.h>
#include <AK/Result.h>
#include <AK/URL.h>
#include <AK/Utf8View.h>
#include <LibCore/AnonymousBuffer.h>
@ -496,7 +497,7 @@ public:
for (auto& message : endpoint.messages) {
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";
if (is_synchronous) {
if (message.outputs.size() == 1)
@ -504,14 +505,23 @@ public:
else if (!message.outputs.is_empty())
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.pascal_name", pascal_case(message.name));
message_generator.set("message.complex_return_type", return_type);
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.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) {
auto& parameter = parameters[i];
@ -525,18 +535,21 @@ public:
message_generator.append(") {");
if (is_synchronous) {
if (is_synchronous && !is_try) {
if (return_type != "void") {
message_generator.append(R"~~~(
return )~~~");
if (message.outputs.size() != 1)
message_generator.append(" move(*");
message_generator.append("move(*");
} else {
message_generator.append(R"~~~(
)~~~");
}
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 {
message_generator.append(R"~~~(
m_connection.post_message(Messages::@endpoint.name@::@message.pascal_name@ { )~~~");
@ -554,7 +567,7 @@ public:
argument_generator.append(", ");
}
if (is_synchronous) {
if (is_synchronous && !is_try) {
if (return_type != "void") {
message_generator.append(")");
}
@ -566,20 +579,36 @@ public:
} else
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 {
message_generator.append(R"~~~( });
}
)~~~");
}
message_generator.append(R"~~~(
}
)~~~");
};
do_implement_proxy(message.name, message.inputs, message.is_synchronous);
if (message.is_synchronous)
do_implement_proxy(message.name, message.inputs, false);
do_implement_proxy(message.name, message.inputs, message.is_synchronous, false);
if (message.is_synchronous) {
do_implement_proxy(message.name, message.inputs, false, false);
do_implement_proxy(message.name, message.inputs, true, true);
}
}
endpoint_generator.append(R"~~~(

View file

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

View file

@ -37,6 +37,10 @@ struct MessageBuffer {
Vector<RefPtr<AutoCloseFileDescriptor>> fds;
};
enum class ErrorCode : u32 {
PeerDisconnected
};
class Message {
public:
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());
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");
return {};
}
auto& response = response_or_error.value();
DecodedImage image;
image.is_animated = response->is_animated();
image.loop_count = response->loop_count();
image.frames.resize(response->bitmaps().size());
image.is_animated = response.is_animated();
image.loop_count = response.loop_count();
image.frames.resize(response.bitmaps().size());
for (size_t i = 0; i < image.frames.size(); ++i) {
auto& frame = image.frames[i];
frame.bitmap = response->bitmaps()[i].bitmap();
frame.duration = response->durations()[i];
frame.bitmap = response.bitmaps()[i].bitmap();
frame.duration = response.durations()[i];
}
return image;
}