首页 文章

SSL_read无限期地阻止

提问于
浏览
1

我试图使用SSL_read从Openssl链接套接字读取数据 . 我在客户端模式下执行Openssl操作,该模式发送命令并从实际服务器接收数据 . 我使用了两个线程,其中一个线程处理所有Openssl操作,如connect,write和close . 我在一个单独的线程中执行SSL_read . 当我发出一次SSL_read时,我能够正确读取数据 .

但是当我尝试执行多个连接,写入,关闭序列时,我遇到了问题 . 理想情况下,我应该终止执行SSL_read的线程以响应close . 这是因为对于下一次连接,我们将获得一个新的ssl指针,因此我们不希望对旧的ssl指针执行读取 . 但问题是当我执行SSL_read时,我被困住直到SSL缓冲区中有可用的数据 . 它在SSL指针上被阻止,即使我在另一个线程中关闭了SSL连接 .

while(1) {
    memset(sbuf, 0, sizeof(uint8_t) * TLS_READ_RCVBUF_MAX_LEN);

    read_data_len = SSL_read(con, sbuf, TLS_READ_RCVBUF_MAX_LEN);
    switch (SSL_get_error(con, read)) {
        case SSL_ERROR_NONE:
.
.
.
}

我尝试了所有可能的问题解决方案但不起作用 . 大多数情况下,我试着让我知道SSL缓冲区中可能有数据,但没有一个返回正确的指示 .

我试过了:

  • 首先进行SSL_pending以了解SSL缓冲区中是否有数据 . 但这总是归零

  • 在Openssl套接字上执行select以查看它是否返回大于零的值 . 但它总是返回零 .

  • 使套接字成为非阻塞并尝试选择,但它似乎不起作用 . 我不确定我是否正确使用了代码 .

我使用select用于阻塞套接字的示例如下 . 但是select总是返回零 .

while(1) {
    //  The use of Select here is to timeout
    //  while waiting for data to read on SSL. 
    //  The timeout is set to 1 second
    i = select(width, &readfds, NULL,
            NULL, &tv);
    if (i < 0) {
        // Select Error. Take appropriate action for this error
    }

    //  Check if there is data to be read
    if (i > 0) {
        if (FD_ISSET(SSL_get_fd(con), &readfds)) {
            // TODO: We have data in the SSL buffer. But are we
            //       sure that the data is from read buffer? If not,
            //       SSL_read can be stuck indefinitely.
            //       Maybe we can do SSL_read(con, sbuf, 0) followed
            //       by SSL_pending to find out?
            memset(sbuf, 0, sizeof(uint8_t) * TLS_READ_RCVBUF_MAX_LEN);

            read_data_len = SSL_read(con, sbuf, TLS_READ_RCVBUF_MAX_LEN);
            error = SSL_get_error(con, read_data_len);
            switch (error) {
.
.
}

所以你可以看到我已经尝试了很多方法让线程执行SSL_read以响应close而终止,但是我没有按照我的预期让它工作 . 有人让SSL_read正常工作吗?非阻塞套接字只能解决我的问题吗?对于阻塞套接字如果从未得到命令响应,如何解决从SSL_read退出的问题?你能给出一个非阻塞套接字工作解决方案的例子吗?

1 回答

  • 0

    我可以向您介绍一个使用SSL的非阻塞客户端套接字的工作示例... https://github.com/darrenjs/openssl_examples

    它使用带有标准linux IO的非阻塞套接字(基于轮询事件循环) . 原始数据从套接字读取,然后送入SSL存储器BIO,然后执行解密 .

    我使用的方法是单线程 . 单个线程执行连接,写入和读取 . 这意味着关闭套接字的一个线程不会出现任何问题,而另一个线程正在尝试使用该套接字 . 此外,正如SSL常见问题解答"an SSL connection cannot be used concurrently by multiple threads"(https://www.openssl.org/docs/faq.html#PROG1)所述,因此单线程方法避免了并发SSL写入和读取的问题 .

    单线程方法面临的挑战是,您需要创建某种同步队列和信令机制,以便为出站提交和保留待处理数据(例如,您要从客户端发送到服务器的命令),并获取套接字事件循环检测何时有待写入的数据并从队列中提取等 . 为此,我会查看标准的std :: list,std :: mutex等,以及pipe2或eventfd用于发信号通知事件循环 .

相关问题