RFC-0053:表情符号

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

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

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

“您的服务器在此长眠”

摘要

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

设计初衷

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

一种用例是,服务器上的错误大多是致命的,发生错误时,与客户端的所有连接都会关闭。在这种情况下,开发者需要一个通用的错误报告机制,因为对方法的所有活跃调用都将以相同的错误终止。为每个方法声明潜在错误的做法会很麻烦且不方便。

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

此 FTP 的目标也不是定义一组通用错误代码。

设计

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

线路格式

线路格式规范目前有一个关于墓志铭的部分。此部分将修订为如下内容:

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.

源语言

源语言规范目前有一个关于 墓志铭的部分。 它将进行适当更新。

第一类语言绑定

实现应考虑到以下事实:如果发送墓志铭消息,则该消息应是关闭之前的最后一条消息;以及不同语言以不同方式处理错误(例如,在 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 将在收到墓志铭后立即关闭通道。

开发者将能够使用 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. 当客户端收到墓志铭消息时,必须立即关闭其通道端。 它不得尝试从可能由不符合规范的服务器实现发送的通道中读取任何其他消息。

  3. 当客户端在未收到墓志铭的情况下观察到对等方已关闭时,必须像收到 ZX_ERR_PEER_CLOSED 墓志铭一样继续操作;这两个状态在语义上是等效的。

  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. 如果服务器因并非响应客户端执行的操作(例如关停或内存不足)而无法继续提供协议服务,则不必发送任何墓志铭。 如上所述,客户端会将其视为 ZX_ERR_PEER_CLOSED

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

    f. 此列表并不详尽。 服务器可以根据需要发送其他错误。 与往常一样,建议 FIDL 作者清楚地记录其协议可能返回的错误,包括墓志铭。

向后兼容性

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

性能

不适用

安全

不适用。

测试

此功能的单元测试将添加到相应的 FIDL 绑定。在 每个受支持的 FIDL 绑定获得支持后,我们应扩充 FIDL 兼容性测试集

缺点、替代方案和未知事项

我们考虑创建一个包含 Epitaph 事件的 System 接口,该接口将是所有其他接口消息的父级。 墓志铭本身并不需要进行如此大的更改。目前,这方面还存在两个实现障碍。 首先,派生类型目前不起作用,但这种情况应该很快就会改变。 其次,由于此提案更改了运行时,而 FIDL 解析器 / 生成器依赖于运行时,因此引入 System 消息并尝试在运行时中使用它会导致循环依赖。

由此 FTP 产生的 API 更改不会阻止墓志铭支持移入未来的 System 消息。

有人提出将一些墓志铭处理纳入源语言,允许将 zx_status 标志映射为 FIDL 定义的枚举。 这被推迟到以后的工作中。

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