内存BIO场景下如何实现SSL_pending功能?
问题分析与解决方案
你遇到的核心问题是:使用内存BIO(BIO_s_mem)搭配Winsock实现异步SSL通信时,往输入BIO写入套接字数据后,OpenSSL不会自动解析处理这些数据,导致SSL_pending()无法检测到待处理的应用数据——因为这些数据还停留在BIO层,没有被SSL层解密并放入内部应用缓冲区。
为什么SSL_pending()不工作?
SSL_pending()仅检测SSL层内部已解密的应用数据队列,不会主动扫描输入BIO中的原始SSL记录。只有当SSL层主动从输入BIO读取并处理数据后,解密后的应用数据才会被存入内部缓冲区,SSL_pending()才能返回正确值。
可行的解决方案
要实现无需读取数据就能知晓待处理数据的需求,核心是触发SSL层处理输入BIO中的数据,同时不消耗应用数据。最合理的方式是使用SSL_peek()配合极小缓冲区:
具体实现步骤
- 调用
SSL_peek(),传入一个1字节的缓冲区(避免不必要的数据复制)。该函数会触发SSL层完成以下操作:- 从输入BIO读取SSL记录;
- 完成握手、重协商、心跳等SSL层操作;
- 将解密后的应用数据存入内部缓冲区,但不会取出数据。
- 处理
SSL_peek()的返回值,尤其是SSL_ERROR_WANT_WRITE(需要发送SSL层生成的输出数据,比如握手响应)。
代码示例
// 往输入BIO写入套接字接收的数据后,触发SSL层处理 char dummy_buf[1]; int ret = SSL_peek(ssl, dummy_buf, sizeof(dummy_buf)); if (ret < 0) { int err_code = SSL_get_error(ssl, ret); if (err_code == SSL_ERROR_WANT_WRITE) { // 处理输出BIO中的待发送数据(如握手包、重协商数据) char send_buf[1024]; int send_len; while ((send_len = BIO_read(ssl_output, send_buf, sizeof(send_buf))) > 0) { // 将数据发送到Winsock套接字 send(your_socket, send_buf, send_len, 0); } // 发送完成后可再次尝试调用SSL_peek(),确保数据处理完成 ret = SSL_peek(ssl, dummy_buf, sizeof(dummy_buf)); } else if (err_code != SSL_ERROR_WANT_READ) { // 处理其他错误(如SSL协议错误、连接断开) // ... } } // 此时SSL_pending()会返回正确的待处理应用数据长度 int pending_data_len = SSL_pending(ssl);
注意事项
- 每次往输入BIO写入新数据后,都需要执行一次上述触发操作,才能保证
SSL_pending()的准确性。 SSL_peek()的返回值>0时,说明已有解密后的应用数据在内部缓冲区;返回0表示连接已关闭;返回<0且错误码为SSL_ERROR_WANT_READ时,说明输入BIO中的数据还不足以完成SSL层处理(需要等待更多数据)。
内容的提问来源于stack exchange,提问作者TrisT
相关产品推荐
相关产品推荐

