为什么这个SSL_pending调用总是返回零?

时间:2011-07-07 20:47:53

标签: https openssl winsock

此代码适用于使用阻塞套接字的HTTPS服务器:

  request := '';
  start := gettickcount;
  repeat
    if SSL_pending(ssl) > 0 then
      begin
      bytesin := SSL_read(ssl, buffer, sizeof(buffer)-1);
      if bytesin > 0 then
        begin
        buffer[bytesin] := #0;
        request := request + buffer;
        end
      else break; // read failed
      end; // pending
   until (gettickcount - start) > LARGETIMEOUT;
   // "request" is ready, though possibly empty

SSL_pending()始终返回零,并且永远不会达到SSL_read()。如果删除了SSL_pending()调用,则执行SSL_read()。为什么SSL_pending()不指示可用的字节数?

请注意,如果您调用SSL_read()并且返回的字节数小于缓冲区大小,那么您已阅读所有内容并已完成。

如果传入的数据大于缓冲区大小,则第一个SSL_read()调用将填充缓冲区,您可以重复调用SSL_read(),直到无法填充缓冲区为止。

BUT 如果传入的数据是缓冲区大小的精确倍数,则最后一块数据填充缓冲区。如果您尝试另一个SSL_read()认为阻塞套接字上可能有更多数据,它会无限期挂起。因此,首先要检查SSL_pending()。然而,这似乎不起作用。

如何避免挂在最终的SSL_read()上? (我无法想象答案是非阻塞,因为这意味着你永远不能将SSL_read与阻塞一起使用。)

更新:以下有效。显然SSL_pending()在第一个SSL_read()之后才起作用:

  request := '';
  repeat
    bytesin := SSL_read(ssl, buffer, sizeof(buffer)-1);
    if bytesin > 0 then
      begin
      buffer[bytesin] := #0;
      request := request + buffer;
      end
    else break; // read failed
  until SSL_pending(ssl) <= 0;
  // "request" is ready, though possibly empty

2 个答案:

答案 0 :(得分:6)

您正在以完全错误的方式使用SSL_pending()。 OpenSSL使用状态机,其中SSL_pending()指示状态机是否有任何已缓冲且正在等待处理的待处理字节。由于您永远不会调用SSL_read(),因此您永远不会缓冲任何数据或推进状态机。

答案 1 :(得分:2)

如果SSL_pending函数返回的返回码为0,则并不一定意味着SSL会话上没有可立即读取的数据。返回码0表示当前SSL数据记录中没有更多数据。但是,可能已从网络接收到更多SSL数据记录。如果SSL_pending函数返回0的返回码,则发出select函数,传递套接字的文件描述符以检查套接字是否可读。可读意味着已从套接字上的网络接收到更多数据。