template <typename Protocol>
class WireClient
Defined at line 111 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
|WireClient| is a client for sending and receiving FIDL wire messages, that
must be managed and used from a [synchronized async dispatcher][synchronized-dispatcher].
See |WireSharedClient| for a client that may be moved or cloned to different
dispatchers or arbitrary threads.
Generated FIDL APIs are accessed by 'dereferencing' the client value:
// Creates a client that speaks over |client_end|, on the |my_dispatcher| dispatcher.
fidl::WireClient client(std::move(client_end), my_dispatcher);
// Call the |Foo| method asynchronously, passing in a callback that will be
// invoked on a dispatcher thread when the server response arrives.
auto status = client->Foo(args, [] (Result result) {});
## Lifecycle
A client must be **bound** to an endpoint before it could be used. This
association between the endpoint and the client is called a "binding".
Binding a client to an endpoint starts the monitoring of incoming messages.
Those messages are appropriately dispatched: to response callbacks, to event
handlers, etc. FIDL methods (asynchronous or synchronous) may only be invoked
on a bound client.
Internally, a client is a lightweight reference to the binding, performing
its duties indirectly through that object, as illustrated by the simplified
diagram below:
references makes
client -------------> binding --------> FIDL call
This means that the client _object_ and the binding have overlapping but
slightly different lifetimes. For example, the binding may terminate in
response to fatal communication errors, leaving the client object alive but
unable to make any calls.
To stop the monitoring of incoming messages, one may **teardown** the
binding. When teardown is initiated, the client will not monitor new messages
on the endpoint. Ongoing callbacks will be allowed to run to completion. When
teardown is complete, further calls on the same client will fail. Unfulfilled
response callbacks will be dropped.
Destruction of a client object will initiate teardown.
Teardown will also be initiated when the binding encounters a terminal error:
- The server-end of the channel was closed.
- An epitaph was received.
- Decoding or encoding failed.
- An invalid or unknown message was encountered.
- Error waiting on, reading from, or writing to the channel.
In this case, the user will be notified of the detailed error via the
|on_fidl_error| method on the event handler.
## Thread safety
|WireClient| provides an easier to use API in exchange of a more restrictive
threading model:
- The provided |async_dispatcher_t| must be a [synchronized dispatcher][synchronized-dispatcher].
- The client must be bound on a task running on that dispatcher.
- The client must be destroyed on a task running on that dispatcher.
- FIDL method calls must be made from tasks running on that dispatcher.
- Responses are always delivered from dispatcher tasks, as are events.
The above rules are checked in debug builds at run-time. In short, the client
is local to its associated dispatcher.
Note that FIDL method calls must be synchronized with operations that consume
or mutate the |WireClient| itself:
- Assigning a new value to the |WireClient| variable.
- Moving the |WireClient| to a different location.
- Destroying the |WireClient|.
|WireClient| is suitable for systems with stronger sequential threading
guarantees. It is intended to be used as a local variable with fixed
lifetime, or as a member of a larger class where it is uniquely owned by
instances of that class. Destroying the |WireClient| is guaranteed to stop
message dispatch: since the client is destroyed on the dispatcher thread,
there is no opportunity of parallel callbacks to user code, and
use-after-free of user objects is naturally avoided during teardown.
See |WireSharedClient| for a client that supports binding and destroying on
arbitrary threads, at the expense of requiring two-phase shutdown.
[synchronized-dispatcher]:
https://fuchsia.dev/fuchsia-src/development/languages/c-cpp/thread-safe-async#synchronized-dispatcher
Public Methods
template <typename AsyncEventHandler = fidl::WireAsyncEventHandler<Protocol>>
void WireClient<Protocol> (fidl::internal::ClientEndType<Protocol> client_end, async_dispatcher_t * dispatcher, AsyncEventHandler * event_handler)
Create an initialized client which manages the binding of the client end of
a channel to a dispatcher, as if that client had been default-constructed
then later bound to that endpoint via |Bind|.
It is a logic error to use a dispatcher that is shutting down or already
shut down. Doing so will result in a panic.
If any other error occurs during initialization, the
|event_handler->on_fidl_error| handler will be invoked asynchronously with
the reason, if specified.
Defined at line 124 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
void WireClient<Protocol> ()
Create an uninitialized client. The client may then be bound to an endpoint
later via |Bind|.
Prefer using the constructor overload that binds the client to a channel
atomically during construction. Use this default constructor only when the
client must be constructed first before a channel could be obtained (for
example, if the client is an instance variable).
Defined at line 136 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
bool is_valid ()
Returns if the |WireClient| is initialized.
Defined at line 139 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
bool operator bool ()
Defined at line 140 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
void ~WireClient<Protocol> ()
The destructor of |WireClient| will initiate binding teardown.
When the client destructs:
- The channel will be closed.
- Pointers obtained via |get| will be invalidated.
- Binding teardown will happen, implying:
* In-progress calls will be forgotten. Async callbacks will be dropped.
Defined at line 149 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
void WireClient<Protocol> (WireClient<Protocol> && other)
|WireClient|s can be safely moved without affecting any in-flight FIDL
method calls. Note that calling methods on a client should be serialized
with respect to operations that consume the client, such as moving it or
destroying it.
Defined at line 155 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
WireClient<Protocol> & operator= (WireClient<Protocol> && other)
Defined at line 156 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
void Bind (fidl::internal::ClientEndType<Protocol> client_end, async_dispatcher_t * dispatcher, fidl::WireAsyncEventHandler<Protocol> * event_handler)
Initializes the client by binding the |client_end| endpoint to the
dispatcher.
It is a logic error to invoke |Bind| on a dispatcher that is shutting down
or already shut down. Doing so will result in a panic.
When other errors occur during binding, the |event_handler->on_fidl_error|
handler will be asynchronously invoked with the reason, if specified.
It is not allowed to call |Bind| on an initialized client. To rebind a
|WireClient| to a different endpoint, simply replace the |WireClient|
variable with a new instance.
Defined at line 170 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
auto operator-> ()
Returns the interface for making outgoing FIDL calls with managed memory
allocation. The client must be initialized first.
If the binding has been torn down, calls on the interface return error with
status |ZX_ERR_CANCELED| and reason |fidl::Reason::kUnbind|.
Persisting this pointer to a local variable is discouraged, since that
results in unsafe borrows. Always prefer making calls directly via the
|WireClient| reference-counting type.
Defined at line 187 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
template <typename MemoryResource>
auto buffer (MemoryResource && resource)
Returns a veneer object which exposes the caller-allocating API, using the
provided |resource| to allocate buffers necessary for each call. Requests
will live on those buffers. Responses on the other hand do not live on
those buffers; they are separately managed and may become invalid after the
corresponding async response/result callback returns.
Examples of supported memory resources are:
* |fidl::BufferSpan|, referencing a range of bytes.
* |fidl::AnyArena
&
|, referencing an arena.
* Any type for which there is a |MakeAnyBufferAllocator| specialization.
See |AnyBufferAllocator|.
This interface is suitable when one needs complete control over memory
allocation. Instead of implicitly heap allocating the necessary bookkeeping
for in-flight operations, the methods take a raw pointer to a
|fidl::WireResponseContext
<FidlMethod
>|, which may be allocated via any
means as long as it outlives the duration of this async FIDL call. Refer to
documentation on the response context.
The returned object borrows from this object, hence must not outlive
the client object.
The returned object may be briefly persisted for use over multiple calls:
fidl::Arena my_arena;
fidl::WireClient client(std::move(client_end), some_dispatcher);
auto buffered = client.buffer(my_arena);
buffered->FooMethod(args, foo_response_context);
buffered->BarMethod(args, bar_response_context);
...
In this situation, those calls will all use the initially provided memory
resource (`my_arena`) to allocate their message buffers. The memory
resource won't be reset/overwritten across calls. Note that if a
|BufferSpan| is provided as the memory resource, sharing memory resource in
this manner may eventually exhaust the capacity of the buffer span since it
represents a single fixed size buffer. To reuse (overwrite) the underlying
buffer across multiple calls, obtain a new caller-allocating veneer object
for each call:
fidl::BufferSpan span(some_large_buffer, size);
fidl::WireClient client(std::move(client_end), some_dispatcher);
client.buffer(span)->FooMethod(args, foo_response_context);
client.buffer(span)->BarMethod(args, bar_response_context);
Defined at line 238 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
auto sync ()
Returns a veneer object exposing synchronous calls. Example:
fidl::WireClient client(std::move(client_end), some_dispatcher);
fidl::WireResult result = client.sync()->FooMethod(args);
Defined at line 249 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
fit::result<fidl::Error, fidl::ClientEnd<Protocol>> UnbindMaybeGetEndpoint ()
Attempts to disassociate the client object from its endpoint and stop
monitoring it for messages. After this call, subsequent operations will
fail with an unbound error.
If there are pending two-way async calls, the endpoint is closed and this
method will fail with |fidl::Reason::kPendingTwoWayCallPreventsUnbind|. The
caller needs to arrange things such that unbinding happens after any
replies to two-way calls.
If the endpoint was already closed due to an earlier error, that error will
be returned here.
Otherwise, returns the client endpoint.
Defined at line 267 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h
Friends
template <typename Protocol>
class ClientChecker