From 78024584bb9fc549a654bdd72a81d1d6fac9b64e Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Tue, 10 Apr 2018 21:37:39 -0400 Subject: [PATCH] [core] check if SOCK_NONBLOCK is ignored (fixes #2883) x-ref: "fdevent_init should check if SOCK_NONBLOCK works" https://redmine.lighttpd.net/issues/2883 --- src/fdevent.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/fdevent.c b/src/fdevent.c index b27f2efb..e1c2459d 100644 --- a/src/fdevent.c +++ b/src/fdevent.c @@ -20,6 +20,9 @@ #ifdef SOCK_CLOEXEC static int use_sock_cloexec; #endif +#ifdef SOCK_NONBLOCK +static int use_sock_nonblock; +#endif int fdevent_config(server *srv) { static const struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = @@ -157,9 +160,15 @@ fdevents *fdevent_init(server *srv) { /* Test if SOCK_CLOEXEC is supported by kernel. * Linux kernels < 2.6.27 might return EINVAL if SOCK_CLOEXEC used * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=529929 - * http://www.linksysinfo.org/index.php?threads/lighttpd-no-longer-starts-toastman-1-28-0510-7.73132/ */ - int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); + * http://www.linksysinfo.org/index.php?threads/lighttpd-no-longer-starts-toastman-1-28-0510-7.73132/ + * Test if SOCK_NONBLOCK is ignored by kernel on sockets. + * (reported on Android running a custom ROM) + * https://redmine.lighttpd.net/issues/2883 + */ + int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (fd >= 0) { + int flags = fcntl(fd, F_GETFL, 0); + use_sock_nonblock = (-1 != flags && (flags & O_NONBLOCK)); use_sock_cloexec = 1; close(fd); } @@ -477,7 +486,7 @@ int fdevent_fcntl_set_nb_cloexec(fdevents *ev, int fd) { int fdevent_fcntl_set_nb_cloexec_sock(fdevents *ev, int fd) { #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) - if (use_sock_cloexec) + if (use_sock_cloexec && use_sock_nonblock) return 0; #endif return fdevent_fcntl_set_nb_cloexec(ev, fd); @@ -500,7 +509,7 @@ int fdevent_socket_cloexec(int domain, int type, int protocol) { int fdevent_socket_nb_cloexec(int domain, int type, int protocol) { int fd; #ifdef SOCK_CLOEXEC - if (use_sock_cloexec) + if (use_sock_cloexec && use_sock_nonblock) return socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol); #endif if (-1 != (fd = socket(domain, type, protocol))) { @@ -569,7 +578,14 @@ int fdevent_accept_listenfd(int listenfd, struct sockaddr *addr, size_t *addrlen int sock_cloexec = use_sock_cloexec; if (sock_cloexec) { fd = accept4(listenfd, addr, &len, SOCK_CLOEXEC | SOCK_NONBLOCK); - if (fd < 0 && (errno == ENOSYS || errno == ENOTSUP)) { + if (fd >= 0) { + if (!use_sock_nonblock) { + if (0 != fdevent_fcntl_set_nb(NULL, fd)) { + close(fd); + fd = -1; + } + } + } else if (errno == ENOSYS || errno == ENOTSUP) { fd = accept(listenfd, addr, &len); sock_cloexec = 0; }