xref: /lighttpd1.4/src/fdevent.c (revision 49e9f0ac)
1 #include "first.h"
2 
3 #include "fdevent_impl.h"
4 #include "fdevent.h"
5 #include "base.h"
6 #include "buffer.h"
7 #include "log.h"
8 
9 #include <sys/types.h>
10 #include <sys/wait.h>
11 #include "sys-socket.h"
12 
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <time.h>
19 
20 #ifdef SOCK_CLOEXEC
21 static int use_sock_cloexec;
22 #endif
23 #ifdef SOCK_NONBLOCK
24 static int use_sock_nonblock;
25 #endif
26 
27 int fdevent_config(server *srv) {
28 	static const struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
29 	{
30 		/* - epoll is most reliable
31 		 * - select works everywhere
32 		 */
33 #ifdef FDEVENT_USE_LINUX_EPOLL
34 		{ FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
35 		{ FDEVENT_HANDLER_LINUX_SYSEPOLL, "epoll" },
36 #endif
37 #ifdef FDEVENT_USE_SOLARIS_PORT
38 		{ FDEVENT_HANDLER_SOLARIS_PORT,   "solaris-eventports" },
39 #endif
40 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
41 		{ FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
42 #endif
43 #ifdef FDEVENT_USE_FREEBSD_KQUEUE
44 		{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
45 		{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
46 #endif
47 #ifdef FDEVENT_USE_POLL
48 		{ FDEVENT_HANDLER_POLL,           "poll" },
49 #endif
50 #ifdef FDEVENT_USE_SELECT
51 		{ FDEVENT_HANDLER_SELECT,         "select" },
52 #endif
53 #ifdef FDEVENT_USE_LIBEV
54 		{ FDEVENT_HANDLER_LIBEV,          "libev" },
55 #endif
56 		{ FDEVENT_HANDLER_UNSET,          NULL }
57 	};
58 
59 	if (buffer_string_is_empty(srv->srvconf.event_handler)) {
60 		/* choose a good default
61 		 *
62 		 * the event_handler list is sorted by 'goodness'
63 		 * taking the first available should be the best solution
64 		 */
65 		srv->event_handler = event_handlers[0].et;
66 
67 		if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
68 			log_error_write(srv, __FILE__, __LINE__, "s",
69 					"sorry, there is no event handler for this system");
70 
71 			return -1;
72 		}
73 
74 		buffer_copy_string(srv->srvconf.event_handler, event_handlers[0].name);
75 	} else {
76 		/*
77 		 * User override
78 		 */
79 
80 		for (size_t i = 0; event_handlers[i].name; i++) {
81 			if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
82 				srv->event_handler = event_handlers[i].et;
83 				break;
84 			}
85 		}
86 
87 		if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
88 			log_error_write(srv, __FILE__, __LINE__, "sb",
89 					"the selected event-handler in unknown or not supported:",
90 					srv->srvconf.event_handler );
91 
92 			return -1;
93 		}
94 	}
95 
96       #ifdef FDEVENT_USE_SELECT
97 	if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
98 		/* select limits itself
99 		 *
100 		 * as it is a hard limit and will lead to a segfault we add some safety
101 		 * */
102 		srv->max_fds = FD_SETSIZE - 200;
103 	}
104 	else
105       #endif
106 	{
107 		srv->max_fds = 4096;
108 	}
109 
110 	return 0;
111 }
112 
113 const char * fdevent_show_event_handlers(void) {
114     return
115       "\nEvent Handlers:\n\n"
116 #ifdef FDEVENT_USE_SELECT
117       "\t+ select (generic)\n"
118 #else
119       "\t- select (generic)\n"
120 #endif
121 #ifdef FDEVENT_USE_POLL
122       "\t+ poll (Unix)\n"
123 #else
124       "\t- poll (Unix)\n"
125 #endif
126 #ifdef FDEVENT_USE_LINUX_EPOLL
127       "\t+ epoll (Linux)\n"
128 #else
129       "\t- epoll (Linux)\n"
130 #endif
131 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL
132       "\t+ /dev/poll (Solaris)\n"
133 #else
134       "\t- /dev/poll (Solaris)\n"
135 #endif
136 #ifdef FDEVENT_USE_SOLARIS_PORT
137       "\t+ eventports (Solaris)\n"
138 #else
139       "\t- eventports (Solaris)\n"
140 #endif
141 #ifdef FDEVENT_USE_FREEBSD_KQUEUE
142       "\t+ kqueue (FreeBSD)\n"
143 #else
144       "\t- kqueue (FreeBSD)\n"
145 #endif
146 #ifdef FDEVENT_USE_LIBEV
147       "\t+ libev (generic)\n"
148 #else
149       "\t- libev (generic)\n"
150 #endif
151       ;
152 }
153 
154 fdevents *fdevent_init(server *srv) {
155 	fdevents *ev;
156 	int type = srv->event_handler;
157 	size_t maxfds;
158 
159       #ifdef SOCK_CLOEXEC
160 	/* Test if SOCK_CLOEXEC is supported by kernel.
161 	 * Linux kernels < 2.6.27 might return EINVAL if SOCK_CLOEXEC used
162 	 * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=529929
163 	 * http://www.linksysinfo.org/index.php?threads/lighttpd-no-longer-starts-toastman-1-28-0510-7.73132/
164 	 * Test if SOCK_NONBLOCK is ignored by kernel on sockets.
165 	 * (reported on Android running a custom ROM)
166 	 * https://redmine.lighttpd.net/issues/2883
167 	 */
168        #ifdef SOCK_NONBLOCK
169 	int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
170        #else
171 	int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
172        #endif
173 	if (fd >= 0) {
174 		int flags = fcntl(fd, F_GETFL, 0);
175               #ifdef SOCK_NONBLOCK
176 		use_sock_nonblock = (-1 != flags && (flags & O_NONBLOCK));
177               #endif
178 		use_sock_cloexec = 1;
179 		close(fd);
180 	}
181       #endif
182 
183       #ifdef FDEVENT_USE_SELECT
184 	if (type == FDEVENT_HANDLER_SELECT) {
185 		if (srv->max_fds > (int)FD_SETSIZE - 200) {
186 			srv->max_fds = (int)FD_SETSIZE - 200;
187 		}
188 	}
189       #endif
190 	maxfds = srv->max_fds + 1; /*(+1 for event-handler fd)*/
191 
192 	ev = calloc(1, sizeof(*ev));
193 	force_assert(NULL != ev);
194 	ev->srv = srv;
195 	ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
196 	if (NULL == ev->fdarray) {
197 		log_error_write(srv, __FILE__, __LINE__, "SDS",
198 				"server.max-fds too large? (", maxfds-1, ")");
199 		free(ev);
200 		return NULL;
201 	}
202 	ev->maxfds = maxfds;
203 
204 	switch(type) {
205 	#ifdef FDEVENT_USE_POLL
206 	case FDEVENT_HANDLER_POLL:
207 		if (0 == fdevent_poll_init(ev)) return ev;
208 		break;
209 	#endif
210 	#ifdef FDEVENT_USE_SELECT
211 	case FDEVENT_HANDLER_SELECT:
212 		if (0 == fdevent_select_init(ev)) return ev;
213 		break;
214 	#endif
215 	#ifdef FDEVENT_USE_LINUX_EPOLL
216 	case FDEVENT_HANDLER_LINUX_SYSEPOLL:
217 		if (0 == fdevent_linux_sysepoll_init(ev)) return ev;
218 		break;
219 	#endif
220 	#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
221 	case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
222 		if (0 == fdevent_solaris_devpoll_init(ev)) return ev;
223 		break;
224 	#endif
225 	#ifdef FDEVENT_USE_SOLARIS_PORT
226 	case FDEVENT_HANDLER_SOLARIS_PORT:
227 		if (0 == fdevent_solaris_port_init(ev)) return ev;
228 		break;
229 	#endif
230 	#ifdef FDEVENT_USE_FREEBSD_KQUEUE
231 	case FDEVENT_HANDLER_FREEBSD_KQUEUE:
232 		if (0 == fdevent_freebsd_kqueue_init(ev)) return ev;
233 		break;
234 	#endif
235 	#ifdef FDEVENT_USE_LIBEV
236 	case FDEVENT_HANDLER_LIBEV:
237 		if (0 == fdevent_libev_init(ev)) return ev;
238 		break;
239 	#endif
240 	case FDEVENT_HANDLER_UNSET:
241 	default:
242 		break;
243 	}
244 
245 	free(ev->fdarray);
246 	free(ev);
247 
248 	log_error_write(srv, __FILE__, __LINE__, "sBS",
249 		"event-handler failed:", srv->srvconf.event_handler, "; try to set server.event-handler = \"poll\" or \"select\"");
250 	return NULL;
251 }
252 
253 void fdevent_free(fdevents *ev) {
254 	size_t i;
255 	if (!ev) return;
256 
257 	if (ev->free) ev->free(ev);
258 
259 	for (i = 0; i < ev->maxfds; i++) {
260 		/* (fdevent_sched_run() should already have been run,
261 		 *  but take reasonable precautions anyway) */
262 		if (ev->fdarray[i])
263 			free((fdnode *)((uintptr_t)ev->fdarray[i] & ~0x3));
264 	}
265 
266 	free(ev->fdarray);
267 	free(ev);
268 }
269 
270 int fdevent_reset(fdevents *ev) {
271 	int rc = (NULL != ev->reset) ? ev->reset(ev) : 0;
272 	if (-1 == rc) {
273 		log_error_write(ev->srv, __FILE__, __LINE__, "sBS",
274 			"event-handler failed:", ev->srv->srvconf.event_handler, "; try to set server.event-handler = \"poll\" or \"select\"");
275 	}
276 	return rc;
277 }
278 
279 static fdnode *fdnode_init(void) {
280 	return calloc(1, sizeof(fdnode));
281 }
282 
283 static void fdnode_free(fdnode *fdn) {
284 	free(fdn);
285 }
286 
287 fdnode * fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
288 	fdnode *fdn  = ev->fdarray[fd] = fdnode_init();
289 	force_assert(NULL != fdn);
290 	fdn->handler = handler;
291 	fdn->fd      = fd;
292 	fdn->ctx     = ctx;
293 	fdn->events  = 0;
294 	fdn->fde_ndx = -1;
295       #ifdef FDEVENT_USE_LIBEV
296 	fdn->handler_ctx = NULL;
297       #endif
298 	return fdn;
299 }
300 
301 void fdevent_unregister(fdevents *ev, int fd) {
302 	fdnode *fdn = ev->fdarray[fd];
303 	if ((uintptr_t)fdn & 0x3) return; /*(should not happen)*/
304 	ev->fdarray[fd] = NULL;
305 	fdnode_free(fdn);
306 }
307 
308 void fdevent_sched_close(fdevents *ev, int fd, int issock) {
309 	fdnode *fdn = ev->fdarray[fd];
310 	if ((uintptr_t)fdn & 0x3) return;
311 	ev->fdarray[fd] = (fdnode *)((uintptr_t)fdn | (issock ? 0x1 : 0x2));
312 	fdn->handler = (fdevent_handler)NULL;
313 	fdn->ctx = ev->pendclose;
314 	ev->pendclose = fdn;
315 }
316 
317 static void fdevent_sched_run(fdevents *ev) {
318 	server *srv = ev->srv;
319 	for (fdnode *fdn = ev->pendclose; fdn; ) {
320 		int fd, rc;
321 		fdnode *fdn_tmp;
322 	      #ifdef _WIN32
323 		rc = (uintptr_t)fdn & 0x3;
324 	      #endif
325 		fdn = (fdnode *)((uintptr_t)fdn & ~0x3);
326 		fd = fdn->fd;
327 	      #ifdef _WIN32
328 		if (rc == 0x1) {
329 			rc = closesocket(fd);
330 		}
331 		else if (rc == 0x2) {
332 			rc = close(fd);
333 		}
334 	      #else
335 		rc = close(fd);
336 	      #endif
337 
338 		if (0 != rc) {
339 			log_error_write(srv, __FILE__, __LINE__, "sds", "close failed ", fd, strerror(errno));
340 		}
341 		else {
342 			--srv->cur_fds;
343 		}
344 
345 		fdn_tmp = fdn;
346 		fdn = (fdnode *)fdn->ctx; /* next */
347 		/*(fdevent_unregister)*/
348 		fdnode_free(fdn_tmp);
349 		ev->fdarray[fd] = NULL;
350 	}
351 	ev->pendclose = NULL;
352 }
353 
354 static void fdevent_fdnode_event_unsetter(fdevents *ev, fdnode *fdn) {
355     if (-1 == fdn->fde_ndx) return;
356     if (0 == ev->event_del(ev, fdn)) {
357         fdn->fde_ndx = -1;
358         fdn->events = 0;
359     }
360     else {
361         log_error_write(ev->srv, __FILE__, __LINE__, "SS",
362                         "fdevent event_del failed: ", strerror(errno));
363     }
364 }
365 
366 static void fdevent_fdnode_event_setter(fdevents *ev, fdnode *fdn, int events) {
367     /*(Note: skips registering with kernel if initial events is 0,
368      * so caller should pass non-zero events for initial registration.
369      * If never registered due to never being called with non-zero events,
370      * then FDEVENT_HUP or FDEVENT_ERR will never be returned.) */
371     if (fdn->events == events) return;/*(no change; nothing to do)*/
372 
373     if (0 == ev->event_set(ev, fdn, events))
374         fdn->events = events;
375     else
376         log_error_write(ev->srv, __FILE__, __LINE__, "SS",
377                         "fdevent event_set failed: ", strerror(errno));
378 }
379 
380 void fdevent_fdnode_event_del(fdevents *ev, fdnode *fdn) {
381     if (NULL != fdn) fdevent_fdnode_event_unsetter(ev, fdn);
382 }
383 
384 void fdevent_fdnode_event_set(fdevents *ev, fdnode *fdn, int events) {
385     if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, events);
386 }
387 
388 void fdevent_fdnode_event_add(fdevents *ev, fdnode *fdn, int event) {
389     if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, (fdn->events|event));
390 }
391 
392 void fdevent_fdnode_event_clr(fdevents *ev, fdnode *fdn, int event) {
393     if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, (fdn->events&~event));
394 }
395 
396 int fdevent_poll(fdevents *ev, int timeout_ms) {
397     int n = ev->poll(ev, timeout_ms);
398     if (n >= 0)
399         fdevent_sched_run(ev);
400     else if (errno != EINTR)
401         log_error_write(ev->srv, __FILE__, __LINE__, "SS",
402                         "fdevent_poll failed: ", strerror(errno));
403     return n;
404 }
405 
406 void fdevent_setfd_cloexec(int fd) {
407 #ifdef FD_CLOEXEC
408 	if (fd < 0) return;
409 	force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
410 #else
411 	UNUSED(fd);
412 #endif
413 }
414 
415 void fdevent_clrfd_cloexec(int fd) {
416 #ifdef FD_CLOEXEC
417 	if (fd >= 0) force_assert(-1 != fcntl(fd, F_SETFD, 0));
418 #else
419 	UNUSED(fd);
420 #endif
421 }
422 
423 int fdevent_fcntl_set_nb(fdevents *ev, int fd) {
424 	UNUSED(ev);
425 #ifdef O_NONBLOCK
426 	return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
427 #else
428 	UNUSED(fd);
429 	return 0;
430 #endif
431 }
432 
433 int fdevent_fcntl_set_nb_cloexec(fdevents *ev, int fd) {
434 	fdevent_setfd_cloexec(fd);
435 	return fdevent_fcntl_set_nb(ev, fd);
436 }
437 
438 int fdevent_fcntl_set_nb_cloexec_sock(fdevents *ev, int fd) {
439 #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
440 	if (use_sock_cloexec && use_sock_nonblock)
441 		return 0;
442 #endif
443 	return fdevent_fcntl_set_nb_cloexec(ev, fd);
444 }
445 
446 int fdevent_socket_cloexec(int domain, int type, int protocol) {
447 	int fd;
448 #ifdef SOCK_CLOEXEC
449 	if (use_sock_cloexec)
450 		return socket(domain, type | SOCK_CLOEXEC, protocol);
451 #endif
452 	if (-1 != (fd = socket(domain, type, protocol))) {
453 #ifdef FD_CLOEXEC
454 		force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
455 #endif
456 	}
457 	return fd;
458 }
459 
460 int fdevent_socket_nb_cloexec(int domain, int type, int protocol) {
461 	int fd;
462 #ifdef SOCK_CLOEXEC
463        #ifdef SOCK_NONBLOCK
464 	if (use_sock_cloexec && use_sock_nonblock)
465 		return socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
466        #else
467 	if (use_sock_cloexec) {
468 		fd = socket(domain, type | SOCK_CLOEXEC, protocol);
469 	      #ifdef O_NONBLOCK
470 		if (-1 != fd) force_assert(-1 != fcntl(fd,F_SETFL,O_NONBLOCK|O_RDWR));
471 	      #endif
472 		return fd;
473 	}
474        #endif
475 #endif
476 	if (-1 != (fd = socket(domain, type, protocol))) {
477 #ifdef FD_CLOEXEC
478 		force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
479 #endif
480 #ifdef O_NONBLOCK
481 		force_assert(-1 != fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR));
482 #endif
483 	}
484 	return fd;
485 }
486 
487 #ifndef O_BINARY
488 #define O_BINARY 0
489 #endif
490 #ifndef O_LARGEFILE
491 #define O_LARGEFILE 0
492 #endif
493 #ifndef O_NOCTTY
494 #define O_NOCTTY 0
495 #endif
496 #ifndef O_NOFOLLOW
497 #define O_NOFOLLOW 0
498 #endif
499 
500 /*(O_NOFOLLOW is not handled here)*/
501 /*(Note: O_NOFOLLOW affects only the final path segment, the target file,
502  * not any intermediate symlinks along the path)*/
503 
504 /* O_CLOEXEC handled further below, if defined) */
505 #ifdef O_NONBLOCK
506 #define FDEVENT_O_FLAGS \
507         (O_BINARY | O_LARGEFILE | O_NOCTTY | O_NONBLOCK)
508 #else
509 #define FDEVENT_O_FLAGS \
510         (O_BINARY | O_LARGEFILE | O_NOCTTY )
511 #endif
512 
513 int fdevent_open_cloexec(const char *pathname, int symlinks, int flags, mode_t mode) {
514 	if (!symlinks) flags |= O_NOFOLLOW;
515 #ifdef O_CLOEXEC
516 	return open(pathname, flags | O_CLOEXEC | FDEVENT_O_FLAGS, mode);
517 #else
518 	int fd = open(pathname, flags | FDEVENT_O_FLAGS, mode);
519 #ifdef FD_CLOEXEC
520 	if (fd != -1)
521 		force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
522 #endif
523 	return fd;
524 #endif
525 }
526 
527 
528 int fdevent_open_devnull(void) {
529   #if defined(_WIN32)
530     return fdevent_open_cloexec("nul", 0, O_RDWR, 0);
531   #else
532     return fdevent_open_cloexec("/dev/null", 0, O_RDWR, 0);
533   #endif
534 }
535 
536 
537 int fdevent_open_dirname(char *path, int symlinks) {
538     /*(handle special cases of no dirname or dirname is root directory)*/
539     char * const c = strrchr(path, '/');
540     const char * const dname = (NULL != c ? c == path ? "/" : path : ".");
541     int dfd;
542     int flags = O_RDONLY;
543   #ifdef O_DIRECTORY
544     flags |= O_DIRECTORY;
545   #endif
546     if (NULL != c) *c = '\0';
547     dfd = fdevent_open_cloexec(dname, symlinks, flags, 0);
548     if (NULL != c) *c = '/';
549     return dfd;
550 }
551 
552 
553 int fdevent_mkstemp_append(char *path) {
554   #ifdef __COVERITY__
555     /* POSIX-2008 requires mkstemp create file with 0600 perms */
556     umask(0600);
557   #endif
558     /* coverity[secure_temp : FALSE] */
559     const int fd = mkstemp(path);
560     if (fd < 0) return fd;
561 
562     if (0 != fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_APPEND)) {
563         /* (should not happen; fd is regular file) */
564         int errnum = errno;
565         close(fd);
566         errno = errnum;
567         return -1;
568     }
569 
570     fdevent_setfd_cloexec(fd);
571     return fd;
572 }
573 
574 
575 int fdevent_accept_listenfd(int listenfd, struct sockaddr *addr, size_t *addrlen) {
576 	int fd;
577 	socklen_t len = (socklen_t) *addrlen;
578 
579       #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
580        #if defined(__NetBSD__)
581 	const int sock_cloexec = 1;
582 	fd = paccept(listenfd, addr, &len, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK);
583        #else
584 	int sock_cloexec = use_sock_cloexec;
585 	if (sock_cloexec) {
586 		fd = accept4(listenfd, addr, &len, SOCK_CLOEXEC | SOCK_NONBLOCK);
587 		if (fd >= 0) {
588 			if (!use_sock_nonblock) {
589 				if (0 != fdevent_fcntl_set_nb(NULL, fd)) {
590 					close(fd);
591 					fd = -1;
592 				}
593 			}
594 		} else if (errno == ENOSYS || errno == ENOTSUP) {
595 			fd = accept(listenfd, addr, &len);
596 			sock_cloexec = 0;
597 		}
598 	}
599 	else {
600 		fd = accept(listenfd, addr, &len);
601 	}
602        #endif
603       #else
604 	const int sock_cloexec = 0;
605 	fd = accept(listenfd, addr, &len);
606       #endif
607 
608 	if (fd >= 0) {
609 		*addrlen = (size_t)len;
610 		if (!sock_cloexec && 0 != fdevent_fcntl_set_nb_cloexec(NULL, fd)) {
611 			close(fd);
612 			fd = -1;
613 		}
614 	}
615 	return fd;
616 }
617 
618 
619 #ifdef __APPLE__
620 #include <crt_externs.h>
621 #define environ (* _NSGetEnviron())
622 #else
623 extern char **environ;
624 #endif
625 char ** fdevent_environ (void) { return environ; }
626 
627 
628 #ifdef FD_CLOEXEC
629 static int fdevent_dup2_close_clrfd_cloexec(int oldfd, int newfd) {
630     if (oldfd >= 0) {
631         if (oldfd != newfd) {
632             force_assert(oldfd > STDERR_FILENO);
633             if (newfd != dup2(oldfd, newfd)) return -1;
634         }
635         else {
636             fdevent_clrfd_cloexec(newfd);
637         }
638     }
639     return newfd;
640 }
641 #else
642 static int fdevent_dup2_close_clrfd_cloexec(int oldfd, int newfd, int reuse) {
643     if (oldfd >= 0) {
644         if (oldfd != newfd) {
645             force_assert(oldfd > STDERR_FILENO);
646             if (newfd != dup2(oldfd, newfd)) return -1;
647             if (!reuse) close(oldfd);
648         }
649     }
650     return newfd;
651 }
652 #endif
653 
654 
655 int fdevent_set_stdin_stdout_stderr(int fdin, int fdout, int fderr) {
656   #ifdef FD_CLOEXEC
657     if (STDIN_FILENO != fdevent_dup2_close_clrfd_cloexec(fdin, STDIN_FILENO))
658         return -1;
659     if (STDOUT_FILENO != fdevent_dup2_close_clrfd_cloexec(fdout, STDOUT_FILENO))
660         return -1;
661     if (STDERR_FILENO != fdevent_dup2_close_clrfd_cloexec(fderr, STDERR_FILENO))
662         return -1;
663   #else
664     if (STDIN_FILENO != fdevent_dup2_close_clrfd_cloexec(fdin, STDIN_FILENO,
665                                                          fdin == fdout
666                                                          || fdin == fderr))
667         return -1;
668     if (STDOUT_FILENO != fdevent_dup2_close_clrfd_cloexec(fdout, STDOUT_FILENO,
669                                                           fdout == fderr))
670         return -1;
671     if (STDERR_FILENO != fdevent_dup2_close_clrfd_cloexec(fderr, STDERR_FILENO,
672                                                           0))
673         return -1;
674   #endif
675 
676     return 0;
677 }
678 
679 
680 #include <stdio.h>      /* perror() */
681 #include <signal.h>     /* signal() */
682 
683 pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd) {
684  #ifdef HAVE_FORK
685 
686     pid_t pid = fork();
687     if (0 != pid) return pid; /* parent (pid > 0) or fork() error (-1 == pid) */
688 
689     /* child (0 == pid) */
690 
691     if (-1 != dfd) {
692         if (0 != fchdir(dfd))
693             _exit(errno);
694         close(dfd);
695     }
696 
697     if (0 != fdevent_set_stdin_stdout_stderr(fdin, fdout, fderr)) _exit(errno);
698   #ifdef FD_CLOEXEC
699     /*(might not be sufficient for open fds, but modern OS have FD_CLOEXEC)*/
700     for (int i = 3; i < 256; ++i) close(i);
701   #endif
702 
703     /* reset_signals which may have been ignored (SIG_IGN) */
704   #ifdef SIGTTOU
705     signal(SIGTTOU, SIG_DFL);
706   #endif
707   #ifdef SIGTTIN
708     signal(SIGTTIN, SIG_DFL);
709   #endif
710   #ifdef SIGTSTP
711     signal(SIGTSTP, SIG_DFL);
712   #endif
713     signal(SIGPIPE, SIG_DFL);
714 
715     execve(name, argv, envp ? envp : environ);
716 
717     if (0 == memcmp(argv[0], "/bin/sh", sizeof("/bin/sh")-1)
718         && argv[1] && 0 == memcmp(argv[1], "-c", sizeof("-c")-1))
719         perror(argv[2]);
720     else
721         perror(argv[0]);
722     _exit(errno);
723 
724  #else
725 
726     UNUSED(name);
727     UNUSED(argv);
728     UNUSED(envp);
729     UNUSED(fdin);
730     UNUSED(fdout);
731     UNUSED(fderr);
732     UNUSED(dfd);
733     return (pid_t)-1;
734 
735  #endif
736 }
737 
738 
739 typedef struct fdevent_cmd_pipe {
740     pid_t pid;
741     int fds[2];
742     const char *cmd;
743     time_t start;
744 } fdevent_cmd_pipe;
745 
746 typedef struct fdevent_cmd_pipes {
747     fdevent_cmd_pipe *ptr;
748     size_t used;
749     size_t size;
750 } fdevent_cmd_pipes;
751 
752 static fdevent_cmd_pipes cmd_pipes;
753 
754 
755 static pid_t fdevent_open_logger_pipe_spawn(const char *logger, int rfd) {
756     char *args[4];
757     int devnull = fdevent_open_devnull();
758     pid_t pid;
759 
760     if (-1 == devnull) {
761         return -1;
762     }
763 
764     *(const char **)&args[0] = "/bin/sh";
765     *(const char **)&args[1] = "-c";
766     *(const char **)&args[2] = logger;
767     args[3] = NULL;
768 
769     pid = fdevent_fork_execve(args[0], args, NULL, rfd, devnull, devnull, -1);
770 
771     if (pid > 0) {
772         close(devnull);
773     }
774     else {
775         int errnum = errno;
776         close(devnull);
777         errno = errnum;
778     }
779     return pid;
780 }
781 
782 
783 static void fdevent_restart_logger_pipe(fdevent_cmd_pipe *fcp, time_t ts) {
784     if (fcp->pid > 0) return;  /* assert */
785     if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
786         /* restart child process using existing pipe fds */
787         fcp->start = ts;
788         fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd, fcp->fds[0]);
789     }
790 }
791 
792 
793 void fdevent_restart_logger_pipes(time_t ts) {
794     for (size_t i = 0; i < cmd_pipes.used; ++i) {
795         fdevent_cmd_pipe * const fcp = cmd_pipes.ptr+i;
796         if (fcp->pid > 0) continue;
797         fdevent_restart_logger_pipe(fcp, ts);
798     }
799 }
800 
801 
802 int fdevent_waitpid_logger_pipe_pid(pid_t pid, time_t ts) {
803     for (size_t i = 0; i < cmd_pipes.used; ++i) {
804         fdevent_cmd_pipe * const fcp = cmd_pipes.ptr+i;
805         if (pid != fcp->pid) continue;
806         fcp->pid = -1;
807         fdevent_restart_logger_pipe(fcp, ts);
808         return 1;
809     }
810     return 0;
811 }
812 
813 
814 void fdevent_clr_logger_pipe_pids(void) {
815     for (size_t i = 0; i < cmd_pipes.used; ++i) {
816         fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
817         fcp->pid = -1;
818     }
819 }
820 
821 
822 int fdevent_reaped_logger_pipe(pid_t pid) {
823     for (size_t i = 0; i < cmd_pipes.used; ++i) {
824         fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
825         if (fcp->pid == pid) {
826             time_t ts = time(NULL);
827             if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
828                 fcp->start = ts;
829                 fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd,fcp->fds[0]);
830                 return 1;
831             }
832             else {
833                 fcp->pid = -1;
834                 return -1;
835             }
836         }
837     }
838     return 0;
839 }
840 
841 
842 void fdevent_close_logger_pipes(void) {
843     for (size_t i = 0; i < cmd_pipes.used; ++i) {
844         fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
845         close(fcp->fds[0]);
846         if (fcp->fds[1] != STDERR_FILENO) close(fcp->fds[1]);
847     }
848     free(cmd_pipes.ptr);
849     cmd_pipes.ptr = NULL;
850     cmd_pipes.used = 0;
851     cmd_pipes.size = 0;
852 }
853 
854 
855 void fdevent_breakagelog_logger_pipe(int fd) {
856     for (size_t i = 0; i < cmd_pipes.used; ++i) {
857         fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
858         if (fcp->fds[1] != fd) continue;
859         fcp->fds[1] = STDERR_FILENO;
860         break;
861     }
862 }
863 
864 
865 static void fdevent_init_logger_pipe(const char *cmd, int fds[2], pid_t pid) {
866     fdevent_cmd_pipe *fcp;
867     if (cmd_pipes.used == cmd_pipes.size) {
868         cmd_pipes.size += 4;
869         cmd_pipes.ptr =
870           realloc(cmd_pipes.ptr, cmd_pipes.size * sizeof(fdevent_cmd_pipe));
871         force_assert(cmd_pipes.ptr);
872     }
873     fcp = cmd_pipes.ptr + cmd_pipes.used++;
874     fcp->cmd = cmd; /* note: cmd must persist in memory (or else copy here) */
875     fcp->fds[0] = fds[0];
876     fcp->fds[1] = fds[1];
877     fcp->pid = pid;
878     fcp->start = time(NULL);
879 }
880 
881 
882 static int fdevent_open_logger_pipe(const char *logger) {
883     int fds[2];
884     pid_t pid;
885     if (pipe(fds)) {
886         return -1;
887     }
888     fdevent_setfd_cloexec(fds[0]);
889     fdevent_setfd_cloexec(fds[1]);
890     /*(nonblocking write() from lighttpd)*/
891     if (0 != fdevent_fcntl_set_nb(NULL, fds[1])) { /*(ignore)*/ }
892 
893     pid = fdevent_open_logger_pipe_spawn(logger, fds[0]);
894 
895     if (pid > 0) {
896         fdevent_init_logger_pipe(logger, fds, pid);
897         return fds[1];
898     }
899     else {
900         int errnum = errno;
901         close(fds[0]);
902         close(fds[1]);
903         errno = errnum;
904         return -1;
905     }
906 }
907 
908 
909 int fdevent_open_logger(const char *logger) {
910     if (logger[0] != '|') { /*(permit symlinks)*/
911         int flags = O_APPEND | O_WRONLY | O_CREAT;
912         return fdevent_open_cloexec(logger, 1, flags, 0644);
913     }
914     else {
915         return fdevent_open_logger_pipe(logger+1); /*(skip the '|')*/
916     }
917 }
918 
919 int fdevent_cycle_logger(const char *logger, int *curfd) {
920     if (logger[0] != '|') {
921         int fd = fdevent_open_logger(logger);
922         if (-1 == fd) return -1; /*(error; leave *curfd as-is)*/
923         if (-1 != *curfd) close(*curfd);
924         *curfd = fd;
925     }
926     return *curfd;
927 }
928 
929 
930 #ifndef MSG_DONTWAIT
931 #define MSG_DONTWAIT 0
932 #endif
933 #ifndef MSG_NOSIGNAL
934 #define MSG_NOSIGNAL 0
935 #endif
936 
937 
938 ssize_t fdevent_socket_read_discard (int fd, char *buf, size_t sz, int family, int so_type) {
939   #if defined(MSG_TRUNC) && defined(__linux__)
940     if ((family == AF_INET || family == AF_INET6) && so_type == SOCK_STREAM) {
941         ssize_t len = recv(fd, buf, sz, MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL);
942         if (len >= 0 || errno != EINVAL) return len;
943     }
944   #else
945     UNUSED(family);
946     UNUSED(so_type);
947   #endif
948     return read(fd, buf, sz);
949 }
950 
951 
952 #include <sys/ioctl.h>
953 #ifdef HAVE_SYS_FILIO_H
954 #include <sys/filio.h>  /* FIONREAD (for illumos (OpenIndiana)) */
955 #endif
956 #ifdef _WIN32
957 #include <winsock2.h>
958 #endif
959 int fdevent_ioctl_fionread (int fd, int fdfmt, int *toread) {
960   #ifdef _WIN32
961     if (fdfmt != S_IFSOCK) { errno = ENOTSOCK; return -1; }
962     return ioctlsocket(fd, FIONREAD, toread);
963   #else
964    #ifdef __CYGWIN__
965     /*(cygwin supports FIONREAD on pipes, not sockets)*/
966     if (fdfmt != S_IFIFO) { errno = EOPNOTSUPP; return -1; }
967    #else
968     UNUSED(fdfmt);
969    #endif
970     return ioctl(fd, FIONREAD, toread);
971   #endif
972 }
973 
974 
975 int fdevent_connect_status(int fd) {
976     /* try to finish the connect() */
977     /*(should be called after connect() only when fd is writable (POLLOUT))*/
978     int opt;
979     socklen_t len = sizeof(opt);
980     return (0 == getsockopt(fd,SOL_SOCKET,SO_ERROR,&opt,&len)) ? opt : errno;
981 }
982 
983 
984 #include <netinet/tcp.h>
985 #if (defined(__APPLE__) && defined(__MACH__)) \
986   || defined(__FreeBSD__) || defined(__NetBSD__) \
987   || defined(__OpenBSD__) || defined(__DragonFly__)
988 #include <netinet/tcp_fsm.h>
989 #endif
990 
991 /* fd must be TCP socket (AF_INET, AF_INET6), end-of-stream recv() 0 bytes */
992 int fdevent_is_tcp_half_closed(int fd) {
993   #ifdef TCP_CONNECTION_INFO     /* Darwin */
994     struct tcp_connection_info tcpi;
995     socklen_t tlen = sizeof(tcpi);
996     return (0 == getsockopt(fd, IPPROTO_TCP, TCP_CONNECTION_INFO, &tcpi, &tlen)
997             && tcpi.tcpi_state == TCPS_CLOSE_WAIT);
998   #elif defined(TCP_INFO) && defined(TCPS_CLOSE_WAIT)
999     /* FreeBSD, NetBSD (not present in OpenBSD or DragonFlyBSD) */
1000     struct tcp_info tcpi;
1001     socklen_t tlen = sizeof(tcpi);
1002     return (0 == getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tlen)
1003             && tcpi.tcpi_state == TCPS_CLOSE_WAIT);
1004   #elif defined(TCP_INFO) && defined(__linux__)
1005     /* Linux (TCP_CLOSE_WAIT is enum, so can not #ifdef TCP_CLOSE_WAIT) */
1006     struct tcp_info tcpi;
1007     socklen_t tlen = sizeof(tcpi);/*SOL_TCP == IPPROTO_TCP*/
1008     return (0 == getsockopt(fd,     SOL_TCP, TCP_INFO, &tcpi, &tlen)
1009             && tcpi.tcpi_state == TCP_CLOSE_WAIT);
1010   #else
1011     UNUSED(fd);
1012     /*(0 != getpeername() error might indicate TCP RST, but success
1013      * would not differentiate between half-close and full-close)*/
1014     return 0; /* false (not half-closed) or TCP state unknown */
1015   #endif
1016 }
1017 
1018 
1019 int fdevent_set_tcp_nodelay (const int fd, const int opt)
1020 {
1021     return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
1022 }
1023 
1024 
1025 int fdevent_set_so_reuseaddr (const int fd, const int opt)
1026 {
1027     return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
1028 }
1029