xref: /lighttpd1.4/src/network.c (revision f0786a75)
18abd06a7SGlenn Strauss #include "first.h"
28abd06a7SGlenn Strauss 
3bcdc6a3bSJan Kneschke #include "network.h"
404d76e7aSGlenn Strauss #include "base.h"
5bcdc6a3bSJan Kneschke #include "fdevent.h"
6bcdc6a3bSJan Kneschke #include "log.h"
7bcdc6a3bSJan Kneschke #include "connections.h"
8ed62e354SGlenn Strauss #include "plugin.h"
91367f606SGlenn Strauss #include "sock_addr.h"
10bcdc6a3bSJan Kneschke 
11142971a8SGlenn Strauss #include "network_write.h"
12bcdc6a3bSJan Kneschke #include "sys-socket.h"
13bcdc6a3bSJan Kneschke 
1422e8b456SStefan Bühler #include <sys/types.h>
1522e8b456SStefan Bühler #include <sys/stat.h>
1613ea2d88SGlenn Strauss #include "sys-time.h"
1722e8b456SStefan Bühler 
1822e8b456SStefan Bühler #include <errno.h>
1922e8b456SStefan Bühler #include <fcntl.h>
2022e8b456SStefan Bühler #include <unistd.h>
2122e8b456SStefan Bühler #include <string.h>
2222e8b456SStefan Bühler #include <stdlib.h>
2322e8b456SStefan Bühler 
24416b5729SGlenn Strauss void
network_accept_tcp_nagle_disable(const int fd)25416b5729SGlenn Strauss network_accept_tcp_nagle_disable (const int fd)
26416b5729SGlenn Strauss {
27416b5729SGlenn Strauss     static int noinherit_tcpnodelay = -1;
28416b5729SGlenn Strauss     int opt;
29416b5729SGlenn Strauss 
30416b5729SGlenn Strauss     if (!noinherit_tcpnodelay) /* TCP_NODELAY inherited from listen socket */
31416b5729SGlenn Strauss         return;
32416b5729SGlenn Strauss 
33416b5729SGlenn Strauss     if (noinherit_tcpnodelay < 0) {
34416b5729SGlenn Strauss         socklen_t optlen = sizeof(opt);
35416b5729SGlenn Strauss         if (0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen)) {
36416b5729SGlenn Strauss             noinherit_tcpnodelay = !opt;
37416b5729SGlenn Strauss             if (opt)           /* TCP_NODELAY inherited from listen socket */
38416b5729SGlenn Strauss                 return;
39416b5729SGlenn Strauss         }
40416b5729SGlenn Strauss     }
41416b5729SGlenn Strauss 
42416b5729SGlenn Strauss     opt = 1;
43416b5729SGlenn Strauss     (void)setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
44416b5729SGlenn Strauss }
45416b5729SGlenn Strauss 
network_server_handle_fdevent(void * context,int revents)4605cc88ddSGlenn Strauss static handler_t network_server_handle_fdevent(void *context, int revents) {
47302d82a5SGlenn Strauss     const server_socket * const srv_socket = (server_socket *)context;
4805cc88ddSGlenn Strauss     server * const srv = srv_socket->srv;
49bcdc6a3bSJan Kneschke 
504ae13c32SStefan Bühler     if (0 == (revents & FDEVENT_IN)) {
51010c2894SGlenn Strauss         log_error(srv->errh, __FILE__, __LINE__,
52010c2894SGlenn Strauss           "strange event for server socket %d %d", srv_socket->fd, revents);
53bde65764SJan Kneschke         return HANDLER_ERROR;
54bcdc6a3bSJan Kneschke     }
55bcdc6a3bSJan Kneschke 
56302d82a5SGlenn Strauss     /* accept()s at most 100 new connections before
57302d82a5SGlenn Strauss      * jumping out to process events on other connections */
585a58f696SGlenn Strauss     int loops = (int)srv->lim_conns;
59302d82a5SGlenn Strauss     if (loops > 100)
60302d82a5SGlenn Strauss         loops = 100;
61302d82a5SGlenn Strauss     else if (loops <= 0)
62302d82a5SGlenn Strauss         return HANDLER_GO_ON;
63fb74bb75SGlenn Strauss 
64302d82a5SGlenn Strauss     const int nagle_disable =
65302d82a5SGlenn Strauss       (sock_addr_get_family(&srv_socket->addr) != AF_UNIX);
66302d82a5SGlenn Strauss 
67302d82a5SGlenn Strauss     sock_addr addr;
68302d82a5SGlenn Strauss     size_t addrlen; /*(size_t intentional; not socklen_t)*/
69302d82a5SGlenn Strauss     do {
70302d82a5SGlenn Strauss         addrlen = sizeof(addr);
71302d82a5SGlenn Strauss         int fd = fdevent_accept_listenfd(srv_socket->fd,
72302d82a5SGlenn Strauss                                          (struct sockaddr *)&addr, &addrlen);
73302d82a5SGlenn Strauss         if (-1 == fd) break;
74302d82a5SGlenn Strauss 
75302d82a5SGlenn Strauss         if (nagle_disable)
76302d82a5SGlenn Strauss             network_accept_tcp_nagle_disable(fd);
77aa4d9b63SGlenn Strauss       #ifdef HAVE_SYS_UN_H /*(see sock_addr.h)*/
780e404df2SGlenn Strauss         else if (addrlen <= 2) /*(AF_UNIX if !nagle_disable)*/
7914bfa016SGlenn Strauss             memcpy(addr.un.sun_path, srv_socket->addr.un.sun_path,
8014bfa016SGlenn Strauss                    srv_socket->srv_token_colon < sizeof(addr.un.sun_path)
8114bfa016SGlenn Strauss                    ? (size_t)srv_socket->srv_token_colon+1 /*(+1 for '\0')*/
8214bfa016SGlenn Strauss                    : sizeof(addr.un.sun_path));/*(escaped len might be longer)*/
83aa4d9b63SGlenn Strauss       #endif
84302d82a5SGlenn Strauss 
85302d82a5SGlenn Strauss         connection *con = connection_accepted(srv, srv_socket, &addr, fd);
86302d82a5SGlenn Strauss         if (__builtin_expect( (!con), 0)) return HANDLER_GO_ON;
87b5775b99SGlenn Strauss         connection_state_machine(con);
88302d82a5SGlenn Strauss     } while (--loops);
89302d82a5SGlenn Strauss 
90302d82a5SGlenn Strauss     if (loops) {
91302d82a5SGlenn Strauss         switch (errno) {
92302d82a5SGlenn Strauss           case EAGAIN:
93302d82a5SGlenn Strauss          #if EWOULDBLOCK != EAGAIN
94302d82a5SGlenn Strauss           case EWOULDBLOCK:
95302d82a5SGlenn Strauss          #endif
96302d82a5SGlenn Strauss           case EINTR:
97302d82a5SGlenn Strauss           case ECONNABORTED:
98302d82a5SGlenn Strauss           case EMFILE:
99302d82a5SGlenn Strauss             break;
100302d82a5SGlenn Strauss           default:
101302d82a5SGlenn Strauss             log_perror(srv->errh, __FILE__, __LINE__, "accept()");
102302d82a5SGlenn Strauss         }
103302d82a5SGlenn Strauss     }
104fb74bb75SGlenn Strauss 
105bcdc6a3bSJan Kneschke     return HANDLER_GO_ON;
106bcdc6a3bSJan Kneschke }
107bcdc6a3bSJan Kneschke 
10814bfa016SGlenn Strauss #ifdef HAVE_SYS_UN_H
10914bfa016SGlenn Strauss 
11014bfa016SGlenn Strauss /* abstract socket (Linux, QNX?, Windows 10?) */
11114bfa016SGlenn Strauss 
11214bfa016SGlenn Strauss __attribute_cold__
11314bfa016SGlenn Strauss static void
network_abstract_socket_enc(buffer * const restrict abstract,unsigned char * const restrict sun_path,const uint32_t len)11414bfa016SGlenn Strauss network_abstract_socket_enc (buffer * const restrict abstract,
11514bfa016SGlenn Strauss                              unsigned char * const restrict sun_path,
11614bfa016SGlenn Strauss                              const uint32_t len)
11714bfa016SGlenn Strauss {
11814bfa016SGlenn Strauss     /*(strings needing encoding are expected to be short;
11914bfa016SGlenn Strauss      * code not written for performance)*/
12014bfa016SGlenn Strauss     buffer_clear(abstract);
12114bfa016SGlenn Strauss     uint32_t n = 0;
12214bfa016SGlenn Strauss     for (uint32_t i = 0; i < len; ++i)
12314bfa016SGlenn Strauss         n += (sun_path[i]-20 < 107) ? 1 : 4;
12414bfa016SGlenn Strauss     char *s = buffer_extend(abstract, n);
12514bfa016SGlenn Strauss     for (uint32_t i = 0; i < len; ++i) {
12614bfa016SGlenn Strauss         /* (sun_path[i] >= 20 && sun_path[i] < 127 && sun_path[i] != '\\') */
12714bfa016SGlenn Strauss         if (sun_path[i]-20 < 107 && sun_path[i] != '\\')
12814bfa016SGlenn Strauss             *s++ = ((char *)sun_path)[i];
12914bfa016SGlenn Strauss         else {
13014bfa016SGlenn Strauss             s[0] = '\\';
13114bfa016SGlenn Strauss             s[1] = 'x';
13214bfa016SGlenn Strauss             s[2] = "0123456789abcdef"[sun_path[i] >>  4];
13314bfa016SGlenn Strauss             s[3] = "0123456789abcdef"[sun_path[i] & 0xF];
13414bfa016SGlenn Strauss             s += 4;
13514bfa016SGlenn Strauss         }
13614bfa016SGlenn Strauss     }
13714bfa016SGlenn Strauss }
13814bfa016SGlenn Strauss 
13914bfa016SGlenn Strauss __attribute_cold__
14014bfa016SGlenn Strauss static uint32_t
network_abstract_socket_dec(const buffer * const restrict abstract,char * const restrict sun_path,const uint32_t plen)14114bfa016SGlenn Strauss network_abstract_socket_dec (const buffer * const restrict abstract,
14214bfa016SGlenn Strauss                              char * const restrict sun_path,
14314bfa016SGlenn Strauss                              const uint32_t plen)
14414bfa016SGlenn Strauss {
14514bfa016SGlenn Strauss     /*(strings expected to begin with "\\x00")*/
14614bfa016SGlenn Strauss     /*(strings needing decoding are expected to be short;
14714bfa016SGlenn Strauss      * code not written for performance)*/
14814bfa016SGlenn Strauss     const char *s = abstract->ptr;
14914bfa016SGlenn Strauss     uint32_t n = 0;
15014bfa016SGlenn Strauss     for (int hi, lo; *s && n < plen; ++n) {
15114bfa016SGlenn Strauss         if (s[0] != '\\')
15214bfa016SGlenn Strauss             sun_path[n] = *s++;
15314bfa016SGlenn Strauss         else if (s[1] == 'x'
15414bfa016SGlenn Strauss                  && (hi = hex2int(s[2])) != 0xFF
15514bfa016SGlenn Strauss                  && (lo = hex2int(s[3])) != 0xFF) {
15614bfa016SGlenn Strauss             sun_path[n] = (char)((hi << 4) | lo);
15714bfa016SGlenn Strauss             s += 4;
15814bfa016SGlenn Strauss         }
15914bfa016SGlenn Strauss         else
16014bfa016SGlenn Strauss             break;
16114bfa016SGlenn Strauss     }
16214bfa016SGlenn Strauss     return *s == '\0' ? n : 0;
16314bfa016SGlenn Strauss }
16414bfa016SGlenn Strauss 
16514bfa016SGlenn Strauss __attribute_cold__
16614bfa016SGlenn Strauss static int
network_abstract_socket_parse(const buffer * abstract,sock_addr * addr,socklen_t * addr_len,log_error_st * errh)16714bfa016SGlenn Strauss network_abstract_socket_parse (const buffer *abstract,
16814bfa016SGlenn Strauss                                sock_addr *addr, socklen_t *addr_len,
16914bfa016SGlenn Strauss                                log_error_st *errh)
17014bfa016SGlenn Strauss {
17114bfa016SGlenn Strauss     /* abstract socket (Linux, QNX?, Windows 10?) */
17214bfa016SGlenn Strauss     /*assert(*addr_len >= sizeof(struct sockaddr_un));*/
17314bfa016SGlenn Strauss     memset(addr, 0, sizeof(struct sockaddr_un));
17414bfa016SGlenn Strauss     addr->un.sun_family = AF_UNIX;
17514bfa016SGlenn Strauss     uint32_t len =
17614bfa016SGlenn Strauss       (uint32_t)(*addr_len - offsetof(struct sockaddr_un, sun_path));
17714bfa016SGlenn Strauss     if (len > sizeof(addr->un.sun_path))
17814bfa016SGlenn Strauss         len = sizeof(addr->un.sun_path);
17914bfa016SGlenn Strauss     len = network_abstract_socket_dec(abstract, addr->un.sun_path, len);
18014bfa016SGlenn Strauss     if (len) {
18114bfa016SGlenn Strauss         *addr_len = offsetof(struct sockaddr_un, sun_path) + len;
18214bfa016SGlenn Strauss         return 0;
18314bfa016SGlenn Strauss     }
18414bfa016SGlenn Strauss     else {
18514bfa016SGlenn Strauss         log_error(errh, __FILE__, __LINE__,
18614bfa016SGlenn Strauss           "abstract unix socket filename invalid encoding or too long: %s",
18714bfa016SGlenn Strauss           abstract->ptr);
18814bfa016SGlenn Strauss         return -1;
18914bfa016SGlenn Strauss     }
19014bfa016SGlenn Strauss }
19114bfa016SGlenn Strauss 
19214bfa016SGlenn Strauss #endif /* HAVE_SYS_UN_H */
19314bfa016SGlenn Strauss 
network_host_normalize_addr_str(buffer * host,sock_addr * addr,socklen_t addr_len)19414bfa016SGlenn Strauss static void network_host_normalize_addr_str(buffer *host, sock_addr *addr, socklen_t addr_len) {
195f69bd9cdSGlenn Strauss     buffer_clear(host);
1961367f606SGlenn Strauss     sock_addr_stringify_append_buffer(host, addr);
19714bfa016SGlenn Strauss   #ifdef HAVE_SYS_UN_H
19814bfa016SGlenn Strauss     if (AF_UNIX == sock_addr_get_family(addr) && 0 == buffer_clen(host))
19914bfa016SGlenn Strauss         network_abstract_socket_enc(host, (unsigned char *)addr->un.sun_path,
20014bfa016SGlenn Strauss                                     (uint32_t)(addr_len
20114bfa016SGlenn Strauss                                     - offsetof(struct sockaddr_un, sun_path)));
20214bfa016SGlenn Strauss   #else
20314bfa016SGlenn Strauss     UNUSED(addr_len);
20414bfa016SGlenn Strauss   #endif
2053549fc82SGlenn Strauss }
2063549fc82SGlenn Strauss 
network_host_parse_addr(server * srv,sock_addr * addr,socklen_t * addr_len,buffer * host,int use_ipv6)2073549fc82SGlenn Strauss static int network_host_parse_addr(server *srv, sock_addr *addr, socklen_t *addr_len, buffer *host, int use_ipv6) {
2083549fc82SGlenn Strauss     char *h;
2093549fc82SGlenn Strauss     char *colon = NULL;
2103549fc82SGlenn Strauss     const char *chost;
2113549fc82SGlenn Strauss     sa_family_t family = use_ipv6 ? AF_INET6 : AF_INET;
2123549fc82SGlenn Strauss     unsigned int port = srv->srvconf.port;
213af3df29aSGlenn Strauss     if (buffer_is_blank(host)) {
214010c2894SGlenn Strauss         log_error(srv->errh, __FILE__, __LINE__,
215010c2894SGlenn Strauss           "value of $SERVER[\"socket\"] must not be empty");
2163549fc82SGlenn Strauss         return -1;
2173549fc82SGlenn Strauss     }
2183549fc82SGlenn Strauss     h = host->ptr;
21914bfa016SGlenn Strauss     if (h[0] == '/' || h[0] == '\\') {
2203549fc82SGlenn Strauss       #ifdef HAVE_SYS_UN_H
22114bfa016SGlenn Strauss         if (h[0] == '\\' && h[1] == 'x' && h[2] == '0' && h[3] == '0')
22214bfa016SGlenn Strauss             return network_abstract_socket_parse(host,addr,addr_len,srv->errh);
223010c2894SGlenn Strauss         return (1 ==
224010c2894SGlenn Strauss                 sock_addr_from_str_hints(addr,addr_len,h,AF_UNIX,0,srv->errh))
2253549fc82SGlenn Strauss           ? 0
2263549fc82SGlenn Strauss           : -1;
2273549fc82SGlenn Strauss       #else
22814bfa016SGlenn Strauss         log_error(srv->errh, __FILE__, __LINE__,
2293549fc82SGlenn Strauss           "ERROR: Unix Domain sockets are not supported.");
2303549fc82SGlenn Strauss         return -1;
2313549fc82SGlenn Strauss       #endif
2323549fc82SGlenn Strauss     }
233ca97505aSGlenn Strauss     buffer * const tb = srv->tmp_buf;
234ca97505aSGlenn Strauss     buffer_copy_buffer(tb, host);
235ca97505aSGlenn Strauss     h = tb->ptr;
2363549fc82SGlenn Strauss     if (h[0] == '[') {
2373549fc82SGlenn Strauss         family = AF_INET6;
2383549fc82SGlenn Strauss         if ((h = strchr(h, ']'))) {
2393549fc82SGlenn Strauss             *h++ = '\0';
2403549fc82SGlenn Strauss             if (*h == ':') colon = h;
2413549fc82SGlenn Strauss         } /*(else should not happen; validated in configparser.y)*/
242ca97505aSGlenn Strauss         h = tb->ptr+1;
2433549fc82SGlenn Strauss     }
2443549fc82SGlenn Strauss     else {
2453549fc82SGlenn Strauss         colon = strrchr(h, ':');
2463549fc82SGlenn Strauss     }
2473549fc82SGlenn Strauss     if (colon) {
2483549fc82SGlenn Strauss         *colon++ = '\0';
249cbdbd60bSGlenn Strauss         port = (unsigned int)strtol(colon, NULL, 10);
2503549fc82SGlenn Strauss         if (port == 0 || port > 65535) {
251010c2894SGlenn Strauss             log_error(srv->errh, __FILE__, __LINE__,
252cbdbd60bSGlenn Strauss               "port not set or out of range: %u", port);
2533549fc82SGlenn Strauss             return -1;
2543549fc82SGlenn Strauss         }
2553549fc82SGlenn Strauss     }
256086945bfSGlenn Strauss     if (h[0] == '*' && h[1] == '\0') {
257086945bfSGlenn Strauss         family = AF_INET;
258086945bfSGlenn Strauss         ++h;
259086945bfSGlenn Strauss     }
2603549fc82SGlenn Strauss     chost = *h ? h : family == AF_INET ? "0.0.0.0" : "::";
261010c2894SGlenn Strauss     if (1 !=
262010c2894SGlenn Strauss         sock_addr_from_str_hints(addr,addr_len,chost,family,port,srv->errh)) {
2633549fc82SGlenn Strauss         return -1;
2643549fc82SGlenn Strauss     }
2653549fc82SGlenn Strauss     return 0;
2663549fc82SGlenn Strauss }
2673549fc82SGlenn Strauss 
network_srv_sockets_append(server * srv,server_socket * srv_socket)2685b0e27f8SGlenn Strauss static void network_srv_sockets_append(server *srv, server_socket *srv_socket) {
269c412bb59SGlenn Strauss     server_socket_array * const srv_sockets = &srv->srv_sockets;
270c412bb59SGlenn Strauss     if (!(srv_sockets->used & (4-1)))
271c412bb59SGlenn Strauss         ck_realloc_u32((void **)&srv_sockets->ptr, srv_sockets->used,
272c412bb59SGlenn Strauss                        4, sizeof(*srv_sockets->ptr));
273c412bb59SGlenn Strauss     srv_sockets->ptr[srv_sockets->used++] = srv_socket;
2745b0e27f8SGlenn Strauss }
2755b0e27f8SGlenn Strauss 
276ed62e354SGlenn Strauss typedef struct {
277ed62e354SGlenn Strauss     /* global or per-socket config; not patched per connection */
278ed62e354SGlenn Strauss     int listen_backlog;
279ed62e354SGlenn Strauss     unsigned char ssl_enabled;
280ed62e354SGlenn Strauss     unsigned char use_ipv6;
281ed62e354SGlenn Strauss     unsigned char set_v6only; /* set_v6only is only a temporary option */
282ed62e354SGlenn Strauss     unsigned char defer_accept;
283025f2d0dSGlenn Strauss     int8_t v4mapped;
284ed62e354SGlenn Strauss     const buffer *socket_perms;
285ed62e354SGlenn Strauss     const buffer *bsd_accept_filter;
286ed62e354SGlenn Strauss } network_socket_config;
287ed62e354SGlenn Strauss 
288ed62e354SGlenn Strauss typedef struct {
289ed62e354SGlenn Strauss     PLUGIN_DATA;
290ed62e354SGlenn Strauss     network_socket_config defaults;
291ed62e354SGlenn Strauss     network_socket_config conf;
292ed62e354SGlenn Strauss } network_plugin_data;
293ed62e354SGlenn Strauss 
network_merge_config_cpv(network_socket_config * const pconf,const config_plugin_value_t * const cpv)294ed62e354SGlenn Strauss static void network_merge_config_cpv(network_socket_config * const pconf, const config_plugin_value_t * const cpv) {
295ed62e354SGlenn Strauss     switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
296ed62e354SGlenn Strauss       case 0: /* ssl.engine */
297ed62e354SGlenn Strauss         pconf->ssl_enabled = (0 != cpv->v.u);
298ed62e354SGlenn Strauss         break;
299ed62e354SGlenn Strauss       case 1: /* server.listen-backlog */
300ed62e354SGlenn Strauss         pconf->listen_backlog = (int)cpv->v.u;
301ed62e354SGlenn Strauss         break;
302ed62e354SGlenn Strauss       case 2: /* server.socket-perms */
303ed62e354SGlenn Strauss         pconf->socket_perms = cpv->v.b;
304ed62e354SGlenn Strauss         break;
305ed62e354SGlenn Strauss       case 3: /* server.bsd-accept-filter */
306ed62e354SGlenn Strauss         pconf->bsd_accept_filter = cpv->v.b;
307ed62e354SGlenn Strauss         break;
308ed62e354SGlenn Strauss       case 4: /* server.defer-accept */
309ed62e354SGlenn Strauss         pconf->defer_accept = (0 != cpv->v.u);
310ed62e354SGlenn Strauss         break;
311ed62e354SGlenn Strauss       case 5: /* server.use-ipv6 */
312ed62e354SGlenn Strauss         pconf->use_ipv6 = (0 != cpv->v.u);
313ed62e354SGlenn Strauss         break;
314ed62e354SGlenn Strauss       case 6: /* server.set-v6only */
315ed62e354SGlenn Strauss         pconf->set_v6only = (0 != cpv->v.u);
316ed62e354SGlenn Strauss         break;
317025f2d0dSGlenn Strauss       case 7: /* server.v4mapped */
318025f2d0dSGlenn Strauss         pconf->v4mapped = (0 != cpv->v.u);
319025f2d0dSGlenn Strauss         break;
320ed62e354SGlenn Strauss       default:/* should not happen */
321ed62e354SGlenn Strauss         return;
322ed62e354SGlenn Strauss     }
323ed62e354SGlenn Strauss }
324ed62e354SGlenn Strauss 
network_merge_config(network_socket_config * const pconf,const config_plugin_value_t * cpv)325ed62e354SGlenn Strauss static void network_merge_config(network_socket_config * const pconf, const config_plugin_value_t *cpv) {
326ed62e354SGlenn Strauss     do {
327ed62e354SGlenn Strauss         network_merge_config_cpv(pconf, cpv);
328ed62e354SGlenn Strauss     } while ((++cpv)->k_id != -1);
329ed62e354SGlenn Strauss }
330ed62e354SGlenn Strauss 
3315c2f5577SGlenn Strauss __attribute_pure__
network_srv_token_colon(const buffer * const b)3325c2f5577SGlenn Strauss static uint8_t network_srv_token_colon (const buffer * const b) {
3335c2f5577SGlenn Strauss     const char *colon = NULL;
3345c2f5577SGlenn Strauss     const char * const p = b->ptr;
3355c2f5577SGlenn Strauss     if (*p == '[') {
3365c2f5577SGlenn Strauss         colon = strstr(p, "]:");
3375c2f5577SGlenn Strauss         if (colon) ++colon;
3385c2f5577SGlenn Strauss     }
3395c2f5577SGlenn Strauss     else if (*p != '/') {
3405c2f5577SGlenn Strauss         colon = strchr(p, ':');
3415c2f5577SGlenn Strauss     }
342af3df29aSGlenn Strauss     return colon ? (uint8_t)(colon - p) : (uint8_t)buffer_clen(b);
3435c2f5577SGlenn Strauss }
3445c2f5577SGlenn Strauss 
network_srv_socket_init_token(server_socket * const srv_socket,const buffer * const token)34514bfa016SGlenn Strauss static void network_srv_socket_init_token (server_socket * const srv_socket, const buffer * const token) {
34614bfa016SGlenn Strauss     buffer * const srv_token = srv_socket->srv_token = buffer_init();
34714bfa016SGlenn Strauss     buffer_copy_buffer(srv_token, token);
34814bfa016SGlenn Strauss   #ifdef HAVE_SYS_UN_H
34914bfa016SGlenn Strauss     /*(srv_socket->addr must have been initialized by caller)*/
35014bfa016SGlenn Strauss     if (AF_UNIX == sock_addr_get_family(&srv_socket->addr))
35114bfa016SGlenn Strauss         srv_socket->srv_token_colon = buffer_clen(srv_token);
35214bfa016SGlenn Strauss     else
35314bfa016SGlenn Strauss   #endif
35414bfa016SGlenn Strauss         srv_socket->srv_token_colon = network_srv_token_colon(srv_token);
35514bfa016SGlenn Strauss }
35614bfa016SGlenn Strauss 
network_server_init(server * srv,const network_socket_config * s,buffer * host_token,size_t sidx,int stdin_fd)3575c4cc9f5SGlenn Strauss static int network_server_init(server *srv, const network_socket_config *s, buffer *host_token, size_t sidx, int stdin_fd) {
358bcdc6a3bSJan Kneschke 	server_socket *srv_socket;
359bcdc6a3bSJan Kneschke 	const char *host;
360f5ff2a01SGlenn Strauss 	socklen_t addr_len = sizeof(sock_addr);
3619a69f31bSGlenn Strauss 	sock_addr addr;
3621367f606SGlenn Strauss 	int family = 0;
3635c4cc9f5SGlenn Strauss 	int use_ipv6 = s->use_ipv6;
364f394207dSGlenn Strauss 	int set_v6only = 0;
365bcdc6a3bSJan Kneschke 
366af3df29aSGlenn Strauss 	if (buffer_is_blank(host_token)) {
367010c2894SGlenn Strauss 		log_error(srv->errh, __FILE__, __LINE__,
368010c2894SGlenn Strauss 		  "value of $SERVER[\"socket\"] must not be empty");
369f5ff2a01SGlenn Strauss 		return -1;
370f5ff2a01SGlenn Strauss 	}
371f5ff2a01SGlenn Strauss 
3729a69f31bSGlenn Strauss 	/* check if we already know this socket, and if yes, don't init it
3739a69f31bSGlenn Strauss 	 * (optimization: check strings here to filter out exact matches;
3749a69f31bSGlenn Strauss 	 *  binary addresses are matched further below) */
37562e97967SGlenn Strauss 	for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
3763f2561deSGlenn Strauss 		if (buffer_is_equal(srv->srv_sockets.ptr[i]->srv_token, host_token)) {
37793d64662SGlenn Strauss 			if ((unsigned short)~0u == srv->srv_sockets.ptr[i]->sidx) {
37893d64662SGlenn Strauss 				srv->srv_sockets.ptr[i]->sidx = sidx;
37993d64662SGlenn Strauss 				srv->srv_sockets.ptr[i]->is_ssl = s->ssl_enabled;
38093d64662SGlenn Strauss 			}
3819a69f31bSGlenn Strauss 			return 0;
38200d976b1SGlenn Strauss 		}
3833f2561deSGlenn Strauss 	}
384bcdc6a3bSJan Kneschke 
385f5ff2a01SGlenn Strauss 	host = host_token->ptr;
3865c4cc9f5SGlenn Strauss 	if ((use_ipv6 && (*host == '\0' || *host == ':')) || (host[0] == '[' && host[1] == ']')) {
387010c2894SGlenn Strauss 		log_error(srv->errh, __FILE__, __LINE__,
388010c2894SGlenn Strauss 		  "warning: please use server.use-ipv6 only for hostnames, "
389010c2894SGlenn Strauss 		  "not without server.bind / empty address; your config will "
390010c2894SGlenn Strauss 		  "break if the kernel default for IPV6_V6ONLY changes");
3915248b46cSGlenn Strauss 	}
3925c4cc9f5SGlenn Strauss 	if (*host == '[') use_ipv6 = 1;
393a69a803eSGlenn Strauss 
3949a69f31bSGlenn Strauss 	memset(&addr, 0, sizeof(addr));
3959a69f31bSGlenn Strauss 	if (-1 != stdin_fd) {
3969a69f31bSGlenn Strauss 		if (-1 == getsockname(stdin_fd, (struct sockaddr *)&addr, &addr_len)) {
397010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__, "getsockname()");
3989a69f31bSGlenn Strauss 			return -1;
3999a69f31bSGlenn Strauss 		}
4005c4cc9f5SGlenn Strauss 	} else if (0 != network_host_parse_addr(srv, &addr, &addr_len, host_token, use_ipv6)) {
40100d976b1SGlenn Strauss 		return -1;
4026c35e38fSGlenn Strauss 	}
403f394207dSGlenn Strauss 
4041367f606SGlenn Strauss 	family = sock_addr_get_family(&addr);
4051367f606SGlenn Strauss 
406f394207dSGlenn Strauss       #ifdef HAVE_IPV6
4071367f606SGlenn Strauss 	if (*host != '\0' && AF_INET6 == family) {
408f394207dSGlenn Strauss 		if (s->set_v6only) {
409f394207dSGlenn Strauss 			set_v6only = 1;
410f394207dSGlenn Strauss 		} else {
411010c2894SGlenn Strauss 			log_error(srv->errh, __FILE__, __LINE__,
412010c2894SGlenn Strauss 			  "warning: server.set-v6only will be removed soon, "
413010c2894SGlenn Strauss 			  "update your config to have different sockets for ipv4 and ipv6");
414f394207dSGlenn Strauss 		}
415f394207dSGlenn Strauss 	}
416025f2d0dSGlenn Strauss 	if (AF_INET6 == family && -1 != s->v4mapped) { /*(configured; -1 is unset)*/
417f8369910SGlenn Strauss 		set_v6only = (s->v4mapped ? -1 : 1);
418025f2d0dSGlenn Strauss 	}
419f394207dSGlenn Strauss       #endif
420f394207dSGlenn Strauss 
42114bfa016SGlenn Strauss 	network_host_normalize_addr_str(host_token, &addr, addr_len);
422f5ff2a01SGlenn Strauss 	host = host_token->ptr;
423292309f8SGlenn Strauss 
4246c35e38fSGlenn Strauss 	if (srv->srvconf.preflight_check) {
42500d976b1SGlenn Strauss 		return 0;
4266c35e38fSGlenn Strauss 	}
4276c35e38fSGlenn Strauss 
4289a69f31bSGlenn Strauss 	/* check if we already know this socket (after potential DNS resolution), and if yes, don't init it */
42962e97967SGlenn Strauss 	for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
4303f2561deSGlenn Strauss 		if (0 == memcmp(&srv->srv_sockets.ptr[i]->addr, &addr, sizeof(addr))) {
431da8025fbSGlenn Strauss 			if ((unsigned short)~0u == srv->srv_sockets.ptr[i]->sidx) {
432da8025fbSGlenn Strauss 				srv->srv_sockets.ptr[i]->sidx = sidx;
433da8025fbSGlenn Strauss 				srv->srv_sockets.ptr[i]->is_ssl = s->ssl_enabled;
434da8025fbSGlenn Strauss 			}
4359a69f31bSGlenn Strauss 			return 0;
4369a69f31bSGlenn Strauss 		}
4373f2561deSGlenn Strauss 	}
4389a69f31bSGlenn Strauss 
4395e14db43SGlenn Strauss 	srv_socket = ck_calloc(1, sizeof(*srv_socket));
4409a69f31bSGlenn Strauss 	memcpy(&srv_socket->addr, &addr, addr_len);
4419a69f31bSGlenn Strauss 	srv_socket->fd = -1;
4429a69f31bSGlenn Strauss 	srv_socket->sidx = sidx;
4436886e78bSGlenn Strauss 	srv_socket->is_ssl = s->ssl_enabled;
44405cc88ddSGlenn Strauss 	srv_socket->srv = srv;
44514bfa016SGlenn Strauss 	network_srv_socket_init_token(srv_socket, host_token);
4465b0e27f8SGlenn Strauss 	network_srv_sockets_append(srv, srv_socket);
4479a69f31bSGlenn Strauss 
4481812f554SGlenn Strauss 	if (srv->sockets_disabled) { /* lighttpd -1 (one-shot mode) */
44900d976b1SGlenn Strauss 		return 0;
4501812f554SGlenn Strauss 	}
4511812f554SGlenn Strauss 
452ce7b47c0SGlenn Strauss 	if (srv->srvconf.systemd_socket_activation) {
45362e97967SGlenn Strauss 		for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
454ce7b47c0SGlenn Strauss 			if (0 != memcmp(&srv->srv_sockets_inherited.ptr[i]->addr, &srv_socket->addr, addr_len)) continue;
455ce7b47c0SGlenn Strauss 			if ((unsigned short)~0u == srv->srv_sockets_inherited.ptr[i]->sidx) {
456ce7b47c0SGlenn Strauss 				srv->srv_sockets_inherited.ptr[i]->sidx = sidx;
457ce7b47c0SGlenn Strauss 			}
458ce7b47c0SGlenn Strauss 			stdin_fd = srv->srv_sockets_inherited.ptr[i]->fd;
459ce7b47c0SGlenn Strauss 			break;
460ce7b47c0SGlenn Strauss 		}
461ce7b47c0SGlenn Strauss 	}
462ce7b47c0SGlenn Strauss 
4639a69f31bSGlenn Strauss 	if (-1 != stdin_fd) {
4649a69f31bSGlenn Strauss 		srv_socket->fd = stdin_fd;
46548004c6aSGlenn Strauss 		if (-1 == fdevent_fcntl_set_nb_cloexec(stdin_fd)) {
466010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__, "fcntl");
46760a98ebaSGlenn Strauss 			return -1;
46860a98ebaSGlenn Strauss 		}
4699a69f31bSGlenn Strauss 	} else
4706c35e38fSGlenn Strauss #ifdef HAVE_SYS_UN_H
4711367f606SGlenn Strauss 	if (AF_UNIX == family) {
4720f437f2cSJan Kneschke 		/* check if the socket exists and try to connect to it. */
473879a282dSGlenn Strauss 		force_assert(host); /*(static analysis hint)*/
4741367f606SGlenn Strauss 		if (-1 == (srv_socket->fd = fdevent_socket_cloexec(AF_UNIX, SOCK_STREAM, 0))) {
475010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__, "socket");
47600d976b1SGlenn Strauss 			return -1;
4776c35e38fSGlenn Strauss 		}
4786c35e38fSGlenn Strauss 		if (0 == connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
479010c2894SGlenn Strauss 			log_error(srv->errh, __FILE__, __LINE__,
480010c2894SGlenn Strauss 			  "server socket is still in use: %s", host);
48100d976b1SGlenn Strauss 			return -1;
4820f437f2cSJan Kneschke 		}
4830f437f2cSJan Kneschke 
4840f437f2cSJan Kneschke 		/* connect failed */
4850f437f2cSJan Kneschke 		switch(errno) {
4860f437f2cSJan Kneschke 		case ECONNREFUSED:
48714bfa016SGlenn Strauss 			if (*host == '/') unlink(host);
4880f437f2cSJan Kneschke 			break;
4890f437f2cSJan Kneschke 		case ENOENT:
4900f437f2cSJan Kneschke 			break;
4910f437f2cSJan Kneschke 		default:
492010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__,
493010c2894SGlenn Strauss 			  "testing socket failed: %s", host);
49400d976b1SGlenn Strauss 			return -1;
4950f437f2cSJan Kneschke 		}
49693afda9cSGlenn Strauss 
49748004c6aSGlenn Strauss 		if (-1 == fdevent_fcntl_set_nb(srv_socket->fd)) {
498010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__, "fcntl");
49978f24ba1SGlenn Strauss 			return -1;
50078f24ba1SGlenn Strauss 		}
5016c35e38fSGlenn Strauss 	} else
5026c35e38fSGlenn Strauss #endif
5036c35e38fSGlenn Strauss 	{
5041367f606SGlenn Strauss 		if (-1 == (srv_socket->fd = fdevent_socket_nb_cloexec(family, SOCK_STREAM, IPPROTO_TCP))) {
505010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__, "socket");
50600d976b1SGlenn Strauss 			return -1;
507bcdc6a3bSJan Kneschke 		}
508bcdc6a3bSJan Kneschke 
5096c35e38fSGlenn Strauss #ifdef HAVE_IPV6
510025f2d0dSGlenn Strauss 		if (set_v6only) {
511025f2d0dSGlenn Strauss 				int val = (set_v6only > 0);
5126c35e38fSGlenn Strauss 				if (-1 == setsockopt(srv_socket->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
513010c2894SGlenn Strauss 					log_perror(srv->errh, __FILE__, __LINE__, "setsockopt(IPV6_V6ONLY)");
51400d976b1SGlenn Strauss 					return -1;
5156c35e38fSGlenn Strauss 				}
5166c35e38fSGlenn Strauss 		}
5176c35e38fSGlenn Strauss #endif
518025f2d0dSGlenn Strauss 	}
5196c35e38fSGlenn Strauss 
5206c35e38fSGlenn Strauss 	/* */
5216c35e38fSGlenn Strauss 	srv->cur_fds = srv_socket->fd;
5226c35e38fSGlenn Strauss 
52393e91954SGlenn Strauss 	if (fdevent_set_so_reuseaddr(srv_socket->fd, 1) < 0) {
524010c2894SGlenn Strauss 		log_perror(srv->errh, __FILE__, __LINE__, "setsockopt(SO_REUSEADDR)");
52500d976b1SGlenn Strauss 		return -1;
526292309f8SGlenn Strauss 	}
527292309f8SGlenn Strauss 
5281367f606SGlenn Strauss 	if (family != AF_UNIX) {
52993e91954SGlenn Strauss 		if (fdevent_set_tcp_nodelay(srv_socket->fd, 1) < 0) {
530010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__, "setsockopt(TCP_NODELAY)");
53100d976b1SGlenn Strauss 			return -1;
532416b5729SGlenn Strauss 		}
533416b5729SGlenn Strauss 	}
534416b5729SGlenn Strauss 
5355c25f629SGlenn Strauss 	if (-1 != stdin_fd) { } else
536bcdc6a3bSJan Kneschke 	if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
537010c2894SGlenn Strauss 		log_perror(srv->errh, __FILE__, __LINE__,
538010c2894SGlenn Strauss 		  "can't bind to socket: %s", host);
53900d976b1SGlenn Strauss 		return -1;
540bcdc6a3bSJan Kneschke 	}
541bcdc6a3bSJan Kneschke 
54214bfa016SGlenn Strauss   #ifdef HAVE_SYS_UN_H
5435c25f629SGlenn Strauss 	if (-1 != stdin_fd) { } else
544af3df29aSGlenn Strauss 	if (AF_UNIX == family && s->socket_perms) {
545d15ddcb6SGlenn Strauss 		mode_t m = 0;
546d15ddcb6SGlenn Strauss 		for (char *str = s->socket_perms->ptr; *str; ++str) {
547d15ddcb6SGlenn Strauss 			m <<= 3;
548d15ddcb6SGlenn Strauss 			m |= (*str - '0');
549d15ddcb6SGlenn Strauss 		}
55014bfa016SGlenn Strauss 		if (0 != m && *host == '/' && -1 == chmod(host, m)) {
551010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__,
552010c2894SGlenn Strauss 			  "chmod(\"%s\", %s)", host, s->socket_perms->ptr);
553ed088f57SGlenn Strauss 			return -1;
554d15ddcb6SGlenn Strauss 		}
555d15ddcb6SGlenn Strauss 	}
55614bfa016SGlenn Strauss   #endif
557d15ddcb6SGlenn Strauss 
5585c25f629SGlenn Strauss 	if (-1 != stdin_fd) { } else
55919d2190aSGlenn Strauss 	if (-1 == listen(srv_socket->fd, s->listen_backlog)) {
560010c2894SGlenn Strauss 		log_perror(srv->errh, __FILE__, __LINE__, "listen");
56100d976b1SGlenn Strauss 		return -1;
56219d2190aSGlenn Strauss 	}
56319d2190aSGlenn Strauss 
5646886e78bSGlenn Strauss 	if (s->ssl_enabled) {
5657eac25acSGlenn Strauss 	}
5660226d4bfSStefan Bühler #ifdef TCP_DEFER_ACCEPT
5677eac25acSGlenn Strauss 	else if (s->defer_accept) {
5680226d4bfSStefan Bühler 		int v = s->defer_accept;
5690226d4bfSStefan Bühler 		if (-1 == setsockopt(srv_socket->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &v, sizeof(v))) {
570010c2894SGlenn Strauss 			log_perror(srv->errh, __FILE__, __LINE__, "can't set TCP_DEFER_ACCEPT");
5710226d4bfSStefan Bühler 		}
5727eac25acSGlenn Strauss 	}
5730226d4bfSStefan Bühler #endif
5744eeeb8fcSGlenn Strauss #if defined(__FreeBSD__) || defined(__NetBSD__) \
5756ec66c4dSGlenn Strauss  || defined(__OpenBSD__) || defined(__DragonFly__)
5767eac25acSGlenn Strauss #ifdef SO_ACCEPTFILTER
5777eac25acSGlenn Strauss 	else if (s->bsd_accept_filter
5784eeeb8fcSGlenn Strauss 		   && (buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("httpready"))
5794eeeb8fcSGlenn Strauss 			|| buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("dataready")))) {
5800226d4bfSStefan Bühler 		/* FreeBSD accf_http filter */
5810226d4bfSStefan Bühler 		struct accept_filter_arg afa;
582279af959SJan Kneschke 		memset(&afa, 0, sizeof(afa));
583eb4f9533SGlenn Strauss 		strncpy(afa.af_name, s->bsd_accept_filter->ptr, sizeof(afa.af_name)-1);
584279af959SJan Kneschke 		if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
585279af959SJan Kneschke 			if (errno != ENOENT) {
586010c2894SGlenn Strauss 				log_perror(srv->errh, __FILE__, __LINE__,
587010c2894SGlenn Strauss 				  "can't set accept-filter '%s'", s->bsd_accept_filter->ptr);
588279af959SJan Kneschke 			}
589279af959SJan Kneschke 		}
590bcdc6a3bSJan Kneschke 	}
5917eac25acSGlenn Strauss #endif
5927eac25acSGlenn Strauss #endif
593bcdc6a3bSJan Kneschke 
594bcdc6a3bSJan Kneschke 	return 0;
595bcdc6a3bSJan Kneschke }
596bcdc6a3bSJan Kneschke 
network_close(server * srv)597bcdc6a3bSJan Kneschke int network_close(server *srv) {
59862e97967SGlenn Strauss 	for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
599bcdc6a3bSJan Kneschke 		server_socket *srv_socket = srv->srv_sockets.ptr[i];
6005c20c426SJan Kneschke 		if (srv_socket->fd != -1) {
6016c1e6e66SGlenn Strauss 			network_unregister_sock(srv, srv_socket);
602bcdc6a3bSJan Kneschke 			close(srv_socket->fd);
603bcdc6a3bSJan Kneschke 		}
604bcdc6a3bSJan Kneschke 
605bcdc6a3bSJan Kneschke 		buffer_free(srv_socket->srv_token);
606bcdc6a3bSJan Kneschke 
607bcdc6a3bSJan Kneschke 		free(srv_socket);
608bcdc6a3bSJan Kneschke 	}
609bcdc6a3bSJan Kneschke 
610bcdc6a3bSJan Kneschke 	free(srv->srv_sockets.ptr);
6116c1e6e66SGlenn Strauss 	srv->srv_sockets.ptr = NULL;
6126c1e6e66SGlenn Strauss 	srv->srv_sockets.used = 0;
613bcdc6a3bSJan Kneschke 
61462e97967SGlenn Strauss 	for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
615ce7b47c0SGlenn Strauss 		server_socket *srv_socket = srv->srv_sockets_inherited.ptr[i];
616ce7b47c0SGlenn Strauss 		if (srv_socket->fd != -1 && srv_socket->sidx != (unsigned short)~0u) {
617ce7b47c0SGlenn Strauss 			close(srv_socket->fd);
618ce7b47c0SGlenn Strauss 		}
619ce7b47c0SGlenn Strauss 
620ce7b47c0SGlenn Strauss 		buffer_free(srv_socket->srv_token);
621ce7b47c0SGlenn Strauss 
622ce7b47c0SGlenn Strauss 		free(srv_socket);
623ce7b47c0SGlenn Strauss 	}
624ce7b47c0SGlenn Strauss 
625ce7b47c0SGlenn Strauss 	free(srv->srv_sockets_inherited.ptr);
626ce7b47c0SGlenn Strauss 	srv->srv_sockets_inherited.ptr = NULL;
627ce7b47c0SGlenn Strauss 	srv->srv_sockets_inherited.used = 0;
628ce7b47c0SGlenn Strauss 
629bcdc6a3bSJan Kneschke 	return 0;
630bcdc6a3bSJan Kneschke }
631bcdc6a3bSJan Kneschke 
network_socket_activation_to_env(server * const srv)632352d5d77SGlenn Strauss void network_socket_activation_to_env (server * const srv) {
633352d5d77SGlenn Strauss     /* set up listening sockets for systemd socket activation
634352d5d77SGlenn Strauss      * and ensure FD_CLOEXEC flag is not set on listen fds */
635352d5d77SGlenn Strauss     int fd = 3; /* #define SD_LISTEN_FDS_START 3 */
636352d5d77SGlenn Strauss     for (uint32_t n = 0, i; n < srv->srv_sockets.used; ++n) {
637352d5d77SGlenn Strauss         server_socket *srv_socket = srv->srv_sockets.ptr[n];
638352d5d77SGlenn Strauss         if (srv_socket->fd < fd) continue;
639352d5d77SGlenn Strauss         if (srv_socket->fd == fd) {
640352d5d77SGlenn Strauss             fdevent_clrfd_cloexec(fd);
641352d5d77SGlenn Strauss             ++fd;
642352d5d77SGlenn Strauss             continue;
643352d5d77SGlenn Strauss         }
644352d5d77SGlenn Strauss         /* (expecting ordered list, but check if fd is later in list)*/
645352d5d77SGlenn Strauss         for (i = n+1; i < srv->srv_sockets.used; ++i) {
646352d5d77SGlenn Strauss             if (fd == srv->srv_sockets.ptr[i]->fd)
647352d5d77SGlenn Strauss                 break;
648352d5d77SGlenn Strauss         }
649352d5d77SGlenn Strauss         if (i < srv->srv_sockets.used) {
650352d5d77SGlenn Strauss             fdevent_clrfd_cloexec(fd);
651352d5d77SGlenn Strauss             ++fd;
652352d5d77SGlenn Strauss             --n; /* loop to reprocess this entry */
653352d5d77SGlenn Strauss             continue;
654352d5d77SGlenn Strauss         }
655352d5d77SGlenn Strauss 
656352d5d77SGlenn Strauss         /* dup2() removes FD_CLOEXEC on newfd */
657352d5d77SGlenn Strauss         if (fd != dup2(srv_socket->fd, fd)) continue;
658352d5d77SGlenn Strauss         ++fd;
659352d5d77SGlenn Strauss         /* old fd will be closed upon execv() due to its FD_CLOEXEC flag
660352d5d77SGlenn Strauss          * (if not already closed by another dup2() over it) */
661352d5d77SGlenn Strauss     }
662352d5d77SGlenn Strauss     fd -= 3; /* now num fds; #define SD_LISTEN_FDS_START 3 */
663352d5d77SGlenn Strauss     if (0 == fd) return; /*(no active sockets?)*/
664352d5d77SGlenn Strauss     buffer * const tb = srv->tmp_buf;
665352d5d77SGlenn Strauss     buffer_clear(tb);
666352d5d77SGlenn Strauss     buffer_append_int(tb, fd);
667352d5d77SGlenn Strauss     setenv("LISTEN_FDS", tb->ptr, 1);
668352d5d77SGlenn Strauss     buffer_clear(tb);
669352d5d77SGlenn Strauss     buffer_append_int(tb, srv->pid); /* getpid() */
670352d5d77SGlenn Strauss     setenv("LISTEN_PID", tb->ptr, 1);
671352d5d77SGlenn Strauss }
672352d5d77SGlenn Strauss 
network_socket_activation_nfds(server * srv,const network_socket_config * s,int nfds)6735c4cc9f5SGlenn Strauss static int network_socket_activation_nfds(server *srv, const network_socket_config *s, int nfds) {
674ce7b47c0SGlenn Strauss     buffer *host = buffer_init();
675ce7b47c0SGlenn Strauss     socklen_t addr_len;
676ce7b47c0SGlenn Strauss     sock_addr addr;
677ce7b47c0SGlenn Strauss     int rc = 0;
678ce7b47c0SGlenn Strauss     nfds += 3; /* #define SD_LISTEN_FDS_START 3 */
679ce7b47c0SGlenn Strauss     for (int fd = 3; fd < nfds; ++fd) {
680ce7b47c0SGlenn Strauss         addr_len = sizeof(sock_addr);
681ce7b47c0SGlenn Strauss         if (-1 == (rc = getsockname(fd, (struct sockaddr *)&addr, &addr_len))) {
682010c2894SGlenn Strauss             log_perror(srv->errh, __FILE__, __LINE__,
683010c2894SGlenn Strauss               "socket activation getsockname()");
684ce7b47c0SGlenn Strauss             break;
685ce7b47c0SGlenn Strauss         }
68614bfa016SGlenn Strauss         network_host_normalize_addr_str(host, &addr, addr_len);
687ed62e354SGlenn Strauss         rc = network_server_init(srv, s, host, 0, fd);
688ce7b47c0SGlenn Strauss         if (0 != rc) break;
689ce7b47c0SGlenn Strauss         srv->srv_sockets.ptr[srv->srv_sockets.used-1]->sidx = (unsigned short)~0u;
690ce7b47c0SGlenn Strauss     }
691ce7b47c0SGlenn Strauss     buffer_free(host);
692ce7b47c0SGlenn Strauss     memcpy(&srv->srv_sockets_inherited, &srv->srv_sockets, sizeof(server_socket_array));
693ce7b47c0SGlenn Strauss     memset(&srv->srv_sockets, 0, sizeof(server_socket_array));
694ce7b47c0SGlenn Strauss     return rc;
695ce7b47c0SGlenn Strauss }
696b2ee667aSGlenn Strauss 
network_socket_activation_from_env(server * srv,const network_socket_config * s)6975c4cc9f5SGlenn Strauss static int network_socket_activation_from_env(server *srv, const network_socket_config *s) {
698ce7b47c0SGlenn Strauss     char *listen_pid = getenv("LISTEN_PID");
699ce7b47c0SGlenn Strauss     char *listen_fds = getenv("LISTEN_FDS");
700ce7b47c0SGlenn Strauss     pid_t lpid = listen_pid ? (pid_t)strtoul(listen_pid,NULL,10) : 0;
701ce7b47c0SGlenn Strauss     int nfds = listen_fds ? atoi(listen_fds) : 0;
7021e335b37SGlenn Strauss     int rc = (nfds > 0 && nfds < 5000
7031e335b37SGlenn Strauss               && (lpid == getpid()
7041e335b37SGlenn Strauss                  #ifndef _WIN32
7051e335b37SGlenn Strauss                   || (0 == strncmp(listen_pid, "parent:", 7)
7061e335b37SGlenn Strauss                       && getppid() == (pid_t)strtoul(listen_pid+7,NULL,10))
7071e335b37SGlenn Strauss                  #endif
7081e335b37SGlenn Strauss                  ))
709ed62e354SGlenn Strauss       ? network_socket_activation_nfds(srv, s, nfds)
710ce7b47c0SGlenn Strauss       : 0;
711ce7b47c0SGlenn Strauss     unsetenv("LISTEN_PID");
712ce7b47c0SGlenn Strauss     unsetenv("LISTEN_FDS");
713ce7b47c0SGlenn Strauss     unsetenv("LISTEN_FDNAMES");
714ce7b47c0SGlenn Strauss     /*(upon graceful restart, unsetenv will result in no-op above)*/
715ce7b47c0SGlenn Strauss     return rc;
716ce7b47c0SGlenn Strauss }
717ce7b47c0SGlenn Strauss 
network_init(server * srv,int stdin_fd)718ce7b47c0SGlenn Strauss int network_init(server *srv, int stdin_fd) {
719ed62e354SGlenn Strauss     /*(network params used during setup (from $SERVER["socket"] condition))*/
720ed62e354SGlenn Strauss     static const config_plugin_keys_t cpk[] = {
721ed62e354SGlenn Strauss       { CONST_STR_LEN("ssl.engine"),
722ed62e354SGlenn Strauss         T_CONFIG_BOOL,
723b1f7ccd7SGlenn Strauss         T_CONFIG_SCOPE_SOCKET }
724ed62e354SGlenn Strauss      ,{ CONST_STR_LEN("server.listen-backlog"),
725ed62e354SGlenn Strauss         T_CONFIG_INT,
726b1f7ccd7SGlenn Strauss         T_CONFIG_SCOPE_SOCKET }
727ed62e354SGlenn Strauss      ,{ CONST_STR_LEN("server.socket-perms"),
728ed62e354SGlenn Strauss         T_CONFIG_STRING,
729b1f7ccd7SGlenn Strauss         T_CONFIG_SCOPE_SOCKET }
730ed62e354SGlenn Strauss      ,{ CONST_STR_LEN("server.bsd-accept-filter"),
731ed62e354SGlenn Strauss         T_CONFIG_STRING,
732b1f7ccd7SGlenn Strauss         T_CONFIG_SCOPE_SOCKET }
733ed62e354SGlenn Strauss      ,{ CONST_STR_LEN("server.defer-accept"),
734ed62e354SGlenn Strauss         T_CONFIG_BOOL,
735b1f7ccd7SGlenn Strauss         T_CONFIG_SCOPE_SOCKET }
736ed62e354SGlenn Strauss      ,{ CONST_STR_LEN("server.use-ipv6"),
737ed62e354SGlenn Strauss         T_CONFIG_BOOL,
738b1f7ccd7SGlenn Strauss         T_CONFIG_SCOPE_SOCKET }
739ed62e354SGlenn Strauss      ,{ CONST_STR_LEN("server.set-v6only"),
740ed62e354SGlenn Strauss         T_CONFIG_BOOL,
741b1f7ccd7SGlenn Strauss         T_CONFIG_SCOPE_SOCKET }
742025f2d0dSGlenn Strauss      ,{ CONST_STR_LEN("server.v4mapped"),
743025f2d0dSGlenn Strauss         T_CONFIG_BOOL,
744b1f7ccd7SGlenn Strauss         T_CONFIG_SCOPE_SOCKET }
745ed62e354SGlenn Strauss      ,{ NULL, 0,
746ed62e354SGlenn Strauss         T_CONFIG_UNSET,
747ed62e354SGlenn Strauss         T_CONFIG_SCOPE_UNSET }
748ed62e354SGlenn Strauss     };
749ed62e354SGlenn Strauss 
750b2ee667aSGlenn Strauss   #ifdef __WIN32
751b2ee667aSGlenn Strauss     WSADATA wsaData;
752b2ee667aSGlenn Strauss     WORD wVersionRequested = MAKEWORD(2, 2);
753b2ee667aSGlenn Strauss     if (0 != WSAStartup(wVersionRequested, &wsaData)) {
754b2ee667aSGlenn Strauss         /* Tell the user that we could not find a usable WinSock DLL */
755b2ee667aSGlenn Strauss         return -1;
756b2ee667aSGlenn Strauss     }
757b2ee667aSGlenn Strauss   #endif
758b2ee667aSGlenn Strauss 
759142971a8SGlenn Strauss     if (0 != network_write_init(srv)) return -1;
760e290b119SJan Kneschke 
761ed62e354SGlenn Strauss     network_plugin_data np;
762ed62e354SGlenn Strauss     memset(&np, 0, sizeof(network_plugin_data));
763ed62e354SGlenn Strauss     network_plugin_data *p = &np;
764ed62e354SGlenn Strauss 
765ed62e354SGlenn Strauss     if (!config_plugin_values_init(srv, p, cpk, "network"))
766ed62e354SGlenn Strauss         return HANDLER_ERROR;
767ed62e354SGlenn Strauss 
768ed62e354SGlenn Strauss     p->defaults.listen_backlog = 1024;
769ed62e354SGlenn Strauss     p->defaults.defer_accept = 0;
770ed62e354SGlenn Strauss     p->defaults.use_ipv6 = 0;
771ed62e354SGlenn Strauss     p->defaults.set_v6only = 1;
772025f2d0dSGlenn Strauss     p->defaults.v4mapped = -1; /*(-1 for unset; not 0 or 1)*/
773ed62e354SGlenn Strauss 
774ed62e354SGlenn Strauss     /* initialize p->defaults from global config context */
775ed62e354SGlenn Strauss     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
776ed62e354SGlenn Strauss         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
777ed62e354SGlenn Strauss         if (-1 != cpv->k_id)
778ed62e354SGlenn Strauss             network_merge_config(&p->defaults, cpv);
779ed62e354SGlenn Strauss     }
780ed62e354SGlenn Strauss 
781564d8983SGlenn Strauss     if (config_feature_bool(srv, "server.graceful-restart-bg", 0))
782564d8983SGlenn Strauss         srv->srvconf.systemd_socket_activation = 1;
783564d8983SGlenn Strauss 
784ed62e354SGlenn Strauss     int rc = 0;
785ed62e354SGlenn Strauss     do {
786ed62e354SGlenn Strauss 
787ce7b47c0SGlenn Strauss         if (srv->srvconf.systemd_socket_activation) {
78862e97967SGlenn Strauss             for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
789ce7b47c0SGlenn Strauss                 srv->srv_sockets_inherited.ptr[i]->sidx = (unsigned short)~0u;
790ce7b47c0SGlenn Strauss             }
791ed62e354SGlenn Strauss             rc = network_socket_activation_from_env(srv, &p->defaults);
792ed62e354SGlenn Strauss             if (0 != rc) break;
793ce7b47c0SGlenn Strauss             if (0 == srv->srv_sockets_inherited.used) {
794ce7b47c0SGlenn Strauss                 srv->srvconf.systemd_socket_activation = 0;
795ce7b47c0SGlenn Strauss             }
796ce7b47c0SGlenn Strauss         }
797ce7b47c0SGlenn Strauss 
798ad8a27f3SGlenn Strauss         /* special-case srv->srvconf.bindhost = "/dev/stdin" (see server.c) */
799ad8a27f3SGlenn Strauss         if (-1 != stdin_fd) {
8009a69f31bSGlenn Strauss             buffer *b = buffer_init();
8019a69f31bSGlenn Strauss             buffer_copy_buffer(b, srv->srvconf.bindhost);
802ad8a27f3SGlenn Strauss             /*assert(buffer_eq_slen(b, CONST_STR_LEN("/dev/stdin")));*/
803ad8a27f3SGlenn Strauss             rc = (0 == srv->srv_sockets.used)
804ed62e354SGlenn Strauss               ? network_server_init(srv, &p->defaults, b, 0, stdin_fd)
8056b77372aSGlenn Strauss               : close(stdin_fd);/*(graceful restart listening to "/dev/stdin")*/
8069a69f31bSGlenn Strauss             buffer_free(b);
807ed62e354SGlenn Strauss             if (0 != rc) break;
8089a69f31bSGlenn Strauss         }
8099a69f31bSGlenn Strauss 
810bcdc6a3bSJan Kneschke         /* check for $SERVER["socket"] */
811d23071a3SGlenn Strauss         for (uint32_t i = 1; i < srv->config_context->used; ++i) {
812d23071a3SGlenn Strauss             config_cond_info cfginfo;
8137c7f8c46SGlenn Strauss             config_get_config_cond_info(&cfginfo, i);
814ed62e354SGlenn Strauss             if (COMP_SERVER_SOCKET != cfginfo.comp) continue;/* not our stage */
815ed62e354SGlenn Strauss 
816d23071a3SGlenn Strauss             buffer *host_token;
817d23071a3SGlenn Strauss             *(const buffer **)&host_token = cfginfo.string;
818d23071a3SGlenn Strauss             /*(cfginfo.string is modified during config)*/
819bcdc6a3bSJan Kneschke 
820ed62e354SGlenn Strauss             memcpy(&p->conf, &p->defaults, sizeof(network_socket_config));
821ed62e354SGlenn Strauss             for (int j = !p->cvlist[0].v.u2[1]; j < p->nconfig; ++j) {
822ed62e354SGlenn Strauss                 if ((int)i != p->cvlist[j].k_id) continue;
823ed62e354SGlenn Strauss                 const config_plugin_value_t *cpv =
824ed62e354SGlenn Strauss                   p->cvlist + p->cvlist[j].v.u2[0];
825ed62e354SGlenn Strauss                 network_merge_config(&p->conf, cpv);
826ed62e354SGlenn Strauss                 break;
827ed62e354SGlenn Strauss             }
828bcdc6a3bSJan Kneschke 
829ed62e354SGlenn Strauss             if (cfginfo.cond == CONFIG_COND_EQ) {
830ed62e354SGlenn Strauss                 rc = network_server_init(srv, &p->conf, host_token, i, -1);
831ed62e354SGlenn Strauss                 if (0 != rc) break;
832ed62e354SGlenn Strauss             }
833ed62e354SGlenn Strauss             else if (cfginfo.cond == CONFIG_COND_NE) {
8343549fc82SGlenn Strauss                 socklen_t addr_len = sizeof(sock_addr);
8353549fc82SGlenn Strauss                 sock_addr addr;
836ed62e354SGlenn Strauss                 rc = network_host_parse_addr(srv, &addr, &addr_len,
837ed62e354SGlenn Strauss                                              host_token, p->conf.use_ipv6);
838ed62e354SGlenn Strauss                 if (0 != rc) break;
83914bfa016SGlenn Strauss                 network_host_normalize_addr_str(host_token, &addr, addr_len);
8403549fc82SGlenn Strauss             }
841396d141eSJan Kneschke         }
842ed62e354SGlenn Strauss         if (0 != rc) break;
843bcdc6a3bSJan Kneschke 
844ad8a27f3SGlenn Strauss         /* process srv->srvconf.bindhost
845ad8a27f3SGlenn Strauss          * init global config for server.bindhost and server.port after
846ad8a27f3SGlenn Strauss          * initializing $SERVER["socket"] so that if bindhost and port match
847ad8a27f3SGlenn Strauss          * another $SERVER["socket"], the $SERVER["socket"] config is used,
848ad8a27f3SGlenn Strauss          * as the $SERVER["socket"] config inherits from the global scope and
849ad8a27f3SGlenn Strauss          * can then be overridden.  (bindhost = "/dev/stdin" is handled above)
850ad8a27f3SGlenn Strauss          * (skip if systemd socket activation is enabled and bindhost is empty;
851ad8a27f3SGlenn Strauss          *  do not additionally listen on "*") */
852ad8a27f3SGlenn Strauss         if ((!srv->srvconf.systemd_socket_activation || srv->srvconf.bindhost)
853ad8a27f3SGlenn Strauss             && -1 == stdin_fd) {
854ad8a27f3SGlenn Strauss             buffer *b = buffer_init();
855ad8a27f3SGlenn Strauss             if (srv->srvconf.bindhost)
856ad8a27f3SGlenn Strauss                 buffer_copy_buffer(b, srv->srvconf.bindhost);
857ad8a27f3SGlenn Strauss             /*(skip adding port if unix socket path)*/
85814bfa016SGlenn Strauss             if (!b->ptr || (b->ptr[0] != '/' && b->ptr[0] != '\\')) {
859f2610d23SGlenn Strauss                 buffer_append_char(b, ':');
860ad8a27f3SGlenn Strauss                 buffer_append_int(b, srv->srvconf.port);
861ad8a27f3SGlenn Strauss             }
862f99cb7d7SGlenn Strauss           #ifdef __COVERITY__
863f99cb7d7SGlenn Strauss             force_assert(b->ptr);
864f99cb7d7SGlenn Strauss           #endif
865ad8a27f3SGlenn Strauss 
866ad8a27f3SGlenn Strauss             rc = network_server_init(srv, &p->defaults, b, 0, -1);
867ad8a27f3SGlenn Strauss             buffer_free(b);
868ad8a27f3SGlenn Strauss             if (0 != rc) break;
869ad8a27f3SGlenn Strauss         }
870ad8a27f3SGlenn Strauss 
871ce7b47c0SGlenn Strauss         if (srv->srvconf.systemd_socket_activation) {
872ed62e354SGlenn Strauss             /* activate any inherited sockets not explicitly listed in config */
873ce7b47c0SGlenn Strauss             server_socket *srv_socket;
87462e97967SGlenn Strauss             for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
875ed62e354SGlenn Strauss                     if ((unsigned short)~0u
876ed62e354SGlenn Strauss                         != srv->srv_sockets_inherited.ptr[i]->sidx)
877ed62e354SGlenn Strauss                         continue;
878ce7b47c0SGlenn Strauss                     srv->srv_sockets_inherited.ptr[i]->sidx = 0;
8795e14db43SGlenn Strauss                 srv_socket = ck_calloc(1, sizeof(server_socket));
880ed62e354SGlenn Strauss                 memcpy(srv_socket, srv->srv_sockets_inherited.ptr[i],
881ed62e354SGlenn Strauss                        sizeof(server_socket));
882da8025fbSGlenn Strauss                 srv_socket->is_ssl = p->defaults.ssl_enabled;
88314bfa016SGlenn Strauss                 /*(note: re-inits srv_socket->srv_token to new buffer ptr)*/
88414bfa016SGlenn Strauss                 network_srv_socket_init_token(srv_socket,srv_socket->srv_token);
885ce7b47c0SGlenn Strauss                 network_srv_sockets_append(srv, srv_socket);
886ce7b47c0SGlenn Strauss             }
887ce7b47c0SGlenn Strauss         }
888ce7b47c0SGlenn Strauss 
889da8025fbSGlenn Strauss         /* reset sidx of any graceful sockets not explicitly listed in config */
890da8025fbSGlenn Strauss         for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
891da8025fbSGlenn Strauss             if ((unsigned short)~0u == srv->srv_sockets.ptr[i]->sidx) {
892da8025fbSGlenn Strauss                 srv->srv_sockets.ptr[i]->sidx = 0;
893da8025fbSGlenn Strauss                 srv->srv_sockets.ptr[i]->is_ssl = p->defaults.ssl_enabled;
894da8025fbSGlenn Strauss             }
895da8025fbSGlenn Strauss         }
896da8025fbSGlenn Strauss 
897ed62e354SGlenn Strauss     } while (0);
898ed62e354SGlenn Strauss 
899ed62e354SGlenn Strauss     free(p->cvlist);
900ed62e354SGlenn Strauss     return rc;
901bcdc6a3bSJan Kneschke }
902bcdc6a3bSJan Kneschke 
network_unregister_sock(server * srv,server_socket * srv_socket)9036c1e6e66SGlenn Strauss void network_unregister_sock(server *srv, server_socket *srv_socket) {
9049113011dSGlenn Strauss 	fdnode *fdn = srv_socket->fdn;
9059113011dSGlenn Strauss 	if (NULL == fdn) return;
9069113011dSGlenn Strauss 	srv_socket->fdn = NULL;
907*f0786a75SGlenn Strauss 	fdevent_fdnode_event_del(srv->ev, fdn);
908*f0786a75SGlenn Strauss 	fdevent_unregister(srv->ev, fdn);
9096c1e6e66SGlenn Strauss }
9106c1e6e66SGlenn Strauss 
network_register_fdevents(server * srv)911bcdc6a3bSJan Kneschke int network_register_fdevents(server *srv) {
912e47ae008SJan Kneschke 	if (-1 == fdevent_reset(srv->ev)) {
913e47ae008SJan Kneschke 		return -1;
914e47ae008SJan Kneschke 	}
915bcdc6a3bSJan Kneschke 
9161812f554SGlenn Strauss 	if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
9171812f554SGlenn Strauss 
918bcdc6a3bSJan Kneschke 	/* register fdevents after reset */
91962e97967SGlenn Strauss 	for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
920bcdc6a3bSJan Kneschke 		server_socket *srv_socket = srv->srv_sockets.ptr[i];
921bcdc6a3bSJan Kneschke 
9229113011dSGlenn Strauss 		srv_socket->fdn = fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
9239113011dSGlenn Strauss 		fdevent_fdnode_event_set(srv->ev, srv_socket->fdn, FDEVENT_IN);
924bcdc6a3bSJan Kneschke 	}
925bcdc6a3bSJan Kneschke 	return 0;
926bcdc6a3bSJan Kneschke }
927