[vlc-commits] src: add vlc_write() and vlc_writev() helpers against SIGPIPE

Rémi Denis-Courmont git at videolan.org
Wed Jun 3 19:25:28 CEST 2015


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed May 13 19:31:53 2015 +0300| [d89c4195077ae0623e39b3c41121ecd9b20d0d9e] | committer: Rémi Denis-Courmont

src: add vlc_write() and vlc_writev() helpers against SIGPIPE

We would rather not terminate the whole VLC process in case of a
broken pipe or remotely closed TCP connection.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d89c4195077ae0623e39b3c41121ecd9b20d0d9e
---

 include/vlc_fs.h       |    4 ++++
 src/libvlccore.sym     |    2 ++
 src/posix/filesystem.c |   55 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/win32/filesystem.c |   10 +++++++++
 4 files changed, 71 insertions(+)

diff --git a/include/vlc_fs.h b/include/vlc_fs.h
index 4786a2e..83d892e 100644
--- a/include/vlc_fs.h
+++ b/include/vlc_fs.h
@@ -37,6 +37,7 @@
  *    dirent structure pointers to its callbacks.
  *  - vlc_accept() takes an extra boolean for nonblocking mode (compare with
  *    the flags parameter in POSIX.next accept4()).
+ *  - Writing functions do not emit a SIGPIPE signal in case of broken pipe.
  */
 
 #include <sys/types.h>
@@ -107,6 +108,7 @@ static inline void vlc_rewinddir( DIR *dir )
 #endif
 
 struct stat;
+struct iovec;
 
 VLC_API int vlc_stat( const char *filename, struct stat *buf );
 VLC_API int vlc_lstat( const char *filename, struct stat *buf );
@@ -115,4 +117,6 @@ VLC_API int vlc_mkstemp( char * );
 
 VLC_API int vlc_dup( int );
 VLC_API int vlc_pipe( int[2] );
+VLC_API ssize_t vlc_write( int, const void *, size_t );
+VLC_API ssize_t vlc_writev( int, const struct iovec *, int );
 #endif
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 86a3a82..1ae7c98 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -455,6 +455,8 @@ vlc_rename
 vlc_getcwd
 vlc_dup
 vlc_pipe
+vlc_write
+vlc_writev
 vlc_socket
 vlc_accept
 utf8_vfprintf
diff --git a/src/posix/filesystem.c b/src/posix/filesystem.c
index 79856e3..2cd6d1b 100644
--- a/src/posix/filesystem.c
+++ b/src/posix/filesystem.c
@@ -30,6 +30,7 @@
 #include <stdio.h>
 #include <limits.h> /* NAME_MAX */
 #include <errno.h>
+#include <signal.h>
 
 #include <sys/types.h>
 #include <unistd.h>
@@ -271,6 +272,60 @@ int vlc_pipe (int fds[2])
     return 0;
 }
 
+/**
+ * Writes data to a file descriptor. Unlike write(), if EPIPE error occurs,
+ * this function does not generate a SIGPIPE signal.
+ * @note If the file descriptor is known to be neither a pipe/FIFO nor a
+ * connection-oriented socket, the normal write() should be used.
+ */
+ssize_t vlc_write(int fd, const void *buf, size_t len)
+{
+    struct iovec iov = { .iov_base = (void *)buf, .iov_len = len };
+
+    return vlc_writev(fd, &iov, 1);
+}
+
+/**
+ * Writes data from an iovec structure to a file descriptor. Unlike writev(),
+ * if EPIPE error occurs, this function does not generate a SIGPIPE signal.
+ */
+ssize_t vlc_writev(int fd, const struct iovec *iov, int count)
+{
+    sigset_t set, oset;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGPIPE);
+    pthread_sigmask(SIG_BLOCK, &set, &oset);
+
+    ssize_t val = writev(fd, iov, count);
+    if (val < 0 && errno == EPIPE)
+    {
+#if (_POSIX_REALTIME_SIGNALS > 0)
+        siginfo_t info;
+        struct timespec ts = { 0, 0 };
+
+        while (sigtimedwait(&set, &info, &ts) >= 0 || errno != EAGAIN);
+#else
+        for (;;)
+        {
+            sigset_t s;
+            int num;
+
+            sigpending(&s);
+            if (!sigismember(&s, SIGPIPE))
+                break;
+
+            sigwait(&set, &num);
+            assert(num == SIGPIPE);
+        }
+#endif
+    }
+
+    if (!sigismember(&oset, SIGPIPE)) /* Restore the signal mask if changed */
+        pthread_sigmask(SIG_SETMASK, &oset, NULL);
+    return val;
+}
+
 #include <vlc_network.h>
 
 /**
diff --git a/src/win32/filesystem.c b/src/win32/filesystem.c
index 045ad99..cf722ab 100644
--- a/src/win32/filesystem.c
+++ b/src/win32/filesystem.c
@@ -284,6 +284,16 @@ int vlc_pipe (int fds[2])
 #endif
 }
 
+ssize_t vlc_write(int fd, const void *buf, size_t len)
+{
+    return write(fd, buf, len);
+}
+
+ssize_t vlc_writev(int fd, const struct iovec *iov, int count)
+{
+    vlc_assert_unreachable();
+}
+
 #include <vlc_network.h>
 
 int vlc_socket (int pf, int type, int proto, bool nonblock)



More information about the vlc-commits mailing list