From 236e8efea96031c97c0ff3ab336cb6898870d392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?= <grubba@grubba.org> Date: Wed, 24 Sep 2014 18:21:46 +0200 Subject: [PATCH] Runtime: Added check and fallback for accept4(2). accept4(2) is a system call available on current Linux and many BSDs, that allows for setting the close-on-exec and non-blocking flags on the resulting fd. --- src/configure.in | 1 + src/fd_control.c | 16 ++++++++++++++++ src/fd_control.h | 30 ++++++++++++++++++++++++++++++ src/fdlib.h | 2 ++ 4 files changed, 49 insertions(+) diff --git a/src/configure.in b/src/configure.in index 03f08ac115..cb9c5fa8bd 100644 --- a/src/configure.in +++ b/src/configure.in @@ -4510,6 +4510,7 @@ fi AC_CHECK_FUNCS( \ _crypt \ poll \ + accept4 \ closefrom \ crypt \ fdwalk \ diff --git a/src/fd_control.c b/src/fd_control.c index 90ac7acee5..2e9295657f 100644 --- a/src/fd_control.c +++ b/src/fd_control.c @@ -224,6 +224,22 @@ PMOD_EXPORT int set_close_on_exec(int fd, int which) #endif /* !HAVE_BROKEN_F_SETFD */ } +#ifndef HAVE_ACCEPT4 +int accept4(int fd, struct sockaddr *addr, ACCEPT_SIZE_T *addrlen, int flags) +{ + int fd = fd_accept(fd, addr, addrlen); + if (!flags || (fd < 0)) return fd; + if (((flags & SOCK_NONBLOCK) && (set_nonblocking(fd, 1) < 0)) || + ((flags & SOCK_CLOEXEC) && (set_close_on_exec(fd, 1) < 0))) { + int e = errno; + fd_close(fd); + errno = e; + return -1; + } + return fd; +} +#endif /* !HAVE_ACCEPT4 */ + #endif /* !TESTING */ #ifdef TESTING diff --git a/src/fd_control.h b/src/fd_control.h index 11d27bf4a0..f1f0d35830 100644 --- a/src/fd_control.h +++ b/src/fd_control.h @@ -7,6 +7,33 @@ #ifndef FD_CONTROL_H #define FD_CONTROL_H +#ifndef HAVE_ACCEPT4 +/* NB: The default values are compatible with Linux, + * but should work on other OSs as well, since + * accept4(2) is emulated by us anyway. + */ +enum pike_sock_flags { +#ifndef SOCK_CLOEXEC +#if !defined(SOCK_NONBLOCK) || (SOCK_NONBLOCK != 0x80000) + SOCK_CLOEXEC = 0x80000, +#else + /* Unlikely, but... */ + SOCK_CLOEXEC = 0x40000, +#endif /* !SOCK_NONBLOCK || SOCK_NONBLOCK != 0x80000 */ +#define SOCK_CLOEXEC SOCK_CLOEXEC +#endif +#ifndef SOCK_NONBLOCK +#if (SOCK_CLOEXEC != 0x00800) + SOCK_NONBLOCK = 0x00800, +#else + /* Unlikely, but... */ + SOCK_NONBLOCK = 0x00400, +#endif +#define SOCK_NONBLOCK SOCK_NONBLOCK +#endif +}; +#endif /* !HAVE_ACCEPT4 */ + /* Prototypes begin here */ PMOD_EXPORT int set_nonblocking(int fd,int which); PMOD_EXPORT int query_nonblocking(int fd); @@ -16,6 +43,9 @@ PMOD_EXPORT int set_close_on_exec(int fd, int which); void do_close_on_exec(void); void cleanup_close_on_exec(void); #endif /* HAVE_BROKEN_F_SETFD */ +#ifndef HAVE_ACCEPT4 +int accept4(int fd, struct sockaddr *addr, ACCEPT_SIZE_T *addrlen, int flags) +#endif /* !HAVE_ACCEPT4 */ /* Prototypes end here */ #endif diff --git a/src/fdlib.h b/src/fdlib.h index 3b653652b1..d3775fffa5 100644 --- a/src/fdlib.h +++ b/src/fdlib.h @@ -90,6 +90,7 @@ typedef off_t PIKE_OFF_T; #define fd_socket(X,Y,Z) dmalloc_register_fd(debug_fd_socket((X),(Y),(Z))) #define fd_pipe(X) debug_fd_pipe( (X) DMALLOC_POS ) #define fd_accept(X,Y,Z) dmalloc_register_fd(debug_fd_accept((X),(Y),(Z))) +#define fd_accept4(X,Y,Z,F) dmalloc_register_fd(accept4((X),(Y),(Z),(F))) #define fd_bind(fd,X,Y) debug_fd_bind(dmalloc_touch_fd(fd), (X), (Y)) #define fd_getsockopt(fd,X,Y,Z,Q) debug_fd_getsockopt(dmalloc_touch_fd(fd), (X),(Y),(Z),(Q)) @@ -340,6 +341,7 @@ typedef off_t PIKE_OFF_T; #define fd_socket(X,Y,Z) dmalloc_register_fd(socket((X),(Y),(Z))) #define fd_pipe pipe /* FIXME */ #define fd_accept(X,Y,Z) dmalloc_register_fd(accept((X),(Y),(Z))) +#define fd_accept4(X,Y,Z,F) dmalloc_register_fd(accept4((X),(Y),(Z),(F))) #define fd_bind(fd,X,Y) bind(dmalloc_touch_fd(fd), (X), (Y)) #define fd_getsockopt(fd,X,Y,Z,Q) getsockopt(dmalloc_touch_fd(fd), (X),(Y),(Z),(Q)) -- GitLab