The goal of this proposal is to allow a server to send a message prior to closing a connection that provides an indication of why the connection is being closed.
|Date submitted (year-month-day)||2018-07-19|
|Date reviewed (year-month-day)||2018-10-04|
"Here lies your server"
The goal of this proposal is to allow a server to send a message prior to closing a connection that provides an indication of why the connection is being closed. While epitaphs are covered in the specification, they are not implemented yet.
Currently, there is no standard way for servers to communicate to clients why a connection has been closed. This has the effect that the responsibility for ensuring error handling falls to the developer. The developer can either foresee this, and build special error handling into their message, or simply ignore error handling (and risk undiagnosable errors).
One use case is for servers where errors are mostly fatal, and when they happen, all connections to clients are closed. In such cases, developers want a general-purpose error reporting mechanism, because all active calls to methods will be terminated with the same error. The alternative of declaring a potential error for each method would be cumbersome and awkward.
This FTP does not have a goal of providing an extensive error reporting mechanism. Specifically, the ability to communicate large amounts of detail (including detailed messages, process state, or propagated causes) to the other end of the connection is out of scope.
This FTP also does not have a goal of defining a set of common error codes.
This proposal modifies the wire format, the source language, and the first class language bindings.
The wire format specification currently has a section on Epitaphs. This section will be revised to read as follows:
Epitaph (Control Message Ordinal 0xFFFFFFFF) An epitaph is a message with ordinal **0xFFFFFFFF**. A server may send an epitaph as the last message prior to closing the connection, to provide an indication of why the connection is being closed. No further messages may be sent through the channel after the epitaph. Epitaphs are not sent from clients to servers. When a client receives an epitaph message, it can assume that it has received the last message, and the channel is about to be closed. The contents of the epitaph message explain the disposition of the channel. The epitaph contains an error status. The error status of the epitaph is stored in the reserved uint32 of the message header. The reserved word is treated as being of type **zx_status_t**: negative numbers are reserved for system error codes, positive numbers are reserved for application error codes, and ZX_OK is used to indicate normal connection closure. The message is otherwise empty.
The source language specification currently has a section on Epitaphs. It will be updated appropriately.
First class language bindings
Implementations should account for the fact that, if an Epitaph message is sent,
it should be the last message prior to closure, and for the fact that errors are
handled differently in different languages (via, for example, delivery of error
codes in C/C++, Result
We will add a method fidl_epitaph_write(channel, zx_status_t) to the C bindings, as well as a fidl_epitaph_t type.
We will add the following documentation to the C bindings to the section on Raw Bindings:
fidl_epitaph_write Declared in lib/fidl/epitaph.h, defined in epitaph.c. This function sends an epitaph with the given error number down the given channel. An epitaph is a special message, with ordinal 0xFFFFFFFF, which contains an error code. The epitaph must be the last thing sent down the channel before it is closed.
CL for the C changes: https://fuchsia-review.googlesource.com/c/zircon/+/178250
We will change the C++ bindings to do the following:
fidl::Binding will immediately close the channel on receipt of an Epitaph.
Developers will be able to close the channel with fidl::Binding::Close
Error codes will be propagated to the error handler set by the client using set_error_handler(). We will add a new error_handler variant that takes a closure that takes an int variable representing the error code, and remove the existing one. Potential future work involves having a "sensible default" error handler, although it is not currently clear what this would be.
Any pending reads from this channel will return
CL for C++ bindings: https://fuchsia-review.googlesource.com/c/garnet/+/177939
The other bindings need to be updated, including Dart, Rust, and Go.
Documentation and examples
The documentation will be updated as described in the previous section.
Guidance for Developers
The purpose of an epitaph is to enable a server to provide actionable information to the client regarding the disposition of the channel and requests that may have been in flight.
This section describes the intended behavior and usage of epitaphs.
An epitaph message is only ever sent from a server to a client, never in the other direction. If sent, it must be the last message sent by the server to the client before the server closes its end of the channel.
When a client receives an epitaph message, it must immediately close its end of the channel. It must not attempt to read any further messages from the channel that may have been sent by a non-conforming server implementation.
When a client observes peer closed without having received an epitaph, then it must proceed as if it has received a
ZX_ERR_PEER_CLOSEDepitaph; these two states are semantically equivalent.
A server is expected to send a
ZX_OKepitaph when the closure of the channel was an anticipated side-effect of the protocol reaching its designated successful end state.
a. Example: When a client calls Commit() on an interface representing an individual database transaction, the server should attempt to apply the requested changes. If successful, the server must send a
ZX_OKepitaph before closing its end of the channel. The client may reasonably construe that the
ZX_OKepitaph indicates that the transaction was successfully committed.
b. Counter-example: Many protocols do not have designated successful end states; the client expects to be able to connect to a server and issue an unbounded number of requests without observing peer closed until such time as the client closes its own end of the channel. In these situations, the server closing its end of the channel constitutes an abnormal end state, so the server should never send a
A server may send a non-
ZX_OKepitaph prior to closing its end of a channel for any reason other than the protocol reaching its designated successful end state. We suggest the following convention:
a. If the server is closing the connection because the client sent it an malformed FIDL message, it should send a
b. If the server is closing the connection because the client sent it a request that is not valid in its present state, it should send a
c. If the server was unreachable (e.g. could not be started) when the client attempted to connect to it via a service discovery mechanism, this mechanism should send a
ZX_ERR_UNAVAILABLEepitaph. (See also this sketch.)
d. If the server is unable to continue serving the protocol for reasons that are not in response to actions performed by the client (e.g. shutting down or out of memory), it does not have to send any epitaph. The client will perceive this as
ZX_ERR_PEER_CLOSEDas described above.
e. If a server encounters an application specific error, it should send an application-defined error code. For example, if the server controls a filesystem, and the user tries to perform a write that it is not allowed to perform, it may wish to close the connection with an error.
f. This list is not exhaustive. A server may send other errors as appropriate. As per usual, FIDL authors are advised to clearly document the errors their protocols may return, including epitaphs.
The FIDL documentation currently states that 0x80000001 is the ordinal for an epitaph. We are changing it to 0xFFFFFFFF, because 0x80000001 is in use by IO. Nothing is currently relying on Epitaphs using 0x80000001. Otherwise, there are no backwards compatibility concerns.
Unittests for this feature will be added to the appropriate FIDL bindings. After each supported FIDL binding gets support, we should augment the set of FIDL compatibility tests.
Drawbacks, alternatives, and unknowns
We considered making a
System interface containing the
event, which would be the parent of all other interface messages. Epitaphs, on
their own, do not warrant such a large change. There are also currently two
implementation hurdles to this. First, derived types do not currently work,
although that is supposed to change soon. Next, because this proposal changes
the runtime, and the FIDL parser / generator depends on the runtime, introducing
a System message and trying to use it in the runtime would result in a circular
The API changes that will result from this FTP will not prevent Epitaph support from moving into a future System message.
An idea was floated of incorporating some epitaph handling into the source
language, allowing the
zx_status flag to be mapped as a FIDL-defined enum.
This is deferred to future work.
The proposed implementation is racy. If one thread writes a message
concurrently with another thread closing the channel, the epitaph may be written
prior to the other thread's message, but before the call to
zx_handle_close(). Alternatives include locking the channel or providing
an explicit system call. We are starting with the thread-unsafe version to
further develop our understanding of the problem space.