我想知道使用 AcceptEx 和 OpenSSL 处理来自客户端的新连接的正确方法。我有一个运行良好的服务器,它通过常规 HTTP 使用带有 IO 完成端口的 AcceptEx。我想为其添加 OpenSSL 支持。
我在互联网上阅读了几篇有关使用 OpenSSL 和非阻塞套接字的文章:
- IO Completion Ports and OpenSSL
- http://zzz.zggg.com/2007/12/22/ssl-server-with-openssl-memory-bio-a-k-a-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 想要什么。
我现在陷入困境,但我会继续尝试更多的事情。如果我发现任何问题,我会用评论更新这个问题。
最佳答案
您在套接字上发出新的重叠读取,等待其完成,将数据推送到您的 BIO 中,并再次循环执行您当前正在执行的步骤。
ERROR_SSL_WANT_READ
表示 BIO 需要更多数据,即它需要再次读取。
在数据流期间的任何时刻,您可能需要允许 SSL 层发送或接收更多数据,然后才能将更多应用程序级数据推送到 BIO。
我认为我在您引用的文章中非常清楚地介绍了所有这些内容;那篇文章中的代码是我在自己的基于 IOCP 的服务器中使用的代码的基础...
关于openssl - AcceptEx 和 OpenSSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8510731/