RFC-0053:表情符号

RFC-0053:墓志铭
状态已接受
区域
  • FIDL
说明

此提案的目标是允许服务器在关闭连接之前发送一条消息,以指明关闭连接的原因。

作者
提交日期(年-月-日)2018-07-19
审核日期(年-月-日)2018-10-04

“您的服务器位于此处”

摘要

此提案的目标是允许服务器在关闭连接之前发送一条消息,以指明关闭连接的原因。虽然规范中涵盖了墓志铭,但尚未实现。

设计初衷

目前,服务器没有标准方法可以向客户端传达关闭连接的原因。这会导致确保错误处理的责任落在开发者身上。开发者可以预见这一点,并在消息中构建特殊的错误处理机制,也可以直接忽略错误处理(并冒上无法诊断错误的风险)。

一个用例是,对于错误通常是严重错误的服务器,当发生错误时,系统会关闭与客户端的所有连接。在这种情况下,开发者需要通用的错误报告机制,因为对方法的所有有效调用都将以相同的错误终止。为每种方法声明潜在错误的替代方法会很麻烦且不方便。

此 FTP 的目标不是提供全面的错误报告机制。具体而言,无法向连接另一端传达大量详细信息(包括详细消息、进程状态或传播的原因)不在该规范的适用范围之内。

此 FTP 也不以定义一组常见错误代码为目标。

设计

此提案修改了线格格式、源语言和第一类语言绑定。

线格格式

有线格式规范目前包含一个关于 Epitaph 的部分。此部分将修改为如下所示:

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.

源语言

源语言规范目前包含一个关于墓志铭的部分。我们会适时更新该时间。

一流的语言绑定

实现应考虑以下事实:如果发送了 Epitaph 消息,则该消息应是关闭前的最后一条消息;不同语言处理错误的方式也不同(例如,C/C++ 中通过传送错误代码、Rust 中通过 Result<t, e=""> 处理错误,以及 Dart 中通过异常处理错误)。</t,>

我们将向 C 绑定添加一个方法 fidl_epitaph_write(channel, zx_status_t),以及一个 fidl_epitaph_t 类型。

我们将在“原始绑定”部分中为 C 绑定添加以下文档:

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.

C 更改的 CL:https://fuchsia-review.googlesource.com/c/zircon/+/178250

我们将更改 C++ 绑定,以执行以下操作:

fidl::Binding 会在收到 Epitaph 时立即关闭通道。

开发者将能够使用 fidl::Binding::Close 关闭通道

错误代码将传播到客户端使用 set_error_handler() 设置的错误处理程序。我们将添加一个新的 error_handler 变体,该变体接受一个接受表示错误代码的 int 变量的闭包,并移除现有变体。未来可能的工作包括提供“合理的默认”错误处理程序,但目前尚不清楚这是什么。

从此通道进行的任何待处理读取都将返回 ZX_ERR_PEER_CLOSED

C++ 绑定的 CL:https://fuchsia-review.googlesource.com/c/garnet/+/177939

其他绑定(包括 Dart、Rust 和 Go)也需要更新。

文档和示例

我们将按照上一部分中的说明更新相关文档。

面向开发者的指南

墓志铭的目的是让服务器能够向客户端提供有关可能正在处理的通道和请求的操作性信息。

本部分介绍了墓志铭的预期行为和用法。

  1. 墓志铭消息只能从服务器发送到客户端,而不能向相反方向发送。如果发送了,则必须是服务器在关闭其端的通道之前发送给客户端的最后一条消息。

  2. 当客户端收到 epitaph 消息时,必须立即关闭其端的通道。不得尝试从可能由不合规的服务器实现发送的通道读取任何其他消息。

  3. 如果客户端发现对等方已关闭,但未收到 epitaph,则必须像收到 ZX_ERR_PEER_CLOSED epitaph 一样继续操作;这两种状态在语义上是等效的。

  4. 如果协议达到指定的成功结束状态时,通道的关闭是预期的副作用,则服务器应发送 ZX_OK 挽联。

    a. 示例:当客户端对表示单个数据库事务的接口调用 Commit() 时,服务器应尝试应用请求的更改。如果成功,服务器必须在关闭其端的通道之前发送 ZX_OK 墓志铭。客户端可以合理推断,ZX_OK 墓志铭表示交易已成功提交。

    b. 反例:许多协议没有指定的成功结束状态;客户端希望能够连接到服务器并发出无限数量的请求,而不会观察到对等方关闭,直到客户端关闭自己的通道端为止。在这些情况下,服务器关闭其端口的通道构成了异常结束状态,因此服务器绝不应发送 ZX_OK 挽联。

  5. 除了协议达到指定的成功结束状态之外,服务器在关闭其端口之前,可能会出于任何其他原因发送非 ZX_OK 赔辞。我们建议采用以下惯例:

    a. 如果服务器因客户端向其发送了格式错误的 FIDL 消息而关闭连接,则应发送 ZX_ERR_INVALID_ARGS 墓志铭。

    b. 如果服务器因客户端发送的请求在其当前状态下无效而关闭连接,则应发送 ZX_ERR_BAD_STATE 挽联。

    c. 如果客户端尝试通过服务发现机制连接到服务器时,服务器不可访问(例如无法启动),此机制应发送 ZX_ERR_UNAVAILABLE 墓志铭。(另请参阅此草图。)

    d. 如果服务器因并非响应客户端执行的操作(例如关闭或内存不足)的原因而无法继续提供协议,则无需发送任何 epitaph。客户端将其视为 ZX_ERR_PEER_CLOSED,如上所述。

    e. 如果服务器遇到应用专用错误,则应发送应用定义的错误代码。例如,如果服务器控制着文件系统,而用户尝试执行不允许执行的写入操作,服务器可能希望发送错误消息来关闭连接。

    f. 此处并未列出所有这类网址。服务器可能会根据需要发送其他错误。一如既往,我们建议 FIDL 作者明确记录其协议可能会返回的错误,包括墓志铭。

向后兼容性

FIDL 文档目前指出,0x80000001 是 epitaph 的序数。我们将其更改为 0xFFFFFFFF,因为 IO 正在使用 0x80000001。目前没有任何内容依赖于使用 0x80000001 的 Epitaph。否则,没有向后兼容性问题。

性能

不适用

安全

不适用。

测试

此功能的单元测试将添加到适当的 FIDL 绑定中。在每个受支持的 FIDL 绑定都获得支持后,我们应增强一组 FIDL 兼容性测试

缺点、替代方案和未知情况

我们考虑过创建一个包含 Epitaph 事件的 System 接口,该接口将是所有其他接口消息的父级。仅凭墓志铭并不能保证会发生如此大的变化。目前,实现此功能还存在两个障碍。首先,派生类型目前不起作用,但应该很快就会有所改变。接下来,由于此提案会更改运行时,而 FIDL 解析器 / 生成器依赖于运行时,因此引入 System 消息并尝试在运行时中使用它会导致循环依赖项。

此 FTP 带来的 API 更改不会阻止将 Epitaph 支持移至未来的系统消息。

有人提出了一个想法,即将一些 epitaph 处理功能纳入源语言,以允许将 zx_status 标志映射为 FIDL 定义的枚举。这将推迟到日后进行。

所提议的实现存在竞争问题。如果一个线程在另一个线程关闭通道的同时写入消息,则挽联可能会在另一个线程的消息之前写入,但在调用 zx_handle_close() 之前写入。替代方案包括锁定通道或提供显式系统调用。我们将从线程不安全的版本开始,以便进一步了解问题空间。