如何结合SSL_read和epoll?

How to combine SSL_read and epoll?

我正在用基于事件的网络库(使用 epoll)编写一个 HTTP 代理服务器。

假设有一个快速的 HTTPS 上游和一个慢速的 HTTP(S) 下游。所以我必须将上游数据存储到缓冲区,并在缓冲区已满时从网络库中分离上游读取事件。

但正如我们所知,SSL_read 可能 return 部分数据。所以考虑以下情况:

  1. 缓冲区大小为 32 并在网络库上附加读取事件
  2. 上游发送 32 字节,整个 HTTP 消息是 32 字节
  3. 网络库调用读取事件回调
  4. 调用 SSL_read(ssl, buf, 32)SSL_read returns 16
  5. 向下游发送 16 字节并在网络库上附加读取事件
  6. 永远不会调用读取回调,因为剩余的 16 个字节在 openssl 缓冲区中并且没有来自上游的更多字节

那么有什么好的解决办法吗?

OpenSSL 较旧的基于 SSL 的 API 不遵循您尝试使用的传统套接字 I/O 事件模型。

使用非阻塞套接字时,您不应在调用 SSL_read() 之前等待套接字读取事件。您应该无条件地调用 SSL_read() 并让它通过返回 SSL_ERROR_WANT_READ 错误来告诉您何时需要来自套接字的更多数据。只有这样,您才应该在再次调用 SSL_read() 之前等待套接字读取事件(如果它 returns SSL_ERROR_WANT_WRITE,则等待套接字写入事件)。

如果您想使用传统的套接字事件来驱动您的 reading/writing,请改用 OpenSSL 的更新的基于 BIO 的 API。使用 BIO 对将接收到的加密字节推送到 OpenSSL 引擎,并让它在读取时将解密字节推送给您,反之亦然。然后你可以随心所欲地处理套接字 I/O 。