Commit d89c4195 authored by Rémi Denis-Courmont's avatar 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.
parent 128a1f17
......@@ -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
......@@ -455,6 +455,8 @@ vlc_rename
vlc_getcwd
vlc_dup
vlc_pipe
vlc_write
vlc_writev
vlc_socket
vlc_accept
utf8_vfprintf
......
......@@ -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>
/**
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment