[core] lighttpd -1 handles single request on stdin socket (fixes #1584)
(e.g. when called from xinetd) Note: lighttpd is designed as a high performance, long-running server, not a one-shot executable. This one-shot mode of operation has not been tuned for performance. lighttpd server start-up and initialization aims for correctness, not speed. If using this one-shot mode as part of fork and exec from xinetd, then performance is already not of high concern. x-ref: "support for xinetd" https://redmine.lighttpd.net/issues/1584
This commit is contained in:
parent
6c35e38fe1
commit
1812f5541a
|
@ -42,6 +42,9 @@ Do not daemonize (go into background). The default is to daemonize.
|
|||
\fB\-i\ \fP \fIsecs\fP
|
||||
Trigger daemon graceful shutdown after \fIsecs\fP of inactivity.
|
||||
.TP 8
|
||||
\fB\-1\fP
|
||||
Process single (one) request on stdin socket, then exit.
|
||||
.TP 8
|
||||
\fB\-v\fP
|
||||
Show version and exit.
|
||||
.TP 8
|
||||
|
|
|
@ -894,6 +894,11 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
|
|||
}
|
||||
return NULL;
|
||||
} else {
|
||||
return connection_accepted(srv, srv_socket, &cnt_addr, cnt);
|
||||
}
|
||||
}
|
||||
|
||||
connection *connection_accepted(server *srv, server_socket *srv_socket, sock_addr *cnt_addr, int cnt) {
|
||||
connection *con;
|
||||
|
||||
srv->cur_fds++;
|
||||
|
@ -917,7 +922,7 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
|
|||
connection_set_state(srv, con, CON_STATE_REQUEST_START);
|
||||
|
||||
con->connection_start = srv->cur_ts;
|
||||
con->dst_addr = cnt_addr;
|
||||
con->dst_addr = *cnt_addr;
|
||||
buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
|
||||
con->srv_socket = srv_socket;
|
||||
|
||||
|
@ -947,7 +952,6 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
|
|||
}
|
||||
#endif
|
||||
return con;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ int connection_reset(server *srv, connection *con);
|
|||
void connections_free(server *srv);
|
||||
|
||||
connection * connection_accept(server *srv, server_socket *srv_sock);
|
||||
connection * connection_accepted(server *srv, server_socket *srv_socket, sock_addr *cnt_addr, int cnt);
|
||||
|
||||
int connection_set_state(server *srv, connection *con, connection_state_t state);
|
||||
const char * connection_get_state(connection_state_t state);
|
||||
|
|
|
@ -334,6 +334,13 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
|
|||
goto error_free_socket;
|
||||
}
|
||||
|
||||
if (srv->sockets_disabled) { /* lighttpd -1 (one-shot mode) */
|
||||
#ifdef USE_OPENSSL
|
||||
if (s->ssl_enabled) srv_socket->ssl_ctx = s->ssl_ctx;
|
||||
#endif
|
||||
goto srv_sockets_append;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
if (AF_UNIX == srv_socket->addr.plain.sa_family) {
|
||||
/* check if the socket exists and try to connect to it. */
|
||||
|
@ -455,6 +462,7 @@ static int network_server_init(server *srv, buffer *host_token, specific_config
|
|||
#endif
|
||||
}
|
||||
|
||||
srv_sockets_append:
|
||||
srv_socket->is_ssl = s->ssl_enabled;
|
||||
|
||||
if (srv->srv_sockets.size == 0) {
|
||||
|
@ -1026,6 +1034,8 @@ int network_register_fdevents(server *srv) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (srv->sockets_disabled) return 0; /* lighttpd -1 (one-shot mode) */
|
||||
|
||||
/* register fdevents after reset */
|
||||
for (i = 0; i < srv->srv_sockets.used; i++) {
|
||||
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
||||
|
|
132
src/server.c
132
src/server.c
|
@ -424,6 +424,110 @@ static void remove_pid_file(server *srv, int *pid_fd) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static server_socket * server_oneshot_getsock(server *srv, sock_addr *cnt_addr) {
|
||||
server_socket *srv_socket, *srv_socket_wild = NULL;
|
||||
size_t i;
|
||||
for (i = 0; i < srv->srv_sockets.used; ++i) {
|
||||
srv_socket = srv->srv_sockets.ptr[i];
|
||||
if (cnt_addr->plain.sa_family != srv_socket->addr.plain.sa_family) continue;
|
||||
switch (cnt_addr->plain.sa_family) {
|
||||
case AF_INET:
|
||||
if (srv_socket->addr.ipv4.sin_port != cnt_addr->ipv4.sin_port) continue;
|
||||
if (srv_socket->addr.ipv4.sin_addr.s_addr == cnt_addr->ipv4.sin_addr.s_addr) {
|
||||
return srv_socket;
|
||||
}
|
||||
if (srv_socket->addr.ipv4.sin_addr.s_addr == htonl(INADDR_ANY)) {
|
||||
srv_socket_wild = srv_socket;
|
||||
}
|
||||
continue;
|
||||
#ifdef HAVE_IPV6
|
||||
case AF_INET6:
|
||||
if (srv_socket->addr.ipv6.sin6_port != cnt_addr->ipv6.sin6_port) continue;
|
||||
if (0 == memcmp(&srv_socket->addr.ipv6.sin6_addr, &cnt_addr->ipv6.sin6_addr, sizeof(struct in6_addr))) {
|
||||
return srv_socket;
|
||||
}
|
||||
if (0 == memcmp(&srv_socket->addr.ipv6.sin6_addr, &in6addr_any, sizeof(struct in6_addr))) {
|
||||
srv_socket_wild = srv_socket;
|
||||
}
|
||||
continue;
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
case AF_UNIX:
|
||||
if (0 == strcmp(srv_socket->addr.un.sun_path, cnt_addr->un.sun_path)) {
|
||||
return srv_socket;
|
||||
}
|
||||
continue;
|
||||
#endif
|
||||
default: continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != srv_socket_wild) {
|
||||
return srv_socket_wild;
|
||||
} else if (srv->srv_sockets.used) {
|
||||
return srv->srv_sockets.ptr[0];
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "no sockets configured");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int server_oneshot_init(server *srv, int fd) {
|
||||
/* Note: does not work with netcat due to requirement that fd be socket.
|
||||
* STDOUT_FILENO was not saved earlier in startup, and that is to where
|
||||
* netcat expects output to be sent. Since lighttpd expects connections
|
||||
* to be sockets, con->fd is where output is sent; separate fds are not
|
||||
* stored for input and output, but netcat has different fds for stdin
|
||||
* and * stdout. To support netcat, would additionally need to avoid
|
||||
* S_ISSOCK(), getsockname(), and getpeername() below, reconstructing
|
||||
* addresses from environment variables:
|
||||
* NCAT_LOCAL_ADDR NCAT_LOCAL_PORT
|
||||
* NCAT_REMOTE_ADDR NCAT_REMOTE_PORT
|
||||
* NCAT_PROTO
|
||||
*/
|
||||
connection *con;
|
||||
server_socket *srv_socket;
|
||||
sock_addr cnt_addr;
|
||||
socklen_t cnt_len;
|
||||
struct stat st;
|
||||
|
||||
if (0 != fstat(fd, &st)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "fstat:", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISSOCK(st.st_mode)) {
|
||||
/* require that fd is a socket
|
||||
* (modules might expect STDIN_FILENO and STDOUT_FILENO opened to /dev/null) */
|
||||
log_error_write(srv, __FILE__, __LINE__, "s", "lighttpd -1 stdin is not a socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cnt_len = sizeof(cnt_addr);
|
||||
if (0 != getsockname(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "getsockname:", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
srv_socket = server_oneshot_getsock(srv, &cnt_addr);
|
||||
if (NULL == srv_socket) return 0;
|
||||
|
||||
cnt_len = sizeof(cnt_addr);
|
||||
if (0 != getpeername(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "getpeername:", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
con = connection_accepted(srv, srv_socket, &cnt_addr, fd);
|
||||
if (NULL == con) return 0;
|
||||
|
||||
connection_state_machine(srv, con);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void show_version (void) {
|
||||
#ifdef USE_OPENSSL
|
||||
# define TEXT_SSL " (ssl)"
|
||||
|
@ -600,6 +704,7 @@ static void show_help (void) {
|
|||
" -f <name> filename of the config-file\n" \
|
||||
" -m <name> module directory (default: "LIBRARY_DIR")\n" \
|
||||
" -i <secs> graceful shutdown after <secs> of inactivity\n" \
|
||||
" -1 process single (one) request on stdin socket, then exit\n" \
|
||||
" -p print the parsed config-file in internal form, and exit\n" \
|
||||
" -t test the config-file, and exit\n" \
|
||||
" -D don't go to background (default: go to background)\n" \
|
||||
|
@ -633,6 +738,7 @@ int main (int argc, char **argv) {
|
|||
#ifdef HAVE_FORK
|
||||
int parent_pipe_fd = -1;
|
||||
#endif
|
||||
int oneshot_fd = 0;
|
||||
|
||||
#ifdef USE_ALARM
|
||||
struct itimerval interval;
|
||||
|
@ -662,7 +768,7 @@ int main (int argc, char **argv) {
|
|||
srv->srvconf.dont_daemonize = 0;
|
||||
srv->srvconf.preflight_check = 0;
|
||||
|
||||
while(-1 != (o = getopt(argc, argv, "f:m:i:hvVDpt"))) {
|
||||
while(-1 != (o = getopt(argc, argv, "f:m:i:hvVD1pt"))) {
|
||||
switch(o) {
|
||||
case 'f':
|
||||
if (srv->config_storage) {
|
||||
|
@ -694,6 +800,7 @@ int main (int argc, char **argv) {
|
|||
}
|
||||
case 'p': print_config = 1; break;
|
||||
case 't': ++test_config; break;
|
||||
case '1': oneshot_fd = dup(STDIN_FILENO); break;
|
||||
case 'D': srv->srvconf.dont_daemonize = 1; break;
|
||||
case 'v': show_version(); server_free(srv); return 0;
|
||||
case 'V': show_features(); server_free(srv); return 0;
|
||||
|
@ -740,6 +847,24 @@ int main (int argc, char **argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (oneshot_fd) {
|
||||
if (oneshot_fd <= STDERR_FILENO) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"Invalid fds at startup with lighttpd -1");
|
||||
server_free(srv);
|
||||
return -1;
|
||||
}
|
||||
graceful_shutdown = 1;
|
||||
srv->sockets_disabled = 1;
|
||||
srv->srvconf.dont_daemonize = 1;
|
||||
buffer_reset(srv->srvconf.pid_file);
|
||||
if (srv->srvconf.max_worker) {
|
||||
srv->srvconf.max_worker = 0;
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"server one-shot command line option disables server.max-worker config file option.");
|
||||
}
|
||||
}
|
||||
|
||||
/* close stdin and stdout, as they are not needed */
|
||||
openDevNull(STDIN_FILENO);
|
||||
openDevNull(STDOUT_FILENO);
|
||||
|
@ -1344,12 +1469,17 @@ int main (int argc, char **argv) {
|
|||
|
||||
for (i = 0; i < srv->srv_sockets.used; i++) {
|
||||
server_socket *srv_socket = srv->srv_sockets.ptr[i];
|
||||
if (srv->sockets_disabled) continue; /* lighttpd -1 (one-shot mode) */
|
||||
if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (oneshot_fd && !server_oneshot_init(srv, oneshot_fd)) {
|
||||
close(oneshot_fd);
|
||||
}
|
||||
|
||||
/* main-loop */
|
||||
while (!srv_shutdown) {
|
||||
int n;
|
||||
|
|
Loading…
Reference in New Issue