blob: 2c49b35c89b6f1d32ed40165ba6218762aca17b2 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fidl/fidl.test.compatibility/cpp/wire.h>
#include <fuchsia/sys/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/stdcompat/optional.h>
#include <lib/sys/cpp/component_context.h>
#include <zircon/status.h>
#include <cstdlib>
#include <iostream>
#include <string>
constexpr const char kEchoInterfaceName[] = "fidl.test.compatibility.Echo";
using namespace fidl_test_compatibility;
class EchoClientApp {
public:
EchoClientApp(::fidl::StringView server_url)
: context_(sys::ComponentContext::CreateAndServeOutgoingDirectory()),
client_(fidl::WireSyncClient<Echo>(ConnectTo(server_url))) {}
// Half the methods are testing the managed flavor; the other half are testing caller-allocate.
fidl::WireResult<Echo::EchoMinimal> EchoMinimal(::fidl::StringView forward_to_server) {
return client_->EchoMinimal(std::move(forward_to_server));
}
fidl::WireResult<Echo::EchoMinimalWithError> EchoMinimalWithError(
::fidl::StringView forward_to_server, wire::RespondWith result_variant) {
return client_->EchoMinimalWithError(std::move(forward_to_server), result_variant);
}
zx_status_t EchoMinimalNoRetVal(::fidl::StringView forward_to_server,
fidl::WireSyncEventHandler<Echo>& event_handler) {
auto result = client_->EchoMinimalNoRetVal(std::move(forward_to_server));
if (result.status() != ZX_OK) {
return result.status();
}
return client_.HandleOneEvent(event_handler).status();
}
fidl::WireResult<Echo::EchoStruct> EchoStruct(wire::Struct value,
::fidl::StringView forward_to_server) {
return client_->EchoStruct(std::move(value), std::move(forward_to_server));
}
fidl::WireResult<Echo::EchoStructWithError> EchoStructWithError(
wire::Struct value, wire::DefaultEnum err, ::fidl::StringView forward_to_server,
wire::RespondWith result_variant) {
return client_->EchoStructWithError(std::move(value), err, std::move(forward_to_server),
result_variant);
}
zx_status_t EchoStructNoRetVal(wire::Struct value, ::fidl::StringView forward_to_server,
fidl::WireSyncEventHandler<Echo>& event_handler) {
auto result = client_->EchoStructNoRetVal(std::move(value), std::move(forward_to_server));
if (result.status() != ZX_OK) {
return result.status();
}
return client_.HandleOneEvent(event_handler).status();
}
fidl::WireUnownedResult<Echo::EchoArrays> EchoArrays(::fidl::BufferSpan buffer,
wire::ArraysStruct value,
::fidl::StringView forward_to_server) {
return client_.buffer(buffer)->EchoArrays(std::move(value), forward_to_server);
}
fidl::WireResult<Echo::EchoArraysWithError> EchoArraysWithError(
wire::ArraysStruct value, wire::DefaultEnum err, ::fidl::StringView forward_to_server,
wire::RespondWith result_variant) {
return client_->EchoArraysWithError(std::move(value), err, std::move(forward_to_server),
result_variant);
}
fidl::WireResult<Echo::EchoVectors> EchoVectors(wire::VectorsStruct value,
::fidl::StringView forward_to_server) {
return client_->EchoVectors(std::move(value), std::move(forward_to_server));
}
fidl::WireResult<Echo::EchoVectorsWithError> EchoVectorsWithError(
wire::VectorsStruct value, wire::DefaultEnum err, ::fidl::StringView forward_to_server,
wire::RespondWith result_variant) {
return client_->EchoVectorsWithError(std::move(value), err, std::move(forward_to_server),
result_variant);
}
fidl::WireUnownedResult<Echo::EchoTable> EchoTable(::fidl::BufferSpan buffer,
wire::AllTypesTable value,
::fidl::StringView forward_to_server) {
return client_.buffer(buffer)->EchoTable(value, forward_to_server);
}
fidl::WireUnownedResult<Echo::EchoTableWithError> EchoTableWithError(
::fidl::BufferSpan buffer, wire::AllTypesTable value, wire::DefaultEnum err,
::fidl::StringView forward_to_server, wire::RespondWith result_variant) {
return client_.buffer(buffer)->EchoTableWithError(value, err, forward_to_server,
result_variant);
}
fidl::WireResult<Echo::EchoXunions> EchoXunions(::fidl::VectorView<wire::AllTypesXunion> value,
::fidl::StringView forward_to_server) {
return client_->EchoXunions(std::move(value), std::move(forward_to_server));
}
fidl::WireResult<Echo::EchoXunionsWithError> EchoXunionsWithError(
::fidl::VectorView<wire::AllTypesXunion> value, wire::DefaultEnum err,
::fidl::StringView forward_to_server, wire::RespondWith result_variant) {
return client_->EchoXunionsWithError(std::move(value), err, std::move(forward_to_server),
result_variant);
}
EchoClientApp(const EchoClientApp&) = delete;
EchoClientApp& operator=(const EchoClientApp&) = delete;
private:
// Called once upon construction to launch and connect to the server.
::fidl::ClientEnd<fidl_test_compatibility::Echo> ConnectTo(::fidl::StringView server_url) {
fuchsia::sys::LaunchInfo launch_info;
launch_info.url = std::string(server_url.data(), server_url.size());
echo_provider_ = sys::ServiceDirectory::CreateWithRequest(&launch_info.directory_request);
fuchsia::sys::LauncherPtr launcher;
context_->svc()->Connect(launcher.NewRequest());
launcher->CreateComponent(std::move(launch_info), controller_.NewRequest());
auto echo_ends = ::fidl::CreateEndpoints<fidl_test_compatibility::Echo>();
ZX_ASSERT(echo_ends.is_ok());
ZX_ASSERT(echo_provider_->Connect(kEchoInterfaceName, echo_ends->server.TakeChannel()) ==
ZX_OK);
return std::move(echo_ends->client);
}
std::unique_ptr<sys::ComponentContext> context_;
std::shared_ptr<sys::ServiceDirectory> echo_provider_;
fuchsia::sys::ComponentControllerPtr controller_;
fidl::WireSyncClient<Echo> client_;
};
class EchoConnection final : public fidl::WireServer<Echo> {
public:
EchoConnection() = default;
void EchoMinimal(EchoMinimalRequestView request, EchoMinimalCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
completer.Reply();
} else {
EchoClientApp app(request->forward_to_server);
auto result = app.EchoMinimal("");
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s",
result.FormatDescription().c_str());
completer.Reply();
}
}
void EchoMinimalWithError(EchoMinimalWithErrorRequestView request,
EchoMinimalWithErrorCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
if (request->result_variant == wire::RespondWith::kErr) {
completer.ReplyError(0u);
} else {
completer.ReplySuccess();
}
} else {
EchoClientApp app(request->forward_to_server);
auto result = app.EchoMinimalWithError("", request->result_variant);
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s",
result.FormatDescription().c_str());
completer.Reply(std::move(result->result));
}
}
void EchoMinimalNoRetVal(EchoMinimalNoRetValRequestView request,
EchoMinimalNoRetValCompleter::Sync&) override {
if (request->forward_to_server.empty()) {
fidl::Result result = server_binding_.value()->EchoMinimalEvent();
ZX_ASSERT_MSG(result.ok(), "Replying with event failed: %s",
result.FormatDescription().c_str());
} else {
class EventHandler : public fidl::WireSyncEventHandler<Echo> {
public:
explicit EventHandler(EchoConnection* connection) : connection_(connection) {}
fidl::Result result() const { return result_; }
void EchoMinimalEvent(fidl::WireResponse<Echo::EchoMinimalEvent>* event) override {
result_ = connection_->server_binding_.value()->EchoMinimalEvent();
}
zx_status_t Unknown() override {
ZX_PANIC("Received unexpected event");
return ZX_ERR_INVALID_ARGS;
}
private:
EchoConnection* const connection_;
fidl::Result result_ = fidl::Result::Ok();
};
EchoClientApp app(request->forward_to_server);
EventHandler event_handler(this);
zx_status_t status = app.EchoMinimalNoRetVal("", event_handler);
ZX_ASSERT_MSG(status == ZX_OK, "Replying with event failed direct: %s",
zx_status_get_string(status));
ZX_ASSERT_MSG(event_handler.result().ok(), "Replying with event failed indirect: %s",
event_handler.result().FormatDescription().c_str());
}
}
void EchoStruct(EchoStructRequestView request, EchoStructCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
completer.Reply(std::move(request->value));
} else {
EchoClientApp app(request->forward_to_server);
auto result = app.EchoStruct(std::move(request->value), "");
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s",
result.FormatDescription().c_str());
completer.Reply(std::move(result.Unwrap()->value));
}
}
void EchoStructWithError(EchoStructWithErrorRequestView request,
EchoStructWithErrorCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
if (request->result_variant == wire::RespondWith::kErr) {
completer.ReplyError(request->result_err);
} else {
completer.ReplySuccess(std::move(request->value));
}
} else {
EchoClientApp app(request->forward_to_server);
auto result = app.EchoStructWithError(std::move(request->value), request->result_err, "",
request->result_variant);
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s",
result.FormatDescription().c_str());
completer.Reply(std::move(result->result));
}
}
void EchoStructNoRetVal(EchoStructNoRetValRequestView request,
EchoStructNoRetValCompleter::Sync&) override {
if (request->forward_to_server.empty()) {
fidl::Result result = server_binding_.value()->EchoEvent(std::move(request->value));
ZX_ASSERT_MSG(result.ok(), "Replying with event failed: %s",
result.FormatDescription().c_str());
} else {
class EventHandler : public fidl::WireSyncEventHandler<Echo> {
public:
explicit EventHandler(EchoConnection* connection) : connection_(connection) {}
fidl::Result result() const { return result_; }
void EchoEvent(fidl::WireResponse<Echo::EchoEvent>* event) override {
result_ = connection_->server_binding_.value()->EchoEvent(std::move(event->value));
}
zx_status_t Unknown() override {
ZX_PANIC("Received unexpected event");
return ZX_ERR_INVALID_ARGS;
}
private:
EchoConnection* const connection_;
fidl::Result result_ = fidl::Result::Ok();
};
EchoClientApp app(request->forward_to_server);
EventHandler event_handler(this);
zx_status_t status = app.EchoStructNoRetVal(std::move(request->value), "", event_handler);
ZX_ASSERT_MSG(status == ZX_OK, "Replying with event failed direct: %s",
zx_status_get_string(status));
ZX_ASSERT_MSG(event_handler.result().ok(), "Replying with event failed indirect: %s",
event_handler.result().FormatDescription().c_str());
}
}
void EchoArrays(EchoArraysRequestView request, EchoArraysCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
completer.Reply(std::move(request->value));
} else {
fidl::SyncClientBuffer<Echo::EchoArrays> buffer;
EchoClientApp app(request->forward_to_server);
auto result = app.EchoArrays(buffer.view(), std::move(request->value), "");
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s",
result.FormatDescription().c_str());
completer.Reply(std::move(result.Unwrap()->value));
}
}
void EchoArraysWithError(EchoArraysWithErrorRequestView request,
EchoArraysWithErrorCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
if (request->result_variant == wire::RespondWith::kErr) {
completer.ReplyError(request->result_err);
} else {
completer.ReplySuccess(std::move(request->value));
}
} else {
EchoClientApp app(request->forward_to_server);
auto result = app.EchoArraysWithError(std::move(request->value), request->result_err, "",
request->result_variant);
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s: %s",
zx_status_get_string(result.status()), result.FormatDescription().c_str());
completer.Reply(std::move(result->result));
}
}
void EchoVectors(EchoVectorsRequestView request, EchoVectorsCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
completer.Reply(std::move(request->value));
} else {
EchoClientApp app(request->forward_to_server);
wire::VectorsStruct out_value;
auto result = app.EchoVectors(std::move(request->value), "");
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s: %s",
zx_status_get_string(result.status()), result.FormatDescription().c_str());
completer.Reply(std::move(result.Unwrap()->value));
}
}
void EchoVectorsWithError(EchoVectorsWithErrorRequestView request,
EchoVectorsWithErrorCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
if (request->result_variant == wire::RespondWith::kErr) {
completer.ReplyError(request->result_err);
} else {
completer.ReplySuccess(std::move(request->value));
}
} else {
EchoClientApp app(request->forward_to_server);
auto result = app.EchoVectorsWithError(std::move(request->value), request->result_err, "",
request->result_variant);
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s: %s",
zx_status_get_string(result.status()), result.FormatDescription().c_str());
completer.Reply(std::move(result->result));
}
}
void EchoTable(EchoTableRequestView request, EchoTableCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
completer.Reply(request->value);
} else {
fidl::SyncClientBuffer<Echo::EchoTable> buffer;
EchoClientApp app(request->forward_to_server);
auto result = app.EchoTable(buffer.view(), request->value, "");
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s: %s",
zx_status_get_string(result.status()), result.FormatDescription().c_str());
completer.Reply(result.Unwrap()->value);
}
}
void EchoTableWithError(EchoTableWithErrorRequestView request,
EchoTableWithErrorCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
if (request->result_variant == wire::RespondWith::kErr) {
completer.ReplyError(request->result_err);
} else {
completer.ReplySuccess(request->value);
}
} else {
fidl::SyncClientBuffer<Echo::EchoTableWithError> buffer;
EchoClientApp app(request->forward_to_server);
auto result = app.EchoTableWithError(buffer.view(), request->value, request->result_err, "",
request->result_variant);
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s: %s",
zx_status_get_string(result.status()), result.FormatDescription().c_str());
completer.Reply(std::move(result->result));
}
}
void EchoXunions(EchoXunionsRequestView request, EchoXunionsCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
completer.Reply(std::move(request->value));
} else {
EchoClientApp app(request->forward_to_server);
auto result = app.EchoXunions(std::move(request->value), "");
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s: %s",
zx_status_get_string(result.status()), result.FormatDescription().c_str());
completer.Reply(std::move(result.Unwrap()->value));
}
}
void EchoXunionsWithError(EchoXunionsWithErrorRequestView request,
EchoXunionsWithErrorCompleter::Sync& completer) override {
if (request->forward_to_server.empty()) {
if (request->result_variant == wire::RespondWith::kErr) {
completer.ReplyError(request->result_err);
} else {
completer.ReplySuccess(std::move(request->value));
}
} else {
EchoClientApp app(request->forward_to_server);
auto result = app.EchoXunionsWithError(std::move(request->value), request->result_err, "",
request->result_variant);
ZX_ASSERT_MSG(result.status() == ZX_OK, "Forwarding failed: %s: %s",
zx_status_get_string(result.status()), result.FormatDescription().c_str());
completer.Reply(std::move(result->result));
}
}
void set_server_binding(::fidl::ServerBindingRef<Echo> binding) {
server_binding_.emplace(binding);
}
private:
cpp17::optional<::fidl::ServerBindingRef<Echo>> server_binding_;
};
int main(int argc, const char** argv) {
// The FIDL support lib requires async_get_default_dispatcher() to return
// non-null.
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
std::vector<std::unique_ptr<EchoConnection>> connections;
context->outgoing()->AddPublicService(
std::make_unique<vfs::Service>([&](zx::channel request, async_dispatcher_t* dispatcher) {
auto conn = std::make_unique<EchoConnection>();
auto binding = ::fidl::BindServer(
dispatcher, ::fidl::ServerEnd<fidl_test_compatibility::Echo>(std::move(request)),
conn.get());
conn->set_server_binding(std::move(binding));
connections.push_back(std::move(conn));
}),
kEchoInterfaceName);
loop.Run();
return EXIT_SUCCESS;
}