xref: /lighttpd1.4/src/network.c (revision 463c60ce)
1 #include "first.h"
2 
3 #include "network.h"
4 #include "base.h"
5 #include "fdevent.h"
6 #include "log.h"
7 #include "connections.h"
8 #include "plugin.h"
9 #include "sock_addr.h"
10 
11 #include "network_write.h"
12 #include "sys-socket.h"
13 
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include "sys-time.h"
17 
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <stdlib.h>
23 
24 void
25 network_accept_tcp_nagle_disable (const int fd)
26 {
27     static int noinherit_tcpnodelay = -1;
28     int opt;
29 
30     if (!noinherit_tcpnodelay) /* TCP_NODELAY inherited from listen socket */
31         return;
32 
33     if (noinherit_tcpnodelay < 0) {
34         socklen_t optlen = sizeof(opt);
35         if (0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen)) {
36             noinherit_tcpnodelay = !opt;
37             if (opt)           /* TCP_NODELAY inherited from listen socket */
38                 return;
39         }
40     }
41 
42     opt = 1;
43     (void)setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
44 }
45 
46 static handler_t network_server_handle_fdevent(void *context, int revents) {
47     const server_socket * const srv_socket = (server_socket *)context;
48     server * const srv = srv_socket->srv;
49 
50     if (0 == (revents & FDEVENT_IN)) {
51         log_error(srv->errh, __FILE__, __LINE__,
52           "strange event for server socket %d %d", srv_socket->fd, revents);
53         return HANDLER_ERROR;
54     }
55 
56     /* accept()s at most 100 new connections before
57      * jumping out to process events on other connections */
58     int loops = (int)srv->lim_conns;
59     if (loops > 100)
60         loops = 100;
61     else if (loops <= 0)
62         return HANDLER_GO_ON;
63 
64     const int nagle_disable =
65       (sock_addr_get_family(&srv_socket->addr) != AF_UNIX);
66 
67     sock_addr addr;
68     size_t addrlen; /*(size_t intentional; not socklen_t)*/
69     do {
70         addrlen = sizeof(addr);
71         int fd = fdevent_accept_listenfd(srv_socket->fd,
72                                          (struct sockaddr *)&addr, &addrlen);
73         if (-1 == fd) break;
74 
75         if (nagle_disable)
76             network_accept_tcp_nagle_disable(fd);
77       #ifdef HAVE_SYS_UN_H /*(see sock_addr.h)*/
78         else if (addrlen <= 2) /*(AF_UNIX if !nagle_disable)*/
79             memcpy(addr.un.sun_path, srv_socket->addr.un.sun_path,
80                    srv_socket->srv_token_colon < sizeof(addr.un.sun_path)
81                    ? (size_t)srv_socket->srv_token_colon+1 /*(+1 for '\0')*/
82                    : sizeof(addr.un.sun_path));/*(escaped len might be longer)*/
83       #endif
84 
85         connection *con = connection_accepted(srv, srv_socket, &addr, fd);
86         if (__builtin_expect( (!con), 0)) return HANDLER_GO_ON;
87         connection_state_machine(con);
88     } while (--loops);
89 
90     if (loops) {
91         switch (errno) {
92           case EAGAIN:
93          #if EWOULDBLOCK != EAGAIN
94           case EWOULDBLOCK:
95          #endif
96           case EINTR:
97           case ECONNABORTED:
98           case EMFILE:
99             break;
100           default:
101             log_perror(srv->errh, __FILE__, __LINE__, "accept()");
102         }
103     }
104 
105     return HANDLER_GO_ON;
106 }
107 
108 #ifdef HAVE_SYS_UN_H
109 
110 /* abstract socket (Linux, QNX?, Windows 10?) */
111 
112 __attribute_cold__
113 static void
114 network_abstract_socket_enc (buffer * const restrict abstract,
115                              unsigned char * const restrict sun_path,
116                              const uint32_t len)
117 {
118     /*(strings needing encoding are expected to be short;
119      * code not written for performance)*/
120     buffer_clear(abstract);
121     uint32_t n = 0;
122     for (uint32_t i = 0; i < len; ++i)
123         n += (sun_path[i]-20 < 107) ? 1 : 4;
124     char *s = buffer_extend(abstract, n);
125     for (uint32_t i = 0; i < len; ++i) {
126         /* (sun_path[i] >= 20 && sun_path[i] < 127 && sun_path[i] != '\\') */
127         if (sun_path[i]-20 < 107 && sun_path[i] != '\\')
128             *s++ = ((char *)sun_path)[i];
129         else {
130             s[0] = '\\';
131             s[1] = 'x';
132             s[2] = "0123456789abcdef"[sun_path[i] >>  4];
133             s[3] = "0123456789abcdef"[sun_path[i] & 0xF];
134             s += 4;
135         }
136     }
137 }
138 
139 __attribute_cold__
140 static uint32_t
141 network_abstract_socket_dec (const buffer * const restrict abstract,
142                              char * const restrict sun_path,
143                              const uint32_t plen)
144 {
145     /*(strings expected to begin with "\\x00")*/
146     /*(strings needing decoding are expected to be short;
147      * code not written for performance)*/
148     const char *s = abstract->ptr;
149     uint32_t n = 0;
150     for (int hi, lo; *s && n < plen; ++n) {
151         if (s[0] != '\\')
152             sun_path[n] = *s++;
153         else if (s[1] == 'x'
154                  && (hi = hex2int(s[2])) != 0xFF
155                  && (lo = hex2int(s[3])) != 0xFF) {
156             sun_path[n] = (char)((hi << 4) | lo);
157             s += 4;
158         }
159         else
160             break;
161     }
162     return *s == '\0' ? n : 0;
163 }
164 
165 __attribute_cold__
166 static int
167 network_abstract_socket_parse (const buffer *abstract,
168                                sock_addr *addr, socklen_t *addr_len,
169                                log_error_st *errh)
170 {
171     /* abstract socket (Linux, QNX?, Windows 10?) */
172     /*assert(*addr_len >= sizeof(struct sockaddr_un));*/
173     memset(addr, 0, sizeof(struct sockaddr_un));
174     addr->un.sun_family = AF_UNIX;
175     uint32_t len =
176       (uint32_t)(*addr_len - offsetof(struct sockaddr_un, sun_path));
177     if (len > sizeof(addr->un.sun_path))
178         len = sizeof(addr->un.sun_path);
179     len = network_abstract_socket_dec(abstract, addr->un.sun_path, len);
180     if (len) {
181         *addr_len = offsetof(struct sockaddr_un, sun_path) + len;
182         return 0;
183     }
184     else {
185         log_error(errh, __FILE__, __LINE__,
186           "abstract unix socket filename invalid encoding or too long: %s",
187           abstract->ptr);
188         return -1;
189     }
190 }
191 
192 #endif /* HAVE_SYS_UN_H */
193 
194 static void network_host_normalize_addr_str(buffer *host, sock_addr *addr, socklen_t addr_len) {
195     buffer_clear(host);
196     sock_addr_stringify_append_buffer(host, addr);
197   #ifdef HAVE_SYS_UN_H
198     if (AF_UNIX == sock_addr_get_family(addr) && 0 == buffer_clen(host))
199         network_abstract_socket_enc(host, (unsigned char *)addr->un.sun_path,
200                                     (uint32_t)(addr_len
201                                     - offsetof(struct sockaddr_un, sun_path)));
202   #else
203     UNUSED(addr_len);
204   #endif
205 }
206 
207 static int network_host_parse_addr(server *srv, sock_addr *addr, socklen_t *addr_len, buffer *host, int use_ipv6) {
208     char *h;
209     char *colon = NULL;
210     const char *chost;
211     sa_family_t family = use_ipv6 ? AF_INET6 : AF_INET;
212     unsigned int port = srv->srvconf.port;
213     if (buffer_is_blank(host)) {
214         log_error(srv->errh, __FILE__, __LINE__,
215           "value of $SERVER[\"socket\"] must not be empty");
216         return -1;
217     }
218     h = host->ptr;
219     if (h[0] == '/' || h[0] == '\\') {
220       #ifdef HAVE_SYS_UN_H
221         if (h[0] == '\\' && h[1] == 'x' && h[2] == '0' && h[3] == '0')
222             return network_abstract_socket_parse(host,addr,addr_len,srv->errh);
223         return (1 ==
224                 sock_addr_from_str_hints(addr,addr_len,h,AF_UNIX,0,srv->errh))
225           ? 0
226           : -1;
227       #else
228         log_error(srv->errh, __FILE__, __LINE__,
229           "ERROR: Unix Domain sockets are not supported.");
230         return -1;
231       #endif
232     }
233     buffer * const tb = srv->tmp_buf;
234     buffer_copy_buffer(tb, host);
235     h = tb->ptr;
236     if (h[0] == '[') {
237         family = AF_INET6;
238         if ((h = strchr(h, ']'))) {
239             *h++ = '\0';
240             if (*h == ':') colon = h;
241         } /*(else should not happen; validated in configparser.y)*/
242         h = tb->ptr+1;
243     }
244     else {
245         colon = strrchr(h, ':');
246     }
247     if (colon) {
248         *colon++ = '\0';
249         port = (unsigned int)strtol(colon, NULL, 10);
250         if (port == 0 || port > 65535) {
251             log_error(srv->errh, __FILE__, __LINE__,
252               "port not set or out of range: %u", port);
253             return -1;
254         }
255     }
256     if (h[0] == '*' && h[1] == '\0') {
257         family = AF_INET;
258         ++h;
259     }
260     chost = *h ? h : family == AF_INET ? "0.0.0.0" : "::";
261     if (1 !=
262         sock_addr_from_str_hints(addr,addr_len,chost,family,port,srv->errh)) {
263         return -1;
264     }
265     return 0;
266 }
267 
268 static void network_srv_sockets_append(server *srv, server_socket *srv_socket) {
269 	if (srv->srv_sockets.used == srv->srv_sockets.size) {
270 		srv->srv_sockets.size += 4;
271 		srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket*));
272 		force_assert(NULL != srv->srv_sockets.ptr);
273 	}
274 
275 	srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
276 }
277 
278 typedef struct {
279     /* global or per-socket config; not patched per connection */
280     int listen_backlog;
281     unsigned char ssl_enabled;
282     unsigned char use_ipv6;
283     unsigned char set_v6only; /* set_v6only is only a temporary option */
284     unsigned char defer_accept;
285     int8_t v4mapped;
286     const buffer *socket_perms;
287     const buffer *bsd_accept_filter;
288 } network_socket_config;
289 
290 typedef struct {
291     PLUGIN_DATA;
292     network_socket_config defaults;
293     network_socket_config conf;
294 } network_plugin_data;
295 
296 static void network_merge_config_cpv(network_socket_config * const pconf, const config_plugin_value_t * const cpv) {
297     switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
298       case 0: /* ssl.engine */
299         pconf->ssl_enabled = (0 != cpv->v.u);
300         break;
301       case 1: /* server.listen-backlog */
302         pconf->listen_backlog = (int)cpv->v.u;
303         break;
304       case 2: /* server.socket-perms */
305         pconf->socket_perms = cpv->v.b;
306         break;
307       case 3: /* server.bsd-accept-filter */
308         pconf->bsd_accept_filter = cpv->v.b;
309         break;
310       case 4: /* server.defer-accept */
311         pconf->defer_accept = (0 != cpv->v.u);
312         break;
313       case 5: /* server.use-ipv6 */
314         pconf->use_ipv6 = (0 != cpv->v.u);
315         break;
316       case 6: /* server.set-v6only */
317         pconf->set_v6only = (0 != cpv->v.u);
318         break;
319       case 7: /* server.v4mapped */
320         pconf->v4mapped = (0 != cpv->v.u);
321         break;
322       default:/* should not happen */
323         return;
324     }
325 }
326 
327 static void network_merge_config(network_socket_config * const pconf, const config_plugin_value_t *cpv) {
328     do {
329         network_merge_config_cpv(pconf, cpv);
330     } while ((++cpv)->k_id != -1);
331 }
332 
333 __attribute_pure__
334 static uint8_t network_srv_token_colon (const buffer * const b) {
335     const char *colon = NULL;
336     const char * const p = b->ptr;
337     if (*p == '[') {
338         colon = strstr(p, "]:");
339         if (colon) ++colon;
340     }
341     else if (*p != '/') {
342         colon = strchr(p, ':');
343     }
344     return colon ? (uint8_t)(colon - p) : (uint8_t)buffer_clen(b);
345 }
346 
347 static void network_srv_socket_init_token (server_socket * const srv_socket, const buffer * const token) {
348     buffer * const srv_token = srv_socket->srv_token = buffer_init();
349     buffer_copy_buffer(srv_token, token);
350   #ifdef HAVE_SYS_UN_H
351     /*(srv_socket->addr must have been initialized by caller)*/
352     if (AF_UNIX == sock_addr_get_family(&srv_socket->addr))
353         srv_socket->srv_token_colon = buffer_clen(srv_token);
354     else
355   #endif
356         srv_socket->srv_token_colon = network_srv_token_colon(srv_token);
357 }
358 
359 static int network_server_init(server *srv, const network_socket_config *s, buffer *host_token, size_t sidx, int stdin_fd) {
360 	server_socket *srv_socket;
361 	const char *host;
362 	socklen_t addr_len = sizeof(sock_addr);
363 	sock_addr addr;
364 	int family = 0;
365 	int use_ipv6 = s->use_ipv6;
366 	int set_v6only = 0;
367 
368 	if (buffer_is_blank(host_token)) {
369 		log_error(srv->errh, __FILE__, __LINE__,
370 		  "value of $SERVER[\"socket\"] must not be empty");
371 		return -1;
372 	}
373 
374 	/* check if we already know this socket, and if yes, don't init it
375 	 * (optimization: check strings here to filter out exact matches;
376 	 *  binary addresses are matched further below) */
377 	for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
378 		if (buffer_is_equal(srv->srv_sockets.ptr[i]->srv_token, host_token)) {
379 			if ((unsigned short)~0u == srv->srv_sockets.ptr[i]->sidx) {
380 				srv->srv_sockets.ptr[i]->sidx = sidx;
381 				srv->srv_sockets.ptr[i]->is_ssl = s->ssl_enabled;
382 			}
383 			return 0;
384 		}
385 	}
386 
387 	host = host_token->ptr;
388 	if ((use_ipv6 && (*host == '\0' || *host == ':')) || (host[0] == '[' && host[1] == ']')) {
389 		log_error(srv->errh, __FILE__, __LINE__,
390 		  "warning: please use server.use-ipv6 only for hostnames, "
391 		  "not without server.bind / empty address; your config will "
392 		  "break if the kernel default for IPV6_V6ONLY changes");
393 	}
394 	if (*host == '[') use_ipv6 = 1;
395 
396 	memset(&addr, 0, sizeof(addr));
397 	if (-1 != stdin_fd) {
398 		if (-1 == getsockname(stdin_fd, (struct sockaddr *)&addr, &addr_len)) {
399 			log_perror(srv->errh, __FILE__, __LINE__, "getsockname()");
400 			return -1;
401 		}
402 	} else if (0 != network_host_parse_addr(srv, &addr, &addr_len, host_token, use_ipv6)) {
403 		return -1;
404 	}
405 
406 	family = sock_addr_get_family(&addr);
407 
408       #ifdef HAVE_IPV6
409 	if (*host != '\0' && AF_INET6 == family) {
410 		if (s->set_v6only) {
411 			set_v6only = 1;
412 		} else {
413 			log_error(srv->errh, __FILE__, __LINE__,
414 			  "warning: server.set-v6only will be removed soon, "
415 			  "update your config to have different sockets for ipv4 and ipv6");
416 		}
417 	}
418 	if (AF_INET6 == family && -1 != s->v4mapped) { /*(configured; -1 is unset)*/
419 		set_v6only = (s->v4mapped ? -1 : 1);
420 	}
421       #endif
422 
423 	network_host_normalize_addr_str(host_token, &addr, addr_len);
424 	host = host_token->ptr;
425 
426 	if (srv->srvconf.preflight_check) {
427 		return 0;
428 	}
429 
430 	/* check if we already know this socket (after potential DNS resolution), and if yes, don't init it */
431 	for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
432 		if (0 == memcmp(&srv->srv_sockets.ptr[i]->addr, &addr, sizeof(addr))) {
433 			if ((unsigned short)~0u == srv->srv_sockets.ptr[i]->sidx) {
434 				srv->srv_sockets.ptr[i]->sidx = sidx;
435 				srv->srv_sockets.ptr[i]->is_ssl = s->ssl_enabled;
436 			}
437 			return 0;
438 		}
439 	}
440 
441 	srv_socket = calloc(1, sizeof(*srv_socket));
442 	force_assert(NULL != srv_socket);
443 	memcpy(&srv_socket->addr, &addr, addr_len);
444 	srv_socket->fd = -1;
445 	srv_socket->sidx = sidx;
446 	srv_socket->is_ssl = s->ssl_enabled;
447 	srv_socket->srv = srv;
448 	network_srv_socket_init_token(srv_socket, host_token);
449 	network_srv_sockets_append(srv, srv_socket);
450 
451 	if (srv->sockets_disabled) { /* lighttpd -1 (one-shot mode) */
452 		return 0;
453 	}
454 
455 	if (srv->srvconf.systemd_socket_activation) {
456 		for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
457 			if (0 != memcmp(&srv->srv_sockets_inherited.ptr[i]->addr, &srv_socket->addr, addr_len)) continue;
458 			if ((unsigned short)~0u == srv->srv_sockets_inherited.ptr[i]->sidx) {
459 				srv->srv_sockets_inherited.ptr[i]->sidx = sidx;
460 			}
461 			stdin_fd = srv->srv_sockets_inherited.ptr[i]->fd;
462 			break;
463 		}
464 	}
465 
466 	if (-1 != stdin_fd) {
467 		srv_socket->fd = stdin_fd;
468 		if (-1 == fdevent_fcntl_set_nb_cloexec(stdin_fd)) {
469 			log_perror(srv->errh, __FILE__, __LINE__, "fcntl");
470 			return -1;
471 		}
472 	} else
473 #ifdef HAVE_SYS_UN_H
474 	if (AF_UNIX == family) {
475 		/* check if the socket exists and try to connect to it. */
476 		force_assert(host); /*(static analysis hint)*/
477 		if (-1 == (srv_socket->fd = fdevent_socket_cloexec(AF_UNIX, SOCK_STREAM, 0))) {
478 			log_perror(srv->errh, __FILE__, __LINE__, "socket");
479 			return -1;
480 		}
481 		if (0 == connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
482 			log_error(srv->errh, __FILE__, __LINE__,
483 			  "server socket is still in use: %s", host);
484 			return -1;
485 		}
486 
487 		/* connect failed */
488 		switch(errno) {
489 		case ECONNREFUSED:
490 			if (*host == '/') unlink(host);
491 			break;
492 		case ENOENT:
493 			break;
494 		default:
495 			log_perror(srv->errh, __FILE__, __LINE__,
496 			  "testing socket failed: %s", host);
497 			return -1;
498 		}
499 
500 		if (-1 == fdevent_fcntl_set_nb(srv_socket->fd)) {
501 			log_perror(srv->errh, __FILE__, __LINE__, "fcntl");
502 			return -1;
503 		}
504 	} else
505 #endif
506 	{
507 		if (-1 == (srv_socket->fd = fdevent_socket_nb_cloexec(family, SOCK_STREAM, IPPROTO_TCP))) {
508 			log_perror(srv->errh, __FILE__, __LINE__, "socket");
509 			return -1;
510 		}
511 
512 #ifdef HAVE_IPV6
513 		if (set_v6only) {
514 				int val = (set_v6only > 0);
515 				if (-1 == setsockopt(srv_socket->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
516 					log_perror(srv->errh, __FILE__, __LINE__, "setsockopt(IPV6_V6ONLY)");
517 					return -1;
518 				}
519 		}
520 #endif
521 	}
522 
523 	/* */
524 	srv->cur_fds = srv_socket->fd;
525 
526 	if (fdevent_set_so_reuseaddr(srv_socket->fd, 1) < 0) {
527 		log_perror(srv->errh, __FILE__, __LINE__, "setsockopt(SO_REUSEADDR)");
528 		return -1;
529 	}
530 
531 	if (family != AF_UNIX) {
532 		if (fdevent_set_tcp_nodelay(srv_socket->fd, 1) < 0) {
533 			log_perror(srv->errh, __FILE__, __LINE__, "setsockopt(TCP_NODELAY)");
534 			return -1;
535 		}
536 	}
537 
538 	if (-1 != stdin_fd) { } else
539 	if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
540 		log_perror(srv->errh, __FILE__, __LINE__,
541 		  "can't bind to socket: %s", host);
542 		return -1;
543 	}
544 
545   #ifdef HAVE_SYS_UN_H
546 	if (-1 != stdin_fd) { } else
547 	if (AF_UNIX == family && s->socket_perms) {
548 		mode_t m = 0;
549 		for (char *str = s->socket_perms->ptr; *str; ++str) {
550 			m <<= 3;
551 			m |= (*str - '0');
552 		}
553 		if (0 != m && *host == '/' && -1 == chmod(host, m)) {
554 			log_perror(srv->errh, __FILE__, __LINE__,
555 			  "chmod(\"%s\", %s)", host, s->socket_perms->ptr);
556 			return -1;
557 		}
558 	}
559   #endif
560 
561 	if (-1 != stdin_fd) { } else
562 	if (-1 == listen(srv_socket->fd, s->listen_backlog)) {
563 		log_perror(srv->errh, __FILE__, __LINE__, "listen");
564 		return -1;
565 	}
566 
567 	if (s->ssl_enabled) {
568 	}
569 #ifdef TCP_DEFER_ACCEPT
570 	else if (s->defer_accept) {
571 		int v = s->defer_accept;
572 		if (-1 == setsockopt(srv_socket->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &v, sizeof(v))) {
573 			log_perror(srv->errh, __FILE__, __LINE__, "can't set TCP_DEFER_ACCEPT");
574 		}
575 	}
576 #endif
577 #if defined(__FreeBSD__) || defined(__NetBSD__) \
578  || defined(__OpenBSD__) || defined(__DragonFly__)
579 #ifdef SO_ACCEPTFILTER
580 	else if (s->bsd_accept_filter
581 		   && (buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("httpready"))
582 			|| buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("dataready")))) {
583 		/* FreeBSD accf_http filter */
584 		struct accept_filter_arg afa;
585 		memset(&afa, 0, sizeof(afa));
586 		strncpy(afa.af_name, s->bsd_accept_filter->ptr, sizeof(afa.af_name)-1);
587 		if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
588 			if (errno != ENOENT) {
589 				log_perror(srv->errh, __FILE__, __LINE__,
590 				  "can't set accept-filter '%s'", s->bsd_accept_filter->ptr);
591 			}
592 		}
593 	}
594 #endif
595 #endif
596 
597 	return 0;
598 }
599 
600 int network_close(server *srv) {
601 	for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
602 		server_socket *srv_socket = srv->srv_sockets.ptr[i];
603 		if (srv_socket->fd != -1) {
604 			network_unregister_sock(srv, srv_socket);
605 			close(srv_socket->fd);
606 		}
607 
608 		buffer_free(srv_socket->srv_token);
609 
610 		free(srv_socket);
611 	}
612 
613 	free(srv->srv_sockets.ptr);
614 	srv->srv_sockets.ptr = NULL;
615 	srv->srv_sockets.used = 0;
616 	srv->srv_sockets.size = 0;
617 
618 	for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
619 		server_socket *srv_socket = srv->srv_sockets_inherited.ptr[i];
620 		if (srv_socket->fd != -1 && srv_socket->sidx != (unsigned short)~0u) {
621 			close(srv_socket->fd);
622 		}
623 
624 		buffer_free(srv_socket->srv_token);
625 
626 		free(srv_socket);
627 	}
628 
629 	free(srv->srv_sockets_inherited.ptr);
630 	srv->srv_sockets_inherited.ptr = NULL;
631 	srv->srv_sockets_inherited.used = 0;
632 	srv->srv_sockets_inherited.size = 0;
633 
634 	return 0;
635 }
636 
637 void network_socket_activation_to_env (server * const srv) {
638     /* set up listening sockets for systemd socket activation
639      * and ensure FD_CLOEXEC flag is not set on listen fds */
640     int fd = 3; /* #define SD_LISTEN_FDS_START 3 */
641     for (uint32_t n = 0, i; n < srv->srv_sockets.used; ++n) {
642         server_socket *srv_socket = srv->srv_sockets.ptr[n];
643         if (srv_socket->fd < fd) continue;
644         if (srv_socket->fd == fd) {
645             fdevent_clrfd_cloexec(fd);
646             ++fd;
647             continue;
648         }
649         /* (expecting ordered list, but check if fd is later in list)*/
650         for (i = n+1; i < srv->srv_sockets.used; ++i) {
651             if (fd == srv->srv_sockets.ptr[i]->fd)
652                 break;
653         }
654         if (i < srv->srv_sockets.used) {
655             fdevent_clrfd_cloexec(fd);
656             ++fd;
657             --n; /* loop to reprocess this entry */
658             continue;
659         }
660 
661         /* dup2() removes FD_CLOEXEC on newfd */
662         if (fd != dup2(srv_socket->fd, fd)) continue;
663         ++fd;
664         /* old fd will be closed upon execv() due to its FD_CLOEXEC flag
665          * (if not already closed by another dup2() over it) */
666     }
667     fd -= 3; /* now num fds; #define SD_LISTEN_FDS_START 3 */
668     if (0 == fd) return; /*(no active sockets?)*/
669     buffer * const tb = srv->tmp_buf;
670     buffer_clear(tb);
671     buffer_append_int(tb, fd);
672     setenv("LISTEN_FDS", tb->ptr, 1);
673     buffer_clear(tb);
674     buffer_append_int(tb, srv->pid); /* getpid() */
675     setenv("LISTEN_PID", tb->ptr, 1);
676 }
677 
678 static int network_socket_activation_nfds(server *srv, const network_socket_config *s, int nfds) {
679     buffer *host = buffer_init();
680     socklen_t addr_len;
681     sock_addr addr;
682     int rc = 0;
683     nfds += 3; /* #define SD_LISTEN_FDS_START 3 */
684     for (int fd = 3; fd < nfds; ++fd) {
685         addr_len = sizeof(sock_addr);
686         if (-1 == (rc = getsockname(fd, (struct sockaddr *)&addr, &addr_len))) {
687             log_perror(srv->errh, __FILE__, __LINE__,
688               "socket activation getsockname()");
689             break;
690         }
691         network_host_normalize_addr_str(host, &addr, addr_len);
692         rc = network_server_init(srv, s, host, 0, fd);
693         if (0 != rc) break;
694         srv->srv_sockets.ptr[srv->srv_sockets.used-1]->sidx = (unsigned short)~0u;
695     }
696     buffer_free(host);
697     memcpy(&srv->srv_sockets_inherited, &srv->srv_sockets, sizeof(server_socket_array));
698     memset(&srv->srv_sockets, 0, sizeof(server_socket_array));
699     return rc;
700 }
701 
702 static int network_socket_activation_from_env(server *srv, const network_socket_config *s) {
703     char *listen_pid = getenv("LISTEN_PID");
704     char *listen_fds = getenv("LISTEN_FDS");
705     pid_t lpid = listen_pid ? (pid_t)strtoul(listen_pid,NULL,10) : 0;
706     int nfds = listen_fds ? atoi(listen_fds) : 0;
707     int rc = (nfds > 0 && nfds < 5000
708               && (lpid == getpid()
709                  #ifndef _WIN32
710                   || (0 == strncmp(listen_pid, "parent:", 7)
711                       && getppid() == (pid_t)strtoul(listen_pid+7,NULL,10))
712                  #endif
713                  ))
714       ? network_socket_activation_nfds(srv, s, nfds)
715       : 0;
716     unsetenv("LISTEN_PID");
717     unsetenv("LISTEN_FDS");
718     unsetenv("LISTEN_FDNAMES");
719     /*(upon graceful restart, unsetenv will result in no-op above)*/
720     return rc;
721 }
722 
723 int network_init(server *srv, int stdin_fd) {
724     /*(network params used during setup (from $SERVER["socket"] condition))*/
725     static const config_plugin_keys_t cpk[] = {
726       { CONST_STR_LEN("ssl.engine"),
727         T_CONFIG_BOOL,
728         T_CONFIG_SCOPE_SOCKET }
729      ,{ CONST_STR_LEN("server.listen-backlog"),
730         T_CONFIG_INT,
731         T_CONFIG_SCOPE_SOCKET }
732      ,{ CONST_STR_LEN("server.socket-perms"),
733         T_CONFIG_STRING,
734         T_CONFIG_SCOPE_SOCKET }
735      ,{ CONST_STR_LEN("server.bsd-accept-filter"),
736         T_CONFIG_STRING,
737         T_CONFIG_SCOPE_SOCKET }
738      ,{ CONST_STR_LEN("server.defer-accept"),
739         T_CONFIG_BOOL,
740         T_CONFIG_SCOPE_SOCKET }
741      ,{ CONST_STR_LEN("server.use-ipv6"),
742         T_CONFIG_BOOL,
743         T_CONFIG_SCOPE_SOCKET }
744      ,{ CONST_STR_LEN("server.set-v6only"),
745         T_CONFIG_BOOL,
746         T_CONFIG_SCOPE_SOCKET }
747      ,{ CONST_STR_LEN("server.v4mapped"),
748         T_CONFIG_BOOL,
749         T_CONFIG_SCOPE_SOCKET }
750      ,{ NULL, 0,
751         T_CONFIG_UNSET,
752         T_CONFIG_SCOPE_UNSET }
753     };
754 
755   #ifdef __WIN32
756     WSADATA wsaData;
757     WORD wVersionRequested = MAKEWORD(2, 2);
758     if (0 != WSAStartup(wVersionRequested, &wsaData)) {
759         /* Tell the user that we could not find a usable WinSock DLL */
760         return -1;
761     }
762   #endif
763 
764     if (0 != network_write_init(srv)) return -1;
765 
766     network_plugin_data np;
767     memset(&np, 0, sizeof(network_plugin_data));
768     network_plugin_data *p = &np;
769 
770     if (!config_plugin_values_init(srv, p, cpk, "network"))
771         return HANDLER_ERROR;
772 
773     p->defaults.listen_backlog = 1024;
774     p->defaults.defer_accept = 0;
775     p->defaults.use_ipv6 = 0;
776     p->defaults.set_v6only = 1;
777     p->defaults.v4mapped = -1; /*(-1 for unset; not 0 or 1)*/
778 
779     /* initialize p->defaults from global config context */
780     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
781         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
782         if (-1 != cpv->k_id)
783             network_merge_config(&p->defaults, cpv);
784     }
785 
786     if (config_feature_bool(srv, "server.graceful-restart-bg", 0))
787         srv->srvconf.systemd_socket_activation = 1;
788 
789     int rc = 0;
790     do {
791 
792         if (srv->srvconf.systemd_socket_activation) {
793             for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
794                 srv->srv_sockets_inherited.ptr[i]->sidx = (unsigned short)~0u;
795             }
796             rc = network_socket_activation_from_env(srv, &p->defaults);
797             if (0 != rc) break;
798             if (0 == srv->srv_sockets_inherited.used) {
799                 srv->srvconf.systemd_socket_activation = 0;
800             }
801         }
802 
803         /* special-case srv->srvconf.bindhost = "/dev/stdin" (see server.c) */
804         if (-1 != stdin_fd) {
805             buffer *b = buffer_init();
806             buffer_copy_buffer(b, srv->srvconf.bindhost);
807             /*assert(buffer_eq_slen(b, CONST_STR_LEN("/dev/stdin")));*/
808             rc = (0 == srv->srv_sockets.used)
809               ? network_server_init(srv, &p->defaults, b, 0, stdin_fd)
810               : close(stdin_fd);/*(graceful restart listening to "/dev/stdin")*/
811             buffer_free(b);
812             if (0 != rc) break;
813         }
814 
815         /* check for $SERVER["socket"] */
816         for (uint32_t i = 1; i < srv->config_context->used; ++i) {
817             config_cond_info cfginfo;
818             config_get_config_cond_info(&cfginfo, i);
819             if (COMP_SERVER_SOCKET != cfginfo.comp) continue;/* not our stage */
820 
821             buffer *host_token;
822             *(const buffer **)&host_token = cfginfo.string;
823             /*(cfginfo.string is modified during config)*/
824 
825             memcpy(&p->conf, &p->defaults, sizeof(network_socket_config));
826             for (int j = !p->cvlist[0].v.u2[1]; j < p->nconfig; ++j) {
827                 if ((int)i != p->cvlist[j].k_id) continue;
828                 const config_plugin_value_t *cpv =
829                   p->cvlist + p->cvlist[j].v.u2[0];
830                 network_merge_config(&p->conf, cpv);
831                 break;
832             }
833 
834             if (cfginfo.cond == CONFIG_COND_EQ) {
835                 rc = network_server_init(srv, &p->conf, host_token, i, -1);
836                 if (0 != rc) break;
837             }
838             else if (cfginfo.cond == CONFIG_COND_NE) {
839                 socklen_t addr_len = sizeof(sock_addr);
840                 sock_addr addr;
841                 rc = network_host_parse_addr(srv, &addr, &addr_len,
842                                              host_token, p->conf.use_ipv6);
843                 if (0 != rc) break;
844                 network_host_normalize_addr_str(host_token, &addr, addr_len);
845             }
846         }
847         if (0 != rc) break;
848 
849         /* process srv->srvconf.bindhost
850          * init global config for server.bindhost and server.port after
851          * initializing $SERVER["socket"] so that if bindhost and port match
852          * another $SERVER["socket"], the $SERVER["socket"] config is used,
853          * as the $SERVER["socket"] config inherits from the global scope and
854          * can then be overridden.  (bindhost = "/dev/stdin" is handled above)
855          * (skip if systemd socket activation is enabled and bindhost is empty;
856          *  do not additionally listen on "*") */
857         if ((!srv->srvconf.systemd_socket_activation || srv->srvconf.bindhost)
858             && -1 == stdin_fd) {
859             buffer *b = buffer_init();
860             if (srv->srvconf.bindhost)
861                 buffer_copy_buffer(b, srv->srvconf.bindhost);
862             /*(skip adding port if unix socket path)*/
863             if (!b->ptr || (b->ptr[0] != '/' && b->ptr[0] != '\\')) {
864                 buffer_append_char(b, ':');
865                 buffer_append_int(b, srv->srvconf.port);
866             }
867           #ifdef __COVERITY__
868             force_assert(b->ptr);
869           #endif
870 
871             rc = network_server_init(srv, &p->defaults, b, 0, -1);
872             buffer_free(b);
873             if (0 != rc) break;
874         }
875 
876         if (srv->srvconf.systemd_socket_activation) {
877             /* activate any inherited sockets not explicitly listed in config */
878             server_socket *srv_socket;
879             for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
880                     if ((unsigned short)~0u
881                         != srv->srv_sockets_inherited.ptr[i]->sidx)
882                         continue;
883                     srv->srv_sockets_inherited.ptr[i]->sidx = 0;
884                 srv_socket = calloc(1, sizeof(server_socket));
885                 force_assert(NULL != srv_socket);
886                 memcpy(srv_socket, srv->srv_sockets_inherited.ptr[i],
887                        sizeof(server_socket));
888                 srv_socket->is_ssl = p->defaults.ssl_enabled;
889                 /*(note: re-inits srv_socket->srv_token to new buffer ptr)*/
890                 network_srv_socket_init_token(srv_socket,srv_socket->srv_token);
891                 network_srv_sockets_append(srv, srv_socket);
892             }
893         }
894 
895         /* reset sidx of any graceful sockets not explicitly listed in config */
896         for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
897             if ((unsigned short)~0u == srv->srv_sockets.ptr[i]->sidx) {
898                 srv->srv_sockets.ptr[i]->sidx = 0;
899                 srv->srv_sockets.ptr[i]->is_ssl = p->defaults.ssl_enabled;
900             }
901         }
902 
903     } while (0);
904 
905     free(p->cvlist);
906     return rc;
907 }
908 
909 void network_unregister_sock(server *srv, server_socket *srv_socket) {
910 	fdnode *fdn = srv_socket->fdn;
911 	if (NULL == fdn) return;
912 	fdevent_fdnode_event_del(srv->ev, fdn);
913 	fdevent_unregister(srv->ev, fdn->fd);
914 	srv_socket->fdn = NULL;
915 }
916 
917 int network_register_fdevents(server *srv) {
918 	if (-1 == fdevent_reset(srv->ev)) {
919 		return -1;
920 	}
921 
922 	if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
923 
924 	/* register fdevents after reset */
925 	for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
926 		server_socket *srv_socket = srv->srv_sockets.ptr[i];
927 
928 		srv_socket->fdn = fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
929 		fdevent_fdnode_event_set(srv->ev, srv_socket->fdn, FDEVENT_IN);
930 	}
931 	return 0;
932 }
933