blob: b408b733eef821b704cd1d5201cbd0e8670025aa [file] [log] [blame]
// Copyright 2021 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.
#ifndef LIB_FIDL_LLCPP_INTERNAL_TRANSPORT_CHANNEL_H_
#define LIB_FIDL_LLCPP_INTERNAL_TRANSPORT_CHANNEL_H_
#ifndef __Fuchsia__
#error Fuchsia-only Header
#endif
#include <lib/async/dispatcher.h>
#include <lib/async/wait.h>
#include <lib/fidl/llcpp/internal/endpoints.h>
#include <lib/fidl/llcpp/internal/transport.h>
#include <lib/fidl/llcpp/message_storage.h>
#include <lib/zx/channel.h>
#include <zircon/syscalls.h>
namespace fidl {
template <typename Protocol>
class ClientEnd;
template <typename Protocol>
class UnownedClientEnd;
template <typename Protocol>
class ServerEnd;
template <typename Protocol>
class ServerBindingRef;
template <typename FidlMethod>
class WireUnownedResult;
template <typename FidlMethod>
class Result;
namespace internal {
struct ChannelMessageStorageView;
struct ChannelTransport {
using OwnedType = zx::channel;
using UnownedType = zx::unowned_channel;
template <typename Protocol>
using ClientEnd = fidl::ClientEnd<Protocol>;
template <typename Protocol>
using UnownedClientEnd = fidl::UnownedClientEnd<Protocol>;
template <typename Protocol>
using ServerEnd = fidl::ServerEnd<Protocol>;
template <typename Protocol>
using ServerBindingRef = fidl::ServerBindingRef<Protocol>;
template <typename FidlMethod>
using WireUnownedResult = fidl::WireUnownedResult<FidlMethod>;
template <typename FidlMethod>
using Result = fidl::Result<FidlMethod>;
using HandleMetadata = fidl_channel_handle_metadata_t;
using IncomingTransportContextType = struct {};
using OutgoingTransportContextType = struct {};
using MessageStorageView = ChannelMessageStorageView;
static constexpr bool kTransportProvidesReadBuffer = false;
// This is chosen for performance reasons. It should generally be the same as kIovecChunkSize in
// the kernel.
static constexpr uint32_t kNumIovecs = 16;
static const TransportVTable VTable;
static const CodingConfig EncodingConfiguration;
};
template <>
struct AssociatedTransportImpl<zx::channel> {
using type = ChannelTransport;
};
template <>
struct AssociatedTransportImpl<zx::unowned_channel> {
using type = ChannelTransport;
};
template <>
struct AssociatedTransportImpl<fidl_channel_handle_metadata_t> {
using type = ChannelTransport;
};
static_assert(sizeof(fidl_handle_t) == sizeof(zx_handle_t));
class ChannelWaiter : private async_wait_t, public TransportWaiter {
public:
ChannelWaiter(fidl_handle_t handle, async_dispatcher_t* dispatcher,
TransportWaitSuccessHandler success_handler,
TransportWaitFailureHandler failure_handler)
: async_wait_t({{ASYNC_STATE_INIT},
&ChannelWaiter::OnWaitFinished,
handle,
ZX_CHANNEL_PEER_CLOSED | ZX_CHANNEL_READABLE,
0}),
dispatcher_(dispatcher),
success_handler_(std::move(success_handler)),
failure_handler_(std::move(failure_handler)) {}
zx_status_t Begin() override {
zx_status_t status = async_begin_wait(dispatcher_, static_cast<async_wait_t*>(this));
if (status == ZX_ERR_BAD_STATE) {
// async_begin_wait return ZX_ERR_BAD_STATE if the dispatcher is shutting down.
return ZX_ERR_CANCELED;
}
return status;
}
zx_status_t Cancel() override {
return async_cancel_wait(dispatcher_, static_cast<async_wait_t*>(this));
}
private:
static void OnWaitFinished(async_dispatcher_t* dispatcher, async_wait_t* wait, zx_status_t status,
const zx_packet_signal_t* signal) {
static_cast<ChannelWaiter*>(wait)->HandleWaitFinished(dispatcher, status, signal);
}
void HandleWaitFinished(async_dispatcher_t* dispatcher, zx_status_t status,
const zx_packet_signal_t* signal);
async_dispatcher_t* dispatcher_;
TransportWaitSuccessHandler success_handler_;
TransportWaitFailureHandler failure_handler_;
};
// A view into an object providing storage for messages read from a Zircon channel.
struct ChannelMessageStorageView : public MessageStorageViewBase {
fidl::BufferSpan bytes;
zx_handle_t* handles;
fidl_channel_handle_metadata_t* handle_metadata;
uint32_t handle_capacity;
};
// Base class with common functionality for all storage classes backing messages
// read from a Zircon channel.
template <typename Derived>
struct ChannelMessageStorageBase {
ChannelMessageStorageView view() {
auto* derived = static_cast<Derived*>(this);
return ChannelMessageStorageView{
.bytes = derived->bytes_.view(),
.handles = derived->handles_.data(),
.handle_metadata = derived->handle_metadata_.data(),
.handle_capacity = Derived::kNumHandles,
};
}
};
} // namespace internal
// The client endpoint of a FIDL channel.
//
// The remote (server) counterpart of the channel expects this end of the
// channel to speak the protocol represented by |Protocol|. This type is the
// dual of |ServerEnd|.
//
// |ClientEnd| is thread-compatible: it may be transferred to another thread
// or another process.
template <typename Protocol>
class ClientEnd final : public internal::ClientEndBase<Protocol, internal::ChannelTransport> {
static_assert(std::is_same_v<typename Protocol::Transport, internal::ChannelTransport>);
using ClientEndBase = internal::ClientEndBase<Protocol, internal::ChannelTransport>;
public:
using ClientEndBase::ClientEndBase;
// The underlying channel.
const zx::channel& channel() const { return ClientEndBase::handle_; }
zx::channel& channel() { return ClientEndBase::handle_; }
// Transfers ownership of the underlying channel to the caller.
zx::channel TakeChannel() { return std::move(ClientEndBase::handle_); }
};
// A typed client endpoint that does not claim ownership. It is typically
// created from an owning |fidl::ClientEnd<Protocol>|.
// These types are used by generated FIDL APIs that do not take ownership.
//
// The remote (server) counterpart of the channel expects this end of the
// channel to speak the protocol represented by |Protocol|.
//
// Compared to a |const fidl::ClientEnd<Protocol>&|,
// |fidl::UnownedClientEnd<Protocol>| has the additional flexibility of being
// able to be stored in a member variable or field, while still remembering
// the associated FIDL protocol.
template <typename Protocol>
class UnownedClientEnd final
: public internal::UnownedClientEndBase<Protocol, internal::ChannelTransport> {
static_assert(std::is_same_v<typename Protocol::Transport, internal::ChannelTransport>);
using UnownedClientEndBase = internal::UnownedClientEndBase<Protocol, internal::ChannelTransport>;
public:
using UnownedClientEndBase::UnownedClientEndBase;
zx::unowned_channel channel() const { return zx::unowned_channel(UnownedClientEndBase::handle_); }
};
// The server endpoint of a FIDL handle.
//
// The remote (client) counterpart of the handle expects this end of the
// handle to serve the protocol represented by |Protocol|. This type is the
// dual of |ClientEnd|.
//
// |ServerEnd| is thread-compatible: the caller should not use the underlying
// handle (e.g. sending an event) while the server-end object is being mutated
// in a different thread.
template <typename Protocol>
class ServerEnd : public internal::ServerEndBase<Protocol, internal::ChannelTransport> {
static_assert(std::is_same_v<typename Protocol::Transport, internal::ChannelTransport>);
using ServerEndBase = internal::ServerEndBase<Protocol, internal::ChannelTransport>;
public:
using ServerEndBase::ServerEndBase;
const zx::channel& channel() const { return ServerEndBase::handle_; }
zx::channel& channel() { return ServerEndBase::handle_; }
// Transfers ownership of the underlying channel to the caller.
zx::channel TakeChannel() { return ServerEndBase::TakeHandle(); }
// Sends an epitaph over the underlying channel, then closes the channel.
// An epitaph is a final optional message sent over a server-end towards
// the client, before the server-end is closed down. See the FIDL
// language spec for more information about epitaphs.
//
// The server-end must be holding a valid underlying channel.
// Returns the status of the channel write operation.
zx_status_t Close(zx_status_t epitaph_value) {
if (!ServerEndBase::is_valid()) {
ZX_PANIC("Cannot close an invalid ServerEnd.");
}
zx::channel channel = TakeChannel();
return fidl_epitaph_write(channel.get(), epitaph_value);
}
};
} // namespace fidl
#endif // LIB_FIDL_LLCPP_INTERNAL_TRANSPORT_CHANNEL_H_