SSL_write报告成功但在Safari中失败

时间:2016-03-24 18:22:51

标签: c++ sockets safari openssl

我有自己的使用openssl的网络服务器的实现。

我正在使用SSL_write的阻止版本在OSX上传输数据和最新的Safari。

我的逻辑如下:

num_bytes = 0;
while( num_bytes < bytes_to_send) {
  int n = SSL_write(...);
  if (n <= 0) {
     ... // Handle error, break loop
  }
  num_bytes += n;
}
// Close the socket

我在Safari报告Failed to load resource: The network connection was lost.

时遇到的问题很少见

当我在Safari下的开发人员窗格中检查资源时,它显示收到的字节数少于预期。

我调试了我的代码并确定SSL_write报告在关闭连接之前已传输所有字节。

当我不关闭连接时,不再出现此错误。

这使我得出以下结论:

SSL_write错误地报告在实际发生之前成功传输了多个字节,并且在切断传输短路后立即关闭连接。

我是否正确,或者是否有关于我遗失的SSL_write的详细信息?

更新

在检查了我处理SSL_shutdown的方式后,我看到报告了几个SSL_ERROR_SYSCALL错误。这可能与我的问题有关,也可能没有,因为在受影响的http传输后不会直接返回这些错误。奇怪的是,在受影响的http传输过程中,除了阻止呼叫的重试错误之外,SSL_shutdown没有报告错误。

关闭代码

// First shutdown SSL
SSL_CTX_free(ctx);
if (SSL_shutdown(ssl) == 0) {
  // Call SSL Shutdown again
  SSL_shutdown(ssl);
}
SSL_free(ssl);

// Now shutdown port
struct linger linger;
linger.l_onoff = 1;
linger.l_linger = 10;
setsockopt(socket, SOL_SOCKET, SO_LINGER, (char *)&linger,
           sizeof(linger));

shutdown(socket, SHUT_WR);
while(recv(...) > 0) { }
closesocket(socket);

更新#2

我使用ssl解密设置wireshark来捕获错误。这是它的样子: Safari Error Message: PatientSearch.js Wireshark Capture: See PatientSearch.js Successfully Transferred

注意第一个绿线,它显示来自Safari的PatientSearch.js的HTTP请求。现在,第二个绿线显示来自我的网络服务器的HTTP响应。此响应包含整个文件,后跟断开协议。

更新#3

第二种情况越来越神秘。在检查wireshark跟踪以成功传输之后,成功传输中的协议模式与中断传输没有区别。现在完全糊涂了。

1 个答案:

答案 0 :(得分:2)

您的发送循环无法正确跟踪发送的字节数。它应该看起来更像是这样:

unsigned char *data = ...;
while (bytes_to_send > 0) {
  int num_sent = SSL_write(ssl, data, bytes_to_send);
  if (num_sent <= 0) {
    // handle error as needed...
    break;
  }
  data += num_sent;
  bytes_to_send -= num_sent;
}
// Close the socket

或者这个:

unsigned char *data = ...;
int num_total_sent = 0;
while (num_total_sent < bytes_to_send) {
  int num_sent = SSL_write(ssl, &data[num_total_sent], bytes_to_send - num_total_sent);
  if (num_sent <= 0) {
    // handle error as needed...
    break;
  }
  num_total_sent += num_sent;
}
// Close the socket

更新

  

SSL_write错误地报告在实际发生之前成功传输了多个字节

返回值报告它从您接收的字节数。这并不能保证那些字节实际上已经传输了。它们被加密并用于创建一个传出的SSL帧,它位于底层套接字的出站缓冲区中,等待内核在后台实际传输它。这种传输可能需要一些时间,特别是如果在套接字上启用Nagle算法(通常默认情况下)。

  

在切断转移短路后立即关闭连接。

这是可能的,具体取决于您关闭连接的方式,如何配置套接字的逗留选项等。默认情况下,正常关闭套接字应该允许内核在后台花费一些额外的时间在它之前写出任何未决数据然后实际关闭连接。您通常需要采取额外措施来改变这种行为。