我想知道使用 AcceptEx 和 OpenSSL 处理来自客户端的新连接的正确方法。我有一个非常好的工作服务器,它通过常规 HTTP 使用带有 IO 完成端口的 AcceptEx。我想为其添加 OpenSSL 支持。
我在互联网上阅读了几篇关于将 OpenSSL 与非阻塞套接字一起使用的文章:
- IO 完成端口和 OpenSSL
- http://zzz.zggg.com/2007/12/22/ssl-server-with-openssl-memory-bio-aka-prerequisite-to-asynchronous-openssl/
- http://marc.info/?l=openssl-users&m=99909952822335&w=2
- http://www.lenholgate.com/blog/2002/11/using-openssl-with-asynchronous-sockets.html
他们似乎都没有涉及如何做到这一点,因为他们主要关心连接的客户端。AcceptEx 建立套接字连接并向您返回从客户端发送的第一条数据。我发布的第一个链接讨论了如何使用 IOCP 处理传入数据。到目前为止,我已经尝试过在那里发布的内容,但没有任何运气。基本上我在服务器上看到的内容如下:
- 接收到接受的连接完成。
- 我使用 SSL_new(ctx) 创建 SSL 对象
- 我用 BIO_new(BIO_s_mem()) 创建了输入和输出 BIO 对象。
- 我通过调用 SSL_set_bio(ssl, bioIn, bioOut) 在 SSL 对象中设置 BIO。
- 我调用 SSL_set_accept_state(ssl) 以允许 SSL_read 和 SSL_write 进行协商。
然后我继续尝试处理 AcceptEx 调用读取的第一个数据缓冲区。
- 我调用 BIO_Write(bioIn, buf, len) 将读取的数据复制到 SSL 中。
- 然后,我检查 bioOut 上的待处理握手数据,看看是否需要将其发送回客户端。不过,在接受新连接时,我从未见过 bioOut 中有任何数据。
- 然后我调用 SSL_read(ssl, plainTextBuf, len) 来尝试解密我在第 6 步中放入 bioIn 的数据。这总是返回 -1,而 SSL_get_error 返回 ERROR_SSL_WANT_READ。据我了解,这意味着 bioIn 没有完整的 SSL 记录,因此 SSL 需要来自客户端的更多数据才能解密任何内容。
这是我开始遇到问题的地方,也是我认为我需要一些指导的地方。我已经尝试了很多东西。如果我此时重复调用 SSL_read,它将无限返回 ERROR_SSL_WANT_READ,大概是因为使用内存 BIO 实际上并没有通过套接字进行通信以接收更多数据。我应该发布 WSARecv 调用以等待来自客户端的更多数据吗?
此时我还尝试使用 BIO_read 检查 bioOut 缓冲区,以查看是否有数据需要发送回客户端。确实有一些,我使用 WSASend 将其发回,并发布另一个 WSARecv 调用以等待更多数据(以响应我的发送)。这导致从客户端接收更多数据(WSARecv 在发送完成后完成),因此看起来好像连接正在进行中。但是,当我处理完成的读取时,SSL_read 和 BIO_read 都返回 ERROR_SSL_WANT_READ。所以,我没有足够的数据来解密完整的记录,也没有什么可以发回给客户。发布另一个 WSARecv 调用以响应这种情况也不会从客户端接收更多数据。我不知道 SSL 在这里想要什么。
我现在卡住了,但我会继续尝试更多的东西。如果我发现任何问题,我会用评论更新这个问题。