[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
personal/stbuehler/fix-fdevent
Glenn Strauss 2018-04-10 21:37:39 -04:00
parent 3efaff973f
commit 78024584bb
1 changed files with 21 additions and 5 deletions

View File

@ -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;
}