lighttpd 1.4.x https://www.lighttpd.net/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2007 lines
56 KiB

#include "first.h"
#include "base.h"
#include "buffer.h"
#include "network.h"
#include "log.h"
#include "rand.h"
#include "chunk.h"
#include "h2.h" /* h2_send_1xx() */
#include "http_auth.h" /* http_auth_dumbdata_reset() */
#include "http_vhostdb.h" /* http_vhostdb_dumbdata_reset() */
#include "fdevent.h"
#include "connections.h"
#include "sock_addr.h"
#include "stat_cache.h"
#include "plugin.h"
#include "plugin_config.h" /* config_plugin_value_tobool() */
#include "network_write.h" /* network_write_show_handlers() */
#include "reqpool.h" /* request_pool_init() request_pool_free() */
#include "response.h" /* http_response_send_1xx_cb_set() strftime_cache_reset() */
#ifdef HAVE_VERSIONSTAMP_H
# include "versionstamp.h"
#else
# define REPO_VERSION ""
#endif
#define PACKAGE_DESC PACKAGE_NAME "/" PACKAGE_VERSION REPO_VERSION
static const buffer default_server_tag = { CONST_STR_LEN(PACKAGE_DESC)+1, 0 };
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <locale.h>
#include <stdio.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#ifdef HAVE_VALGRIND_VALGRIND_H
# include <valgrind/valgrind.h>
#endif
#ifdef HAVE_PWD_H
# include <grp.h>
# include <pwd.h>
#endif
#ifdef HAVE_SYS_LOADAVG_H
# include <sys/loadavg.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
# include <sys/prctl.h>
#endif
#include "sys-crypto.h"
#if defined(USE_OPENSSL_CRYPTO) \
|| defined(USE_MBEDTLS_CRYPTO) \
|| defined(USE_NSS_CRYPTO) \
|| defined(USE_GNUTLS_CRYPTO) \
|| defined(USE_WOLFTLS_CRYPTO)
#define TEXT_SSL " (ssl)"
#else
#define TEXT_SSL
#endif
#ifndef __sgi
/* IRIX doesn't like the alarm based time() optimization */
/* #define USE_ALARM */
#endif
static int oneshot_fd = 0;
static int oneshot_fdout = -1;
static fdnode *oneshot_fdn = NULL;
static int (*oneshot_read_cq)(connection *con, chunkqueue *cq, off_t max_bytes);
static volatile int pid_fd = -2;
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
static server_socket_array graceful_sockets;
static server_socket_array inherited_sockets;
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
static volatile sig_atomic_t graceful_restart = 0;
static volatile sig_atomic_t graceful_shutdown = 0;
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
static volatile sig_atomic_t srv_shutdown = 0;
static volatile sig_atomic_t handle_sig_child = 0;
static volatile sig_atomic_t handle_sig_alarm = 1;
static volatile sig_atomic_t handle_sig_hup = 0;
static time_t idle_limit = 0;
#if defined(HAVE_SIGACTION) && defined(SA_SIGINFO)
static volatile siginfo_t last_sigterm_info;
static volatile siginfo_t last_sighup_info;
static void sigaction_handler(int sig, siginfo_t *si, void *context) {
static const siginfo_t empty_siginfo;
UNUSED(context);
if (!si) *(const siginfo_t **)&si = &empty_siginfo;
switch (sig) {
case SIGTERM:
srv_shutdown = 1;
last_sigterm_info = *si;
break;
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
case SIGUSR1:
if (!graceful_shutdown) {
graceful_restart = 1;
graceful_shutdown = 1;
last_sigterm_info = *si;
}
break;
case SIGINT:
if (graceful_shutdown) {
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
if (2 == graceful_restart)
graceful_restart = 1;
else
srv_shutdown = 1;
} else {
graceful_shutdown = 1;
}
last_sigterm_info = *si;
break;
case SIGALRM:
handle_sig_alarm = 1;
break;
case SIGHUP:
handle_sig_hup = 1;
last_sighup_info = *si;
break;
case SIGCHLD:
handle_sig_child = 1;
break;
}
}
#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
static void signal_handler(int sig) {
switch (sig) {
case SIGTERM: srv_shutdown = 1; break;
case SIGUSR1:
if (!graceful_shutdown) {
graceful_restart = 1;
graceful_shutdown = 1;
}
break;
case SIGINT:
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
if (graceful_shutdown) {
if (2 == graceful_restart)
graceful_restart = 1;
else
srv_shutdown = 1;
} else {
graceful_shutdown = 1;
}
break;
case SIGALRM: handle_sig_alarm = 1; break;
case SIGHUP: handle_sig_hup = 1; break;
case SIGCHLD: handle_sig_child = 1; break;
}
}
#endif
#ifdef HAVE_FORK
static int daemonize(void) {
int pipefd[2];
pid_t pid;
#ifdef SIGTTOU
signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN);
#endif
if (pipe(pipefd) < 0) exit(-1);
if (0 > (pid = fork())) exit(-1);
if (0 < pid) {
char buf;
ssize_t bytes;
close(pipefd[1]);
/* parent waits for grandchild to be ready */
do {
bytes = read(pipefd[0], &buf, sizeof(buf));
} while (bytes < 0 && EINTR == errno);
close(pipefd[0]);
if (bytes <= 0) {
/* closed fd (without writing) == failure in grandchild */
fputs("daemonized server failed to start; check error log for details\n", stderr);
exit(-1);
}
exit(0);
}
close(pipefd[0]);
if (-1 == setsid()) exit(0);
signal(SIGHUP, SIG_IGN);
if (0 != fork()) exit(0);
if (0 != chdir("/")) exit(0);
fdevent_setfd_cloexec(pipefd[1]);
return pipefd[1];
}
#endif
__attribute_cold__
static server *server_init(void) {
server *srv = calloc(1, sizeof(*srv));
force_assert(srv);
#define CLEAN(x) \
srv->x = buffer_init();
CLEAN(tmp_buf);
#undef CLEAN
connection_joblist = &srv->joblist_A;
strftime_cache_reset();
li_rand_reseed();
srv->startup_ts = log_epoch_secs = time(NULL);
srv->errh = log_error_st_init();
config_init(srv);
srv->request_env = plugins_call_handle_request_env;
srv->loadavg[0] = 0.0;
srv->loadavg[1] = 0.0;
srv->loadavg[2] = 0.0;
srv->stdin_fd = -1;
return srv;
}
__attribute_cold__
static void server_free(server *srv) {
if (oneshot_fd > 0) {
if (oneshot_fdn) {
fdevent_fdnode_event_del(srv->ev, oneshot_fdn);
fdevent_unregister(srv->ev, oneshot_fd);
oneshot_fdn = NULL;
}
close(oneshot_fd);
}
if (oneshot_fdout >= 0) {
close(oneshot_fdout);
}
if (srv->stdin_fd >= 0) {
close(srv->stdin_fd);
}
#define CLEAN(x) \
buffer_free(srv->x);
CLEAN(tmp_buf);
#undef CLEAN
fdevent_free(srv->ev);
config_free(srv);
free(srv->joblist_A.ptr);
free(srv->joblist_B.ptr);
free(srv->fdwaitqueue.ptr);
stat_cache_free();
li_rand_cleanup();
chunkqueue_chunk_pool_free();
log_error_st_free(srv->errh);
free(srv);
}
__attribute_cold__
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
static void remove_pid_file(server *srv) {
if (pid_fd <= -2) return;
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
if (!buffer_string_is_empty(srv->srvconf.pid_file) && 0 <= pid_fd) {
if (0 != ftruncate(pid_fd, 0)) {
log_perror(srv->errh, __FILE__, __LINE__,
"ftruncate failed for: %s", srv->srvconf.pid_file->ptr);
}
}
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
if (0 <= pid_fd) {
close(pid_fd);
pid_fd = -1;
}
if (!buffer_string_is_empty(srv->srvconf.pid_file) &&
buffer_string_is_empty(srv->srvconf.changeroot)) {
if (0 != unlink(srv->srvconf.pid_file->ptr)) {
if (errno != EACCES && errno != EPERM) {
log_perror(srv->errh, __FILE__, __LINE__,
"unlink failed for: %s", srv->srvconf.pid_file->ptr);
}
}
}
}
__attribute_cold__
static server_socket * server_oneshot_getsock(server *srv, sock_addr *cnt_addr) {
server_socket *srv_socket, *srv_socket_wild = NULL;
for (uint32_t i = 0; i < srv->srv_sockets.used; ++i) {
srv_socket = srv->srv_sockets.ptr[i];
if (!sock_addr_is_port_eq(&srv_socket->addr,cnt_addr)) continue;
if (sock_addr_is_addr_eq(&srv_socket->addr,cnt_addr)) return srv_socket;
if (NULL != srv_socket_wild) continue;
if (sock_addr_is_addr_wildcard(&srv_socket->addr)) {
srv_socket_wild = srv_socket;
}
}
if (NULL != srv_socket_wild) {
return srv_socket_wild;
} else if (srv->srv_sockets.used) {
return srv->srv_sockets.ptr[0];
} else {
log_error(srv->errh, __FILE__, __LINE__, "no sockets configured");
return NULL;
}
}
static int server_oneshot_read_cq(connection *con, chunkqueue *cq, off_t max_bytes) {
/* temporary set con->fd to oneshot_fd (fd input) rather than outshot_fdout
* (lighttpd generally assumes operation on sockets, so this is a kludge) */
int fd = con->fd;
con->fd = oneshot_fdn->fd;
int rc = oneshot_read_cq(con, cq, max_bytes);
con->fd = fd;
/* note: optimistic reads (elsewhere) may or may not be enough to re-enable
* read interest after FDEVENT_IN interest was paused for other reasons */
const int events = fdevent_fdnode_interest(oneshot_fdn);
int n = con->is_readable > 0 ? 0 : FDEVENT_IN;
if (events & FDEVENT_RDHUP)
n |= FDEVENT_RDHUP;
fdevent_fdnode_event_set(con->srv->ev, oneshot_fdn, n);
return rc;
}
static handler_t server_oneshot_handle_fdevent(void *context, int revents) {
connection *con = context;
/* note: not sync'd with con->fdn or connection_set_fdevent_interest() */
int rdhup = 0;
int n = fdevent_fdnode_interest(oneshot_fdn);
if (revents & FDEVENT_IN)
n &= ~FDEVENT_IN;
request_st * const r = &con->request;
if (r->state != CON_STATE_ERROR && (revents & (FDEVENT_HUP|FDEVENT_RDHUP))){
revents &= ~(FDEVENT_HUP|FDEVENT_RDHUP);
/* copied and modified from connection_handle_fdevent()
* fdevent_is_tcp_half_closed() will fail on pipe
* and, besides, read end of pipes should treat POLLHUP as POLLRDHUP */
n &= ~(FDEVENT_IN|FDEVENT_RDHUP);
rdhup = 1;
}
fdevent_fdnode_event_set(con->srv->ev, oneshot_fdn, n);
fdnode * const fdn = con->fdn; /* fdn->ctx == con */
handler_t rc = ((fdevent_handler)NULL != fdn->handler)
? (*fdn->handler)(con, revents)
: HANDLER_FINISHED;
if (rdhup) {
r->conf.stream_request_body &=
~(FDEVENT_STREAM_REQUEST_BUFMIN|FDEVENT_STREAM_REQUEST_POLLIN);
r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLRDHUP;
r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_TCP_FIN;
con->is_readable = 1; /*(can read 0 for end-of-stream)*/
if (chunkqueue_is_empty(con->read_queue)) r->keep_alive = 0;
if (r->reqbody_length < -1) /*(transparent proxy mode; no more data)*/
r->reqbody_length = r->reqbody_queue.bytes_in;
}
return rc;
}
__attribute_cold__
static int server_oneshot_init_pipe(server *srv, int fdin, int fdout) {
/* Note: attempt to work with netcat pipes though other code expects socket.
* netcat has different fds (pipes) for stdin and stdout. To support
* netcat, need to avoid S_ISSOCK(), getsockname(), and getpeername(),
* reconstructing addresses from environment variables:
* NCAT_LOCAL_ADDR NCAT_LOCAL_PORT
* NCAT_REMOTE_ADDR NCAT_REMOTE_PORT
* NCAT_PROTO (TCP, UDP, SCTP)
*/
connection *con;
server_socket *srv_socket;
sock_addr cnt_addr;
/* detect if called from netcat or else fabricate localhost addrs */
const char * const ncat =
getenv("NCAT_LOCAL_ADDR");
const char * const ncat_local_addr =
ncat ? ncat : "127.0.0.1"; /*(fabricated)*/
const char * const ncat_local_port =
ncat ? getenv("NCAT_LOCAL_PORT") : "80"; /*(fabricated)*/
const char * const ncat_remote_addr =
ncat ? getenv("NCAT_REMOTE_ADDR") : "127.0.0.1"; /*(fabricated)*/
const char * const ncat_remote_port =
ncat ? getenv("NCAT_REMOTE_PORT") : "48080"; /*(fabricated)*/
if (NULL == ncat_local_addr || NULL == ncat_local_port) return 0;
if (NULL == ncat_remote_addr || NULL == ncat_remote_port) return 0;
const int family = ncat && strchr(ncat_local_addr,':') ? AF_INET6 : AF_INET;
unsigned short port;
port = (unsigned short)strtol(ncat_local_port, NULL, 10);
if (1 != sock_addr_inet_pton(&cnt_addr, ncat_local_addr, family, port)) {
log_error(srv->errh, __FILE__, __LINE__, "invalid local addr");
return 0;
}
srv_socket = server_oneshot_getsock(srv, &cnt_addr);
if (NULL == srv_socket) return 0;
port = (unsigned short)strtol(ncat_remote_port, NULL, 10);
if (1 != sock_addr_inet_pton(&cnt_addr, ncat_remote_addr, family, port)) {
log_error(srv->errh, __FILE__, __LINE__, "invalid remote addr");
return 0;
}
/*(must set flags; fd did not pass through fdevent accept() logic)*/
if (-1 == fdevent_fcntl_set_nb_cloexec(fdin)) {
log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
return 0;
}
if (-1 == fdevent_fcntl_set_nb_cloexec(fdout)) {
log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
return 0;
}
con = connection_accepted(srv, srv_socket, &cnt_addr, fdout);
if (NULL == con) return 0;
/* note: existing routines assume socket, not pipe
* connections.c:connection_read_cq()
* uses recv() ifdef __WIN32
* passes S_IFSOCK to fdevent_ioctl_fionread()
* (The routine could be copied and modified, if required)
* This is unlikely to work if TLS is used over pipe since the SSL_CTX
* is associated with the other end of the pipe. However, if using
* pipes, using TLS is unexpected behavior.
*/
/*assert(oneshot_fd == fdin);*/
oneshot_read_cq = con->network_read;
con->network_read = server_oneshot_read_cq;
oneshot_fdn =
fdevent_register(srv->ev, fdin, server_oneshot_handle_fdevent, con);
fdevent_fdnode_event_set(srv->ev, oneshot_fdn, FDEVENT_RDHUP);
connection_state_machine(con);
return 1;
}
__attribute_cold__
static int server_oneshot_init(server *srv, int fd) {
connection *con;
server_socket *srv_socket;
sock_addr cnt_addr;
socklen_t cnt_len;
cnt_len = sizeof(cnt_addr);
if (0 != getsockname(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
log_perror(srv->errh, __FILE__, __LINE__, "getsockname()");
return 0;
}
srv_socket = server_oneshot_getsock(srv, &cnt_addr);
if (NULL == srv_socket) return 0;
#ifdef __clang_analyzer__
memset(&cnt_addr, 0, sizeof(cnt_addr));
#endif
cnt_len = sizeof(cnt_addr);
if (0 != getpeername(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
log_perror(srv->errh, __FILE__, __LINE__, "getpeername()");
return 0;
}
/*(must set flags; fd did not pass through fdevent accept() logic)*/
if (-1 == fdevent_fcntl_set_nb_cloexec(fd)) {
log_perror(srv->errh, __FILE__, __LINE__, "fcntl()");
return 0;
}
if (sock_addr_get_family(&cnt_addr) != AF_UNIX) {
network_accept_tcp_nagle_disable(fd);
}
con = connection_accepted(srv, srv_socket, &cnt_addr, fd);
if (NULL == con) return 0;
connection_state_machine(con);
return 1;
}
__attribute_cold__
static void show_version (void) {
char *b = PACKAGE_DESC TEXT_SSL \
" - a light and fast webserver\n"
#ifdef NONREPRODUCIBLE_BUILD
"Build-Date: " __DATE__ " " __TIME__ "\n";
#endif
;
write_all(STDOUT_FILENO, b, strlen(b));
}
__attribute_cold__
static void show_features (void) {
static const char features[] =
"\nFeatures:\n\n"
#ifdef HAVE_IPV6
"\t+ IPv6 support\n"
#else
"\t- IPv6 support\n"
#endif
#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
"\t+ zlib support\n"
#else
"\t- zlib support\n"
#endif
#if defined HAVE_ZSTD_H && defined HAVE_ZSTD
"\t+ zstd support\n"
#else
"\t- zstd support\n"
#endif
#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
"\t+ bzip2 support\n"
#else
"\t- bzip2 support\n"
#endif
#if defined HAVE_BROTLI_ENCODE_H && defined HAVE_BROTLI
"\t+ brotli support\n"
#else
"\t- brotli support\n"
#endif
#if defined(HAVE_CRYPT) || defined(HAVE_CRYPT_R) || defined(HAVE_LIBCRYPT)
"\t+ crypt support\n"
#else
"\t- crypt support\n"
#endif
#ifdef USE_OPENSSL_CRYPTO
"\t+ OpenSSL support\n"
#else
"\t- OpenSSL support\n"
#endif
#ifdef USE_MBEDTLS_CRYPTO
"\t+ mbedTLS support\n"
#else
"\t- mbedTLS support\n"
#endif
#ifdef USE_NSS_CRYPTO
"\t+ NSS crypto support\n"
#else
"\t- NSS crypto support\n"
#endif
#ifdef USE_GNUTLS_CRYPTO
"\t+ GnuTLS support\n"
#else
"\t- GnuTLS support\n"
#endif
#ifdef USE_WOLFSSL_CRYPTO
"\t+ WolfSSL support\n"
#else
"\t- WolfSSL support\n"
#endif
#ifdef USE_NETTLE_CRYPTO
"\t+ Nettle support\n"
#else
"\t- Nettle support\n"
#endif
#ifdef HAVE_LIBPCRE
"\t+ PCRE support\n"
#else
"\t- PCRE support\n"
#endif
#ifdef HAVE_MYSQL
"\t+ MySQL support\n"
#else
"\t- MySQL support\n"
#endif
#ifdef HAVE_PGSQL
"\t+ PgSQL support\n"
#else
"\t- PgSQL support\n"
#endif
#ifdef HAVE_DBI
"\t+ DBI support\n"
#else
"\t- DBI support\n"
#endif
#ifdef HAVE_KRB5
"\t+ Kerberos support\n"
#else
"\t- Kerberos support\n"
#endif
#if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
"\t+ LDAP support\n"
#else
"\t- LDAP support\n"
#endif
#ifdef HAVE_PAM
"\t+ PAM support\n"
#else
"\t- PAM support\n"
#endif
#ifdef USE_MEMCACHED
"\t+ memcached support\n"
#else
"\t- memcached support\n"
#endif
#ifdef HAVE_FAM_H
"\t+ FAM support\n"
#else
"\t- FAM support\n"
#endif
#ifdef HAVE_LUA_H
"\t+ LUA support\n"
#else
"\t- LUA support\n"
#endif
#ifdef HAVE_LIBXML_H
"\t+ xml support\n"
#else
"\t- xml support\n"
#endif
#ifdef HAVE_SQLITE3_H
"\t+ SQLite support\n"
#else
"\t- SQLite support\n"
#endif
#ifdef HAVE_GDBM_H
"\t+ GDBM support\n"
#else
"\t- GDBM support\n"
#endif
;
show_version();
printf("%s%s%s\n", fdevent_show_event_handlers(), network_write_show_handlers(), features);
}
__attribute_cold__
static void show_help (void) {
char *b = PACKAGE_DESC TEXT_SSL
#ifdef NONREPRODUCIBLE_BUILD
" ("__DATE__ " " __TIME__ ")"
#endif
" - a light and fast webserver\n" \
"usage:\n" \
" -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 config-file syntax, then exit\n" \
" -tt test config-file syntax, load and init modules, then exit\n" \
" -D don't go to background (default: go to background)\n" \
" -v show version\n" \
" -V show compile-time features\n" \
" -h show this help\n" \
"\n"
;
write_all(STDOUT_FILENO, b, strlen(b));
}
__attribute_cold__
[core] graceful restart with SIGUSR1 (fixes #2785) more consistent cleanup of resources at shutdown (e.g. upon error conditions) Notes: graceful restart with SIGUSR1 - not available if chroot()ed, oneshot mode, or if idle timeout occurs - preserve process id (pid) - preserve existing listen sockets - i.e. does not close old listen sockets from prior configs (even if old listen sockets no longer in the new config) (sockets may have been bound w/ root privileges no longer available) - will fail to add listen sockets from new config if privileges lighttpd configured to drop privileges to non-root user, and new listen socket attempts to bind to low-numbered port requiring root privileges. - will fail if listen sockets in new config conflict with any previous old listen sockets - These failure modes will result in lighttpd shutting down instead of graceful restart. These failure modes are not detectable with preflight checks ('lighttpd -tt -f lighttpd.conf') because the new instance of lighttpd running the preflight check does not known config state of n prior graceful restarts, or even the config state of the currently running lighttpd server. - due to lighttpd feature of optionally managing backends (e.g. fastcgi and scgi via "bin-path"), lighttpd must wait for all child processes to exit prior to restarting. Restarting new workers while old workers (and old backends) were still running would result in failure of restarted lighttpd process to be able to bind to sockets already in use by old backends (e.g. unix "socket" path) x-ref: "graceful restart with SIGUSR1" https://redmine.lighttpd.net/issues/2785
5 years ago
static void server_sockets_save (server *srv) { /* graceful_restart */
for (uint32_t i = 0; i < srv->srv_sockets.used; ++i)
srv->srv_sockets.ptr[i]->srv = NULL; /* srv will shortly be invalid */
for (uint32_t i = 0; i < srv->srv_sockets_inherited.used; ++i)
srv->srv_sockets_inherited.ptr[i]->srv = NULL; /* srv to be invalid */