[core] consolidate backend network write handlers
[lighttpd.git] / src / network.c
blob17dc3f794d5cd39196f3dcf817816c5466e8824d
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 "configfile.h"
9 #include "sock_addr.h"
11 #include "network_write.h"
12 #include "sys-socket.h"
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/time.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <stdlib.h>
24 void
25 network_accept_tcp_nagle_disable (const int fd)
27 static int noinherit_tcpnodelay = -1;
28 int opt;
30 if (!noinherit_tcpnodelay) /* TCP_NODELAY inherited from listen socket */
31 return;
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;
42 opt = 1;
43 (void)setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
46 static handler_t network_server_handle_fdevent(server *srv, void *context, int revents) {
47 server_socket *srv_socket = (server_socket *)context;
48 connection *con;
49 int loops = 0;
51 UNUSED(context);
53 if (0 == (revents & FDEVENT_IN)) {
54 log_error_write(srv, __FILE__, __LINE__, "sdd",
55 "strange event for server socket",
56 srv_socket->fd,
57 revents);
58 return HANDLER_ERROR;
61 /* accept()s at most 100 connections directly
63 * we jump out after 100 to give the waiting connections a chance */
64 for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
65 connection_state_machine(srv, con);
67 return HANDLER_GO_ON;
70 static void network_host_normalize_addr_str(buffer *host, sock_addr *addr) {
71 buffer_reset(host);
72 sock_addr_stringify_append_buffer(host, addr);
75 static int network_host_parse_addr(server *srv, sock_addr *addr, socklen_t *addr_len, buffer *host, int use_ipv6) {
76 char *h;
77 char *colon = NULL;
78 const char *chost;
79 sa_family_t family = use_ipv6 ? AF_INET6 : AF_INET;
80 unsigned int port = srv->srvconf.port;
81 if (buffer_string_is_empty(host)) {
82 log_error_write(srv, __FILE__, __LINE__, "s", "value of $SERVER[\"socket\"] must not be empty");
83 return -1;
85 h = host->ptr;
86 if (h[0] == '/') {
87 #ifdef HAVE_SYS_UN_H
88 return (1 == sock_addr_from_str_hints(srv,addr,addr_len,h,AF_UNIX,0))
89 ? 0
90 : -1;
91 #else
92 log_error_write(srv, __FILE__, __LINE__, "s",
93 "ERROR: Unix Domain sockets are not supported.");
94 return -1;
95 #endif
97 buffer_copy_buffer(srv->tmp_buf, host);
98 h = srv->tmp_buf->ptr;
99 if (h[0] == '[') {
100 family = AF_INET6;
101 if ((h = strchr(h, ']'))) {
102 *h++ = '\0';
103 if (*h == ':') colon = h;
104 } /*(else should not happen; validated in configparser.y)*/
105 h = srv->tmp_buf->ptr+1;
107 else {
108 colon = strrchr(h, ':');
110 if (colon) {
111 *colon++ = '\0';
112 port = strtol(colon, NULL, 10);
113 if (port == 0 || port > 65535) {
114 log_error_write(srv, __FILE__, __LINE__, "sd",
115 "port not set or out of range:", port);
116 return -1;
119 chost = *h ? h : family == AF_INET ? "0.0.0.0" : "::";
120 if (1 != sock_addr_from_str_hints(srv,addr,addr_len,chost,family,port)) {
121 return -1;
123 return 0;
126 static int network_server_init(server *srv, buffer *host_token, size_t sidx, int stdin_fd) {
127 server_socket *srv_socket;
128 const char *host;
129 specific_config *s = srv->config_storage[sidx];
130 socklen_t addr_len = sizeof(sock_addr);
131 sock_addr addr;
132 int family = 0;
133 int set_v6only = 0;
135 #ifdef __WIN32
136 int err;
137 WORD wVersionRequested;
138 WSADATA wsaData;
140 wVersionRequested = MAKEWORD( 2, 2 );
142 err = WSAStartup( wVersionRequested, &wsaData );
143 if ( err != 0 ) {
144 /* Tell the user that we could not find a usable */
145 /* WinSock DLL. */
146 return -1;
148 #endif
150 if (buffer_string_is_empty(host_token)) {
151 log_error_write(srv, __FILE__, __LINE__, "s", "value of $SERVER[\"socket\"] must not be empty");
152 return -1;
155 /* check if we already know this socket, and if yes, don't init it
156 * (optimization: check strings here to filter out exact matches;
157 * binary addresses are matched further below) */
158 for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
159 if (buffer_is_equal(srv->srv_sockets.ptr[i]->srv_token, host_token)) {
160 buffer_copy_buffer(host_token, srv->srv_sockets.ptr[i]->srv_token);
161 return 0;
165 host = host_token->ptr;
166 if ((s->use_ipv6 && (*host == '\0' || *host == ':')) || (host[0] == '[' && host[1] == ']')) {
167 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");
169 if (*host == '[') s->use_ipv6 = 1;
171 memset(&addr, 0, sizeof(addr));
172 if (-1 != stdin_fd) {
173 if (0 == sidx && srv->srv_sockets.used > 0) {
174 close(stdin_fd);/*(graceful restart listening to "/dev/stdin")*/
175 return 0;
177 if (-1 == getsockname(stdin_fd, (struct sockaddr *)&addr, &addr_len)) {
178 log_error_write(srv, __FILE__, __LINE__, "ss",
179 "getsockname()", strerror(errno));
180 return -1;
182 } else if (0 != network_host_parse_addr(srv, &addr, &addr_len, host_token, s->use_ipv6)) {
183 return -1;
186 family = sock_addr_get_family(&addr);
188 #ifdef HAVE_IPV6
189 if (*host != '\0' && AF_INET6 == family) {
190 if (s->set_v6only) {
191 set_v6only = 1;
192 } else {
193 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");
196 #endif
198 network_host_normalize_addr_str(host_token, &addr);
199 host = host_token->ptr;
201 if (srv->srvconf.preflight_check) {
202 return 0;
205 /* check if we already know this socket (after potential DNS resolution), and if yes, don't init it */
206 for (size_t i = 0; i < srv->srv_sockets.used; ++i) {
207 if (0 == memcmp(&srv->srv_sockets.ptr[i]->addr, &addr, sizeof(addr))) {
208 return 0;
212 srv_socket = calloc(1, sizeof(*srv_socket));
213 force_assert(NULL != srv_socket);
214 memcpy(&srv_socket->addr, &addr, addr_len);
215 srv_socket->fd = -1;
216 srv_socket->fde_ndx = -1;
217 srv_socket->sidx = sidx;
218 srv_socket->is_ssl = s->ssl_enabled;
219 srv_socket->srv_token = buffer_init_buffer(host_token);
221 if (srv->srv_sockets.size == 0) {
222 srv->srv_sockets.size = 4;
223 srv->srv_sockets.used = 0;
224 srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket*));
225 force_assert(NULL != srv->srv_sockets.ptr);
226 } else if (srv->srv_sockets.used == srv->srv_sockets.size) {
227 srv->srv_sockets.size += 4;
228 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket*));
229 force_assert(NULL != srv->srv_sockets.ptr);
231 srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
233 if (srv->sockets_disabled) { /* lighttpd -1 (one-shot mode) */
234 return 0;
237 if (-1 != stdin_fd) {
238 srv_socket->fd = stdin_fd;
239 if (-1 == fdevent_fcntl_set_nb_cloexec(srv->ev, stdin_fd)) {
240 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl:", strerror(errno));
241 return -1;
243 } else
244 #ifdef HAVE_SYS_UN_H
245 if (AF_UNIX == family) {
246 /* check if the socket exists and try to connect to it. */
247 force_assert(host); /*(static analysis hint)*/
248 if (-1 == (srv_socket->fd = fdevent_socket_cloexec(AF_UNIX, SOCK_STREAM, 0))) {
249 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
250 return -1;
252 if (0 == connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
253 log_error_write(srv, __FILE__, __LINE__, "ss",
254 "server socket is still in use:",
255 host);
258 return -1;
261 /* connect failed */
262 switch(errno) {
263 case ECONNREFUSED:
264 unlink(host);
265 break;
266 case ENOENT:
267 break;
268 default:
269 log_error_write(srv, __FILE__, __LINE__, "sds",
270 "testing socket failed:",
271 host, strerror(errno));
273 return -1;
276 fdevent_fcntl_set_nb(srv->ev, srv_socket->fd);
277 } else
278 #endif
280 if (-1 == (srv_socket->fd = fdevent_socket_nb_cloexec(family, SOCK_STREAM, IPPROTO_TCP))) {
281 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
282 return -1;
286 #ifdef HAVE_IPV6
287 if (set_v6only && -1 == stdin_fd) {
288 int val = 1;
289 if (-1 == setsockopt(srv_socket->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
290 log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(IPV6_V6ONLY) failed:", strerror(errno));
291 return -1;
294 #endif
296 /* */
297 srv->cur_fds = srv_socket->fd;
299 if (fdevent_set_so_reuseaddr(srv_socket->fd, 1) < 0) {
300 log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(SO_REUSEADDR) failed:", strerror(errno));
301 return -1;
304 if (family != AF_UNIX) {
305 if (fdevent_set_tcp_nodelay(srv_socket->fd, 1) < 0) {
306 log_error_write(srv, __FILE__, __LINE__, "ss", "setsockopt(TCP_NODELAY) failed:", strerror(errno));
307 return -1;
311 if (-1 != stdin_fd) { } else
312 if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
313 log_error_write(srv, __FILE__, __LINE__, "sss",
314 "can't bind to socket:", host, strerror(errno));
315 return -1;
318 if (-1 != stdin_fd) { } else
319 if (AF_UNIX == family && !buffer_string_is_empty(s->socket_perms)) {
320 mode_t m = 0;
321 for (char *str = s->socket_perms->ptr; *str; ++str) {
322 m <<= 3;
323 m |= (*str - '0');
325 if (0 != m && -1 == chmod(host, m)) {
326 log_error_write(srv, __FILE__, __LINE__, "sssbss", "chmod(\"", host, "\", ", s->socket_perms, "):", strerror(errno));
330 if (-1 != stdin_fd) { } else
331 if (-1 == listen(srv_socket->fd, s->listen_backlog)) {
332 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
333 return -1;
336 if (s->ssl_enabled) {
337 #ifdef TCP_DEFER_ACCEPT
338 } else if (s->defer_accept) {
339 int v = s->defer_accept;
340 if (-1 == setsockopt(srv_socket->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &v, sizeof(v))) {
341 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set TCP_DEFER_ACCEPT: ", strerror(errno));
343 #endif
344 #if defined(__FreeBSD__) || defined(__NetBSD__) \
345 || defined(__OpenBSD__) || defined(__DragonFly__)
346 } else if (!buffer_is_empty(s->bsd_accept_filter)
347 && (buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("httpready"))
348 || buffer_is_equal_string(s->bsd_accept_filter, CONST_STR_LEN("dataready")))) {
349 #ifdef SO_ACCEPTFILTER
350 /* FreeBSD accf_http filter */
351 struct accept_filter_arg afa;
352 memset(&afa, 0, sizeof(afa));
353 strncpy(afa.af_name, s->bsd_accept_filter->ptr, sizeof(afa.af_name));
354 if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
355 if (errno != ENOENT) {
356 log_error_write(srv, __FILE__, __LINE__, "SBss", "can't set accept-filter '", s->bsd_accept_filter, "':", strerror(errno));
359 #endif
360 #endif
363 return 0;
366 int network_close(server *srv) {
367 size_t i;
368 for (i = 0; i < srv->srv_sockets.used; i++) {
369 server_socket *srv_socket = srv->srv_sockets.ptr[i];
370 if (srv_socket->fd != -1) {
371 network_unregister_sock(srv, srv_socket);
372 close(srv_socket->fd);
375 buffer_free(srv_socket->srv_token);
377 free(srv_socket);
380 free(srv->srv_sockets.ptr);
381 srv->srv_sockets.ptr = NULL;
382 srv->srv_sockets.used = 0;
383 srv->srv_sockets.size = 0;
385 return 0;
388 int network_init(server *srv, int stdin_fd) {
389 size_t i;
390 if (0 != network_write_init(srv)) return -1;
393 int rc;
394 buffer *b = buffer_init();
395 buffer_copy_buffer(b, srv->srvconf.bindhost);
396 if (b->ptr[0] != '/') { /*(skip adding port if unix socket path)*/
397 buffer_append_string_len(b, CONST_STR_LEN(":"));
398 buffer_append_int(b, srv->srvconf.port);
401 rc = network_server_init(srv, b, 0, stdin_fd);
402 buffer_free(b);
403 if (0 != rc) return -1;
406 /* check for $SERVER["socket"] */
407 for (i = 1; i < srv->config_context->used; i++) {
408 data_config *dc = (data_config *)srv->config_context->data[i];
410 /* not our stage */
411 if (COMP_SERVER_SOCKET != dc->comp) continue;
413 if (dc->cond == CONFIG_COND_NE) {
414 socklen_t addr_len = sizeof(sock_addr);
415 sock_addr addr;
416 if (0 != network_host_parse_addr(srv, &addr, &addr_len, dc->string, srv->config_storage[i]->use_ipv6)) {
417 return -1;
419 network_host_normalize_addr_str(dc->string, &addr);
420 continue;
423 if (dc->cond != CONFIG_COND_EQ) continue;
425 if (0 != network_server_init(srv, dc->string, i, -1)) return -1;
428 return 0;
431 void network_unregister_sock(server *srv, server_socket *srv_socket) {
432 if (-1 == srv_socket->fd || -1 == srv_socket->fde_ndx) return;
433 fdevent_event_del(srv->ev, &srv_socket->fde_ndx, srv_socket->fd);
434 fdevent_unregister(srv->ev, srv_socket->fd);
437 int network_register_fdevents(server *srv) {
438 size_t i;
440 if (-1 == fdevent_reset(srv->ev)) {
441 return -1;
444 if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
446 /* register fdevents after reset */
447 for (i = 0; i < srv->srv_sockets.used; i++) {
448 server_socket *srv_socket = srv->srv_sockets.ptr[i];
450 fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
451 fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
453 return 0;