3

I'm writing a http/https client using openssl-0.9.8e

I get error when I call SSL_read()

then, I call SSL_get_error get SSL_ERROR_SYSCALL and errno ECONNRESET 104 /* Connection reset by peer */

accoring to SSL documetation that's what it means:

 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).

well, Connection reset, I call SSL_shutdown to close connection, oh,Program received signal SIGPIPE, Broken pipe.

God, I call signal(SIGPIPE, SIG_IGN); to ignore "SIGPIPE" signal,but it seem to does't work~

A Segmentation Fault happen

#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

why I get SIGPIPE signal, I have already called signal(SIGPIPE, SIG_IGN); Does anyone know why?

Thanks in advance

user3282867
  • 51
  • 1
  • 3
  • If you get an error when reading other than a timeout, you're almost certainly dealing with a connection that's already broken. Any subsequent errors you may get should probably be ignored. – user207421 Mar 23 '14 at 11:21
  • Are you sure to have actually called `signal(SIGPIPE, SIG_IGN);` in this process? If you called it before a fork and exec, it may be reset. Also it seems to be useless to shutdown correctly a connection which was broken by the peer. – Marian Mar 23 '14 at 11:30

2 Answers2

1

If you get an I/O error with SSL_read it makes not much sense to call SSL_shutdown, because the shutdown tries to send a "close notify" shutdown alert to the peer and this will obviously not work on a broken connection. Therefore you get the SIGPIPE or EPIPE. Getting ECONNRESET from SSL_read in this case probably means, that the client has closed the connection hard, e.g. without doing an SSL_shutdown. You should not continue working with the socket after the error, e.g. not even doing an SSL_shutdown.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • What check can be performed before calling `SSL_shutdown` ? How can I check that the socket is still opened without sending or receiving data ? For example the other peer might have reset the connection without calling `SSL_shutdown` and just before I need to call `SSL_shutdown`. So I don't know if I can actually call it until a preliminary check on the status of the connection is performed. – Bemipefe Sep 09 '21 at 13:54
1

In addition to the @SteffenUllrich answer you can also call SSL_get_shutdown before calling SSL_shutdown and check if the SSL_SENT_SHUTDOWN flag was already set. You can do something like this:

    //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

In a multi threaded program with the SSL * pointer shared among multiple threads it may happen that the SSL_shutdown was already called by another thread and this code can protect you from a SIGPIPE signal.

Bemipefe
  • 1,397
  • 4
  • 17
  • 30
  • 1
    *this code can protect you from a `SIGPIPE` signal.* It **can** protect against a `SIGPIPE` signal, but it can also fail to protect against a `SIGPIPE` signal. Two (or more...) threads can call `SSL_get_shutdown()` before any thread gets far enough into an actual call to `SSL_shutdown()` to set the `SSL_SENT_SHUTDOWN` flag. – Andrew Henle Sep 15 '21 at 23:41
  • 1
    @AndrewHenle you are right. The if else need to be wrapped with a lock and unlock so a mutex is needed here in order to fully protect against the `SIGPIPE`. In this way the exclusive access to the the if-else block should ensure that no thread called or is about to call `SSL_shutdown` when the check is performed. – Bemipefe Sep 16 '21 at 09:26