OpenSSL SSL_shutdown 收到信号 SIGPIPE,Broken pipe

Posted

技术标签:

【中文标题】OpenSSL SSL_shutdown 收到信号 SIGPIPE,Broken pipe【英文标题】:OpenSSL SSL_shutdown received signal SIGPIPE, Broken pipe 【发布时间】:2014-03-23 11:10:41 【问题描述】:

我正在使用 openssl-0.9.8e 编写一个 http/https 客户端

当我打电话给SSL_read() 时出现错误

然后,我调用SSL_get_error 得到SSL_ERROR_SYSCALL 和errno ECONNRESET 104 /* Connection reset by peer */

根据 SSL 文档,这就是它的意思:

 SSL_ERROR_SYSCALL

 Some I/O error occurred. The OpenSSL error queue may contain more information on the error. 
If the error queue is empty (i.e. ERR_get_error() returns 0), ret can be used to find out more about the
    error: If ret == 0, an EOF was observed that violates the protocol. If ret == -1, the underlying BIO
    reported an I/O error (for socket I/O on Unix systems, consult errno for details).

好吧,连接重置,我调用SSL_shutdown关闭连接,哦,Program received signal SIGPIPE, Broken pipe.

上帝,我打电话给signal(SIGPIPE, SIG_IGN); 忽略“SIGPIPE”信号,但它似乎不起作用~

发生分段错误

#0  0x00000032bd00d96b in write () from /lib64/libpthread.so.0
#1  0x0000003add478367 in ?? () from /lib64/libcrypto.so.6
#2  0x0000003add4766fe in BIO_write () from /lib64/libcrypto.so.6
#3  0x0000003add8208fd in ssl3_write_pending () from /lib64/libssl.so.6
#4  0x0000003add820d9a in ssl3_dispatch_alert () from /lib64/libssl.so.6
#5  0x0000003add81e982 in ssl3_shutdown () from /lib64/libssl.so.6
#6  0x00000000004565d0 in CWsPollUrl::SSLClear (this=<value optimized out>, ctx=0x2aaab804a1b0, ssl=0x2aaab804a680)
    at ../src/Wspoll.cpp:1122
#7  0x00000000004575e0 in CWsPollUrl::asyncEventDelete (this=0x4d422e50, eev=0x2aaab8001160) at ../src/Wspoll.cpp:1546
#8  0x000000000045928a in CWsPollUrl::onFail (this=0x4d422e50, eev=0x2aaab8001160, errorCode=4) at ../src/Wspoll.cpp:1523
#9  0x000000000045ab17 in CWsPollUrl::handleData (this=0x4d422e50, eev=0x2aaab8001160, len=<value optimized out>) at ../src/Wspoll.cpp:1259
#10 0x000000000045abcc in CWsPollUrl::asyncRecvEvent (this=0x4d422e50, fd=<value optimized out>, eev=0x2aaab8001160)
    at ../src/Wspoll.cpp:1211
#11 0x00000000004636b5 in event_base_loop (base=0x14768360, flags=0) at event.c:1350
#12 0x0000000000456a62 in CWsPollUrl::run (this=<value optimized out>, param=<value optimized out>) at ../src/Wspoll.cpp:461
#13 0x0000000000436c5c in doPollUrl (data=<value optimized out>, user_data=<value optimized out>) at ../src/PollStrategy.cpp:151
#14 0x00000032bf44a95d in ?? () from /lib64/libglib-2.0.so.0
#15 0x00000032bf448e04 in ?? () from /lib64/libglib-2.0.so.0
#16 0x00000032bd00677d in start_thread () from /lib64/libpthread.so.0
#17 0x00000032bc4d3c1d in clone () from /lib64/libc.so.6

为什么我得到 SIGPIPE 信号,我已经打电话给signal(SIGPIPE, SIG_IGN); 有谁知道为什么?

提前致谢

【问题讨论】:

如果您在读取时遇到错误而不是超时,则几乎可以肯定您正在处理已经断开的连接。您可能遇到的任何后续错误都应该被忽略。 你确定在这个过程中真的调用了signal(SIGPIPE, SIG_IGN);吗?如果你在 fork 和 exec 之前调用它,它可能会被重置。此外,正确关闭被对等方断开的连接似乎也没用。 【参考方案1】:

如果 SSL_read 出现 I/O 错误,调用 SSL_shutdown 没有多大意义,因为关闭尝试向对等方发送“关闭通知”关闭警报,这显然不适用于断开的连接。因此,您将获得 SIGPIPE 或 EPIPE。在这种情况下,从 SSL_read 获取 ECONNRESET 可能意味着客户端已硬关闭连接,例如不做 SSL_shutdown。出现错误后,您不应继续使用套接字,例如甚至没有进行 SSL_shutdown。

【讨论】:

在调用SSL_shutdown之前可以进行哪些检查?如何检查套接字是否仍然打开而不发送或接收数据?例如,在我需要调用SSL_shutdown 之前,另一个对等方可能在没有调用SSL_shutdown 的情况下重置了连接。所以在对连接状态进行初步检查之前,我不知道我是否真的可以调用它。【参考方案2】:

除了@SteffenUllrich 答案之外,您还可以在调用SSL_shutdown 之前调用SSL_get_shutdown 并检查SSL_SENT_SHUTDOWN 标志是否已设置。你可以这样做:

    //Perform a mutex lock here

    if(SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN)
    
        printf("shutdown request ignored\n");
    
    else
    
        SSL_shutdown(con->tls.openssl);
    

    //Perform a mutex unlock here

在多线程程序中,SSL * 指针在多个线程之间共享,SSL_shutdown 可能已被另一个线程调用,此代码可以保护您免受SIGPIPE 信号的影响。

【讨论】:

此代码可以保护您免受SIGPIPE 信号的影响。可以 保护您免受SIGPIPE 信号的影响,但它也可能无法防止SIGPIPE 信号。两个(或更多...)线程可以调用SSL_get_shutdown(),然后任何线程才能真正调用SSL_shutdown() 以设置SSL_SENT_SHUTDOWN 标志。 @AndrewHenle 你是对的。 if else 需要用锁包裹和解锁,因此这里需要一个互斥锁以完全防止SIGPIPE。这样,对 if-else 块的独占访问应确保在执行检查时没有线程调用或即将调用SSL_shutdown

以上是关于OpenSSL SSL_shutdown 收到信号 SIGPIPE,Broken pipe的主要内容,如果未能解决你的问题,请参考以下文章

数据安全及OpenSSL

无法使用 openSSL 将 .p12 转换为 .pem

虽然没有收到信号?

Linux信号:孩子没有收到

Qt DBus没有收到信号

Qt:为啥我的按钮没有收到信号?