fd_util: added O_NONBLOCK functions

Changed the wrappers for pipe(), socket(), accept().  On WIN32, this
does not work for pipe().
This commit is contained in:
Max Kellermann 2009-11-08 22:11:35 +01:00
parent b043ade456
commit f66edccffd
6 changed files with 55 additions and 26 deletions

View File

@ -18,7 +18,6 @@
*/ */
#include "event_pipe.h" #include "event_pipe.h"
#include "utils.h"
#include "fd_util.h" #include "fd_util.h"
#include <stdbool.h> #include <stdbool.h>
@ -85,13 +84,9 @@ void event_pipe_init(void)
GIOChannel *channel; GIOChannel *channel;
int ret; int ret;
ret = pipe_cloexec(event_pipe); ret = pipe_cloexec_nonblock(event_pipe);
if (ret < 0) if (ret < 0)
g_error("Couldn't open pipe: %s", strerror(errno)); 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]); channel = g_io_channel_unix_new(event_pipe[0]);
event_pipe_source_id = g_io_add_watch(channel, G_IO_IN, event_pipe_source_id = g_io_add_watch(channel, G_IO_IN,

View File

@ -68,6 +68,29 @@ fd_set_cloexec(int fd, bool enable)
#endif #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 int
open_cloexec(const char *path_fs, int flags) open_cloexec(const char *path_fs, int flags)
{ {
@ -108,7 +131,7 @@ creat_cloexec(const char *path_fs, int mode)
} }
int int
pipe_cloexec(int fd[2]) pipe_cloexec_nonblock(int fd[2])
{ {
#ifdef WIN32 #ifdef WIN32
return _pipe(event_pipe, 512, _O_BINARY); return _pipe(event_pipe, 512, _O_BINARY);
@ -116,7 +139,7 @@ pipe_cloexec(int fd[2])
int ret; int ret;
#ifdef HAVE_PIPE2 #ifdef HAVE_PIPE2
ret = pipe2(fd, O_CLOEXEC); ret = pipe2(fd, O_CLOEXEC|O_NONBLOCK);
if (ret >= 0 || errno != ENOSYS) if (ret >= 0 || errno != ENOSYS)
return ret; return ret;
#endif #endif
@ -125,6 +148,11 @@ pipe_cloexec(int fd[2])
if (ret >= 0) { if (ret >= 0) {
fd_set_cloexec(fd[0], true); fd_set_cloexec(fd[0], true);
fd_set_cloexec(fd[1], true); fd_set_cloexec(fd[1], true);
#ifndef WIN32
fd_set_nonblock(fd[0]);
fd_set_nonblock(fd[1]);
#endif
} }
return ret; return ret;
@ -132,12 +160,12 @@ pipe_cloexec(int fd[2])
} }
int int
socket_cloexec(int domain, int type, int protocol) socket_cloexec_nonblock(int domain, int type, int protocol)
{ {
int fd; int fd;
#ifdef SOCK_CLOEXEC #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
fd = socket(domain, type | SOCK_CLOEXEC, protocol); fd = socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
if (fd >= 0 || errno != EINVAL) if (fd >= 0 || errno != EINVAL)
return fd; return fd;
#endif #endif
@ -150,13 +178,15 @@ socket_cloexec(int domain, int type, int protocol)
} }
int 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; int ret;
socklen_t address_length = *address_length_r; socklen_t address_length = *address_length_r;
#ifdef HAVE_ACCEPT4 #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 || errno != ENOSYS) {
if (ret >= 0) if (ret >= 0)
*address_length_r = address_length; *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); ret = accept(fd, address, &address_length);
if (ret >= 0) { if (ret >= 0) {
fd_set_cloexec(ret, true); fd_set_cloexec(ret, true);
fd_set_nonblock(ret);
*address_length_r = address_length; *address_length_r = address_length;
} }

View File

@ -49,23 +49,27 @@ creat_cloexec(const char *path_fs, int mode);
/** /**
* Wrapper for pipe(), which sets the CLOEXEC flag (atomically if * Wrapper for pipe(), which sets the CLOEXEC flag (atomically if
* supported by the OS). * supported by the OS).
*
* On systems that supports it (everybody except for Windows), it also
* sets the NONBLOCK flag.
*/ */
int int
pipe_cloexec(int fd[2]); pipe_cloexec_nonblock(int fd[2]);
/** /**
* Wrapper for socket(), which sets the CLOEXEC flag (atomically if * Wrapper for socket(), which sets the CLOEXEC and the NONBLOCK flag
* supported by the OS). * (atomically if supported by the OS).
*/ */
int 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 * Wrapper for accept(), which sets the CLOEXEC and the NONBLOCK flags
* supported by the OS). * (atomically if supported by the OS).
*/ */
int 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 * Wrapper for inotify_init(), which sets the CLOEXEC flag (atomically

View File

@ -21,7 +21,6 @@
#include "socket_util.h" #include "socket_util.h"
#include "client.h" #include "client.h"
#include "conf.h" #include "conf.h"
#include "utils.h"
#include "fd_util.h" #include "fd_util.h"
#include "config.h" #include "config.h"
@ -429,10 +428,9 @@ listen_in_event(G_GNUC_UNUSED GIOChannel *source,
struct sockaddr_storage sa; struct sockaddr_storage sa;
size_t sa_length = sizeof(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) { if (fd >= 0) {
set_nonblocking(fd);
client_new(fd, (struct sockaddr*)&sa, sa_length, client_new(fd, (struct sockaddr*)&sa, sa_length,
get_remote_uid(fd)); get_remote_uid(fd));
} else if (fd < 0 && errno != EINTR) { } else if (fd < 0 && errno != EINTR) {

View File

@ -195,7 +195,8 @@ httpd_listen_in_event(G_GNUC_UNUSED GIOChannel *source,
/* the listener socket has become readable - a client has /* the listener socket has become readable - a client has
connected */ 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) { if (fd >= 0) {
/* can we allow additional client */ /* can we allow additional client */
if (httpd->open && if (httpd->open &&

View File

@ -103,7 +103,7 @@ socket_bind_listen(int domain, int type, int protocol,
int passcred = 1; int passcred = 1;
#endif #endif
fd = socket_cloexec(domain, type, protocol); fd = socket_cloexec_nonblock(domain, type, protocol);
if (fd < 0) { if (fd < 0) {
g_set_error(error, listen_quark(), errno, g_set_error(error, listen_quark(), errno,
"Failed to create socket: %s", g_strerror(errno)); "Failed to create socket: %s", g_strerror(errno));