| RFC-0099:引入了 `zx_socket_set_disposition` | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 引入 `zx_socket_set_disposition` 以替换 `zx_socket_shutdown`,实现可逆操作。 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2021-05-06 |
| 审核日期(年-月-日) | 2021-06-03 |
摘要
引入 zx_socket_set_disposition 以取代 zx_socket_shutdown。新的系统调用扩展了旧的系统调用,允许反转关闭操作。
引入 ZX_RIGHT_MANAGE_SOCKET 并要求在新的系统调用中使用它。通过 zx_socket_create 新创建的标识名将拥有此权限。
设计初衷
将关停替换为可逆操作的动机
我们在 fdio 中有一个精细的状态机,用于处理未连接的流网络套接字不应接受写入的情况。状态机具有难以传播到其他进程中的复制套接字的本地状态,以及用于驱动本地状态的远程状态(Zircon 套接字上的用户信号)。之所以需要这些技巧,是因为套接字是“打开”创建的,因此必须通过外部方式阻止对它们的 I/O,直到它们通过外部方式“连接”为止。
要求新权限的动机
Zircon 套接字关闭已过于宽松。由于 Zircon 套接字句柄可以(并且实际上)被克隆,因此具有写入权限的单个句柄可以更改所有句柄的套接字状态。如果允许像此处建议的那样撤消关机,此问题会变得更加严重。
归纳总结
将套接字关闭替换为可逆操作,同时禁止非特权句柄启动该操作,可让网络堆栈实现完全驱动套接字状态。
套接字可以在提供给客户端之前先关闭,从而无需在 fdio 中进行上述状态跟踪。
套接字关闭可以完全由网络堆栈中介,由客户端 FIDL 调用发起,从而消除当前存在的竞态条件(例如 https://fxbug.dev/42140031)。
设计
在 FIDL 中定义 ZX_RIGHT_MANAGE_SOCKET:
延长 bits rights:
library zx;
bits rights : uint32 {
MANAGE_SOCKET = 0x00100000;
};
rights.md 中的文档 ZX_RIGHT_MANAGE_SOCKET:
附加到表:
| 右 | 授予的权限 |
|---|---|
| ZX_RIGHT_MANAGE_SOCKET | 允许通过 zx_socket_set_disposition 更改套接字处置 |
在 FIDL 中定义 zx_socket_set_disposition
添加到 protocol socket:
library zx;
protocol socket {
/// Set disposition of writes.
socket_set_disposition(handle:<SOCKET, rights.MANAGE_SOCKET> handle, uint32 disposition, uint32 disposition_peer) -> (status status);
}
/reference/syscalls/socket_set_disposition.md 中的文档 zx_socket_set_disposition
说明
zx_socket_set_disposition 为套接字句柄及其对等方设置 zx_socket_write 调用的处置。
可使用的有效处置标志:
ZX_SOCKET_DISPOSITION_WRITE_DISABLED - 针对指定的套接字端点停用写入。设置后,对指定套接字端点的写入操作将失败并显示 ZX_ERR_BAD_STATE。从指定套接字端点读取数据将成功,直到指定套接字端点中缓冲的所有数据都被使用完毕,之后会失败并返回 ZX_ERR_BAD_STATE。
ZX_SOCKET_DISPOSITION_WRITE_ENABLED - 为指定的套接字端点启用写入。设置后,对指定套接字端点的写入和读取操作将分别按照 zx_socket_write 和 zx_socket_read 中的规定运行。
在具有缓冲数据的套接字端点上指定 ZX_SOCKET_DISPOSITION_WRITE_ENABLED 是无效的;这样做会导致 zx_socket_set_disposition 返回 ZX_ERR_BAD_STATE,并且不会采取任何操作。
在 disposition 或 disposition_peer 中同时指定 ZX_SOCKET_DISPOSITION_WRITE_DISABLED 和 ZX_SOCKET_DISPOSITION_WRITE_ENABLED 是无效的;这样做会导致 zx_socket_set_disposition 返回 ZX_ERR_INVALID_ARGS,并且不会采取任何操作。
返回值
zx_socket_set_disposition() 在成功时返回 ZX_OK。
错误
ZX_ERR_BAD_HANDLE handle 不是有效的句柄。
ZX_ERR_BAD_STATE disposition 或 disposition_peer 包含 ZX_SOCKET_DISPOSITION_WRITE_ENABLED,且 handle 指的是在指定套接字端点上具有缓冲数据的套接字。
ZX_ERR_WRONG_TYPE handle 不是套接字句柄。
ZX_ERR_ACCESS_DENIED handle 不具有 ZX_RIGHT_MANAGE_SOCKET。
ZX_ERR_INVALID_ARGS disposition 或 disposition_peer 包含上述列表之外的标志或无效的标志组合。
Migration
实现后,现有的 zx_socket_shutdown 用法将被替换为对 zx_socket_set_disposition 的等效调用。完成必要的 ABI 过渡后,zx_socket_shutdown 及其关联的选项将被移除。
实现
实现应完全在套接字调度程序内完成。
性能
此更改对效果没有明显影响。
工效学设计
此变更对人体工程学没有明显影响。
向后兼容性
此变更向后兼容,因为不使用新 API 表面的客户端不受影响。
安全注意事项
此更改可简化 fdio 代码,从而提高安全性。除此之外,此项变更对安全性没有任何实质性影响。
隐私注意事项
此项变更对隐私权没有重大影响。
测试
我们将通过对系统调用的单元测试以及用新机制替换已测试的 fdio 状态机的一部分来测试此功能。
文档
zx_socket_write 和 zx_socket_read 将更新为引用 zx_socket_set_disposition 而不是 zx_socket_shutdown。
其他文档将按照实现部分中的说明进行更新。
缺点、替代方案和未知因素
可以向 zx_socket_shutdown 添加一个新标志,以反转其行为,而不是添加新的系统调用。这种方法的优点是避免引入与相应行为不太匹配的新术语(处置)。继续使用 zx_socket_shutdown 的主要缺点是,它接受的标志并不直观;ZX_SOCKET_SHUTDOWN_READ 的功能与描述不符(它禁止对等写入,而不是禁止读取)。
“未关闭”的行为指定为:如果套接字中存在指定方向的数据,则产生错误。另一种选择是允许该操作成功完成;但为了防止出现意外后果,我们选择了更严格的选项。
无需创建新权限,可以使用现有权限。对现有权利的调查表明,没有现有权利与此使用情形非常契合。
仅凭此设计无法完全解决流套接字的状态传播问题。此提案的替代方案是一种更全面的方法,旨在完全消除 fdio 流套接字状态机。此类提案必然也包含此提案。
在先技术和参考资料
流套接字语义实际上是由它们在其他操作系统中的行为定义的,这导致需要区分已连接的套接字和未连接的套接字。