openssl-quic
名称
openssl-quic - OpenSSL QUIC
描述
OpenSSL 3.2 及更高版本支持 QUIC 传输协议。目前,仅支持客户端连接。本手册页描述了 QUIC 客户端功能在现有和新应用程序中的用法。
QUIC 功能使用标准 SSL API。QUIC 连接以与 TLS 连接相同的方式由 SSL 对象表示。现有应用程序使用 libssl API 只需进行最小的更改即可使用 QUIC 客户端功能。要使用 QUIC,请使用 SSL 方法 OSSL_QUIC_client_method(3) 或 OSSL_QUIC_client_thread_method(3) 与 SSL_CTX_new(3) 一起使用。
创建 QUIC 连接时,默认情况下,它以默认流模式运行,旨在提供与现有非 QUIC 应用程序使用模式的兼容性。在此模式下,连接具有与其关联的单个流。对 QUIC 连接 SSL 对象的 SSL_read(3) 和 SSL_write(3) 的调用从该流读取和写入。从 QUIC 的角度来看,流是客户端启动的还是服务器启动的,取决于 SSL_read(3) 或 SSL_write(3) 是先调用的。有关更多信息,请参见操作模式部分。
默认流模式旨在与现有应用程序兼容。建议使用 QUIC 的新应用程序禁用默认流模式并使用多流 API;有关更多信息,请参见操作模式部分和新应用程序的建议部分。
本手册页的其余部分按顺序讨论以下内容:
默认流模式与多流模式;
由 QUIC 相关实现需求驱动的现有 libssl API 的更改,现有应用程序应牢记这些更改;
现有应用程序在采用 QUIC 时必须考虑的方面,包括可能需要的潜在更改。
新应用程序的推荐使用方法。
新的 QUIC 特定 API。
操作模式
默认流模式
QUIC 客户端连接可以在默认流模式或多流模式下使用。默认情况下,新创建的 QUIC 连接 SSL 对象使用默认流模式。
在默认流模式下,隐式创建并绑定到 QUIC 连接 SSL 对象的流;SSL_read(3) 和 SSL_write(3) 对 QUIC 连接 SSL 对象的调用默认情况下有效,并映射到该流。
使用默认流模式时,可以在 QUIC 流 SSL 对象上调用的任何 API 函数也可以在 QUIC 连接 SSL 对象上调用,在这种情况下,它会影响绑定到连接的默认流。
QUIC 流的身份,包括其流 ID,取决于流是客户端启动的还是服务器启动的。在默认流模式下,如果客户端应用程序先于任何对 SSL_write(3) 的调用在连接上调用 SSL_read(3),则假设应用程序协议正在使用服务器启动的流,并且 SSL_read(3) 调用将不会完成(要么阻塞,要么在配置了非阻塞模式的情况下适当地失败),直到服务器启动流。相反,如果客户端应用程序在对连接上的 SSL_read(3) 的任何调用之前调用 SSL_write(3),则假设要使用客户端启动的流,并且会自动创建这样的流。
默认流模式旨在帮助与传统应用程序兼容。采用 QUIC 的新应用程序应使用下面描述的多流模式,并避免使用默认流功能。
可以使用 SSL_new_stream(3) 和 SSL_accept_stream(3) 在默认流模式下使用其他流;请注意,在这种情况下,需要使用 SSL_set_incoming_stream_policy(3) 更改默认传入流策略才能使用 SSL_accept_stream(3)。但是,强烈建议使用其他流的应用程序改用多流模式。
在将默认流与 QUIC 连接 SSL 对象关联之前调用 SSL_new_stream(3) 或 SSL_accept_stream(3) 会抑制将来创建默认流。
多流模式
采用 QUIC 的新应用程序的推荐使用模式是多流模式,在这种模式下,不会将任何默认流附加到 QUIC 连接 SSL 对象,并且尝试在 QUIC 连接 SSL 对象上调用 SSL_read(3) 和 SSL_write(3) 会失败。相反,应用程序调用 SSL_new_stream(3) 或 SSL_accept_stream(3) 来创建用于使用 SSL_read(3) 和 SSL_write(3) 发送和接收应用程序数据的单个流 SSL 对象。
要使用多流模式,请使用参数 SSL_DEFAULT_STREAM_MODE_NONE 调用 SSL_set_default_stream_mode(3);此函数必须在启动连接之前调用。在启动连接后无法更改默认流模式。
使用多流模式时,表示没有默认流与连接关联,如果在 QUIC 连接 SSL 对象上调用定义为在 QUIC 流上运行的 API 函数,则调用会失败。例如,SSL_write(3) 或 SSL_get_stream_id(3) 这样的调用会失败。
现有 API 的更改
大多数 SSL API(如 SSL_read(3) 和 SSL_write(3))与它们在 TLS 连接中的作用相同,并且语义没有变化,但有一些例外。现有 API 语义的更改如下所示
由于 QUIC 使用 UDP,因此 SSL_set_bio(3)、SSL_set0_rbio(3) 和 SSL_set0_wbio(3) 的作用与以前相同,但现在必须接收具有数据报语义的 BIO。应用程序有四种主要选项可用于作为网络 BIO
BIO_s_datagram(3)(建议用于大多数应用程序)替换 BIO_s_socket(3) 并提供 UDP 套接字。
BIO_s_dgram_pair(3) 提供 BIO 对类功能,但具有数据报语义,建议用于使用 BIO 对或内存 BIO 来管理 libssl 与网络通信的现有应用程序。
BIO_s_dgram_mem(3) 提供一个简单的数据报语义的内存 BIO 类接口。与 BIO_s_dgram_pair(3) 不同,它是单向的。
应用程序也可以选择实现自定义 BIO。必须支持新的 BIO_sendmmsg(3) 和 BIO_recvmmsg(3) API。
SSL_set_fd(3)、SSL_set_rfd(3) 和 SSL_set_wfd(3) 传统上实例化 BIO_s_socket(3)。对于 QUIC,这些函数改为实例化 BIO_s_datagram(3)。这相当于实例化 BIO_s_datagram(3) 并使用 SSL_set0_rbio(3) 和 SSL_set0_wbio(3)。
传统上,应用程序级 I/O API(如 SSL_read(3) 和 SSL_write(3))是否以阻塞方式运行,与底层网络套接字是否以阻塞方式配置直接相关。现在不再是这样;应用程序必须使用 SSL_set_blocking_mode(3) 显式配置所需的应用程序级阻塞模式。有关详细信息,请参见 SSL_set_blocking_mode(3)。
网络级 I/O 必须始终以非阻塞方式执行。应用程序仍然可以享受对应用程序级 I/O 函数(如 SSL_read(3) 和 SSL_write(3))的阻塞语义,但提供给 QUIC 的底层网络 BIO(如 BIO_s_datagram(3))必须以非阻塞模式配置。对于应用程序级阻塞功能,请参见 SSL_set_blocking_mode(3)。
BIO_new_ssl_connect(3) 已经更改为在与 QUIC 一起使用时自动使用 BIO_s_datagram(3),因此使用此功能的应用程序不需要更改它们使用的 BIO。
BIO_new_buffer_ssl_connect(3) 无法与 QUIC 一起使用,应用程序必须更改为改为使用 BIO_new_ssl_connect(3)。
SSL_shutdown(3) 在关闭 QUIC 连接的方式方面有重大变化。特别是,应建议应用程序,完全符合 RFC 的 QUIC 关闭过程可能需要很长时间。这可能不适合在完成其对 QUIC 连接的使用后应立即退出的短期进程。此类应用程序可以使用快速关闭模式。有关详细信息,请参见 SSL_shutdown(3)。
SSL_want(3)、SSL_want_read(3) 和 SSL_want_write(3) 不再反映传递给 QUIC SSL 对象的网络 BIO 的 I/O 状态,而是反映与 SSL 对象关联的 QUIC 流的流量控制状态。
在非阻塞模式下使用时,SSL_ERROR_WANT_READ 表示 QUIC 流的接收部分当前没有更多可读数据,并且 SSL_ERROR_WANT_WRITE 表示流的内部缓冲区已满。
要确定 QUIC 实现当前是否希望被告知传入的网络数据报,请使用新函数 SSL_net_read_desired(3);同样,要确定 QUIC 实现当前是否希望被告知何时可以传输网络数据报,请使用新函数 SSL_net_write_desired(3)。只有希望管理自己的事件循环的应用程序才需要使用这些函数;有关更多讨论,请参见应用程序驱动的事件循环。
使用 QUIC 时,必须使用 ALPN。尝试在没有配置 ALPN 的情况下连接会失败。有关如何配置 ALPN 的信息,请参见 SSL_set_alpn_protos(3)。
QUIC 是否以客户端还是服务器模式运行,由使用的 SSL_METHOD 确定,而不是由对 SSL_set_connect_state(3) 或 SSL_set_accept_state(3) 的调用确定。在连接之前,不需要调用 SSL_set_connect_state(3) 或 SSL_set_accept_state(3) 中的任何一个,但如果调用了这两个函数中的任何一个,则调用的函数必须与正在使用的 SSL_METHOD 相一致。目前,只支持客户端模式。
SSL_set_min_proto_version(3) 和 SSL_set_max_proto_version(3) API 不使用,传递给它们的 value 将被忽略,因为 OpenSSL QUIC 当前始终使用 TLS 1.3。
以下 libssl 功能在与 QUIC 一起使用时不可用。
异步功能
SSL_MODE_AUTO_RETRY
记录填充和碎片 (SSL_set_block_padding(3) 等)
SRTP 功能
TLSv1.3 早期数据
TLS 下一个协议协商不再使用,已被 ALPN 取代,必须使用 ALPN。使用 ALPN 在 QUIC 中是强制性的。
握手后客户端身份验证不可用,因为 QUIC 禁止使用它。
QUIC 要求使用 TLSv1.3 或更高版本,因此仅与旧版 TLS 版本相关的功能不可用。
某些通常可用于 TLSv1.3 的密码套件不可用于 QUIC,例如 **TLS_AES_128_CCM_8_SHA256**。您的应用程序可能需要调整它传递给 libssl 的可接受密码套件列表。
CCM 模式当前不支持。
以下 libssl 功能在与 QUIC 一起使用时也不可用,但对相关函数的调用将被视为无操作。
预读 (SSL_set_read_ahead(3) 等)
现有应用程序的注意事项
现有应用程序寻求采用 QUIC 应该应用以下列表来确定他们需要进行哪些更改
希望使用 QUIC 的应用程序必须使用 OSSL_QUIC_client_method(3) 或 OSSL_QUIC_client_thread_method(3) 作为其 SSL 方法。有关这两种方法之间差异的更多信息,请参阅 **线程辅助模式**。
确定如何为 QUIC 提供网络访问权限。确定以下哪些适用于您的应用程序
您的应用程序使用 BIO_s_socket(3) 来构造一个 BIO,该 BIO 传递给 SSL 对象以向其提供网络访问权限。
需要的更改:更改您的应用程序以使用 BIO_s_datagram(3),而不是在使用 QUIC 时使用它。套接字必须在非阻塞模式下配置。您可能需要或不需要使用 SSL_set1_initial_peer_addr(3) 来设置初始对等地址;有关详细信息,请参阅 **特定于 QUIC 的 API** 部分。
您的应用程序使用 BIO_new_ssl_connect(3) 来构造一个 BIO,该 BIO 传递给 SSL 对象以向其提供网络访问权限。
需要的更改:不需要更改。QUIC 的使用会自动检测到,并且会创建一个数据报套接字,而不是一个普通的 TCP 套接字。
您的应用程序使用此列表中的任何其他 I/O 策略,但将其与 BIO_f_buffer(3) 组合使用,例如使用 BIO_push(3)。
需要的更改:在使用 QUIC 时禁用 BIO_f_buffer(3) 的使用。使用此类缓冲区与 QUIC 不兼容,因为 QUIC 在其与网络的交互中需要数据报语义。
您的应用程序使用一对 BIO 使 SSL 对象将网络流量读写到内存缓冲区。您的应用程序以 libssl 不知道的方式自行管理缓冲数据的传输和接收。
需要的更改:从使用传统的 BIO 对切换到使用 BIO_s_dgram_pair(3),它具有必要的数据报语义。您需要修改您的应用程序以使用 UDP 套接字进行传输和接收,并在与 BIO_s_dgram_pair(3) 实例交互时使用数据报语义。
您的应用程序使用自定义 BIO 方法为 SSL 对象提供网络访问权限。
需要的更改:自定义 BIO 必须重新设计以具有数据报语义。必须实现 BIO_sendmmsg(3) 和 BIO_recvmmsg(3)。这些调用必须以非阻塞方式运行。可选地,如果需要,实现 BIO_get_rpoll_descriptor(3) 和 BIO_get_wpoll_descriptor(3) 方法。如果需要 SSL API 级别上的阻塞语义,则必须实现这些方法。
应用程序必须明确配置它是否希望在阻塞模式还是非阻塞模式下使用 SSL API。传统上,SSL 对象会根据底层网络 BIO 是否在阻塞模式或非阻塞模式下运行,自动在阻塞模式或非阻塞模式下运行。QUIC 要求使用非阻塞网络 BIO,因此应用程序必须使用新的 SSL_set_blocking_mode(3) API 明确配置应用程序级别的阻塞模式。默认模式为阻塞。如果应用程序希望在应用程序级别以非阻塞方式使用 SSL 对象 API,则必须添加对 SSL_set_blocking_mode(3) 的调用以禁用阻塞模式。
如果您的应用程序选择不使用线程辅助模式,则必须确保它定期调用 SSL 对象上的 I/O 函数(例如,SSL_read(3) 或 SSL_write(3)),或新的函数 SSL_handle_events(3)。如果 SSL 对象在阻塞模式下使用,则对 I/O 函数的持续阻塞调用将满足此要求。这是为了确保 QUIC 需要的计时器事件能够及时处理。
大多数应用程序将通过定期调用 SSL_read(3) 或 SSL_write(3) 来服务 SSL 对象。如果应用程序不这样做,它应该确保定期调用 SSL_handle_events(3)。
SSL_get_event_timeout(3) 可用于确定何时必须下一次调用 SSL_handle_events(3)。
如果 SSL 对象正在与支持轮询的底层网络 BIO 一起使用(例如 BIO_s_datagram(3)),应用程序可以使用 SSL_get_rpoll_descriptor(3)、SSL_get_wpoll_descriptor(3) 来获取可用于确定何时应调用 SSL_handle_events(3)(因为网络 I/O)的资源。
使用线程辅助模式的应用程序不需要关心此要求,因为 QUIC 实现确保计时器事件能够及时处理。有关详细信息,请参阅 **线程辅助模式**。
确保您对 SSL_want(3)、SSL_want_read(3) 和 SSL_want_write(3) 的使用反映了 **现有 API 的更改** 中描述的 API 更改。特别是,您应该使用这些 API 来确定 QUIC 流接收或提供应用程序数据的可能性,而不是为了确定是否需要网络 I/O。
根据 **现有 API 的更改** 中讨论的更改,评估您的应用程序对 SSL_shutdown(3) 的使用。根据您的应用程序是否希望优先考虑 RFC 符合性或快速关闭,请考虑使用新的 SSL_shutdown_ex(3) API。有关详细信息,请参阅 **特定于 QUIC 的 API**。
新应用程序中的推荐用法
新应用程序中的推荐用法取决于三个独立的设计决策
应用程序是否将在应用程序级别使用阻塞或非阻塞 I/O(使用 SSL_set_blocking_mode(3) 配置)。
如果应用程序在应用程序级别执行非阻塞 I/O,它可以选择管理自己的轮询和事件循环;请参阅 **应用程序驱动的事件循环**。
应用程序是否打算直接访问网络套接字(例如通过 BIO_s_datagram(3))为 QUIC 实现提供访问权限,或者它是否打算通过 BIO_s_dgram_pair(3) 或自定义 BIO 缓冲传输和接收的数据报。
前者在可能的情况下更可取,因为它可以减少到网络的延迟,从而使 QUIC 能够实现更高的性能和更准确的连接往返时间 (RTT) 估计。
是否将使用线程辅助模式(请参阅 **线程辅助模式**)。
可以在 https://github.com/openssl/openssl/tree/master/doc/designs/ddd 中找到针对这些不同场景的 QUIC 用法的简单演示。
希望实现特定于 QUIC 的协议的应用程序应该了解 **特定于 QUIC 的 API** 下列出的 API,这些 API 提供对特定于 QUIC 的功能的访问。例如,SSL_stream_conclude(3) 可用于指示流发送部分的结束,SSL_shutdown_ex(3) 可用于在关闭连接时提供 QUIC 应用程序错误代码。
无论选择上述哪些设计决策,建议新应用程序避免使用默认流模式,并通过调用 SSL_set_default_stream_mode(3) 来使用多流 API;有关详细信息,请参阅 **操作模式** 部分。
特定于 QUIC 的 API
本节详细介绍直接或间接与 QUIC 相关的新的 API。有关每个 API 操作的详细信息,请参阅引用的手册页。
以下 SSL API 是新的,但与 QUIC 和 DTLS 相关
- SSL_get_event_timeout(3)
-
确定何时应通过调用 SSL_handle_events(3)(或其他 I/O 函数,例如 SSL_read(3) 或 SSL_write(3))唤醒 QUIC 实现,如果有的话。
这也可以与 DTLS 一起使用,并且取代了 DTLSv1_get_timeout(3) 用于新用法。
- SSL_handle_events(3)
-
这是一个非特定 I/O 操作,它尽力尝试执行任何挂起的 I/O 或超时处理。它可用于通过处理传入的网络流量、生成传出的网络流量和处理任何过期的超时事件来推进 QUIC 状态机。SSL 对象上的大多数其他 I/O 函数(例如 SSL_read(3) 和 SSL_write(3))会隐式地对 SSL 对象执行事件处理,因此仅在不调用任何其他 I/O 函数时才需要调用此函数。
这也可以与 DTLS 一起使用,并且取代了 DTLSv1_handle_timeout(3) 用于新用法。
以下 SSL API 特定于 QUIC
- SSL_set_blocking_mode(3)、SSL_get_blocking_mode(3)
-
配置是否在应用程序级别使用阻塞语义。这决定了对 SSL_read(3) 和 SSL_write(3) 等函数的调用是否会阻塞。
- SSL_get_rpoll_descriptor(3)、SSL_get_wpoll_descriptor(3)
-
这些函数促进了非阻塞模式下的操作。
当 SSL 对象正在与支持轮询的底层网络读取 BIO 一起使用时,SSL_get_rpoll_descriptor(3) 输出一个 OS 资源,该资源可用于同步网络可读性事件,这些事件应该导致调用 SSL_handle_events(3)。对于底层网络写入 BIO,SSL_get_wpoll_descriptor(3) 以类似的方式工作。
只有当 SSL_net_read_desired(3) 和 SSL_net_write_desired(3) 分别返回 1 时,才需要使用这些函数提供的轮询描述符。
- SSL_net_read_desired(3)、SSL_net_write_desired(3)
-
这些函数促进了非阻塞模式下的操作,并与 SSL_get_rpoll_descriptor(3) 和 SSL_get_wpoll_descriptor(3) 分别结合使用。它们确定相应的轮询描述符当前是否与轮询相关。
- SSL_set1_initial_peer_addr(3)
-
此函数可用于设置传出 QUIC 连接的初始对等地址。在创建传出 QUIC 连接的一般情况下,必须使用此函数;但是,在某些情况下,可以自动检测到正确的初始对等地址。有关详细信息,请参阅 SSL_set1_initial_peer_addr(3)。
- SSL_shutdown_ex(3)
-
此扩展了 SSL_shutdown(3),允许指定应用程序错误代码。它还允许客户端决定希望以多快的速度执行关闭,可能通过权衡严格的 RFC 兼容性。
- SSL_stream_conclude(3)
-
这允许应用程序指示 QUIC 流发送部分的正常结束。这对应于 QUIC RFC 中的 FIN 标志。流的接收部分仍然可用。
- SSL_stream_reset(3)
-
这允许应用程序指示流发送部分的非正常终止。这对应于 QUIC RFC 中的 RESET_STREAM 帧。
- SSL_get_stream_write_state(3) 和 SSL_get_stream_read_state(3)
-
这允许应用程序分别确定流发送和接收部分的当前流状态。
- SSL_get_stream_write_error_code(3) 和 SSL_get_stream_read_error_code(3)
-
这允许应用程序确定对等方在执行流的各自发送或接收部分的非正常流终止时发出的应用程序错误代码(如果有)。
- SSL_get_conn_close_info(3)
-
这允许应用程序确定本地或远程端点终止 QUIC 连接时发出的错误代码。
- SSL_get0_connection(3)
-
从 QUIC 流 SSL 对象获取 QUIC 连接 SSL 对象。
- SSL_is_connection(3)
-
如果 SSL 对象不是 QUIC 流 SSL 对象,则返回 1。
- SSL_get_stream_type(3)
-
提供有关附加到 SSL 对象的 QUIC 流类型的信息。
- SSL_get_stream_id(3)
-
返回 QUIC 协议与 QUIC 流关联的 QUIC 流 ID。
- SSL_new_stream(3)
-
创建一个新的 QUIC 流 SSL 对象,代表一个新的、本地发起的 QUIC 流。
- SSL_accept_stream(3)
-
可能会产生一个新的 QUIC 流 SSL 对象,代表一个新的远程发起的 QUIC 流,如果连接配置为这样做,则阻塞直到一个可用。
- SSL_get_accept_stream_queue_len(3)
-
提供有关待处理的远程发起的流数量的信息。
- SSL_set_incoming_stream_policy(3)
-
配置如何处理传入的、远程发起的流。传入流策略可用于自动拒绝对等方创建的流,或允许使用 SSL_accept_stream(3) 处理它们。
- SSL_set_default_stream_mode(3)
-
用于配置或禁用默认流模式;有关详细信息,请参阅操作模式部分。
以下 BIO API 不特定于 QUIC,但已添加以方便 QUIC 特定的需求,并且与它的使用密切相关。
- BIO_s_dgram_pair(3)
-
这是一种新的 BIO 方法,类似于传统的 BIO 对,但提供了数据报语义。
- BIO_get_rpoll_descriptor(3),BIO_get_wpoll_descriptor(3)
-
这是一个新的 BIO API,它允许 BIO 公开一个轮询描述符。此 API 用于实现相应的 SSL API SSL_get_rpoll_descriptor(3) 和 SSL_get_wpoll_descriptor(3)。
- BIO_sendmmsg(3),BIO_recvmmsg(3)
-
这是一个新的 BIO API,可以由实现数据报语义的 BIO 实现。它由 BIO_s_datagram(3) 和 BIO_s_dgram_pair(3) 实现。它由 QUIC 实现用于发送和接收 UDP 数据报。
- BIO_dgram_set_no_trunc(3),BIO_dgram_get_no_trunc(3)
-
默认情况下,BIO_s_dgram_pair(3) 的语义类似于使用数据报语义的伯克利套接字。这允许启用另一种模式,其中数据报如果太大不会被静默截断。
- BIO_dgram_set_caps(3),BIO_dgram_get_caps(3)
-
这些函数用于允许 BIO_s_dgram_pair(3) 一端的使用者向 BIO_s_dgram_pair(3) 的另一端指示其功能。特别是,这允许应用程序通知 QUIC 实现是否准备处理已传输数据报中的本地和/或对等地址,以及在接收数据报中提供适用信息。
- BIO_dgram_get_local_addr_cap(3),BIO_dgram_set_local_addr_enable(3),BIO_dgram_get_local_addr_enable(3)
-
本地寻址支持是指具有数据报语义的 BIO 允许在传输时指定源地址并在接收时报告目标地址的能力。这些函数可用于确定 BIO 是否可以支持本地寻址,以及如果可以,则启用本地寻址支持。
- BIO_err_is_non_fatal(3)
-
这用于确定在调用 BIO_sendmmsg(3) 或 BIO_recvmmsg(3) 时出现的错误是否本质上是短暂的,例如“将阻塞”错误。
线程辅助模式
可选的线程辅助模式可与 OSSL_QUIC_client_thread_method(3) 一起使用。在此模式下,会自动创建一个后台线程。OpenSSL QUIC 实现随后负责确保即使应用程序长时间未调用任何 SSL I/O 函数(如 SSL_read(3) 或 SSL_write(3)),也能及时处理超时事件。
所有必要的锁定都由内部自动处理,但公共 SSL API 的线程安全保证保持不变。因此,如果应用程序希望同时使用公共 SSL API,则仍然必须执行自己的锁定。
由于此方法依赖于线程,因此在不支持线程或 OpenSSL 不支持线程的平台上不可用。但是,它确实为应用程序提供了最简单的使用模式。
实现可能会也可能不会使用公共线程或线程池来服务同一 SSL_CTX 中的多个 SSL 对象。
应用程序驱动的事件循环
OpenSSL 的 QUIC 实现旨在方便希望以阻塞方式使用 SSL API 的应用程序,但也旨在方便希望以非阻塞方式使用 SSL API 并直接管理其自己的事件循环和轮询的应用程序。当希望将 OpenSSL 的 QUIC 实现托管在应用程序现有的非阻塞 I/O 基础设施之上时,这很有用。
这通过轮询描述符的概念得到支持;有关详细信息,请参阅 BIO_get_rpoll_descriptor(3)。概括地说,BIO_POLL_DESCRIPTOR 是一种结构,它表示某种可以用于同步 I/O 事件的操作系统资源。QUIC 实现提供了一个基于底层网络 BIO 提供的轮询描述符的 BIO_POLL_DESCRIPTOR。这通常是操作系统套接字句柄,尽管自定义 BIO 可以选择实现自己的自定义轮询描述符格式。
概括地说,希望管理其自身事件循环的应用程序应按以下方式与 SSL 对象进行交互
它应使用 SSL_set0_rbio(3) 和 SSL_set0_wbio(3) 向 SSL 对象提供具有非阻塞数据报语义的读写 BIO。这可以是抽象网络套接字的 BIO(如 BIO_s_datagram(3)),或抽象某种内存缓冲区的 BIO(如 BIO_s_dgram_pair(3))。使用自定义 BIO 也是可能的。
它应通过调用 SSL_set_blocking_mode(3) 将 SSL 对象配置为非阻塞模式。
它应按需配置 SSL 对象,使用 SSL_set1_initial_peer_addr(3) 设置初始对等方,并通过调用 SSL_connect(3) 触发连接过程。
如果提供的网络读写 BIO 可轮询(例如,BIO_s_datagram(3) 或实现 BIO_get_rpoll_descriptor(3) 和 BIO_get_wpoll_descriptor(3) 的自定义 BIO),则应重复执行以下步骤
应用程序应调用 SSL_get_rpoll_descriptor(3) 和 SSL_get_wpoll_descriptor(3) 来识别可用于同步的操作系统资源。
它应调用 SSL_net_read_desired(3) 和 SSL_net_write_desired(3) 来确定 QUIC 实现当前是否对提供的底层网络 BIO 的可读性和可写性事件感兴趣,并调用 SSL_get_event_timeout(3) 来确定将来是否会发生任何超时事件。
它应等待以下事件之一发生
由 SSL_get_rpoll_descriptor(3) 返回的轮询描述符变为可读(如果 SSL_net_read_desired(3) 返回 1);
由 SSL_get_wpoll_descriptor(3) 返回的轮询描述符变为可写(如果 SSL_net_write_desired(3) 返回 1);
由 SSL_get_event_timeout(3) 返回的超时(如果有)过期。
一旦这些事件中的任何一个发生,就应调用 SSL_handle_events(3)。
如果提供的网络读写 BIO 不可轮询(例如,在 BIO_s_dgram_pair(3) 的情况下),应用程序负责管理和同步网络 I/O。它应在将数据写入 BIO_s_dgram_pair(3) 或采取其他行动后调用 SSL_handle_events(3),以便 QUIC 实现可以通过对底层网络 BIO 调用 BIO_recvmmsg(3) 读取新数据报。QUIC 实现可以通过调用 BIO_sendmmsg(3) 输出数据报,应用程序负责确保传输这些数据报。
应用程序必须在每次调用 SSL_handle_events(3)(或 SSL 对象上的其他 I/O 函数)后调用 SSL_get_event_timeout(3),并确保在指定超时(如果有)后执行对 SSL_handle_events(3) 的调用。
另请参阅
SSL_handle_events(3),SSL_get_event_timeout(3),SSL_net_read_desired(3),SSL_net_write_desired(3),SSL_get_rpoll_descriptor(3),SSL_get_wpoll_descriptor(3),SSL_set_blocking_mode(3),SSL_shutdown_ex(3),SSL_set1_initial_peer_addr(3),SSL_stream_conclude(3),SSL_stream_reset(3),SSL_get_stream_read_state(3),SSL_get_stream_read_error_code(3),SSL_get_conn_close_info(3),SSL_get0_connection(3),SSL_get_stream_type(3),SSL_get_stream_id(3),SSL_new_stream(3),SSL_accept_stream(3),SSL_set_incoming_stream_policy(3),SSL_set_default_stream_mode(3)
版权
版权所有 2022-2023 OpenSSL 项目作者。保留所有权利。
根据 Apache 许可证 2.0(“许可证”)获得许可。除非符合许可证,否则您不得使用此文件。您可以在源代码分发中的 LICENSE 文件或 https://www.openssl.org/source/license.html 中获取副本。