diff --git a/src/event_pipe.c b/src/event_pipe.c index 17e11097a..4b7e741ff 100644 --- a/src/event_pipe.c +++ b/src/event_pipe.c @@ -18,7 +18,6 @@ */ #include "event_pipe.h" -#include "utils.h" #include "fd_util.h" #include @@ -85,13 +84,9 @@ void event_pipe_init(void) GIOChannel *channel; int ret; - ret = pipe_cloexec(event_pipe); + ret = pipe_cloexec_nonblock(event_pipe); if (ret < 0) g_error("Couldn't open pipe: %s", strerror(errno)); -#ifndef WIN32 - if (set_nonblocking(event_pipe[1]) < 0) - g_error("Couldn't set non-blocking I/O: %s", strerror(errno)); -#endif channel = g_io_channel_unix_new(event_pipe[0]); event_pipe_source_id = g_io_add_watch(channel, G_IO_IN, diff --git a/src/fd_util.c b/src/fd_util.c index a8be69be7..2350596c4 100644 --- a/src/fd_util.c +++ b/src/fd_util.c @@ -68,6 +68,29 @@ fd_set_cloexec(int fd, bool enable) #endif } +/** + * Enables non-blocking mode for the specified file descriptor. On + * WIN32, this function only works for sockets. + */ +static int +fd_set_nonblock(int fd) +{ +#ifdef WIN32 + u_long val = 1; + return ioctlsocket(fd, FIONBIO, &val); +#else + int flags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return flags; + + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +#endif +} + int open_cloexec(const char *path_fs, int flags) { @@ -108,7 +131,7 @@ creat_cloexec(const char *path_fs, int mode) } int -pipe_cloexec(int fd[2]) +pipe_cloexec_nonblock(int fd[2]) { #ifdef WIN32 return _pipe(event_pipe, 512, _O_BINARY); @@ -116,7 +139,7 @@ pipe_cloexec(int fd[2]) int ret; #ifdef HAVE_PIPE2 - ret = pipe2(fd, O_CLOEXEC); + ret = pipe2(fd, O_CLOEXEC|O_NONBLOCK); if (ret >= 0 || errno != ENOSYS) return ret; #endif @@ -125,6 +148,11 @@ pipe_cloexec(int fd[2]) if (ret >= 0) { fd_set_cloexec(fd[0], true); fd_set_cloexec(fd[1], true); + +#ifndef WIN32 + fd_set_nonblock(fd[0]); + fd_set_nonblock(fd[1]); +#endif } return ret; @@ -132,12 +160,12 @@ pipe_cloexec(int fd[2]) } int -socket_cloexec(int domain, int type, int protocol) +socket_cloexec_nonblock(int domain, int type, int protocol) { int fd; -#ifdef SOCK_CLOEXEC - fd = socket(domain, type | SOCK_CLOEXEC, protocol); +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + fd = socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol); if (fd >= 0 || errno != EINVAL) return fd; #endif @@ -150,13 +178,15 @@ socket_cloexec(int domain, int type, int protocol) } int -accept_cloexec(int fd, struct sockaddr *address, size_t *address_length_r) +accept_cloexec_nonblock(int fd, struct sockaddr *address, + size_t *address_length_r) { int ret; socklen_t address_length = *address_length_r; #ifdef HAVE_ACCEPT4 - ret = accept4(fd, address, &address_length, SOCK_CLOEXEC); + ret = accept4(fd, address, &address_length, + SOCK_CLOEXEC|SOCK_NONBLOCK); if (ret >= 0 || errno != ENOSYS) { if (ret >= 0) *address_length_r = address_length; @@ -168,6 +198,7 @@ accept_cloexec(int fd, struct sockaddr *address, size_t *address_length_r) ret = accept(fd, address, &address_length); if (ret >= 0) { fd_set_cloexec(ret, true); + fd_set_nonblock(ret); *address_length_r = address_length; } diff --git a/src/fd_util.h b/src/fd_util.h index 2dfc151f2..d9e811d51 100644 --- a/src/fd_util.h +++ b/src/fd_util.h @@ -49,23 +49,27 @@ creat_cloexec(const char *path_fs, int mode); /** * Wrapper for pipe(), which sets the CLOEXEC flag (atomically if * supported by the OS). + * + * On systems that supports it (everybody except for Windows), it also + * sets the NONBLOCK flag. */ int -pipe_cloexec(int fd[2]); +pipe_cloexec_nonblock(int fd[2]); /** - * Wrapper for socket(), which sets the CLOEXEC flag (atomically if - * supported by the OS). + * Wrapper for socket(), which sets the CLOEXEC and the NONBLOCK flag + * (atomically if supported by the OS). */ int -socket_cloexec(int domain, int type, int protocol); +socket_cloexec_nonblock(int domain, int type, int protocol); /** - * Wrapper for accept(), which sets the CLOEXEC flag (atomically if - * supported by the OS). + * Wrapper for accept(), which sets the CLOEXEC and the NONBLOCK flags + * (atomically if supported by the OS). */ int -accept_cloexec(int fd, struct sockaddr *address, size_t *address_length_r); +accept_cloexec_nonblock(int fd, struct sockaddr *address, + size_t *address_length_r); /** * Wrapper for inotify_init(), which sets the CLOEXEC flag (atomically diff --git a/src/listen.c b/src/listen.c index 2490780ad..668a8077c 100644 --- a/src/listen.c +++ b/src/listen.c @@ -21,7 +21,6 @@ #include "socket_util.h" #include "client.h" #include "conf.h" -#include "utils.h" #include "fd_util.h" #include "config.h" @@ -429,10 +428,9 @@ listen_in_event(G_GNUC_UNUSED GIOChannel *source, struct sockaddr_storage sa; size_t sa_length = sizeof(sa); - fd = accept_cloexec(listen_fd, (struct sockaddr*)&sa, &sa_length); + fd = accept_cloexec_nonblock(listen_fd, (struct sockaddr*)&sa, + &sa_length); if (fd >= 0) { - set_nonblocking(fd); - client_new(fd, (struct sockaddr*)&sa, sa_length, get_remote_uid(fd)); } else if (fd < 0 && errno != EINTR) { diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c index 6d5e99c57..53bcc2deb 100644 --- a/src/output/httpd_output_plugin.c +++ b/src/output/httpd_output_plugin.c @@ -195,7 +195,8 @@ httpd_listen_in_event(G_GNUC_UNUSED GIOChannel *source, /* the listener socket has become readable - a client has connected */ - fd = accept_cloexec(httpd->fd, (struct sockaddr*)&sa, &sa_length); + fd = accept_cloexec_nonblock(httpd->fd, (struct sockaddr*)&sa, + &sa_length); if (fd >= 0) { /* can we allow additional client */ if (httpd->open && diff --git a/src/socket_util.c b/src/socket_util.c index edbc67d12..e737fdf06 100644 --- a/src/socket_util.c +++ b/src/socket_util.c @@ -103,7 +103,7 @@ socket_bind_listen(int domain, int type, int protocol, int passcred = 1; #endif - fd = socket_cloexec(domain, type, protocol); + fd = socket_cloexec_nonblock(domain, type, protocol); if (fd < 0) { g_set_error(error, listen_quark(), errno, "Failed to create socket: %s", g_strerror(errno));