A low-effort fix for fixing SIGPIPE being raised in some situations
because OpenSSL uses a naive write() to send data to the socket without
using MSG_NOSIGNAL.

The idea and code for blocking and unqueuing SIGPIPE is taken from:
http://stackoverflow.com/questions/24920748/how-to-handle-a-sigpipe-error-inside-the-object-that-generated-it/24921005#24921005

A proper fix would probably either fix OpenSSL itself, or use a callback
based BIO wrapper.
---
I'm very sorry for even sending this shitty patch.

My hope is that someone else implements a proper fix, because I'm too
lazy to write a proper fix. (Matching OpenSSL's and avio's IO doesn't
sound like fun.)
---
 libavformat/tls.c | 41 +++++++++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 6 deletions(-)

diff --git a/libavformat/tls.c b/libavformat/tls.c
index 4a52e84..892fa6f 100644
--- a/libavformat/tls.c
+++ b/libavformat/tls.c
@@ -57,6 +57,25 @@
 #include <poll.h>
 #endif
 
+#if CONFIG_OPENSSL && HAVE_POLL_H && HAVE_PTHREADS
+#include <pthread.h>
+#include <signal.h>
+#include <errno.h>
+#define BLOCK_SIGPIPE \
+    sigset_t oldset, newset; \
+    siginfo_t si; \
+    struct timespec ts = {0}; \
+    sigemptyset(&newset); \
+    sigaddset(&newset, SIGPIPE); \
+    pthread_sigmask(SIG_BLOCK, &newset, &oldset);
+#define UNBLOCK_SIGPIPE \
+    while (sigtimedwait(&newset, &si, &ts) >= 0 || errno != EAGAIN) {}; \
+    pthread_sigmask(SIG_SETMASK, &oldset, 0);
+#else
+#define BLOCK_SIGPIPE
+#define UNBLOCK_SIGPIPE
+#endif
+
 typedef struct TLSContext {
     const AVClass *class;
     URLContext *tcp;
@@ -155,6 +174,7 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
     struct addrinfo hints = { 0 }, *ai = NULL;
     const char *proxy_path;
     int use_proxy;
+    BLOCK_SIGPIPE
 
     ff_tls_init();
 
@@ -317,12 +337,14 @@ static int tls_open(URLContext *h, const char *uri, int 
flags, AVDictionary **op
             goto fail;
     }
 #endif
+    UNBLOCK_SIGPIPE
     return 0;
 fail:
     TLS_free(c);
     if (c->tcp)
         ffurl_close(c->tcp);
     ff_tls_deinit();
+    UNBLOCK_SIGPIPE
     return ret;
 }
 
@@ -344,25 +366,32 @@ static int tls_read(URLContext *h, uint8_t *buf, int size)
 static int tls_write(URLContext *h, const uint8_t *buf, int size)
 {
     TLSContext *c = h->priv_data;
+    int ret;
+    BLOCK_SIGPIPE
     while (1) {
-        int ret = TLS_write(c, buf, size);
+        ret = TLS_write(c, buf, size);
         if (ret > 0)
-            return ret;
-        if (ret == 0)
-            return AVERROR_EOF;
+            break;
+        if (ret == 0) {
+            ret = AVERROR_EOF;
+            break;
+        }
         if ((ret = do_tls_poll(h, ret)) < 0)
-            return ret;
+            break;
     }
-    return 0;
+    UNBLOCK_SIGPIPE
+    return ret;
 }
 
 static int tls_close(URLContext *h)
 {
     TLSContext *c = h->priv_data;
+    BLOCK_SIGPIPE
     TLS_shutdown(c);
     TLS_free(c);
     ffurl_close(c->tcp);
     ff_tls_deinit();
+    UNBLOCK_SIGPIPE
     return 0;
 }
 
-- 
2.1.4

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to