[network] do not append port to unix socket paths
[lighttpd.git] / src / network.c
blobed42a2bee00d4ea5d65273c2ad394d92b1fbc425
1 #include "first.h"
3 #include "network.h"
4 #include "fdevent.h"
5 #include "log.h"
6 #include "connections.h"
7 #include "plugin.h"
8 #include "joblist.h"
9 #include "configfile.h"
10 #include "inet_ntop_cache.h"
12 #include "network_backends.h"
13 #include "sys-mmap.h"
14 #include "sys-socket.h"
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/time.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdlib.h>
26 void
27 network_accept_tcp_nagle_disable (const int fd)
29 static int noinherit_tcpnodelay = -1;
30 int opt;
32 if (!noinherit_tcpnodelay) /* TCP_NODELAY inherited from listen socket */
33 return;
35 if (noinherit_tcpnodelay < 0) {
36 socklen_t optlen = sizeof(opt);
37 if (0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen)) {
38 noinherit_tcpnodelay = !opt;
39 if (opt) /* TCP_NODELAY inherited from listen socket */
40 return;
44 opt = 1;
45 (void)setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
48 static handler_t network_server_handle_fdevent(server *srv, void *context, int revents) {
49 server_socket *srv_socket = (server_socket *)context;
50 connection *con;
51 int loops = 0;
53 UNUSED(context);
55 if (0 == (revents & FDEVENT_IN)) {
56 log_error_write(srv, __FILE__, __LINE__, "sdd",
57 "strange event for server socket",
58 srv_socket->fd,
59 revents);
60 return HANDLER_ERROR;
63 /* accept()s at most 100 connections directly
65 * we jump out after 100 to give the waiting connections a chance */
66 for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
67 connection_state_machine(srv, con);
69 return HANDLER_GO_ON;
72 static int network_server_init(server *srv, buffer *host_token, size_t sidx) {
73 socklen_t addr_len;
74 server_socket *srv_socket;
75 unsigned int port = 0;
76 const char *host;
77 specific_config *s = srv->config_storage[sidx];
78 buffer *b;
79 int err;
81 #ifdef __WIN32
82 WORD wVersionRequested;
83 WSADATA wsaData;
85 wVersionRequested = MAKEWORD( 2, 2 );
87 err = WSAStartup( wVersionRequested, &wsaData );
88 if ( err != 0 ) {
89 /* Tell the user that we could not find a usable */
90 /* WinSock DLL. */
91 return -1;
93 #endif
94 err = -1;
96 srv_socket = calloc(1, sizeof(*srv_socket));
97 force_assert(NULL != srv_socket);
98 srv_socket->addr.plain.sa_family = AF_INET; /* default */
99 srv_socket->fd = -1;
100 srv_socket->fde_ndx = -1;
101 srv_socket->sidx = sidx;
103 srv_socket->srv_token = buffer_init();
104 buffer_copy_buffer(srv_socket->srv_token, host_token);
106 b = buffer_init();
107 buffer_copy_buffer(b, host_token); /*(allocates b->ptr even if host_token is NULL)*/
109 host = b->ptr;
111 if (host[0] == '/') {
112 /* host is a unix-domain-socket */
113 #ifdef HAVE_SYS_UN_H
114 srv_socket->addr.plain.sa_family = AF_UNIX;
115 #else
116 log_error_write(srv, __FILE__, __LINE__, "s",
117 "ERROR: Unix Domain sockets are not supported.");
118 goto error_free_socket;
119 #endif
120 } else {
121 /* ipv4:port
122 * [ipv6]:port
124 size_t len = buffer_string_length(b);
125 char *sp = NULL;
126 if (0 == len) {
127 log_error_write(srv, __FILE__, __LINE__, "s", "value of $SERVER[\"socket\"] must not be empty");
128 goto error_free_socket;
130 if ((b->ptr[0] == '[' && b->ptr[len-1] == ']') || NULL == (sp = strrchr(b->ptr, ':'))) {
131 /* use server.port if set in config, or else default from config_set_defaults() */
132 port = srv->srvconf.port;
133 sp = b->ptr + len; /* point to '\0' at end of string so end of IPv6 address can be found below */
134 } else {
135 /* found ip:port separator at *sp; port doesn't end in ']', so *sp hopefully doesn't split an IPv6 address */
136 *sp = '\0';
137 port = strtol(sp+1, NULL, 10);
140 /* check for [ and ] */
141 if (b->ptr[0] == '[' && *(sp-1) == ']') {
142 *(sp-1) = '\0';
143 host++;
145 s->use_ipv6 = 1;
148 if (port == 0 || port > 65535) {
149 log_error_write(srv, __FILE__, __LINE__, "sd", "port not set or out of range:", port);
151 goto error_free_socket;
155 #ifdef HAVE_IPV6
156 if (s->use_ipv6) {
157 srv_socket->addr.plain.sa_family = AF_INET6;
159 #endif
161 if (*host == '\0') {
162 if (srv_socket->addr.plain.sa_family == AF_INET6) {
163 log_error_write(srv, __FILE__, __LINE__, "s", "warning: please use server.use-ipv6 only for hostnames, not without server.bind / empty address; your config will break if the kernel default for IPV6_V6ONLY changes");
164 host = "::";
165 } else if (srv_socket->addr.plain.sa_family == AF_INET) {
166 host = "0.0.0.0";
170 if (1 != sock_addr_from_str_hints(srv, &srv_socket->addr, &addr_len, host, srv_socket->addr.plain.sa_family, port)) {
171 goto error_free_socket;
174 if (srv->srvconf.preflight_check) {
175 err = 0;
176 goto error_free_socket;
179 if (srv->sockets_disabled) { /* lighttpd -1 (one-shot mode) */
180 goto srv_sockets_append;
183 #ifdef HAVE_SYS_UN_H
184 if (AF_UNIX == srv_socket->addr.plain.sa_family) {
185 /* check if the socket exists and try to connect to it. */
186 force_assert(host); /*(static analysis hint)*/
187 if (-1 == (srv_socket->fd = fdevent_socket_cloexec(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
188 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
189 goto error_free_socket;
191 if (0 == connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
192 log_error_write(srv, __FILE__, __LINE__, "ss",
193 "server socket is still in use:",
194 host);
197 goto error_free_socket;
200 /* connect failed */
201 switch(errno) {
202 case ECONNREFUSED:
203 unlink(host);
204 break;
205 case ENOENT:
206 break;
207 default:
208 log_error_write(srv, __FILE__, __LINE__, "sds",
209 "testing socket failed:",
210 host, strerror(errno));
212 goto error_free_socket;
215 fdevent_fcntl_set_nb(srv->ev, srv_socket->fd);
216 } else
217 #endif
219 if (-1 == (srv_socket->fd = fdevent_socket_nb_cloexec(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
220 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
221 goto error_free_socket;
224 #ifdef HAVE_IPV6
225 if (AF_INET6 == srv_socket->addr.plain.sa_family
226 && host != NULL) {
227 if (s->set_v6only) {
228 int val = 1;
229 if (-1 == setsockopt(srv_socket->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
230 log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(IPV6_V6ONLY) failed:", strerror(errno));
231 goto error_free_socket;
233 } else {
234 log_error_write(srv, __FILE__, __LINE__, "s", "warning: server.set-v6only will be removed soon, update your config to have different sockets for ipv4 and ipv6");
237 #endif
240 /* */
241 srv->cur_fds = srv_socket->fd;
243 if (fdevent_set_so_reuseaddr(srv_socket->fd, 1) < 0) {
244 log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(SO_REUSEADDR) failed:", strerror(errno));
245 goto error_free_socket;
248 if (srv_socket->addr.plain.sa_family != AF_UNIX) {
249 if (fdevent_set_tcp_nodelay(srv_socket->fd, 1) < 0) {
250 log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(TCP_NODELAY) failed:", strerror(errno));
251 goto error_free_socket;
255 if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
256 switch(srv_socket->addr.plain.sa_family) {
257 case AF_UNIX:
258 log_error_write(srv, __FILE__, __LINE__, "sds",
259 "can't bind to socket:",
260 host, strerror(errno));
261 break;
262 default:
263 log_error_write(srv, __FILE__, __LINE__, "ssds",
264 "can't bind to port:",
265 host, port, strerror(errno));
266 break;
268 goto error_free_socket;
271 if (srv_socket->addr.plain.sa_family == AF_UNIX && !buffer_string_is_empty(s->socket_perms)) {
272 mode_t m = 0;
273 for (char *str = s->socket_perms->ptr; *str; ++str) {
274 m <<= 3;
275 m |= (*str - '0');
277 if (0 != m && -1 == chmod(host, m)) {
278 log_error_write(srv, __FILE__, __LINE__, "sssbss", "chmod(\"", host, "\", ", s->socket_perms, "):", strerror(errno));
282 if (-1 == listen(srv_socket->fd, s->listen_backlog)) {
283 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
284 goto error_free_socket;
287 if (s->ssl_enabled) {
288 #ifdef TCP_DEFER_ACCEPT
289 } else if (s->defer_accept) {
290 int v = s->defer_accept;
291 if (-1 == setsockopt(srv_socket->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &v, sizeof(v))) {
292 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set TCP_DEFER_ACCEPT: ", strerror(errno));
294 #endif
295 #if defined(__FreeBSD__) || defined(__NetBSD__) \
296 || defined(__OpenBSD__) || defined(__DragonFly__)
297 } else if (!buffer_is_empty(s->bsd_accept_filter)
298 && (buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("httpready"))
299 || buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("dataready")))) {
300 #ifdef SO_ACCEPTFILTER
301 /* FreeBSD accf_http filter */
302 struct accept_filter_arg afa;
303 memset(&afa, 0, sizeof(afa));
304 strncpy(afa.af_name, s->bsd_accept_filter->ptr, sizeof(afa.af_name));
305 if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
306 if (errno != ENOENT) {
307 log_error_write(srv, __FILE__, __LINE__, "SBss", "can't set accept-filter '", s->bsd_accept_filter, "':", strerror(errno));
310 #endif
311 #endif
314 srv_sockets_append:
315 srv_socket->is_ssl = s->ssl_enabled;
317 if (srv->srv_sockets.size == 0) {
318 srv->srv_sockets.size = 4;
319 srv->srv_sockets.used = 0;
320 srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket*));
321 force_assert(NULL != srv->srv_sockets.ptr);
322 } else if (srv->srv_sockets.used == srv->srv_sockets.size) {
323 srv->srv_sockets.size += 4;
324 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket*));
325 force_assert(NULL != srv->srv_sockets.ptr);
328 srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
330 buffer_free(b);
332 return 0;
334 error_free_socket:
335 if (srv_socket->fd != -1) {
336 network_unregister_sock(srv, srv_socket);
337 close(srv_socket->fd);
339 buffer_free(srv_socket->srv_token);
340 free(srv_socket);
342 buffer_free(b);
344 return err; /* -1 if error; 0 if srv->srvconf.preflight_check successful */
347 int network_close(server *srv) {
348 size_t i;
349 for (i = 0; i < srv->srv_sockets.used; i++) {
350 server_socket *srv_socket = srv->srv_sockets.ptr[i];
351 if (srv_socket->fd != -1) {
352 network_unregister_sock(srv, srv_socket);
353 close(srv_socket->fd);
356 buffer_free(srv_socket->srv_token);
358 free(srv_socket);
361 free(srv->srv_sockets.ptr);
362 srv->srv_sockets.ptr = NULL;
363 srv->srv_sockets.used = 0;
364 srv->srv_sockets.size = 0;
366 return 0;
369 typedef enum {
370 NETWORK_BACKEND_UNSET,
371 NETWORK_BACKEND_WRITE,
372 NETWORK_BACKEND_WRITEV,
373 NETWORK_BACKEND_SENDFILE,
374 } network_backend_t;
376 int network_init(server *srv) {
377 buffer *b;
378 size_t i, j;
379 network_backend_t backend;
381 struct nb_map {
382 network_backend_t nb;
383 const char *name;
384 } network_backends[] = {
385 /* lowest id wins */
386 #if defined USE_SENDFILE
387 { NETWORK_BACKEND_SENDFILE, "sendfile" },
388 #endif
389 #if defined USE_LINUX_SENDFILE
390 { NETWORK_BACKEND_SENDFILE, "linux-sendfile" },
391 #endif
392 #if defined USE_FREEBSD_SENDFILE
393 { NETWORK_BACKEND_SENDFILE, "freebsd-sendfile" },
394 #endif
395 #if defined USE_SOLARIS_SENDFILEV
396 { NETWORK_BACKEND_SENDFILE, "solaris-sendfilev" },
397 #endif
398 #if defined USE_WRITEV
399 { NETWORK_BACKEND_WRITEV, "writev" },
400 #endif
401 { NETWORK_BACKEND_WRITE, "write" },
402 { NETWORK_BACKEND_UNSET, NULL }
405 b = buffer_init();
407 buffer_copy_buffer(b, srv->srvconf.bindhost);
408 if (b->ptr[0] != '/') { /*(skip adding port if unix socket path)*/
409 buffer_append_string_len(b, CONST_STR_LEN(":"));
410 buffer_append_int(b, srv->srvconf.port);
413 /* check if we already know this socket, and if yes, don't init it */
414 for (j = 0; j < srv->srv_sockets.used; j++) {
415 if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, b)) {
416 break;
419 if (j == srv->srv_sockets.used) {
420 if (0 != network_server_init(srv, b, 0)) {
421 buffer_free(b);
422 return -1;
425 buffer_free(b);
427 /* get a usefull default */
428 backend = network_backends[0].nb;
430 /* match name against known types */
431 if (!buffer_string_is_empty(srv->srvconf.network_backend)) {
432 for (i = 0; network_backends[i].name; i++) {
433 /**/
434 if (buffer_is_equal_string(srv->srvconf.network_backend, network_backends[i].name, strlen(network_backends[i].name))) {
435 backend = network_backends[i].nb;
436 break;
439 if (NULL == network_backends[i].name) {
440 /* we don't know it */
442 log_error_write(srv, __FILE__, __LINE__, "sb",
443 "server.network-backend has a unknown value:",
444 srv->srvconf.network_backend);
446 return -1;
450 switch(backend) {
451 case NETWORK_BACKEND_WRITE:
452 srv->network_backend_write = network_write_chunkqueue_write;
453 break;
454 #if defined(USE_WRITEV)
455 case NETWORK_BACKEND_WRITEV:
456 srv->network_backend_write = network_write_chunkqueue_writev;
457 break;
458 #endif
459 #if defined(USE_SENDFILE)
460 case NETWORK_BACKEND_SENDFILE:
461 srv->network_backend_write = network_write_chunkqueue_sendfile;
462 break;
463 #endif
464 default:
465 return -1;
468 /* check for $SERVER["socket"] */
469 for (i = 1; i < srv->config_context->used; i++) {
470 data_config *dc = (data_config *)srv->config_context->data[i];
472 /* not our stage */
473 if (COMP_SERVER_SOCKET != dc->comp) continue;
475 if (dc->cond != CONFIG_COND_EQ) continue;
477 /* check if we already know this socket,
478 * if yes, don't init it */
479 for (j = 0; j < srv->srv_sockets.used; j++) {
480 if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, dc->string)) {
481 break;
485 if (j == srv->srv_sockets.used) {
486 if (0 != network_server_init(srv, dc->string, i)) return -1;
490 return 0;
493 void network_unregister_sock(server *srv, server_socket *srv_socket) {
494 if (-1 == srv_socket->fd || -1 == srv_socket->fde_ndx) return;
495 fdevent_event_del(srv->ev, &srv_socket->fde_ndx, srv_socket->fd);
496 fdevent_unregister(srv->ev, srv_socket->fd);
499 int network_register_fdevents(server *srv) {
500 size_t i;
502 if (-1 == fdevent_reset(srv->ev)) {
503 return -1;
506 if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
508 /* register fdevents after reset */
509 for (i = 0; i < srv->srv_sockets.used; i++) {
510 server_socket *srv_socket = srv->srv_sockets.ptr[i];
512 fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
513 fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
515 return 0;