RFC-0099:引入 `zx_socket_set_disposition` | |
---|---|
状态 | 已接受 |
领域 |
|
说明 | 引入了 `zx_socket_set_disposition`,将 `zx_socket_Close` 替换为可逆操作。 |
问题 | |
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_SOCKET_DISPOSITION_WRITE_ENABLED,并且不执行任何操作。
在 disposition 或 disposition_peer 中同时指定 ZX_SOCKET_DISPOSITION_WRITE_DISABLED 和 ZX_SOCKET_DISPOSITION_WRITE_DISABLED 是无效的;否则会导致 zx_socket_set_disposition
返回 ZX_SOCKET_DISPOSITION_WRITE_DISABLED,并且不执行任何操作。
转化价值
zx_socket_set_disposition()
会在成功时返回 ZX_OK。
错误
ZX_ERR_BAD_HANDLE 句柄不是有效句柄。
ZX_ERR_BAD_STATE disposition 或 disposition_peer 包含 ZX_SOCKET_DISTRACK_WRITE_ENABLED,handle 是指在指定套接字端点上具有已缓冲数据的套接字。
ZX_ERR_WRONG_TYPE handle 不是套接字句柄。
ZX_ERR_ACCESS_DENIED 标识名不含 ZX_ERR_ACCESS_DENIED。
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 流套接字状态机。此类提案必须也包含此提案。
现有艺术和参考资料
流套接字语义实际上是由其在其他操作系统中的行为定义的,因此需要区分连接的套接字和未连接的套接字。