diff options
Diffstat (limited to 'src/server.c')
-rw-r--r-- | src/server.c | 1792 |
1 files changed, 0 insertions, 1792 deletions
diff --git a/src/server.c b/src/server.c deleted file mode 100644 index be0accc3..00000000 --- a/src/server.c +++ /dev/null @@ -1,1792 +0,0 @@ -#include <sys/types.h> -#include <sys/stat.h> - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#else -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#endif - -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#include <time.h> -#include <signal.h> -#include <assert.h> -#include <locale.h> - -#include <stdio.h> - -#include "settings.h" -#include "server.h" -#include "buffer.h" -#include "network.h" -#include "network_backends.h" -#include "log.h" -#include "keyvalue.h" -#include "response.h" -#include "request.h" -#include "chunk.h" -#include "fdevent.h" -#include "connections.h" -#include "stat_cache.h" -#include "plugin.h" -#include "joblist.h" -#include "status_counter.h" - -/** - * stack-size of the aio-threads - * - * the default is 8Mbyte which is a bit to much. Reducing it to 64k seems to be fine - * If you experience random segfaults, increase it. - */ - -#define LI_THREAD_STACK_SIZE (64 * 1024) - - -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#else -#ifdef _WIN32 -#include "xgetopt.h" -#endif -#endif - -#include "valgrind/valgrind.h" - -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif - -#ifdef HAVE_PWD_H -#include <grp.h> -#include <pwd.h> -#endif - -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#endif - -#ifdef HAVE_SYS_PRCTL_H -#include <sys/prctl.h> -#endif - -#ifdef USE_OPENSSL -#include <openssl/err.h> -#endif - -#ifndef __sgi -/* IRIX doesn't like the alarm based time() optimization */ -/* #define USE_ALARM */ -#endif - -#ifdef _WIN32 -#undef HAVE_SIGNAL -#endif - -#include "sys-files.h" -#include "sys-process.h" -#include "sys-socket.h" - -#ifdef HAVE_GETUID -# ifndef HAVE_ISSETUGID - -static int l_issetugid() { - return (geteuid() != getuid() || getegid() != getgid()); -} - -# define issetugid l_issetugid -# endif -#endif - -static volatile sig_atomic_t srv_shutdown = 0; -static volatile sig_atomic_t graceful_shutdown = 0; -static volatile sig_atomic_t graceful_restart = 0; -static volatile sig_atomic_t handle_sig_alarm = 1; -static volatile sig_atomic_t handle_sig_hup = 0; -static volatile siginfo_t last_sigterm_info; -static volatile siginfo_t last_sighup_info; - -#if defined(HAVE_SIGACTION) && defined(SA_SIGINFO) -static void sigaction_handler(int sig, siginfo_t *si, void *context) { - static siginfo_t empty_siginfo; - UNUSED(context); - - if (!si) si = &empty_siginfo; - - switch (sig) { - case SIGTERM: - srv_shutdown = 1; - memcpy((siginfo_t*) &last_sigterm_info, si, sizeof(*si)); - break; - case SIGINT: - if (graceful_shutdown) { - srv_shutdown = 1; - } else { - graceful_shutdown = 1; - } - - memcpy((siginfo_t*) &last_sigterm_info, si, sizeof(*si)); - - break; - case SIGALRM: - handle_sig_alarm = 1; - break; - case SIGHUP: - handle_sig_hup = 1; - memcpy((siginfo_t*) &last_sighup_info, si, sizeof(*si)); - break; - case SIGCHLD: - break; - } -} -#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION) -static void signal_handler(int sig) { - switch (sig) { - case SIGTERM: srv_shutdown = 1; break; - case SIGINT: - if (graceful_shutdown) srv_shutdown = 1; - else graceful_shutdown = 1; - - break; - case SIGALRM: handle_sig_alarm = 1; break; - case SIGHUP: handle_sig_hup = 1; break; - case SIGCHLD: break; - } -} -#endif - -#ifdef HAVE_FORK -static void daemonize(void) { -#ifdef SIGTTOU - signal(SIGTTOU, SIG_IGN); -#endif -#ifdef SIGTTIN - signal(SIGTTIN, SIG_IGN); -#endif -#ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); -#endif - if (0 != fork()) exit(0); - - if (-1 == setsid()) exit(0); - - signal(SIGHUP, SIG_IGN); - - if (0 != fork()) exit(0); - - if (0 != chdir("/")) exit(0); -} -#endif - -static server *server_init(void) { - int i; - FILE *frandom = NULL; - - server *srv = calloc(1, sizeof(*srv)); - assert(srv); - - srv->max_fds = 1024; -#define CLEAN(x) \ - srv->x = buffer_init(); - - CLEAN(response_header); - CLEAN(parse_full_path); - CLEAN(ts_debug_str); - CLEAN(ts_date_str); - CLEAN(response_range); - CLEAN(tmp_buf); - srv->empty_string = buffer_init_string(""); - CLEAN(cond_check_buf); - - CLEAN(srvconf.errorlog_file); - CLEAN(srvconf.breakagelog_file); - CLEAN(srvconf.groupname); - CLEAN(srvconf.username); - CLEAN(srvconf.changeroot); - CLEAN(srvconf.bindhost); - CLEAN(srvconf.event_handler); - CLEAN(srvconf.pid_file); - - CLEAN(tmp_chunk_len); -#undef CLEAN - -#define CLEAN(x) \ - srv->x = array_init(); - - CLEAN(config_context); - CLEAN(config_touched); -#undef CLEAN - - for (i = 0; i < FILE_CACHE_MAX; i++) { - srv->mtime_cache[i].mtime = (time_t)-1; - srv->mtime_cache[i].str = buffer_init(); - } - - if ((NULL != (frandom = fopen("/dev/urandom", "rb")) || NULL != (frandom = fopen("/dev/random", "rb"))) - && 1 == fread(srv->entropy, sizeof(srv->entropy), 1, frandom)) { - srand(*(unsigned int*)srv->entropy); - srv->is_real_entropy = 1; - } else { - unsigned int j; - srand(time(NULL) ^ getpid()); - srv->is_real_entropy = 0; - for (j = 0; j < sizeof(srv->entropy); j++) - srv->entropy[j] = rand(); - } - if (frandom) fclose(frandom); - - srv->cur_ts = time(NULL); - srv->startup_ts = srv->cur_ts; - - srv->conns = calloc(1, sizeof(*srv->conns)); - assert(srv->conns); - - srv->joblist = calloc(1, sizeof(*srv->joblist)); - assert(srv->joblist); - - srv->joblist_prev = calloc(1, sizeof(*srv->joblist)); - assert(srv->joblist_prev); - - srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue)); - assert(srv->fdwaitqueue); - - srv->srvconf.modules = array_init(); - srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR); - srv->srvconf.network_backend = buffer_init(); - srv->srvconf.upload_tempdirs = array_init(); - - srv->split_vals = array_init(); - -#ifdef USE_LINUX_AIO_SENDFILE - srv->linux_io_ctx = NULL; - /** - * we can't call io_setup before the fork() in daemonize() - */ -#endif - - return srv; -} - -static void server_free(server *srv) { - size_t i; - - for (i = 0; i < FILE_CACHE_MAX; i++) { - buffer_free(srv->mtime_cache[i].str); - } - - -#ifdef USE_LINUX_AIO_SENDFILE - if (srv->linux_io_ctx) { - io_destroy(srv->linux_io_ctx); - } -#endif - -#define CLEAN(x) \ - buffer_free(srv->x); - - CLEAN(response_header); - CLEAN(parse_full_path); - CLEAN(ts_debug_str); - CLEAN(ts_date_str); - CLEAN(response_range); - CLEAN(tmp_buf); - CLEAN(empty_string); - CLEAN(cond_check_buf); - - CLEAN(srvconf.errorlog_file); - CLEAN(srvconf.breakagelog_file); - CLEAN(srvconf.groupname); - CLEAN(srvconf.username); - CLEAN(srvconf.changeroot); - CLEAN(srvconf.bindhost); - CLEAN(srvconf.event_handler); - CLEAN(srvconf.pid_file); - CLEAN(srvconf.modules_dir); - CLEAN(srvconf.network_backend); - - CLEAN(tmp_chunk_len); -#undef CLEAN - -#ifdef USE_GTHREAD - fdevent_unregister(srv->ev, srv->wakeup_iosocket); - iosocket_free(srv->wakeup_iosocket); -#endif - -#if 0 - fdevent_unregister(srv->ev, srv->fd); -#endif - fdevent_free(srv->ev); - - free(srv->conns); - - if (srv->config_storage) { - for (i = 0; i < srv->config_context->used; i++) { - specific_config *s = srv->config_storage[i]; - - if (!s) continue; - - buffer_free(s->document_root); - buffer_free(s->server_name); - buffer_free(s->server_tag); - buffer_free(s->ssl_pemfile); - buffer_free(s->ssl_ca_file); - buffer_free(s->error_handler); - buffer_free(s->errorfile_prefix); - array_free(s->mimetypes); - buffer_free(s->ssl_cipher_list); - buffer_free(s->ssl_verifyclient_username); -#ifdef USE_OPENSSL - SSL_CTX_free(s->ssl_ctx); -#endif - - free(s); - } - free(srv->config_storage); - srv->config_storage = NULL; - } - -#define CLEAN(x) \ - array_free(srv->x); - - CLEAN(config_context); - CLEAN(config_touched); - CLEAN(srvconf.upload_tempdirs); -#undef CLEAN - - joblist_free(srv, srv->joblist); - joblist_free(srv, srv->joblist_prev); - fdwaitqueue_free(srv, srv->fdwaitqueue); - - if (srv->stat_cache) { - stat_cache_free(srv->stat_cache); - } - - array_free(srv->srvconf.modules); - array_free(srv->split_vals); -#ifdef USE_OPENSSL - if (srv->ssl_is_init) { - CRYPTO_cleanup_all_ex_data(); - ERR_free_strings(); - ERR_remove_state(0); - EVP_cleanup(); - } -#endif - free(srv); -} - -static void show_version (void) { -#ifdef USE_OPENSSL -# define TEXT_SSL " (ssl)" -#else -# define TEXT_SSL -#endif - char *b = PACKAGE_NAME "-" PACKAGE_VERSION TEXT_SSL \ -" - a light and fast webserver\n" \ -"Build-Date: " __DATE__ " " __TIME__ "\n"; -; -#undef TEXT_SSL - if (-1 == write(STDOUT_FILENO, b, strlen(b))) { - /* what to do if this happens ? */ - - exit(-1); - } -} - -static void show_features (void) { - const fdevent_handler_info_t *handler; - const network_backend_info_t *backend; - - const char *features = -#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_BZLIB_H && defined HAVE_LIBBZ2 - "\t+ bzip2 support\n" -#else - "\t- bzip2 support\n" -#endif -#ifdef HAVE_LIBCRYPT - "\t+ crypt support\n" -#else - "\t- crypt support\n" -#endif -#ifdef USE_OPENSSL - "\t+ SSL Support\n" -#else - "\t- SSL 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 -#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_MEMCACHE_H - "\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("\nEvent Handlers:\n\n"); - for (handler = fdevent_get_handlers(); handler->name; handler++) { - printf("\t%c %s", handler->init ? '+' : '-', handler->name); - if (handler->description) { - printf(": %s\n", handler->description); - } - else { - printf("\n"); - } - } - - printf("\nNetwork Backends:\n\n"); - for (backend = network_get_backends(); backend->name; backend++) { - printf("\t%c %s", backend->write_handler ? '+' : '-', backend->name); - if (backend->description) { - printf(": %s\n", backend->description); - } - else { - printf("\n"); - } - } - -#ifdef USE_MMAP - printf("\t+ (mmap) support\n"); -#else - printf("\t- (mmap) support\n"); -#endif - printf("\nFeatures:\n\n%s", features); -} - -static void show_help (void) { -#ifdef USE_OPENSSL -# define TEXT_SSL " (ssl)" -#else -# define TEXT_SSL -#endif - char *b = PACKAGE_NAME "-" PACKAGE_VERSION TEXT_SSL " ("__DATE__ " " __TIME__ ")" \ -" - a light and fast webserver\n" \ -"usage:\n" \ -" -f <name> filename of the config-file\n" \ -" -m <name> module directory (default: "LIBRARY_DIR")\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" \ -" -I go to background on SIGINT (useful with -D)\n" \ -" has no effect when using kqueue or /dev/poll\n" \ -" -v show version\n" \ -" -V show compile-time features\n" \ -" -h show this help\n" \ -"\n" -; -#undef TEXT_SSL -#undef TEXT_IPV6 - if (-1 == write(STDOUT_FILENO, b, strlen(b))) { - exit(-1); - } -} - -/** - * call this function whenever you get a EMFILE or ENFILE as return-value - * - * after each socket(), accept(), connect() or open() call - * - */ -int server_out_of_fds(server *srv, connection *con) { - /* we get NULL of accept() ran out of FDs */ - - if (con) { - fdwaitqueue_append(srv, con); - } - - return 0; -} - -static int lighty_mainloop(server *srv) { - fdevent_revents *revents = fdevent_revents_init(); - int poll_errno; - size_t conns_user_at_sockets_disabled = 0; - - /* the getevents and the poll() have to run in parallel - * as soon as one has data, it has to interrupt the otherone */ - - /* main-loop */ - while (!srv_shutdown) { - int n; - size_t ndx; - time_t min_ts; - - if (handle_sig_hup) { - handler_t r; - - /* reset notification */ - handle_sig_hup = 0; - -#if 0 - pid_t pid; - - /* send the old process into a graceful-shutdown and start a - * new process right away - * - * BUGS: - * - if webserver is running on port < 1024 (e.g. 80, 433) - * we don't have the permissions to bind to that port anymore - * - * - * */ - if (0 == (pid = fork())) { - execve(argv[0], argv, envp); - - exit(-1); - } else if (pid == -1) { - - } else { - /* parent */ - - graceful_shutdown = 1; /* shutdown without killing running connections */ - graceful_restart = 1; /* don't delete pid file */ - } -#else - /* cycle logfiles */ - - switch(r = plugins_call_handle_sighup(srv)) { - case HANDLER_GO_ON: - break; - default: - log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r); - break; - } - - if (-1 == log_error_cycle()) { - log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying"); - - return -1; - } else { - TRACE("logfiles cycled by UID=%d, PID=%d", - last_sighup_info.si_uid, - last_sighup_info.si_pid); - } -#endif - } - - if (handle_sig_alarm) { - /* a new second */ - -#ifdef USE_ALARM - /* reset notification */ - handle_sig_alarm = 0; -#endif - - /* get current time */ - min_ts = time(NULL); - - if (min_ts != srv->cur_ts) { - int cs = 0; - connections *conns = srv->conns; - handler_t r; - - switch(r = plugins_call_handle_trigger(srv)) { - case HANDLER_GO_ON: - break; - case HANDLER_ERROR: - log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed"); - break; - default: - log_error_write(srv, __FILE__, __LINE__, "d", r); - break; - } - - /* trigger waitpid */ - srv->cur_ts = min_ts; - - /* cleanup stat-cache */ - stat_cache_trigger_cleanup(srv); - /** - * check all connections for timeouts - * - */ - for (ndx = 0; ndx < conns->used; ndx++) { - int changed = 0; - connection *con; - int t_diff; - - con = conns->ptr[ndx]; - - switch (con->state) { - case CON_STATE_READ_REQUEST_HEADER: - case CON_STATE_READ_REQUEST_CONTENT: - if (con->recv->is_closed) { - if (srv->cur_ts - con->read_idle_ts > con->conf.max_connection_idle) { - /* time - out */ -#if 0 - TRACE("(connection process timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf)); -#endif - connection_set_state(srv, con, CON_STATE_ERROR); - changed = 1; - } - } - - if (con->request_count == 1) { - if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { - /* time - out */ -#if 0 - TRACE("(initial read timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf)); -#endif - connection_set_state(srv, con, CON_STATE_ERROR); - changed = 1; - } - } else { - if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) { - /* time - out */ -#if 0 - TRACE("(keep-alive read timeout) [%s]", SAFE_BUF_STR(con->dst_addr_buf)); -#endif - connection_set_state(srv, con, CON_STATE_ERROR); - changed = 1; - } - } - break; - case CON_STATE_WRITE_RESPONSE_HEADER: - case CON_STATE_WRITE_RESPONSE_CONTENT: - - - if (con->write_request_ts != 0 && - srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) { - /* time - out */ - if (con->conf.log_timeouts) { - log_error_write(srv, __FILE__, __LINE__, "sbsosds", - "NOTE: a request for", - con->request.uri, - "timed out after writing", - con->bytes_written, - "bytes. We waited", - (int)con->conf.max_write_idle, - "seconds. If this a problem increase server.max-write-idle"); - } - connection_set_state(srv, con, CON_STATE_ERROR); - changed = 1; - } - break; - default: - /* the other ones are uninteresting */ - break; - } - /* we don't like div by zero */ - if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1; - - if (con->traffic_limit_reached && - (con->conf.kbytes_per_second == 0 || - ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) { - /* enable connection again */ - con->traffic_limit_reached = 0; - - changed = 1; - } - - if (changed) { - connection_state_machine(srv, con); - } - con->bytes_written_cur_second = 0; - *(con->conf.global_bytes_per_second_cnt_ptr) = 0; - -#if 0 - if (cs == 0) { - fprintf(stderr, "connection-state: "); - cs = 1; - } - - fprintf(stderr, "c[%d,%d]: %s ", - con->fd, - con->fcgi.fd, - connection_get_state(con->state)); -#endif - } - - if (cs == 1) fprintf(stderr, "\n"); - } - } - - if (srv->sockets_disabled) { - /* our server sockets are disabled, why ? */ - - if ((srv->fdwaitqueue->used == 0) && - (srv->conns->used <= srv->max_conns * 9 / 10) && - (0 == graceful_shutdown)) { - size_t i; - - for (i = 0; i < srv->srv_sockets.used; i++) { - server_socket *srv_socket = srv->srv_sockets.ptr[i]; - fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN); - } - - TRACE("[note] sockets enabled again%s", ""); - - srv->sockets_disabled = 0; - } - } else { - if ((srv->fdwaitqueue->used) || /* looks like some cons are waiting for FDs*/ - (srv->conns->used >= srv->max_conns) || /* out of connections */ - (graceful_shutdown)) { /* graceful_shutdown */ - size_t i; - - /* disable server-fds */ - - for (i = 0; i < srv->srv_sockets.used; i++) { - server_socket *srv_socket = srv->srv_sockets.ptr[i]; - - fdevent_event_del(srv->ev, srv_socket->sock); - - if (graceful_shutdown) { - /* we don't want this socket anymore, - * - * closing it right away will make it possible for - * the next lighttpd to take over (graceful restart) - * */ - - fdevent_unregister(srv->ev, srv_socket->sock); - closesocket(srv_socket->sock->fd); - srv_socket->sock->fd = -1; - -#ifdef HAVE_FORK - /* FreeBSD kqueue could possibly work with rfork(RFFDG) - * while Solaris /dev/poll would require re-registering - * all fd */ - if (srv->srvconf.daemonize_on_shutdown && - srv->event_handler != FDEVENT_HANDLER_FREEBSD_KQUEUE && - srv->event_handler != FDEVENT_HANDLER_SOLARIS_DEVPOLL) { - daemonize(); - } -#endif - - /* network_close() will cleanup after us */ - } - } - - if (graceful_shutdown) { - TRACE("[note] graceful shutdown started by UID=%d, PID=%d", last_sigterm_info.si_uid, last_sigterm_info.si_pid); - } else if (srv->fdwaitqueue->used) { - TRACE("[note] out of FDs, server-socket get disabled for a while, we have %zu connections open and they are waiting for %zu FDs", - srv->conns->used, srv->fdwaitqueue->used); - } else if (srv->conns->used >= srv->max_conns) { - TRACE("[note] we reached our connection limit of %zu connections. Disabling server-sockets for a while", srv->max_conns); - } - - srv->sockets_disabled = 1; - - /* we count the number of free fds indirectly. - * - * instead of checking the fds we only check the connection handles we free'd since - * the server-sockets got disabled - * */ - conns_user_at_sockets_disabled = srv->conns->used; - } - } - - if (graceful_shutdown && srv->conns->used == 0) { - /* we are in graceful shutdown phase and all connections are closed - * we are ready to terminate without harming anyone */ - srv_shutdown = 1; - continue; - } - - /* we still have some fds to share */ - if (!srv_shutdown && srv->fdwaitqueue->used) { - /* ok, we are back to the problem of 'how many fds do we have available ?' */ - connection *con; - int fd; - int avail_fds = conns_user_at_sockets_disabled - srv->conns->used; - - if (-1 == (fd = open("/dev/null", O_RDONLY))) { - switch (errno) { - case EMFILE: - avail_fds = 0; - - break; - default: - break; - } - } else { - close(fd); - - /* we have at least one FD as we just checked */ - if (!avail_fds) avail_fds++; - } - - - TRACE("conns used: %zu, fd-waitqueue has %zu entries, fds to share: %d", srv->conns->used, srv->fdwaitqueue->used, avail_fds); - - while (avail_fds-- && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue))) { - connection_state_machine(srv, con); - } - } - n = fdevent_poll(srv->ev, 1000); - poll_errno = errno; -#ifdef USE_GTHREAD - g_atomic_int_set(&srv->did_wakeup, 0); -#endif - - if (n > 0) { - /* n is the number of events */ - size_t i; - fdevent_get_revents(srv->ev, n, revents); - - /* handle client connections first - * - * this is a bit of a hack, but we have to make sure than we handle - * close-events before the connection is reused for a keep-alive - * request - * - * this is mostly an issue for mod_proxy_core, but you never know - * - */ - - for (i = 0; i < revents->used; i++) { - fdevent_revent *revent = revents->ptr[i]; - handler_t r; - - /* skip server-fds */ - if (revent->handler == network_server_handle_fdevent) continue; - - switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) { - case HANDLER_WAIT_FOR_FD: - server_out_of_fds(srv, NULL); - case HANDLER_FINISHED: - case HANDLER_GO_ON: - case HANDLER_WAIT_FOR_EVENT: - break; - case HANDLER_ERROR: - /* should never happen */ - SEGFAULT("got HANDLER_ERROR from a plugin: %s", "dieing"); - break; - default: - ERROR("got handler_t(%d) from a plugin: ignored", r); - break; - } - } - - for (i = 0; i < revents->used; i++) { - fdevent_revent *revent = revents->ptr[i]; - handler_t r; - - /* server fds only */ - if (revent->handler != network_server_handle_fdevent) continue; - - switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) { - case HANDLER_WAIT_FOR_FD: - server_out_of_fds(srv, NULL); - case HANDLER_FINISHED: - case HANDLER_GO_ON: - case HANDLER_WAIT_FOR_EVENT: - break; - case HANDLER_ERROR: - /* should never happen */ - SEGFAULT("got HANDLER_ERROR from a plugin: %s", "dieing"); - break; - default: - ERROR("got handler_t(%d) from a plugin: ignored", r); - break; - } - } - - } else if (n < 0 && poll_errno != EINTR) { - ERROR("fdevent_poll failed: %s", strerror(poll_errno)); - } - - /* - * Note: Two joblist's are needed so a connection can be added back into the joblist - * without getting stuck inside the for loop. - */ -#ifdef USE_GTHREAD - { - connection *con; - while (NULL != (con = g_async_queue_try_pop(srv->joblist_queue))) { - joblist_append(srv, con); - } - } -#endif - if(srv->joblist->used > 0) { - connections *joblist = srv->joblist; - /* switch joblist queues. */ - srv->joblist = srv->joblist_prev; - srv->joblist_prev = joblist; - } - for (ndx = 0; ndx < srv->joblist_prev->used; ndx++) { - connection *con = srv->joblist_prev->ptr[ndx]; - handler_t r; - - con->in_joblist = 0; - connection_state_machine(srv, con); - - switch(r = plugins_call_handle_joblist(srv, con)) { - case HANDLER_FINISHED: - case HANDLER_GO_ON: - break; - default: - ERROR("got handler_t(%d) from a plugin: ignored", r); - break; - } - } - - srv->joblist_prev->used = 0; - } - - fdevent_revents_free(revents); - - return 0; -} - -#ifdef USE_GTHREAD -static handler_t wakeup_handle_fdevent(void *s, void *context, int revent) { - server *srv = (server *)s; - connection *con = context; - char buf[16]; - UNUSED(con); - UNUSED(revent); - - (void) read(srv->wakeup_iosocket->fd, buf, sizeof(buf)); - return HANDLER_GO_ON; -} -#endif - -int main (int argc, char **argv, char **envp) { - server *srv = NULL; - int print_config = 0; - int test_config = 0; - int i_am_root; - int o; - int num_childs = 0; - int pid_fd = -1, fd; - size_t i; -#ifdef USE_GTHREAD - GThread **stat_cache_threads; - GThread **aio_write_threads = NULL; -#ifdef USE_LINUX_AIO_SENDFILE - GThread *linux_aio_read_thread_id = NULL; -#endif - GError *gerr = NULL; -#endif - -#ifdef HAVE_SIGACTION - struct sigaction act; -#endif -#ifdef HAVE_GETRLIMIT - struct rlimit rlim; -#endif - -#ifdef USE_ALARM - struct itimerval interval; - - interval.it_interval.tv_sec = 1; - interval.it_interval.tv_usec = 0; - interval.it_value.tv_sec = 1; - interval.it_value.tv_usec = 0; -#endif - - UNUSED(envp); - - log_init(); - status_counter_init(); - - /* for nice %b handling in strfime() */ - setlocale(LC_TIME, "C"); - - if (NULL == (srv = server_init())) { - fprintf(stderr, "did this really happen?\n"); - return -1; - } - - /* init structs done */ - - srv->srvconf.port = 0; -#ifdef HAVE_GETUID - i_am_root = (getuid() == 0); -#else - i_am_root = 0; -#endif - srv->srvconf.dont_daemonize = 0; - srv->srvconf.daemonize_on_shutdown = 0; - srv->srvconf.max_stat_threads = 4; - srv->srvconf.max_read_threads = 8; - - while(-1 != (o = getopt(argc, argv, "f:m:hvVDIpt"))) { - switch(o) { - case 'f': - if (config_read(srv, optarg)) { - server_free(srv); - return -1; - } - break; - case 'm': - buffer_copy_string(srv->srvconf.modules_dir, optarg); - break; - case 'p': print_config = 1; break; - case 't': test_config = 1; break; - case 'D': srv->srvconf.dont_daemonize = 1; break; - case 'I': srv->srvconf.daemonize_on_shutdown = 1; break; - case 'v': show_version(); return 0; - case 'V': show_features(); return 0; - case 'h': show_help(); return 0; - default: - show_help(); - server_free(srv); - return -1; - } - } - - if (!srv->config_storage) { - log_error_write(srv, __FILE__, __LINE__, "s", - "No configuration available. Try using -f option."); - - server_free(srv); - return -1; - } - - if (print_config) { - data_unset *dc = srv->config_context->data[0]; - if (dc) { - dc->print(dc, 0); - fprintf(stdout, "\n"); - } else { - /* shouldn't happend */ - fprintf(stdout, "global config not found\n"); - } - } - - if (test_config) { - printf("Syntax OK\n"); - } - - if (test_config || print_config) { - server_free(srv); - return 0; - } - - /* close stdin and stdout, as they are not needed */ - /* move stdin to /dev/null */ - if (-1 != (fd = open("/dev/null", O_RDONLY))) { - close(STDIN_FILENO); - dup2(fd, STDIN_FILENO); - close(fd); - } - - /* move stdout to /dev/null */ - if (-1 != (fd = open("/dev/null", O_WRONLY))) { - close(STDOUT_FILENO); - dup2(fd, STDOUT_FILENO); - close(fd); - } - - if (0 != config_set_defaults(srv)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "setting default values failed"); - server_free(srv); - return -1; - } - - /* UID handling */ -#ifdef HAVE_GETUID - if (!i_am_root && issetugid()) { - /* we are setuid-root */ - - log_error_write(srv, __FILE__, __LINE__, "s", - "Are you nuts ? Don't apply a SUID bit to this binary"); - - server_free(srv); - return -1; - } -#endif - - /* check document-root */ - if (srv->config_storage[0]->document_root->used <= 1) { - log_error_write(srv, __FILE__, __LINE__, "s", - "document-root is not set\n"); - - server_free(srv); - - return -1; - } - - if (plugins_load(srv)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "loading plugins finally failed"); - - plugins_free(srv); - server_free(srv); - - return -1; - } - -#ifndef _WIN32 - /* open pid file BEFORE chroot */ - if (srv->srvconf.pid_file->used) { - if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { - struct stat st; - if (errno != EEXIST) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); - return -1; - } - - if (0 != stat(srv->srvconf.pid_file->ptr, &st)) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno)); - } - - if (!S_ISREG(st.st_mode)) { - log_error_write(srv, __FILE__, __LINE__, "sb", - "pid-file exists and isn't regular file:", srv->srvconf.pid_file); - return -1; - } - - if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); - return -1; - } - } - } -#endif - if (srv->event_handler == FDEVENT_HANDLER_SELECT) { - /* select limits itself - * - * as it is a hard limit and will lead to a segfault we add some safety - * */ - fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE); - srv->max_fds = FD_SETSIZE - 4; - } else { - srv->max_fds = 4096; - } - - if (i_am_root) { - struct group *grp = NULL; - struct passwd *pwd = NULL; - int use_rlimit = 1; - - /* valgrind only supports 1024 fds */ - if (RUNNING_ON_VALGRIND) use_rlimit = 0; - -#ifdef HAVE_GETRLIMIT - if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { - log_error_write(srv, __FILE__, __LINE__, - "ss", "couldn't get 'max filedescriptors'", - strerror(errno)); - return -1; - } - - if (use_rlimit && srv->srvconf.max_fds) { - /* set rlimits */ - - rlim.rlim_cur = srv->srvconf.max_fds; - rlim.rlim_max = srv->srvconf.max_fds; - - if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { - log_error_write(srv, __FILE__, __LINE__, - "ss", "couldn't set 'max filedescriptors'", - strerror(errno)); - return -1; - } - } - - if (srv->event_handler == FDEVENT_HANDLER_SELECT) { - srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; - } else { - srv->max_fds = rlim.rlim_cur; - } - - /* set core file rlimit, if enable_cores is set */ - if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { - rlim.rlim_cur = rlim.rlim_max; - setrlimit(RLIMIT_CORE, &rlim); - } -#endif - if (srv->event_handler == FDEVENT_HANDLER_SELECT) { - /* don't raise the limit above FD_SET_SIZE */ - if (srv->max_fds > ((int)FD_SETSIZE) - 200) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "can't raise max filedescriptors above", FD_SETSIZE - 200, - "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); - return -1; - } - } - - -#ifdef HAVE_PWD_H - /* set user and group */ - if (srv->srvconf.username->used) { - if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) { - log_error_write(srv, __FILE__, __LINE__, "sb", - "can't find username", srv->srvconf.username); - return -1; - } - - if (pwd->pw_uid == 0) { - log_error_write(srv, __FILE__, __LINE__, "s", - "I will not set uid to 0\n"); - return -1; - } - } - - if (srv->srvconf.groupname->used) { - if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) { - log_error_write(srv, __FILE__, __LINE__, "sb", - "can't find groupname", srv->srvconf.groupname); - return -1; - } - if (grp->gr_gid == 0) { - log_error_write(srv, __FILE__, __LINE__, "s", - "I will not set gid to 0\n"); - return -1; - } - } -#endif - /* we need root-perms for port < 1024 */ - if (0 != network_init(srv)) { - plugins_free(srv); - server_free(srv); - - return -1; - } - -#ifdef HAVE_PWD_H - /** - * initgroups() has to be called before chroot() - */ - if (srv->srvconf.groupname->used) { - setgid(grp->gr_gid); - setgroups(0, NULL); - if (srv->srvconf.username->used) { - initgroups(srv->srvconf.username->ptr, grp->gr_gid); - } - } -#endif -#ifdef HAVE_CHROOT - if (srv->srvconf.changeroot->used) { - tzset(); - - if (-1 == chroot(srv->srvconf.changeroot->ptr)) { - log_error_write(srv, __FILE__, __LINE__, "ss", "chroot failed: ", strerror(errno)); - return -1; - } - if (-1 == chdir("/")) { - log_error_write(srv, __FILE__, __LINE__, "ss", "chdir failed: ", strerror(errno)); - return -1; - } - } -#endif -#ifdef HAVE_PWD_H - /* drop root privs */ - if (srv->srvconf.username->used) setuid(pwd->pw_uid); -#endif -#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) - /** - * IRIX 6.5.x has prctl() but no PR_SET_DUMPABLE - */ - if (srv->srvconf.enable_cores) { - prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); - } -#endif - } else { - -#ifdef HAVE_GETRLIMIT - if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { - log_error_write(srv, __FILE__, __LINE__, - "ss", "couldn't get 'max filedescriptors'", - strerror(errno)); - return -1; - } - - if (srv->event_handler == FDEVENT_HANDLER_SELECT) { - srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 4 ? rlim.rlim_cur : FD_SETSIZE - 4; - } else { - srv->max_fds = rlim.rlim_cur; - } - - /* set core file rlimit, if enable_cores is set */ - if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { - rlim.rlim_cur = rlim.rlim_max; - setrlimit(RLIMIT_CORE, &rlim); - } - -#endif - if (srv->event_handler == FDEVENT_HANDLER_SELECT) { - /* don't raise the limit above FD_SET_SIZE */ - if (srv->max_fds > ((int)FD_SETSIZE) - 4) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "can't raise max filedescriptors above", FD_SETSIZE - 4, - "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); - return -1; - } - } - - if (0 != network_init(srv)) { - plugins_free(srv); - server_free(srv); - - return -1; - } - } - - /* set max-conns */ - if (srv->srvconf.max_conns > srv->max_fds/2) { - /* we can't have more connections than max-fds/2 */ - log_error_write(srv, __FILE__, __LINE__, "sdd", "can't have more connections than fds/2: ", srv->srvconf.max_conns, srv->max_fds); - srv->max_conns = srv->max_fds/2; - } else if (srv->srvconf.max_conns) { - /* otherwise respect the wishes of the user */ - srv->max_conns = srv->srvconf.max_conns; - } else { - /* or use the default: we really don't want to hit max-fds */ - srv->max_conns = srv->max_fds/3; - } - - if (HANDLER_GO_ON != plugins_call_init(srv)) { - log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down."); - - plugins_free(srv); - network_close(srv); - server_free(srv); - - return -1; - } - -#ifdef HAVE_FORK - /* network is up, let's deamonize ourself */ - if (srv->srvconf.dont_daemonize == 0) daemonize(); -#endif - -#ifdef HAVE_PWD_H - srv->gid = getgid(); - srv->uid = getuid(); -#endif - - /* write pid file */ - if (pid_fd != -1) { - buffer_copy_long(srv->tmp_buf, getpid()); - buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n")); - if (-1 == write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1)) { - ERROR("writing to PID to '%s' failed: %s, ignored", "...", strerror(errno)); - } - close(pid_fd); - pid_fd = -1; - } - - if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { - log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); - - plugins_free(srv); - network_close(srv); - server_free(srv); - - return -1; - } - - /* dump unused config-keys */ - for (i = 0; i < srv->config_context->used; i++) { - array *config = ((data_config *)srv->config_context->data[i])->value; - size_t j; - - for (j = 0; config && j < config->used; j++) { - data_unset *du = config->data[j]; - - /* all var.* is known as user defined variable */ - if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) { - continue; - } - - if (NULL == array_get_element(srv->config_touched, CONST_BUF_LEN(du->key))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "WARNING: unknown config-key:", - du->key, - "(ignored)"); - } - } - } - - if (srv->config_unsupported) { - log_error_write(srv, __FILE__, __LINE__, "s", - "Configuration contains unsupported keys. Going down."); - } - - if (srv->config_deprecated) { - log_error_write(srv, __FILE__, __LINE__, "s", - "Configuration contains deprecated keys. Going down."); - } - - if (srv->config_unsupported || srv->config_deprecated) { - plugins_free(srv); - network_close(srv); - server_free(srv); - - return -1; - } - - if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.breakagelog_file, srv->srvconf.errorlog_use_syslog, srv->srvconf.dont_daemonize)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "opening errorlog failed, dying"); - - plugins_free(srv); - network_close(srv); - server_free(srv); - return -1; - } - -#ifdef HAVE_SIGACTION - memset(&act, 0, sizeof(act)); - act.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &act, NULL); -# if defined(SA_SIGINFO) - act.sa_sigaction = sigaction_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; -# else - act.sa_handler = signal_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; -# endif - sigaction(SIGINT, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGALRM, &act, NULL); - sigaction(SIGCHLD, &act, NULL); - -#elif defined(HAVE_SIGNAL) - /* ignore the SIGPIPE from sendfile() */ - signal(SIGPIPE, SIG_IGN); - signal(SIGALRM, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGHUP, signal_handler); - signal(SIGCHLD, signal_handler); - signal(SIGINT, signal_handler); -#endif - -#ifdef USE_ALARM - signal(SIGALRM, signal_handler); - - /* setup periodic timer (1 second) */ - if (setitimer(ITIMER_REAL, &interval, NULL)) { - log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed"); - return -1; - } - - getitimer(ITIMER_REAL, &interval); -#endif - -#ifdef HAVE_FORK - /* start watcher and workers */ - num_childs = srv->srvconf.max_worker; - if (num_childs > 0) { - int child = 0; - while (!child && !srv_shutdown) { - if (num_childs > 0) { - switch (fork()) { - case -1: - return -1; - case 0: - child = 1; - break; - default: - num_childs--; - break; - } - } else { - int status; - - if (-1 != wait(&status)) { - /* a child terminated, restart it */ - num_childs++; - } else { - /* we got interrupted */ - - switch (errno) { - case EINTR: - /** - * we got asked to rotate the logs - * - * as we are just the parent and have no main-loop we have to fix it ourself - */ - if (handle_sig_hup) { - handle_sig_hup = 0; - - log_error_cycle(); - } - break; - default: - TRACE("(angel) wait() failed with: %s (errno=%d)", strerror(errno), errno); - break; - } - } - } - } - - if (srv_shutdown) { - /* kill all childs */ - kill(0, SIGTERM); - } - - /* if we are the parent, leave here */ - if (!child) return 0; - } -#endif - - if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) { - log_error_write(srv, __FILE__, __LINE__, - "s", "fdevent_init failed"); - return -1; - } - /* - * kqueue() is called here, select resets its internals, - * all server sockets get their handlers - * - * */ - if (0 != network_register_fdevents(srv)) { - plugins_free(srv); - network_close(srv); - server_free(srv); - - return -1; - } - -#ifdef USE_GTHREAD - if (pipe(srv->wakeup_pipe) == -1) { - log_error_write(srv, __FILE__, __LINE__, "s", "pipe() failed"); - return -1; - } - srv->wakeup_iosocket = iosocket_init(); - srv->wakeup_iosocket->type = IOSOCKET_TYPE_PIPE; - srv->wakeup_iosocket->fd = srv->wakeup_pipe[0]; - srv->did_wakeup = 0; - fdevent_fcntl_set(srv->ev, srv->wakeup_iosocket); - /* block on write */ -#ifdef FD_CLOEXEC - /* close fd on exec (cgi) */ - fcntl(srv->wakeup_pipe[1], F_SETFD, FD_CLOEXEC); -#endif - fdevent_register(srv->ev, srv->wakeup_iosocket, wakeup_handle_fdevent, NULL); - fdevent_event_add(srv->ev, srv->wakeup_iosocket, FDEVENT_IN); -#endif - - /* might fail if user is using fam (not gamin) and famd isn't running */ - if (NULL == (srv->stat_cache = stat_cache_init())) { - log_error_write(srv, __FILE__, __LINE__, "s", - "stat-cache could not be setup, dieing."); - return -1; - } - -#ifdef USE_GTHREAD - g_thread_init(NULL); - - srv->stat_queue = g_async_queue_new(); - srv->joblist_queue = g_async_queue_new(); - srv->aio_write_queue = g_async_queue_new(); -#ifdef HAVE_SYS_INOTIFY_H - if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_INOTIFY) { - srv->stat_cache->sock->fd = inotify_init(); - - fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL); - fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN); - } -#endif - stat_cache_threads = calloc(srv->srvconf.max_stat_threads, sizeof(*stat_cache_threads)); - - for (i = 0; i < srv->srvconf.max_stat_threads; i++) { - stat_cache_threads[i] = g_thread_create(stat_cache_thread, srv, 1, &gerr); - if (gerr) { - ERROR("g_thread_create failed: %s", gerr->message); - - return -1; - } - } - -#ifndef _WIN32 - switch (srv->network_backend) { - case NETWORK_BACKEND_GTHREAD_AIO: - aio_write_threads = calloc(srv->srvconf.max_read_threads, sizeof(*aio_write_threads)); - for (i = 0; i < srv->srvconf.max_read_threads; i++) { - aio_write_threads[i] = g_thread_create_full(network_gthread_aio_read_thread, srv, LI_THREAD_STACK_SIZE, 1, TRUE, G_THREAD_PRIORITY_NORMAL, &gerr); - if (gerr) { - ERROR("g_thread_create failed: %s", gerr->message); - - return -1; - } - } - break; -#ifdef USE_GTHREAD_SENDFILE - case NETWORK_BACKEND_GTHREAD_SENDFILE: - aio_write_threads = calloc(srv->srvconf.max_read_threads, sizeof(*aio_write_threads)); - for (i = 0; i < srv->srvconf.max_read_threads; i++) { - aio_write_threads[i] = g_thread_create_full(network_gthread_sendfile_read_thread, srv, LI_THREAD_STACK_SIZE, 1, TRUE, G_THREAD_PRIORITY_NORMAL, &gerr); - if (gerr) { - ERROR("g_thread_create failed: %s", gerr->message); - - return -1; - } - } - break; -#endif -#ifdef USE_GTHREAD_FREEBSD_SENDFILE - case NETWORK_BACKEND_GTHREAD_FREEBSD_SENDFILE: - aio_write_threads = calloc(srv->srvconf.max_read_threads, sizeof(*aio_write_threads)); - for (i = 0; i < srv->srvconf.max_read_threads; i++) { - aio_write_threads[i] = g_thread_create_full(network_gthread_freebsd_sendfile_read_thread, srv, LI_THREAD_STACK_SIZE, 1, TRUE, G_THREAD_PRIORITY_NORMAL, &gerr); - if (gerr) { - ERROR("g_thread_create failed: %s", gerr->message); - - return -1; - } - } - break; -#endif -#ifdef USE_POSIX_AIO - case NETWORK_BACKEND_POSIX_AIO: - srv->posix_aio_iocbs = calloc(srv->srvconf.max_read_threads, sizeof(*srv->posix_aio_iocbs)); - break; -#endif -#ifdef USE_LINUX_AIO_SENDFILE - case NETWORK_BACKEND_LINUX_AIO_SENDFILE: - TRACE("WARNING: You selected the experimental network.backend '%s'", "linux-aio-sendfile"); - srv->linux_io_iocbs = calloc(srv->srvconf.max_read_threads, sizeof(*srv->linux_io_iocbs)); - if (0 != (i = io_setup(srv->srvconf.max_read_threads, &(srv->linux_io_ctx)))) { - ERROR("io-setup() failed somehow %s", strerror(-i)); - - return -1; - } - linux_aio_read_thread_id = g_thread_create(linux_aio_read_thread, srv, 1, &gerr); - if (gerr) { - ERROR("g_thread_create failed: %s", gerr->message); - - return -1; - } - break; -#endif - default: - break; - } -#endif /* ifndef _WIN32 */ - -#endif /* USE_GTHREAD */ - - for (i = 0; i < srv->srv_sockets.used; i++) { - server_socket *srv_socket = srv->srv_sockets.ptr[i]; - if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) { - log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); - return -1; - } - } - - lighty_mainloop(srv); - - if (0 == graceful_restart && - srv->srvconf.pid_file->used && - srv->srvconf.changeroot->used == 0) { - if (0 != unlink(srv->srvconf.pid_file->ptr)) { - if (errno != EACCES && errno != EPERM) { - log_error_write(srv, __FILE__, __LINE__, "sbds", - "unlink failed for:", - srv->srvconf.pid_file, - errno, - strerror(errno)); - } - } - } - - /* kill the threads */ - - srv->is_shutdown = 1; -#ifdef USE_GTHREAD -#ifdef USE_LINUX_AIO_SENDFILE - if (srv->network_backend == NETWORK_BACKEND_LINUX_AIO_SENDFILE) { - g_thread_join(linux_aio_read_thread_id); - free(srv->linux_io_iocbs); - } -#endif -#ifdef USE_POSIX_AIO - if (srv->network_backend == NETWORK_BACKEND_POSIX_AIO) { - free(srv->posix_aio_iocbs); - } -#endif - if (aio_write_threads != NULL) { - for (i = 0; i < srv->srvconf.max_read_threads; i++) { - g_thread_join(aio_write_threads[i]); - } - free(aio_write_threads); - } - - for (i = 0; i < srv->srvconf.max_stat_threads; i++) { - g_async_queue_push(srv->stat_queue, (void *) 1); - } - - for (i = 0; i < srv->srvconf.max_stat_threads; i++) { - g_thread_join(stat_cache_threads[i]); - } - - /* the ref-count should be 0 now */ - g_async_queue_unref(srv->stat_queue); - g_async_queue_unref(srv->joblist_queue); - g_async_queue_unref(srv->aio_write_queue); -#endif - /* clean-up */ - network_close(srv); - connections_free(srv); - plugins_free(srv); - server_free(srv); - - TRACE("server stopped by UID=%d, PID=%d", last_sigterm_info.si_uid, last_sigterm_info.si_pid); - - log_free(); - status_counter_free(); - -#ifdef USE_GTHREAD - free(stat_cache_threads); -#endif - - chunkpool_free(); - - return 0; -} |