From: Roy T. Fielding Date: Thu, 26 Aug 1999 10:45:57 +0000 (+0000) Subject: Rearchitect the mess in http_main.c, http_core.c and buff.c. X-Git-Tag: PRE_APR_CHANGES~39 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bab4dcb050b9ed5508cdf65ffa64cb68d9391647;p=apache Rearchitect the mess in http_main.c, http_core.c and buff.c. Basic restructuring to introduce the MPM concept; includes various changes to the module API... better described by docs/initial_blurb.txt. Created multiple process model (MPM) concept by ripping out the process guts from http_main.c and http_core.c and moving them to separate files under src/modules/mpm/ Moved socket creation stuff to listen.c. Moved connection open, maintenance and close to http_connection.c. I/O layering and BUFF revamp. Much of buff.c moved to ap_iol, iol_socket, and iol_file. See docs/buff.txt. Moved user and auth fields from connection_rec to request_rec. Removed RLIMIT stuff, supposedly to be implemented later in mod_cgi. Disabled suexec, supposedly to be reimplemented later. Submitted by: Dean Gaudet git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@83763 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/http_conf_globals.h b/include/http_conf_globals.h index 3717330b28..5585469ed9 100644 --- a/include/http_conf_globals.h +++ b/include/http_conf_globals.h @@ -62,58 +62,21 @@ extern "C" { #endif -/* - * Process config --- what the process ITSELF is doing - */ - -extern int ap_standalone; -extern int ap_configtestonly; -extern int ap_docrootcheck; -extern uid_t ap_user_id; -extern char *ap_user_name; -extern gid_t ap_group_id; -#ifdef MULTIPLE_GROUPS -extern gid_t group_id_list[NGROUPS_MAX]; -#endif -extern int ap_max_requests_per_child; -extern int ap_threads_per_child; -extern int ap_excess_requests_per_child; -extern struct in_addr ap_bind_address; -extern listen_rec *ap_listeners; -extern int ap_daemons_to_start; -extern int ap_daemons_min_free; -extern int ap_daemons_max_free; -extern int ap_daemons_limit; -extern MODULE_VAR_EXPORT int ap_suexec_enabled; -extern int ap_listenbacklog; -extern int ap_dump_settings; -extern API_VAR_EXPORT int ap_extended_status; - -extern char *ap_pid_fname; -extern char *ap_scoreboard_fname; -extern char *ap_lock_fname; -extern MODULE_VAR_EXPORT char *ap_server_argv0; +/* TODO: this file should be deleted after the other todos are dealt with */ -extern enum server_token_type ap_server_tokens; +/* TODO: extern MODULE_VAR_EXPORT int ap_suexec_enabled; */ +#define ap_suexec_enabled (0) +/* TODO: extern API_VAR_EXPORT int ap_extended_status; */ -/* Trying to allocate these in the config pool gets us into some *nasty* - * chicken-and-egg problems in http_main.c --- where do you stick them - * when pconf gets cleared? Better to just allocate a little space - * statically... - */ - -extern API_VAR_EXPORT char ap_server_root[MAX_STRING_LEN]; -extern char ap_server_confname[MAX_STRING_LEN]; - -/* for -C, -c and -D switches */ -extern array_header *ap_server_pre_read_config; -extern array_header *ap_server_post_read_config; -extern array_header *ap_server_config_defines; +/* TODO: extern enum server_token_type ap_server_tokens; */ /* We want this to have the least chance of being corrupted if there * is some memory corruption, so we allocate it statically. */ -extern char ap_coredump_dir[MAX_STRING_LEN]; +/* TODO: extern char ap_coredump_dir[MAX_STRING_LEN]; */ + +/* TODO: extern int ap_configtestonly; ... although it pains me because this breaks an abstraction */ +/* TODO: extern int ap_docrootcheck; */ #ifdef __cplusplus } diff --git a/include/http_config.h b/include/http_config.h index e0c29306f8..ea89594c81 100644 --- a/include/http_config.h +++ b/include/http_config.h @@ -287,7 +287,9 @@ typedef struct module_struct { * signal an error). See src/include/ap_mmn.h for MMN version history. */ -#define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \ +#define STANDARD_MODULE_STUFF this_module_needs_to_be_ported_to_apache_2_0 + +#define STANDARD20_MODULE_STUFF MODULE_MAGIC_NUMBER_MAJOR, \ MODULE_MAGIC_NUMBER_MINOR, \ -1, \ __FILE__, \ @@ -319,7 +321,7 @@ API_EXPORT_NONSTD(const char *) ap_set_file_slot(cmd_parms *, char *, char *); * it relativizes it wrt server_root. */ -API_EXPORT(char *) ap_server_root_relative(pool *p, char *fname); +API_EXPORT(const char *) ap_server_root_relative(pool *p, const char *fname); /* Finally, the hook for dynamically loading modules in... */ @@ -363,6 +365,10 @@ void *ap_create_request_config(pool *p); CORE_EXPORT(void *) ap_create_per_dir_config(pool *p); void *ap_merge_per_dir_configs(pool *p, void *base, void *new); +/* For http_connection.c... */ + +void *ap_create_conn_config(pool *p); + /* For http_core.c... ( command and virtual hosts) */ int ap_parse_htaccess(void **result, request_rec *r, int override, diff --git a/include/http_core.h b/include/http_core.h index 459fd248f3..bd895a3728 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -243,16 +243,6 @@ typedef struct { */ unsigned d_is_fnmatch : 1; - /* System Resource Control */ -#ifdef RLIMIT_CPU - struct rlimit *limit_cpu; -#endif -#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS) - struct rlimit *limit_mem; -#endif -#ifdef RLIMIT_NPROC - struct rlimit *limit_nproc; -#endif unsigned long limit_req_body; /* limit on bytes in request msg body */ /* logging options */ diff --git a/include/http_main.h b/include/http_main.h index a0d014de78..2b69b1030e 100644 --- a/include/http_main.h +++ b/include/http_main.h @@ -62,110 +62,14 @@ extern "C" { #endif -/* - * Routines in http_main.c which other code --- in particular modules --- - * may want to call. Right now, that's limited to timeout handling. - * There are two functions which modules can call to trigger a timeout - * (with the per-virtual-server timeout duration); these are hard_timeout - * and soft_timeout. - * - * The difference between the two is what happens when the timeout - * expires (or earlier than that, if the client connection aborts) --- - * a soft_timeout just puts the connection to the client in an - * "aborted" state, which will cause http_protocol.c to stop trying to - * talk to the client, but otherwise allows the code to continue normally. - * hard_timeout(), by contrast, logs the request, and then aborts it - * completely --- longjmp()ing out to the accept() loop in http_main. - * Any resources tied into the request's resource pool will be cleaned up; - * everything that isn't will leak. - * - * soft_timeout() is recommended as a general rule, because it gives your - * code a chance to clean up. However, hard_timeout() may be the most - * convenient way of dealing with timeouts waiting for some external - * resource other than the client, if you can live with the restrictions. - * - * (When a hard timeout is in scope, critical sections can be guarded - * with block_alarms() and unblock_alarms() --- these are declared in - * alloc.c because they are most often used in conjunction with - * routines to allocate something or other, to make sure that the - * cleanup does get registered before any alarm is allowed to happen - * which might require it to be cleaned up; they * are, however, - * implemented in http_main.c). - * - * NOTE! It's not "fair" for a hard_timeout to be in scope through calls - * across modules. Your module code really has no idea what other modules may - * be present in the server, and they may not take too kindly to having a - * longjmp() happen -- it could result in corrupted state. Heck they may not - * even take to kindly to a soft_timeout()... because it can cause EINTR to - * happen on pretty much any syscall, and unless all the libraries and modules - * in use are known to deal well with EINTR it could cause corruption as well. - * But things are likely to do much better with a soft_timeout in scope than a - * hard_timeout. - * - * A module MAY NOT use a hard_timeout() across * sub_req_lookup_xxx() - * functions, or across run_sub_request() functions. A module SHOULD NOT use a - * soft_timeout() in either of these cases, but sometimes there's just no - * choice. - * - * kill_timeout() will disarm either variety of timeout. - * - * reset_timeout() resets the timeout in progress. - */ - -void ap_start_shutdown(void); -void ap_start_restart(int); -API_EXPORT(void) ap_hard_timeout(char *, request_rec *); -void ap_keepalive_timeout(char *, request_rec *); -API_EXPORT(void) ap_soft_timeout(char *, request_rec *); -API_EXPORT(void) ap_kill_timeout(request_rec *); -API_EXPORT(void) ap_reset_timeout(request_rec *); +extern MODULE_VAR_EXPORT char *ap_server_argv0; -API_EXPORT(void) ap_child_terminate(request_rec *r); -API_EXPORT(void) ap_sync_scoreboard_image(void); -int ap_update_child_status(int child_num, int status, request_rec *r); -void ap_time_process_request(int child_num, int status); -unsigned int ap_set_callback_and_alarm(void (*fn) (int), int x); -API_EXPORT(int) ap_check_alarm(void); +extern API_VAR_EXPORT const char *ap_server_root; -#ifndef NO_OTHER_CHILD -/* - * register an other_child -- a child which the main loop keeps track of - * and knows it is different than the rest of the scoreboard. - * - * pid is the pid of the child. - * - * maintenance is a function that is invoked with a reason, the data - * pointer passed here, and when appropriate a status result from waitpid(). - * - * write_fd is an fd that is probed for writing by select() if it is ever - * unwritable, then maintenance is invoked with reason OC_REASON_UNWRITABLE. - * This is useful for log pipe children, to know when they've blocked. To - * disable this feature, use -1 for write_fd. - */ -API_EXPORT(void) ap_register_other_child(int pid, - void (*maintenance) (int reason, void *data, ap_wait_t status), void *data, - int write_fd); -#define OC_REASON_DEATH 0 /* child has died, caller must call - * unregister still */ -#define OC_REASON_UNWRITABLE 1 /* write_fd is unwritable */ -#define OC_REASON_RESTART 2 /* a restart is occuring, perform - * any necessary cleanup (including - * sending a special signal to child) - */ -#define OC_REASON_UNREGISTER 3 /* unregister has been called, do - * whatever is necessary (including - * kill the child) */ -#define OC_REASON_LOST 4 /* somehow the child exited without - * us knowing ... buggy os? */ - -/* - * unregister an other_child. Note that the data pointer is used here, and - * is assumed to be unique per other_child. This is because the pid and - * write_fd are possibly killed off separately. - */ -API_EXPORT(void) ap_unregister_other_child(void *data); - -#endif +/* for -C, -c and -D switches */ +extern array_header *ap_server_pre_read_config; +extern array_header *ap_server_post_read_config; +extern array_header *ap_server_config_defines; #ifdef __cplusplus } diff --git a/include/httpd.h b/include/httpd.h index 3dbe5e4dca..9a79bf7941 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -86,7 +86,8 @@ extern "C" { #elif defined(WIN32) /* Set default for Windows file system */ #define HTTPD_ROOT "/apache" -#elif defined(BEOS) +#elif defined (BEOS) +/* Set the default for BeOS */ #define HTTPD_ROOT "/boot/home/apache" #else #define HTTPD_ROOT "/usr/local/apache" @@ -139,8 +140,8 @@ extern "C" { #define DEFAULT_HTTP_PORT 80 #define DEFAULT_HTTPS_PORT 443 #define ap_is_default_port(port,r) ((port) == ap_default_port(r)) -#define ap_http_method(r) "http" -#define ap_default_port(r) DEFAULT_HTTP_PORT +#define ap_http_method(r) ap_run_http_method(r) +#define ap_default_port(r) ap_run_default_port(r) /* --------- Default user name and group name running standalone ---------- */ /* --- These may be specified as numbers by placing a # before a number --- */ @@ -260,12 +261,12 @@ extern "C" { /* The timeout for waiting for messages */ #ifndef DEFAULT_TIMEOUT -#define DEFAULT_TIMEOUT 300 +#define DEFAULT_TIMEOUT 120000 #endif /* The timeout for waiting for keepalive timeout until next request */ #ifndef DEFAULT_KEEPALIVE_TIMEOUT -#define DEFAULT_KEEPALIVE_TIMEOUT 15 +#define DEFAULT_KEEPALIVE_TIMEOUT 300 #endif /* The number of requests to entertain per connection */ @@ -276,46 +277,6 @@ extern "C" { /* The size of the server's internal read-write buffers */ #define IOBUFSIZE 8192 -/* Number of servers to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#ifndef DEFAULT_START_DAEMON -#define DEFAULT_START_DAEMON 5 -#endif - -/* Maximum number of *free* server processes --- more than this, and - * they will die off. - */ - -#ifndef DEFAULT_MAX_FREE_DAEMON -#define DEFAULT_MAX_FREE_DAEMON 10 -#endif - -/* Minimum --- fewer than this, and more will be created */ - -#ifndef DEFAULT_MIN_FREE_DAEMON -#define DEFAULT_MIN_FREE_DAEMON 5 -#endif - -/* Limit on the total --- clients will be locked out if more servers than - * this are needed. It is intended solely to keep the server from crashing - * when things get out of hand. - * - * We keep a hard maximum number of servers, for two reasons --- first off, - * in case something goes seriously wrong, we want to stop the fork bomb - * short of actually crashing the machine we're running on by filling some - * kernel table. Secondly, it keeps the size of the scoreboard file small - * enough that we can read the whole thing without worrying too much about - * the overhead. - */ -#ifndef HARD_SERVER_LIMIT -#ifdef WIN32 -#define HARD_SERVER_LIMIT 1024 -#else -#define HARD_SERVER_LIMIT 256 -#endif -#endif - /* * Special Apache error codes. These are basically used * in http_main.c so we can keep track of various errors. @@ -358,12 +319,9 @@ extern "C" { */ #ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 0 +#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 #endif -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 50 -#endif #ifndef DEFAULT_EXCESS_REQUESTS_PER_CHILD #define DEFAULT_EXCESS_REQUESTS_PER_CHILD 0 #endif @@ -420,16 +378,27 @@ extern "C" { * Example: "Apache/1.1.0 MrWidget/0.1-alpha" */ -#define SERVER_BASEVERSION "Apache/1.3.9" /* SEE COMMENTS ABOVE */ +#define SERVER_BASEVERSION "Apache/mpm-dev" /* SEE COMMENTS ABOVE */ #define SERVER_VERSION SERVER_BASEVERSION + +/* TODO: re-implement the server token/version stuff -- it's part of http_core + * it should be possible to do without touching http_main at all. (or else + * we haven't got enough module hooks) + */ + enum server_token_type { SrvTk_MIN, /* eg: Apache/1.3.0 */ SrvTk_OS, /* eg: Apache/1.3.0 (UNIX) */ SrvTk_FULL /* eg: Apache/1.3.0 (UNIX) PHP/3.0 FooBar/1.2b */ }; +#if 0 API_EXPORT(const char *) ap_get_server_version(void); API_EXPORT(void) ap_add_version_component(const char *component); +#else +#define ap_get_server_version() (SERVER_BASEVERSION) +#define ap_add_version_component(x) ((void)0) +#endif API_EXPORT(const char *) ap_get_server_built(void); /* Numeric release version identifier: MMNNFFRBB: major minor fix final beta @@ -649,7 +618,6 @@ struct htaccess_result { typedef struct conn_rec conn_rec; typedef struct server_rec server_rec; typedef struct request_rec request_rec; -typedef struct listen_rec listen_rec; #include "util_uri.h" @@ -765,6 +733,11 @@ struct request_rec { array_header *content_languages; /* array of (char*) */ char *vlist_validator; /* variant list validator (if negotiated) */ + + char *user; /* If an authentication check was made, + * this gets set to the user name. + */ + char *ap_auth_type; /* Ditto. */ int no_cache; int no_local_copy; @@ -811,13 +784,11 @@ struct request_rec { struct conn_rec { ap_pool *pool; - server_rec *server; server_rec *base_server; /* Physical vhost this conn come in on */ void *vhost_lookup_data; /* used by http_vhost.c */ /* Information about the connection itself */ - int child_num; /* The number of the child handling conn_rec */ BUFF *client; /* Connection to the guy */ /* Who is the client? */ @@ -833,11 +804,6 @@ struct conn_rec { char *remote_logname; /* Only ever set if doing rfc1413 lookups. * N.B. Only access this through * get_remote_logname() */ - char *user; /* If an authentication check was made, - * this gets set to the user name. We assume - * that there's only one user per connection(!) - */ - char *ap_auth_type; /* Ditto. */ unsigned aborted:1; /* Are we still talking? */ signed int keepalive:2; /* Are we using HTTP Keep-Alive? @@ -850,6 +816,9 @@ struct conn_rec { char *local_host; /* used for ap_get_server_name when * UseCanonicalName is set to DNS * (ignores setting of HostnameLookups) */ + long id; /* ID of this connection; unique at any + * point in time */ + void *conn_config; /* Notes on *this* connection */ }; /* Per-vhost config... */ @@ -908,7 +877,6 @@ struct server_rec { int keep_alive_timeout; /* Seconds we'll wait for another request */ int keep_alive_max; /* Maximum requests per connection */ int keep_alive; /* Use persistent connections? */ - int send_buffer_size; /* size of TCP send buffer (in bytes) */ char *path; /* Pathname for ServerPath */ int pathlen; /* Length of path */ @@ -924,14 +892,6 @@ struct server_rec { int limit_req_fields; /* limit on number of request header fields */ }; -/* These are more like real hosts than virtual hosts */ -struct listen_rec { - listen_rec *next; - struct sockaddr_in local_addr; /* local IP address and port */ - int fd; - int used; /* Only used during restart */ -/* more stuff here, like which protocol is bound to the port */ -}; /* Prototypes for utilities... util.c. */ diff --git a/modules/http/http_core.c b/modules/http/http_core.c index e02d32ec5f..0265e87836 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -61,14 +61,13 @@ #include "http_core.h" #include "http_protocol.h" /* For index_of_response(). Grump. */ #include "http_request.h" -#include "http_conf_globals.h" #include "http_vhost.h" #include "http_main.h" /* For the default_handler below... */ #include "http_log.h" #include "rfc1413.h" #include "util_md5.h" -#include "scoreboard.h" #include "fnmatch.h" +#include "http_connection.h" #ifdef USE_MMAP_FILES #include @@ -136,16 +135,6 @@ static void *create_core_dir_config(pool *a, char *dir) conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */ conf->satisfy = SATISFY_NOSPEC; -#ifdef RLIMIT_CPU - conf->limit_cpu = NULL; -#endif -#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) - conf->limit_mem = NULL; -#endif -#ifdef RLIMIT_NPROC - conf->limit_nproc = NULL; -#endif - conf->limit_req_body = 0; conf->sec = ap_make_array(a, 2, sizeof(void *)); #ifdef WIN32 @@ -246,22 +235,6 @@ static void *merge_core_dir_configs(pool *a, void *basev, void *newv) conf->use_canonical_name = new->use_canonical_name; } -#ifdef RLIMIT_CPU - if (new->limit_cpu) { - conf->limit_cpu = new->limit_cpu; - } -#endif -#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) - if (new->limit_mem) { - conf->limit_mem = new->limit_mem; - } -#endif -#ifdef RLIMIT_NPROC - if (new->limit_nproc) { - conf->limit_nproc = new->limit_nproc; - } -#endif - if (new->limit_req_body) { conf->limit_req_body = new->limit_req_body; } @@ -578,7 +551,6 @@ API_EXPORT(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, struct in_addr *iaddr; struct hostent *hptr; int hostname_lookups; - int old_stat = SERVER_DEAD; /* we shouldn't ever be in this state */ /* If we haven't checked the host name, and we want to */ if (dir_config) { @@ -598,8 +570,7 @@ API_EXPORT(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, && conn->remote_host == NULL && (type == REMOTE_DOUBLE_REV || hostname_lookups != HOSTNAME_LOOKUP_OFF)) { - old_stat = ap_update_child_status(conn->child_num, SERVER_BUSY_DNS, - (request_rec*)NULL); + /* ZZZ change to AP functions. */ iaddr = &(conn->remote_addr.sin_addr); hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET); if (hptr != NULL) { @@ -624,10 +595,6 @@ API_EXPORT(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, return NULL; } } - if (old_stat != SERVER_DEAD) { - (void)ap_update_child_status(conn->child_num, old_stat, - (request_rec*)NULL); - } /* * Return the desired information; either the remote DNS name, if found, @@ -695,9 +662,6 @@ API_EXPORT(const char *) ap_get_server_name(request_rec *r) if (conn->local_host == NULL) { struct in_addr *iaddr; struct hostent *hptr; - int old_stat; - old_stat = ap_update_child_status(conn->child_num, - SERVER_BUSY_DNS, r); iaddr = &(conn->local_addr.sin_addr); hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET); @@ -710,7 +674,6 @@ API_EXPORT(const char *) ap_get_server_name(request_rec *r) conn->local_host = ap_pstrdup(conn->pool, r->server->server_hostname); } - (void) ap_update_child_status(conn->child_num, old_stat, r); } return conn->local_host; } @@ -1047,7 +1010,7 @@ static const char *set_document_root(cmd_parms *cmd, void *dummy, char *arg) } arg = ap_os_canonical_filename(cmd->pool, arg); - if (ap_configtestonly && ap_docrootcheck && !ap_is_directory(arg)) { + if (/* TODO: ap_configtestonly && ap_docrootcheck && */ !ap_is_directory(arg)) { if (cmd->server->is_virtual) { fprintf(stderr, "Warning: DocumentRoot [%s] does not exist\n", arg); @@ -1832,26 +1795,6 @@ static const char *set_server_string_slot(cmd_parms *cmd, void *dummy, return NULL; } -static const char *server_type(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - if (!strcasecmp(arg, "inetd")) { - ap_standalone = 0; - } - else if (!strcasecmp(arg, "standalone")) { - ap_standalone = 1; - } - else { - return "ServerType must be either 'inetd' or 'standalone'"; - } - - return NULL; -} - static const char *server_port(cmd_parms *cmd, void *dummy, char *arg) { const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); @@ -1893,93 +1836,6 @@ static const char *set_signature_flag(cmd_parms *cmd, core_dir_config *d, return NULL; } -static const char *set_send_buffer_size(cmd_parms *cmd, void *dummy, char *arg) -{ - int s = atoi(arg); - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - if (s < 512 && s != 0) { - return "SendBufferSize must be >= 512 bytes, or 0 for system default."; - } - cmd->server->send_buffer_size = s; - return NULL; -} - -static const char *set_user(cmd_parms *cmd, void *dummy, char *arg) -{ -#ifdef WIN32 - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, cmd->server, - "User directive has no affect on Win32"); - cmd->server->server_uid = ap_user_id = 1; -#else - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - if (!cmd->server->is_virtual) { - ap_user_name = arg; - cmd->server->server_uid = ap_user_id = ap_uname2id(arg); - } - else { - if (ap_suexec_enabled) { - cmd->server->server_uid = ap_uname2id(arg); - } - else { - cmd->server->server_uid = ap_user_id; - fprintf(stderr, - "Warning: User directive in " - "requires SUEXEC wrapper.\n"); - } - } -#if !defined (BIG_SECURITY_HOLE) && !defined (OS2) - if (cmd->server->server_uid == 0) { - fprintf(stderr, - "Error:\tApache has not been designed to serve pages while\n" - "\trunning as root. There are known race conditions that\n" - "\twill allow any local user to read any file on the system.\n" - "\tIf you still desire to serve pages as root then\n" - "\tadd -DBIG_SECURITY_HOLE to the EXTRA_CFLAGS line in your\n" - "\tsrc/Configuration file and rebuild the server. It is\n" - "\tstrongly suggested that you instead modify the User\n" - "\tdirective in your httpd.conf file to list a non-root\n" - "\tuser.\n"); - exit (1); - } -#endif -#endif /* WIN32 */ - - return NULL; -} - -static const char *set_group(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - if (!cmd->server->is_virtual) { - cmd->server->server_gid = ap_group_id = ap_gname2id(arg); - } - else { - if (ap_suexec_enabled) { - cmd->server->server_gid = ap_gname2id(arg); - } - else { - cmd->server->server_gid = ap_group_id; - fprintf(stderr, - "Warning: Group directive in requires " - "SUEXEC wrapper.\n"); - } - } - - return NULL; -} - static const char *set_server_root(cmd_parms *cmd, void *dummy, char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); @@ -1993,8 +1849,7 @@ static const char *set_server_root(cmd_parms *cmd, void *dummy, char *arg) if (!ap_is_directory(arg)) { return "ServerRoot must be a valid directory"; } - ap_cpystrn(ap_server_root, arg, - sizeof(ap_server_root)); + ap_server_root = arg; return NULL; } @@ -2051,42 +1906,6 @@ static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy, char *arg) return NULL; } -static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - if (cmd->server->is_virtual) { - return "PidFile directive not allowed in "; - } - ap_pid_fname = arg; - return NULL; -} - -static const char *set_scoreboard(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_scoreboard_fname = arg; - return NULL; -} - -static const char *set_lockfile(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_lock_fname = arg; - return NULL; -} - static const char *set_idcheck(cmd_parms *cmd, core_dir_config *d, int arg) { const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); @@ -2167,314 +1986,12 @@ static const char *set_use_canonical_name(cmd_parms *cmd, core_dir_config *d, return NULL; } -static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg) -{ -#ifdef WIN32 - fprintf(stderr, "WARNING: StartServers has no effect on Win32\n"); -#else - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); -#endif - return NULL; -} - -static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_min_free = atoi(arg); - if (ap_daemons_min_free <= 0) { - fprintf(stderr, "WARNING: detected MinSpareServers set to non-positive.\n"); - fprintf(stderr, "Resetting to 1 to avoid almost certain Apache failure.\n"); - fprintf(stderr, "Please read the documentation.\n"); - ap_daemons_min_free = 1; - } - - return NULL; -} - -static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_max_free = atoi(arg); - return NULL; -} - -static const char *set_server_limit (cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_limit = atoi(arg); - if (ap_daemons_limit > HARD_SERVER_LIMIT) { - fprintf(stderr, "WARNING: MaxClients of %d exceeds compile time limit " - "of %d servers,\n", ap_daemons_limit, HARD_SERVER_LIMIT); - fprintf(stderr, " lowering MaxClients to %d. To increase, please " - "see the\n", HARD_SERVER_LIMIT); - fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n"); - ap_daemons_limit = HARD_SERVER_LIMIT; - } - else if (ap_daemons_limit < 1) { - fprintf(stderr, "WARNING: Require MaxClients > 0, setting to 1\n"); - ap_daemons_limit = 1; - } - return NULL; -} - -static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_max_requests_per_child = atoi(arg); - return NULL; -} - -static const char *set_threads(cmd_parms *cmd, void *dummy, char *arg) { - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_threads_per_child = atoi(arg); - if (ap_threads_per_child > HARD_SERVER_LIMIT) { - fprintf(stderr, "WARNING: ThreadsPerChild of %d exceeds compile time limit " - "of %d threads,\n", ap_threads_per_child, HARD_SERVER_LIMIT); - fprintf(stderr, " lowering ThreadsPerChild to %d. To increase, please " - "see the\n", HARD_SERVER_LIMIT); - fprintf(stderr, " HARD_SERVER_LIMIT define in src/include/httpd.h.\n"); - ap_threads_per_child = HARD_SERVER_LIMIT; - } - else if (ap_threads_per_child < 1) { - fprintf(stderr, "WARNING: Require ThreadsPerChild > 0, setting to 1\n"); - ap_threads_per_child = 1; - } - - return NULL; -} - -static const char *set_excess_requests(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_excess_requests_per_child = atoi(arg); - return NULL; -} - - -#if defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS) -static void set_rlimit(cmd_parms *cmd, struct rlimit **plimit, const char *arg, - const char * arg2, int type) -{ - char *str; - struct rlimit *limit; - /* If your platform doesn't define rlim_t then typedef it in ap_config.h */ - rlim_t cur = 0; - rlim_t max = 0; - - *plimit = (struct rlimit *)ap_pcalloc(cmd->pool, sizeof(**plimit)); - limit = *plimit; - if ((getrlimit(type, limit)) != 0) { - *plimit = NULL; - ap_log_error(APLOG_MARK, APLOG_ERR, cmd->server, - "%s: getrlimit failed", cmd->cmd->name); - return; - } - - if ((str = ap_getword_conf(cmd->pool, &arg))) { - if (!strcasecmp(str, "max")) { - cur = limit->rlim_max; - } - else { - cur = atol(str); - } - } - else { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server, - "Invalid parameters for %s", cmd->cmd->name); - return; - } - - if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) { - max = atol(str); - } - - /* if we aren't running as root, cannot increase max */ - if (geteuid()) { - limit->rlim_cur = cur; - if (max) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server, - "Must be uid 0 to raise maximum %s", cmd->cmd->name); - } - } - else { - if (cur) { - limit->rlim_cur = cur; - } - if (max) { - limit->rlim_max = max; - } - } -} -#endif - -#if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC) -static const char *no_set_limit(cmd_parms *cmd, core_dir_config *conf, - char *arg, char *arg2) -{ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, cmd->server, - "%s not supported on this platform", cmd->cmd->name); - return NULL; -} -#endif - -#ifdef RLIMIT_CPU -static const char *set_limit_cpu(cmd_parms *cmd, core_dir_config *conf, - char *arg, char *arg2) -{ - set_rlimit(cmd, &conf->limit_cpu, arg, arg2, RLIMIT_CPU); - return NULL; -} -#endif - -#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS) -static const char *set_limit_mem(cmd_parms *cmd, core_dir_config *conf, - char *arg, char * arg2) -{ -#if defined(RLIMIT_AS) - set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS); -#elif defined(RLIMIT_DATA) - set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA); -#elif defined(RLIMIT_VMEM) - set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_VMEM); -#endif - return NULL; -} -#endif - -#ifdef RLIMIT_NPROC -static const char *set_limit_nproc(cmd_parms *cmd, core_dir_config *conf, - char *arg, char * arg2) -{ - set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC); - return NULL; -} -#endif - -static const char *set_bind_address(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_bind_address.s_addr = ap_get_virthost_addr(arg, NULL); - return NULL; -} - -static const char *set_listener(cmd_parms *cmd, void *dummy, char *ips) -{ - listen_rec *new; - char *ports; - unsigned short port; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ports = strchr(ips, ':'); - if (ports != NULL) { - if (ports == ips) { - return "Missing IP address"; - } - else if (ports[1] == '\0') { - return "Address must end in :"; - } - *(ports++) = '\0'; - } - else { - ports = ips; - } - - new=ap_pcalloc(cmd->pool, sizeof(listen_rec)); - new->local_addr.sin_family = AF_INET; - if (ports == ips) { /* no address */ - new->local_addr.sin_addr.s_addr = htonl(INADDR_ANY); - } - else { - new->local_addr.sin_addr.s_addr = ap_get_virthost_addr(ips, NULL); - } - port = atoi(ports); - if (!port) { - return "Port must be numeric"; - } - new->local_addr.sin_port = htons(port); - new->fd = -1; - new->used = 0; - new->next = ap_listeners; - ap_listeners = new; - return NULL; -} - -static const char *set_listenbacklog(cmd_parms *cmd, void *dummy, char *arg) -{ - int b; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - b = atoi(arg); - if (b < 1) { - return "ListenBacklog must be > 0"; - } - ap_listenbacklog = b; - return NULL; -} - -static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) -{ - struct stat finfo; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - arg = ap_server_root_relative(cmd->pool, arg); - if ((stat(arg, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) { - return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", arg, - " does not exist or is not a directory", NULL); - } - ap_cpystrn(ap_coredump_dir, arg, sizeof(ap_coredump_dir)); - return NULL; -} static const char *include_config (cmd_parms *cmd, void *dummy, char *name) { - name = ap_server_root_relative(cmd->pool, name); - - ap_process_resource_config(cmd->server, name, cmd->pool, cmd->temp_pool); - + ap_process_resource_config(cmd->server, + ap_server_root_relative(cmd->pool, name), + cmd->pool, cmd->temp_pool); return NULL; } @@ -2590,6 +2107,8 @@ static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, char *arg) return err; } + /* TODO: re-implement the server token stuff. */ +#if 0 if (!strcasecmp(arg, "OS")) { ap_server_tokens = SrvTk_OS; } @@ -2599,6 +2118,7 @@ static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, char *arg) else { ap_server_tokens = SrvTk_FULL; } +#endif return NULL; } @@ -2791,16 +2311,10 @@ static const command_rec core_cmds[] = { /* Old server config file commands */ -{ "ServerType", server_type, NULL, RSRC_CONF, TAKE1, - "'inetd' or 'standalone'"}, { "Port", server_port, NULL, RSRC_CONF, TAKE1, "A TCP port number"}, { "HostnameLookups", set_hostname_lookups, NULL, ACCESS_CONF|RSRC_CONF, TAKE1, "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to " "enable double-reverse DNS lookups" }, -{ "User", set_user, NULL, RSRC_CONF, TAKE1, - "Effective user id for this server"}, -{ "Group", set_group, NULL, RSRC_CONF, TAKE1, - "Effective group id for this server"}, { "ServerAdmin", set_server_string_slot, (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, TAKE1, "The email address of the server administrator" }, @@ -2814,12 +2328,6 @@ static const command_rec core_cmds[] = { { "ErrorLog", set_server_string_slot, (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, TAKE1, "The filename of the error log" }, -{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1, - "A file for logging the server process ID"}, -{ "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, TAKE1, - "A file for Apache to maintain runtime process management information"}, -{ "LockFile", set_lockfile, NULL, RSRC_CONF, TAKE1, - "The lockfile used when Apache needs to lock the accept() call"}, { "AccessConfig", set_server_string_slot, (void *)XtOffsetOf (server_rec, access_confname), RSRC_CONF, TAKE1, "The filename of the access config file" }, @@ -2844,60 +2352,15 @@ static const command_rec core_cmds[] = { { "UseCanonicalName", set_use_canonical_name, NULL, RSRC_CONF, TAKE1, "How to work out the ServerName : Port when constructing URLs" }, -{ "StartServers", set_daemons_to_start, NULL, RSRC_CONF, TAKE1, - "Number of child processes launched at server startup" }, -{ "MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, TAKE1, - "Minimum number of idle children, to handle request spikes" }, -{ "MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, - "Maximum number of idle children" }, -{ "MaxServers", set_max_free_servers, NULL, RSRC_CONF, TAKE1, - "Deprecated equivalent to MaxSpareServers" }, -{ "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1, - "Deprecated equivalent to MaxClients" }, -{ "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1, - "Maximum number of children alive at the same time" }, -{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, - "Maximum number of requests a particular child serves before dying." }, -{ "RLimitCPU", -#ifdef RLIMIT_CPU - set_limit_cpu, (void*)XtOffsetOf(core_dir_config, limit_cpu), -#else - no_set_limit, NULL, -#endif - OR_ALL, TAKE12, "Soft/hard limits for max CPU usage in seconds" }, -{ "RLimitMEM", -#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS) - set_limit_mem, (void*)XtOffsetOf(core_dir_config, limit_mem), -#else - no_set_limit, NULL, -#endif - OR_ALL, TAKE12, "Soft/hard limits for max memory usage per process" }, -{ "RLimitNPROC", -#ifdef RLIMIT_NPROC - set_limit_nproc, (void*)XtOffsetOf(core_dir_config, limit_nproc), -#else - no_set_limit, NULL, -#endif - OR_ALL, TAKE12, "soft/hard limits for max number of processes per uid" }, -{ "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1, - "'*', a numeric IP address, or the name of a host with a unique IP address"}, -{ "Listen", set_listener, NULL, RSRC_CONF, TAKE1, - "A port number or a numeric IP address and a port number"}, -{ "SendBufferSize", set_send_buffer_size, NULL, RSRC_CONF, TAKE1, - "Send buffer size in bytes"}, +/* TODOC: MaxServers is deprecated */ +/* TODOC: ServersSafetyLimit is deprecated */ +/* TODO: RlimitFoo should all be part of mod_cgi, not in the core */ +/* TODOC: BindAddress deprecated */ { "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE, "The name of a module" }, { "ClearModuleList", clear_module_list_command, NULL, RSRC_CONF, NO_ARGS, NULL }, -{ "ThreadsPerChild", set_threads, NULL, RSRC_CONF, TAKE1, - "Number of threads a child creates" }, -{ "ExcessRequestsPerChild", set_excess_requests, NULL, RSRC_CONF, TAKE1, - "Maximum number of requests a particular child serves after it is ready " - "to die." }, -{ "ListenBacklog", set_listenbacklog, NULL, RSRC_CONF, TAKE1, - "Maximum length of the queue of pending connections, as used by listen(2)" }, -{ "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1, - "The location of the directory Apache changes to before dumping core" }, +/* TODO: ListenBacklog in MPM */ { "Include", include_config, NULL, (RSRC_CONF | ACCESS_CONF), TAKE1, "Name of the config file to be included" }, { "LogLevel", set_loglevel, NULL, RSRC_CONF, TAKE1, @@ -3007,7 +2470,7 @@ static int default_handler(request_rec *r) core_dir_config *d = (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); int rangestatus, errstatus; - FILE *f; + APRFile fd; /* Abstract out File descriptors. */ #ifdef USE_MMAP_FILES caddr_t mm; #endif diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index 31779312c6..135621aebc 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -74,7 +74,6 @@ * support code... */ #include "util_date.h" /* For parseHTTPdate and BAD_DATE */ #include -#include "http_conf_globals.h" #define SET_BYTES_SENT(r) \ do { if (r->sent_bodyct) \ @@ -668,7 +667,8 @@ static int getline(char *s, int n, BUFF *in, int fold) pos = s; do { - retval = ap_bgets(pos, n, in); /* retval == -1 if error, 0 if EOF */ + retval = ap_bgets(pos, n, in); + /* retval == -1 if error, 0 if EOF */ if (retval <= 0) return ((retval < 0) && (total == 0)) ? -1 : total; @@ -703,7 +703,7 @@ static int getline(char *s, int n, BUFF *in, int fold) * the next line begins with a continuation character. */ } while (fold && (retval != 1) && (n > 1) - && (ap_blookc(&next, in) == 1) + && (next = ap_blookc(in)) && ((next == ' ') || (next == '\t'))); return total; @@ -909,14 +909,13 @@ request_rec *ap_read_request(conn_rec *conn) r = ap_pcalloc(p, sizeof(request_rec)); r->pool = p; r->connection = conn; - conn->server = conn->base_server; - r->server = conn->server; + r->server = conn->base_server; conn->keptalive = conn->keepalive == 1; conn->keepalive = 0; - conn->user = NULL; - conn->ap_auth_type = NULL; + r->user = NULL; + r->ap_auth_type = NULL; r->headers_in = ap_make_table(r->pool, 50); r->subprocess_env = ap_make_table(r->pool, 50); @@ -939,13 +938,14 @@ request_rec *ap_read_request(conn_rec *conn) ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 1); #endif - /* Get the request... */ + ap_bsetopt(conn->client, BO_TIMEOUT, + conn->keptalive + ? &r->server->keep_alive_timeout + : &r->server->timeout); - ap_keepalive_timeout("read request line", r); + /* Get the request... */ if (!read_request_line(r)) { - ap_kill_timeout(r); if (r->status == HTTP_REQUEST_URI_TOO_LARGE) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "request failed: URI too long"); ap_send_error_response(r, 0); @@ -954,10 +954,12 @@ request_rec *ap_read_request(conn_rec *conn) } return NULL; } + if (r->connection->keptalive) { + ap_bsetopt(r->connection->client, BO_TIMEOUT, + &r->server->timeout); + } if (!r->assbackwards) { - ap_hard_timeout("read request headers", r); get_mime_headers(r); - ap_kill_timeout(r); if (r->status != HTTP_REQUEST_TIME_OUT) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "request failed: error reading the headers"); @@ -967,8 +969,6 @@ request_rec *ap_read_request(conn_rec *conn) } } else { - ap_kill_timeout(r); - if (r->header_only) { /* * Client asked for headers only with HTTP/0.9, which doesn't send @@ -1157,8 +1157,8 @@ API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw) * because it has the lifetime of the connection. The other allocations * are temporary and can be tossed away any time. */ - r->connection->user = ap_getword_nulls (r->connection->pool, &t, ':'); - r->connection->ap_auth_type = "Basic"; + r->user = ap_getword_nulls (r->pool, &t, ':'); + r->ap_auth_type = "Basic"; *pw = t; diff --git a/server/config.c b/server/config.c index 8980f98ec4..4a2a6d383f 100644 --- a/server/config.c +++ b/server/config.c @@ -77,7 +77,7 @@ #include "http_core.h" #include "http_log.h" /* for errors in parse_htaccess */ #include "http_request.h" /* for default_handler (see invoke_handler) */ -#include "http_conf_globals.h" /* Sigh... */ +#include "http_main.h" #include "http_vhost.h" #include "explain.h" @@ -1086,7 +1086,7 @@ API_EXPORT_NONSTD(const char *) ap_set_file_slot(cmd_parms *cmd, char *struct_pt static cmd_parms default_parms = {NULL, 0, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; -API_EXPORT(char *) ap_server_root_relative(pool *p, char *file) +API_EXPORT(const char *) ap_server_root_relative(pool *p, const char *file) { if(ap_os_is_path_absolute(file)) return file; @@ -1163,7 +1163,7 @@ static void process_command_config(server_rec *s, array_header *arr, pool *p, ap_cfg_closefile(parms.config_file); } -void ap_process_resource_config(server_rec *s, char *fname, pool *p, pool *ptemp) +void ap_process_resource_config(server_rec *s, const char *fname, pool *p, pool *ptemp) { const char *errmsg; cmd_parms parms; @@ -1305,6 +1305,7 @@ CORE_EXPORT(const char *) ap_init_virtual_host(pool *p, const char *hostname, } #endif + /* TODO: this crap belongs in http_core */ s->server_admin = NULL; s->server_hostname = NULL; s->error_fname = NULL; @@ -1327,8 +1328,10 @@ CORE_EXPORT(const char *) ap_init_virtual_host(pool *p, const char *hostname, s->module_config = create_empty_config(p); s->lookup_defaults = ap_create_per_dir_config(p); +#if 0 s->server_uid = ap_user_id; s->server_gid = ap_group_id; +#endif s->limit_req_line = main_server->limit_req_line; s->limit_req_fieldsize = main_server->limit_req_fieldsize; @@ -1373,9 +1376,6 @@ static void fixup_virtual_hosts(pool *p, server_rec *main_server) if (virt->keep_alive_max == -1) virt->keep_alive_max = main_server->keep_alive_max; - if (virt->send_buffer_size == 0) - virt->send_buffer_size = main_server->send_buffer_size; - /* XXX: this is really something that should be dealt with by a * post-config api phase */ ap_core_reorder_directories(p, virt); @@ -1390,29 +1390,8 @@ static void fixup_virtual_hosts(pool *p, server_rec *main_server) static void init_config_globals(pool *p) { - /* ServerRoot, server_confname set in httpd.c */ - - ap_standalone = 1; - ap_user_name = DEFAULT_USER; - ap_user_id = ap_uname2id(DEFAULT_USER); - ap_group_id = ap_gname2id(DEFAULT_GROUP); - ap_daemons_to_start = DEFAULT_START_DAEMON; - ap_daemons_min_free = DEFAULT_MIN_FREE_DAEMON; - ap_daemons_max_free = DEFAULT_MAX_FREE_DAEMON; - ap_daemons_limit = HARD_SERVER_LIMIT; - ap_pid_fname = DEFAULT_PIDLOG; - ap_scoreboard_fname = DEFAULT_SCOREBOARD; - ap_lock_fname = DEFAULT_LOCKFILE; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_bind_address.s_addr = htonl(INADDR_ANY); - ap_listeners = NULL; - ap_listenbacklog = DEFAULT_LISTENBACKLOG; - ap_extended_status = 0; - /* Global virtual host hash bucket pointers. Init to null. */ ap_init_vhost_config(p); - - ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); } static server_rec *init_server_config(pool *p) @@ -1449,26 +1428,7 @@ static server_rec *init_server_config(pool *p) } -static void default_listeners(pool *p, server_rec *s) -{ - listen_rec *new; - - if (ap_listeners != NULL) { - return; - } - /* allocate a default listener */ - new = ap_pcalloc(p, sizeof(listen_rec)); - new->local_addr.sin_family = AF_INET; - new->local_addr.sin_addr = ap_bind_address; - new->local_addr.sin_port = htons(s->port ? s->port : DEFAULT_HTTP_PORT); - new->fd = -1; - new->used = 0; - new->next = NULL; - ap_listeners = new; -} - - -server_rec *ap_read_config(pool *p, pool *ptemp, char *confname) +server_rec *ap_read_config(pool *p, pool *ptemp, const char *confname) { server_rec *s = init_server_config(p); @@ -1485,7 +1445,6 @@ server_rec *ap_read_config(pool *p, pool *ptemp, char *confname) process_command_config(s, ap_server_post_read_config, p, ptemp); fixup_virtual_hosts(p, s); - default_listeners(p, s); ap_fini_vhost_config(p, s); return s; diff --git a/server/main.c b/server/main.c index 5bd372bbc4..86c204146b 100644 --- a/server/main.c +++ b/server/main.c @@ -1,6291 +1,280 @@ /* ==================================================================== * Copyright (c) 1995-1999 The Apache Group. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * 4. The names "Apache Server" and "Apache Group" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the Apache Group - * for use in the Apache HTTP server project (http://www.apache.org/)." - * - * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Group and was originally based - * on public domain software written at the National Center for - * Supercomputing Applications, University of Illinois, Urbana-Champaign. - * For more information on the Apache Group and the Apache HTTP server - * project, please see . - * - */ - -/* - * httpd.c: simple http daemon for answering WWW file requests - * * - * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3) + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * 03-06-95 blong - * changed server number for child-alone processes to 0 and changed name - * of processes - * - * 03-10-95 blong - * Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) - * including set group before fork, and call gettime before to fork - * to set up libraries. - * - * 04-14-95 rst / rh - * Brandon's code snarfed from NCSA 1.4, but tinkered to work with the - * Apache server, and also to have child processes do accept() directly. - * - * April-July '95 rst - * Extensive rework for Apache. - */ - -#ifndef SHARED_CORE_BOOTSTRAP -#ifndef SHARED_CORE_TIESTATIC - -#ifdef SHARED_CORE -#define REALMAIN ap_main -int ap_main(int argc, char *argv[]); -#else -#define REALMAIN main -#endif + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ #define CORE_PRIVATE +#include "httpd.h" +#include "http_main.h" +#include "http_config.h" +#include "util_uri.h" +#include "ap_mpm.h" -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_protocol.h" /* for read_request */ -#include "http_request.h" /* for process_request */ -#include "http_conf_globals.h" -#include "http_core.h" /* for get_remote_host */ -#include "http_vhost.h" -#include "util_script.h" /* to force util_script.c linking */ -#include "util_uri.h" -#include "scoreboard.h" -#include "multithread.h" -#include -#ifdef USE_SHMGET_SCOREBOARD -#include -#include -#include -#endif -#ifdef SecureWare -#include -#include -#include -#endif -#ifdef WIN32 -#include "../os/win32/getopt.h" -#elif !defined(BEOS) && !defined(TPF) -#include -#endif - -#ifdef HAVE_BSTRING_H -#include /* for IRIX, FD_SET calls bzero() */ -#endif - -#ifdef MULTITHREAD -/* special debug stuff -- PCS */ - -/* Set this non-zero if you are prepared to put up with more than one log entry per second */ -#define SEVERELY_VERBOSE 0 - - /* APD1() to APD5() are macros to help us debug. They can either - * log to the screen or the error_log file. In release builds, these - * macros do nothing. In debug builds, they send messages at priority - * "debug" to the error log file, or if DEBUG_TO_CONSOLE is defined, - * to the console. - */ - -# ifdef _DEBUG -# ifndef DEBUG_TO_CONSOLE -# define APD1(a) ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,server_conf,a) -# define APD2(a,b) ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,server_conf,a,b) -# define APD3(a,b,c) ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,server_conf,a,b,c) -# define APD4(a,b,c,d) ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,server_conf,a,b,c,d) -# define APD5(a,b,c,d,e) ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,server_conf,a,b,c,d,e) -# else -# define APD1(a) printf("%s\n",a) -# define APD2(a,b) do { printf(a,b);putchar('\n'); } while(0); -# define APD3(a,b,c) do { printf(a,b,c);putchar('\n'); } while(0); -# define APD4(a,b,c,d) do { printf(a,b,c,d);putchar('\n'); } while(0); -# define APD5(a,b,c,d,e) do { printf(a,b,c,d,e);putchar('\n'); } while(0); -# endif -# else /* !_DEBUG */ -# define APD1(a) -# define APD2(a,b) -# define APD3(a,b,c) -# define APD4(a,b,c,d) -# define APD5(a,b,c,d,e) -# endif /* _DEBUG */ -#endif /* MULTITHREAD */ - -/* This next function is never used. It is here to ensure that if we - * make all the modules into shared libraries that core httpd still - * includes the full Apache API. Without this function the objects in - * main/util_script.c would not be linked into a minimal httpd. - * And the extra prototype is to make gcc -Wmissing-prototypes quiet. - */ -extern void ap_force_library_loading(void); -void ap_force_library_loading(void) { - ap_add_cgi_vars(NULL); -} - -#include "explain.h" - -#if !defined(max) -#define max(a,b) (a > b ? a : b) -#endif - -#ifdef WIN32 -#include "../os/win32/service.h" -#include "../os/win32/registry.h" -#define DEFAULTSERVICENAME "Apache" -#define PATHSEPARATOR '\\' -#else -#define PATHSEPARATOR '/' -#endif - - -#ifdef MINT -long _stksize = 32768; -#endif - -#ifdef USE_OS2_SCOREBOARD - /* Add MMAP style functionality to OS/2 */ -#define INCL_DOSMEMMGR -#define INCL_DOSEXCEPTIONS -#define INCL_DOSSEMAPHORES -#include -#include -#include -caddr_t create_shared_heap(const char *, size_t); -caddr_t get_shared_heap(const char *); -#endif - -DEF_Explain - -/* Defining GPROF when compiling uses the moncontrol() function to - * disable gprof profiling in the parent, and enable it only for - * request processing in children (or in one_process mode). It's - * absolutely required to get useful gprof results under linux - * because the profile itimers and such are disabled across a - * fork(). It's probably useful elsewhere as well. - */ -#ifdef GPROF -extern void moncontrol(int); -#define MONCONTROL(x) moncontrol(x) -#else -#define MONCONTROL(x) -#endif - -#ifndef MULTITHREAD -/* this just need to be anything non-NULL */ -void *ap_dummy_mutex = &ap_dummy_mutex; -#endif - -/* - * Actual definitions of config globals... here because this is - * for the most part the only code that acts on 'em. (Hmmm... mod_main.c?) - */ - -int ap_standalone=0; -int ap_configtestonly=0; -int ap_docrootcheck=1; -uid_t ap_user_id=0; -char *ap_user_name=NULL; -gid_t ap_group_id=0; -#ifdef MULTIPLE_GROUPS -gid_t group_id_list[NGROUPS_MAX]; -#endif -int ap_max_requests_per_child=0; -int ap_threads_per_child=0; -int ap_excess_requests_per_child=0; -char *ap_pid_fname=NULL; -char *ap_scoreboard_fname=NULL; -char *ap_lock_fname; -char *ap_server_argv0=NULL; -struct in_addr ap_bind_address; -int ap_daemons_to_start=0; -int ap_daemons_min_free=0; -int ap_daemons_max_free=0; -int ap_daemons_limit=0; -time_t ap_restart_time=0; -int ap_suexec_enabled = 0; -int ap_listenbacklog; -int ap_dump_settings = 0; -API_VAR_EXPORT int ap_extended_status = 0; - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across SIGUSR1 restarts. We use this - * value to optimize routines that have to scan the entire scoreboard. - */ -static int max_daemons_limit = -1; +char *ap_server_argv0; -/* - * During config time, listeners is treated as a NULL-terminated list. - * child_main previously would start at the beginning of the list each time - * through the loop, so a socket early on in the list could easily starve out - * sockets later on in the list. The solution is to start at the listener - * after the last one processed. But to do that fast/easily in child_main it's - * way more convenient for listeners to be a ring that loops back on itself. - * The routine setup_listeners() is called after config time to both open up - * the sockets and to turn the NULL-terminated list into a ring that loops back - * on itself. - * - * head_listener is used by each child to keep track of what they consider - * to be the "start" of the ring. It is also set by make_child to ensure - * that new children also don't starve any sockets. - * - * Note that listeners != NULL is ensured by read_config(). - */ -listen_rec *ap_listeners; -static listen_rec *head_listener; - -API_VAR_EXPORT char ap_server_root[MAX_STRING_LEN]=""; -char ap_server_confname[MAX_STRING_LEN]=""; -char ap_coredump_dir[MAX_STRING_LEN]; +API_VAR_EXPORT const char *ap_server_root; array_header *ap_server_pre_read_config; array_header *ap_server_post_read_config; array_header *ap_server_config_defines; -/* *Non*-shared http_main globals... */ - -static server_rec *server_conf; -static JMP_BUF APACHE_TLS jmpbuffer; -static int sd; -static fd_set listenfds; -static int listenmaxfd; -static pid_t pgrp; - -/* one_process --- debugging mode variable; can be set from the command line - * with the -X flag. If set, this gets you the child_main loop running - * in the process which originally started up (no detach, no make_child), - * which is a pretty nice debugging environment. (You'll get a SIGHUP - * early in standalone_main; just continue through. This is the server - * trying to kill off any child processes which it might have lying - * around --- Apache doesn't keep track of their pids, it just sends - * SIGHUP to the process group, ignoring it in the root process. - * Continue through and you'll be fine.). - */ - -static int one_process = 0; - -/* set if timeouts are to be handled by the children and not by the parent. - * i.e. child_timeouts = !standalone || one_process. - */ -static int child_timeouts; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; +static void show_compile_settings(void) +{ + printf("Server version: %s\n", ap_get_server_version()); + printf("Server built: %s\n", ap_get_server_built()); + printf("Server's Module Magic Number: %u:%u\n", + MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR); + printf("Server compiled with....\n"); +#ifdef BIG_SECURITY_HOLE + printf(" -D BIG_SECURITY_HOLE\n"); #endif - -#ifndef NO_OTHER_CHILD -/* used to maintain list of children which aren't part of the scoreboard */ -typedef struct other_child_rec other_child_rec; -struct other_child_rec { - other_child_rec *next; - int pid; - void (*maintenance) (int, void *, ap_wait_t); - void *data; - int write_fd; -}; -static other_child_rec *other_children; +#ifdef SECURITY_HOLE_PASS_AUTHORIZATION + printf(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n"); #endif - -static pool *pglobal; /* Global pool */ -static pool *pconf; /* Pool for config stuff */ -static pool *plog; /* Pool for error-logging files */ -static pool *ptrans; /* Pool for per-transaction stuff */ -static pool *pchild; /* Pool for httpd child stuff */ -static pool *pcommands; /* Pool for -C and -c switches */ - -static int APACHE_TLS my_pid; /* it seems silly to call getpid all the time */ -#ifndef MULTITHREAD -static int my_child_num; +#ifdef HAVE_MMAP + printf(" -D HAVE_MMAP\n"); #endif - -#ifdef TPF -int tpf_child = 0; -char tpf_server_name[INETD_SERVNAME_LENGTH+1]; -#endif /* TPF */ - -scoreboard *ap_scoreboard_image = NULL; - -/* - * Pieces for managing the contents of the Server response header - * field. - */ -static char *server_version = NULL; -static int version_locked = 0; - -/* Global, alas, so http_core can talk to us */ -enum server_token_type ap_server_tokens = SrvTk_FULL; - -/* - * This routine is called when the pconf pool is vacuumed. It resets the - * server version string to a known value and [re]enables modifications - * (which are disabled by configuration completion). - */ -static void reset_version(void *dummy) -{ - version_locked = 0; - ap_server_tokens = SrvTk_FULL; - server_version = NULL; -} - -API_EXPORT(const char *) ap_get_server_version(void) -{ - return (server_version ? server_version : SERVER_BASEVERSION); -} - -API_EXPORT(void) ap_add_version_component(const char *component) -{ - if (! version_locked) { - /* - * If the version string is null, register our cleanup to reset the - * pointer on pool destruction. We also know that, if NULL, - * we are adding the original SERVER_BASEVERSION string. - */ - if (server_version == NULL) { - ap_register_cleanup(pconf, NULL, (void (*)(void *))reset_version, - ap_null_cleanup); - server_version = ap_pstrdup(pconf, component); - } - else { - /* - * Tack the given component identifier to the end of - * the existing string. - */ - server_version = ap_pstrcat(pconf, server_version, " ", - component, NULL); - } - } -} - -/* - * This routine adds the real server base identity to the version string, - * and then locks out changes until the next reconfig. - */ -static void ap_set_version(void) -{ - if (ap_server_tokens == SrvTk_MIN) { - ap_add_version_component(SERVER_BASEVERSION); - } - else { - ap_add_version_component(SERVER_BASEVERSION " (" PLATFORM ")"); - } - /* - * Lock the server_version string if we're not displaying - * the full set of tokens - */ - if (ap_server_tokens != SrvTk_FULL) { - version_locked++; - } -} - -static APACHE_TLS int volatile exit_after_unblock = 0; - -#ifdef GPROF -/* - * change directory for gprof to plop the gmon.out file - * configure in httpd.conf: - * GprofDir logs/ -> $ServerRoot/logs/gmon.out - * GprofDir logs/% -> $ServerRoot/logs/gprof.$pid/gmon.out - */ -static void chdir_for_gprof(void) -{ - core_server_config *sconf = - ap_get_module_config(server_conf->module_config, &core_module); - char *dir = sconf->gprof_dir; - - if(dir) { - char buf[512]; - int len = strlen(sconf->gprof_dir) - 1; - if(*(dir + len) == '%') { - dir[len] = '\0'; - ap_snprintf(buf, sizeof(buf), "%sgprof.%d", dir, (int)getpid()); - } - dir = ap_server_root_relative(pconf, buf[0] ? buf : dir); - if(mkdir(dir, 0755) < 0 && errno != EEXIST) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "gprof: error creating directory %s", dir); - } - } - else { - dir = ap_server_root_relative(pconf, "logs"); - } - - chdir(dir); -} -#else -#define chdir_for_gprof() +#ifdef HAVE_SHMGET + printf(" -D HAVE_SHMGET\n"); #endif - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) __attribute__ ((noreturn)); -static void clean_child_exit(int code) -{ - if (pchild) { - ap_child_exit_modules(pchild, server_conf); - ap_destroy_pool(pchild); - } - chdir_for_gprof(); - exit(code); -} - -#if defined(USE_FCNTL_SERIALIZED_ACCEPT) || defined(USE_FLOCK_SERIALIZED_ACCEPT) -static void expand_lock_fname(pool *p) -{ - /* XXXX possibly bogus cast */ - ap_lock_fname = ap_psprintf(p, "%s.%lu", - ap_server_root_relative(p, ap_lock_fname), (unsigned long)getpid()); -} +#ifdef USE_MMAP_SCOREBOARD + printf(" -D USE_MMAP_SCOREBOARD\n"); #endif - -#if defined (USE_USLOCK_SERIALIZED_ACCEPT) - -#include - -static ulock_t uslock = NULL; - -#define accept_mutex_child_init(x) - -static void accept_mutex_init(pool *p) -{ - ptrdiff_t old; - usptr_t *us; - - - /* default is 8, allocate enough for all the children plus the parent */ - if ((old = usconfig(CONF_INITUSERS, HARD_SERVER_LIMIT + 1)) == -1) { - perror("usconfig(CONF_INITUSERS)"); - exit(-1); - } - - if ((old = usconfig(CONF_LOCKTYPE, US_NODEBUG)) == -1) { - perror("usconfig(CONF_LOCKTYPE)"); - exit(-1); - } - if ((old = usconfig(CONF_ARENATYPE, US_SHAREDONLY)) == -1) { - perror("usconfig(CONF_ARENATYPE)"); - exit(-1); - } - if ((us = usinit("/dev/zero")) == NULL) { - perror("usinit"); - exit(-1); - } - - if ((uslock = usnewlock(us)) == NULL) { - perror("usnewlock"); - exit(-1); - } -} - -static void accept_mutex_on(void) -{ - switch (ussetlock(uslock)) { - case 1: - /* got lock */ - break; - case 0: - fprintf(stderr, "didn't get lock\n"); - clean_child_exit(APEXIT_CHILDFATAL); - case -1: - perror("ussetlock"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -static void accept_mutex_off(void) -{ - if (usunsetlock(uslock) == -1) { - perror("usunsetlock"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -#elif defined (USE_PTHREAD_SERIALIZED_ACCEPT) - -/* This code probably only works on Solaris ... but it works really fast - * on Solaris. Note that pthread mutexes are *NOT* released when a task - * dies ... the task has to free it itself. So we block signals and - * try to be nice about releasing the mutex. - */ - -#include - -static pthread_mutex_t *accept_mutex = (void *)(caddr_t) -1; -static int have_accept_mutex; -static sigset_t accept_block_mask; -static sigset_t accept_previous_mask; - -static void accept_mutex_child_cleanup(void *foo) -{ - if (accept_mutex != (void *)(caddr_t)-1 - && have_accept_mutex) { - pthread_mutex_unlock(accept_mutex); - } -} - -static void accept_mutex_child_init(pool *p) -{ - ap_register_cleanup(p, NULL, accept_mutex_child_cleanup, ap_null_cleanup); -} - -static void accept_mutex_cleanup(void *foo) -{ - if (accept_mutex != (void *)(caddr_t)-1 - && munmap((caddr_t) accept_mutex, sizeof(*accept_mutex))) { - perror("munmap"); - } - accept_mutex = (void *)(caddr_t)-1; -} - -static void accept_mutex_init(pool *p) -{ - pthread_mutexattr_t mattr; - int fd; - - fd = open("/dev/zero", O_RDWR); - if (fd == -1) { - perror("open(/dev/zero)"); - exit(APEXIT_INIT); - } - accept_mutex = (pthread_mutex_t *) mmap((caddr_t) 0, sizeof(*accept_mutex), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (accept_mutex == (void *) (caddr_t) - 1) { - perror("mmap"); - exit(APEXIT_INIT); - } - close(fd); - if ((errno = pthread_mutexattr_init(&mattr))) { - perror("pthread_mutexattr_init"); - exit(APEXIT_INIT); - } - if ((errno = pthread_mutexattr_setpshared(&mattr, - PTHREAD_PROCESS_SHARED))) { - perror("pthread_mutexattr_setpshared"); - exit(APEXIT_INIT); - } - if ((errno = pthread_mutex_init(accept_mutex, &mattr))) { - perror("pthread_mutex_init"); - exit(APEXIT_INIT); - } - sigfillset(&accept_block_mask); - sigdelset(&accept_block_mask, SIGHUP); - sigdelset(&accept_block_mask, SIGTERM); - sigdelset(&accept_block_mask, SIGUSR1); - ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup); -} - -static void accept_mutex_on(void) -{ - int err; - - if (sigprocmask(SIG_BLOCK, &accept_block_mask, &accept_previous_mask)) { - perror("sigprocmask(SIG_BLOCK)"); - clean_child_exit(APEXIT_CHILDFATAL); - } - if ((err = pthread_mutex_lock(accept_mutex))) { - errno = err; - perror("pthread_mutex_lock"); - clean_child_exit(APEXIT_CHILDFATAL); - } - have_accept_mutex = 1; -} - -static void accept_mutex_off(void) -{ - int err; - - if ((err = pthread_mutex_unlock(accept_mutex))) { - errno = err; - perror("pthread_mutex_unlock"); - clean_child_exit(APEXIT_CHILDFATAL); - } - /* There is a slight race condition right here... if we were to die right - * now, we'd do another pthread_mutex_unlock. Now, doing that would let - * another process into the mutex. pthread mutexes are designed to be - * fast, as such they don't have protection for things like testing if the - * thread owning a mutex is actually unlocking it (or even any way of - * testing who owns the mutex). - * - * If we were to unset have_accept_mutex prior to releasing the mutex - * then the race could result in the server unable to serve hits. Doing - * it this way means that the server can continue, but an additional - * child might be in the critical section ... at least it's still serving - * hits. - */ - have_accept_mutex = 0; - if (sigprocmask(SIG_SETMASK, &accept_previous_mask, NULL)) { - perror("sigprocmask(SIG_SETMASK)"); - clean_child_exit(1); - } -} - -#elif defined (USE_SYSVSEM_SERIALIZED_ACCEPT) - -#include -#include -#include - -#ifdef NEED_UNION_SEMUN -/* it makes no sense, but this isn't defined on solaris */ -union semun { - long val; - struct semid_ds *buf; - ushort *array; -}; - +#ifdef USE_SHMGET_SCOREBOARD + printf(" -D USE_SHMGET_SCOREBOARD\n"); #endif - -static int sem_id = -1; -static struct sembuf op_on; -static struct sembuf op_off; - -/* We get a random semaphore ... the lame sysv semaphore interface - * means we have to be sure to clean this up or else we'll leak - * semaphores. - */ -static void accept_mutex_cleanup(void *foo) -{ - union semun ick; - - if (sem_id < 0) - return; - /* this is ignored anyhow */ - ick.val = 0; - semctl(sem_id, 0, IPC_RMID, ick); -} - -#define accept_mutex_child_init(x) - -static void accept_mutex_init(pool *p) -{ - union semun ick; - struct semid_ds buf; - - /* acquire the semaphore */ - sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); - if (sem_id < 0) { - perror("semget"); - exit(APEXIT_INIT); - } - ick.val = 1; - if (semctl(sem_id, 0, SETVAL, ick) < 0) { - perror("semctl(SETVAL)"); - exit(APEXIT_INIT); - } - if (!getuid()) { - /* restrict it to use only by the appropriate user_id ... not that this - * stops CGIs from acquiring it and dinking around with it. - */ - buf.sem_perm.uid = ap_user_id; - buf.sem_perm.gid = ap_group_id; - buf.sem_perm.mode = 0600; - ick.buf = &buf; - if (semctl(sem_id, 0, IPC_SET, ick) < 0) { - perror("semctl(IPC_SET)"); - exit(APEXIT_INIT); - } - } - ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup); - - /* pre-initialize these */ - op_on.sem_num = 0; - op_on.sem_op = -1; - op_on.sem_flg = SEM_UNDO; - op_off.sem_num = 0; - op_off.sem_op = 1; - op_off.sem_flg = SEM_UNDO; -} - -static void accept_mutex_on(void) -{ - while (semop(sem_id, &op_on, 1) < 0) { - if (errno != EINTR) { - perror("accept_mutex_on"); - clean_child_exit(APEXIT_CHILDFATAL); - } - } -} - -static void accept_mutex_off(void) -{ - while (semop(sem_id, &op_off, 1) < 0) { - if (errno != EINTR) { - perror("accept_mutex_off"); - clean_child_exit(APEXIT_CHILDFATAL); - } - } -} - -#elif defined(USE_FCNTL_SERIALIZED_ACCEPT) -static struct flock lock_it; -static struct flock unlock_it; - -static int lock_fd = -1; - -#define accept_mutex_child_init(x) - -/* - * Initialize mutex lock. - * Must be safe to call this on a restart. - */ -static void accept_mutex_init(pool *p) -{ - - lock_it.l_whence = SEEK_SET; /* from current point */ - lock_it.l_start = 0; /* -"- */ - lock_it.l_len = 0; /* until end of file */ - lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ - lock_it.l_pid = 0; /* pid not actually interesting */ - unlock_it.l_whence = SEEK_SET; /* from current point */ - unlock_it.l_start = 0; /* -"- */ - unlock_it.l_len = 0; /* until end of file */ - unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */ - unlock_it.l_pid = 0; /* pid not actually interesting */ - - expand_lock_fname(p); - lock_fd = ap_popenf(p, ap_lock_fname, O_CREAT | O_WRONLY | O_EXCL, 0644); - if (lock_fd == -1) { - perror("open"); - fprintf(stderr, "Cannot open lock file: %s\n", ap_lock_fname); - exit(APEXIT_INIT); - } - unlink(ap_lock_fname); -} - -static void accept_mutex_on(void) -{ - int ret; - - while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR) { - /* nop */ - } - - if (ret < 0) { - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "fcntl: F_SETLKW: Error getting accept lock, exiting! " - "Perhaps you need to use the LockFile directive to place " - "your lock file on a local disk!"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -static void accept_mutex_off(void) -{ - int ret; - - while ((ret = fcntl(lock_fd, F_SETLKW, &unlock_it)) < 0 && errno == EINTR) { - /* nop */ - } - if (ret < 0) { - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "fcntl: F_SETLKW: Error freeing accept lock, exiting! " - "Perhaps you need to use the LockFile directive to place " - "your lock file on a local disk!"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -#elif defined(USE_FLOCK_SERIALIZED_ACCEPT) - -static int lock_fd = -1; - -static void accept_mutex_cleanup(void *foo) -{ - unlink(ap_lock_fname); -} - -/* - * Initialize mutex lock. - * Done by each child at it's birth - */ -static void accept_mutex_child_init(pool *p) -{ - - lock_fd = ap_popenf(p, ap_lock_fname, O_WRONLY, 0600); - if (lock_fd == -1) { - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "Child cannot open lock file: %s", ap_lock_fname); - clean_child_exit(APEXIT_CHILDINIT); - } -} - -/* - * Initialize mutex lock. - * Must be safe to call this on a restart. - */ -static void accept_mutex_init(pool *p) -{ - expand_lock_fname(p); - unlink(ap_lock_fname); - lock_fd = ap_popenf(p, ap_lock_fname, O_CREAT | O_WRONLY | O_EXCL, 0600); - if (lock_fd == -1) { - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "Parent cannot open lock file: %s", ap_lock_fname); - exit(APEXIT_INIT); - } - ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup); -} - -static void accept_mutex_on(void) -{ - int ret; - - while ((ret = flock(lock_fd, LOCK_EX)) < 0 && errno == EINTR) - continue; - - if (ret < 0) { - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "flock: LOCK_EX: Error getting accept lock. Exiting!"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -static void accept_mutex_off(void) -{ - if (flock(lock_fd, LOCK_UN) < 0) { - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "flock: LOCK_UN: Error freeing accept lock. Exiting!"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -#elif defined(USE_OS2SEM_SERIALIZED_ACCEPT) - -static HMTX lock_sem = -1; - -static void accept_mutex_cleanup(void *foo) -{ - DosReleaseMutexSem(lock_sem); - DosCloseMutexSem(lock_sem); -} - -/* - * Initialize mutex lock. - * Done by each child at it's birth - */ -static void accept_mutex_child_init(pool *p) -{ - int rc = DosOpenMutexSem(NULL, &lock_sem); - - if (rc != 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf, - "Child cannot open lock semaphore, rc=%d", rc); - clean_child_exit(APEXIT_CHILDINIT); - } else { - ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup); - } -} - -/* - * Initialize mutex lock. - * Must be safe to call this on a restart. - */ -static void accept_mutex_init(pool *p) -{ - int rc = DosCreateMutexSem(NULL, &lock_sem, DC_SEM_SHARED, FALSE); - - if (rc != 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf, - "Parent cannot create lock semaphore, rc=%d", rc); - exit(APEXIT_INIT); - } - - ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup); -} - -static void accept_mutex_on(void) -{ - int rc = DosRequestMutexSem(lock_sem, SEM_INDEFINITE_WAIT); - - if (rc != 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf, - "OS2SEM: Error %d getting accept lock. Exiting!", rc); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -static void accept_mutex_off(void) -{ - int rc = DosReleaseMutexSem(lock_sem); - - if (rc != 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf, - "OS2SEM: Error %d freeing accept lock. Exiting!", rc); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -#elif defined(USE_TPF_CORE_SERIALIZED_ACCEPT) - -static int tpf_core_held; - -static void accept_mutex_cleanup(void *foo) -{ - if(tpf_core_held) - coruc(RESOURCE_KEY); -} - -#define accept_mutex_init(x) - -static void accept_mutex_child_init(pool *p) -{ - ap_register_cleanup(p, NULL, accept_mutex_cleanup, ap_null_cleanup); - tpf_core_held = 0; -} - -static void accept_mutex_on(void) -{ - corhc(RESOURCE_KEY); - tpf_core_held = 1; - ap_check_signals(); -} - -static void accept_mutex_off(void) -{ - coruc(RESOURCE_KEY); - tpf_core_held = 0; - ap_check_signals(); -} - -#else -/* Default --- no serialization. Other methods *could* go here, - * as #elifs... - */ -#if !defined(MULTITHREAD) -/* Multithreaded systems don't complete between processes for - * the sockets. */ -#define NO_SERIALIZED_ACCEPT -#define accept_mutex_child_init(x) -#define accept_mutex_init(x) -#define accept_mutex_on() -#define accept_mutex_off() -#endif -#endif - -/* On some architectures it's safe to do unserialized accept()s in the single - * Listen case. But it's never safe to do it in the case where there's - * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT - * when it's safe in the single Listen case. - */ -#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) do {if(ap_listeners->next != ap_listeners) {stmt;}} while(0) -#else -#define SAFE_ACCEPT(stmt) do {stmt;} while(0) -#endif - -static void usage(char *bin) -{ - char pad[MAX_STRING_LEN]; - unsigned i; - - for (i = 0; i < strlen(bin); i++) - pad[i] = ' '; - pad[i] = '\0'; -#ifdef SHARED_CORE - fprintf(stderr, "Usage: %s [-R directory] [-D name] [-d directory] [-f file]\n", bin); -#else - fprintf(stderr, "Usage: %s [-D name] [-d directory] [-f file]\n", bin); -#endif - fprintf(stderr, " %s [-C \"directive\"] [-c \"directive\"]\n", pad); - fprintf(stderr, " %s [-v] [-V] [-h] [-l] [-L] [-S] [-t] [-T]\n", pad); -#ifdef WIN32 - fprintf(stderr, " %s [-n service] [-k signal] [-i] [-u]\n", pad); -#endif - fprintf(stderr, "Options:\n"); -#ifdef SHARED_CORE - fprintf(stderr, " -R directory : specify an alternate location for shared object files\n"); -#endif - fprintf(stderr, " -D name : define a name for use in directives\n"); - fprintf(stderr, " -d directory : specify an alternate initial ServerRoot\n"); - fprintf(stderr, " -f file : specify an alternate ServerConfigFile\n"); - fprintf(stderr, " -C \"directive\" : process directive before reading config files\n"); - fprintf(stderr, " -c \"directive\" : process directive after reading config files\n"); - fprintf(stderr, " -v : show version number\n"); - fprintf(stderr, " -V : show compile settings\n"); - fprintf(stderr, " -h : list available command line options (this page)\n"); - fprintf(stderr, " -l : list compiled-in modules\n"); - fprintf(stderr, " -L : list available configuration directives\n"); - fprintf(stderr, " -S : show parsed settings (currently only vhost settings)\n"); - fprintf(stderr, " -t : run syntax check for config files (with docroot check)\n"); - fprintf(stderr, " -T : run syntax check for config files (without docroot check)\n"); -#ifdef WIN32 - fprintf(stderr, " -n name : set service name and use its ServerConfigFile\n"); - fprintf(stderr, " -k shutdown : tell running Apache to shutdown\n"); - fprintf(stderr, " -k restart : tell running Apache to do a graceful restart\n"); - fprintf(stderr, " -k start : tell Apache to start\n"); - fprintf(stderr, " -i : install an Apache service\n"); - fprintf(stderr, " -u : uninstall an Apache service\n"); -#endif - exit(1); -} - -/***************************************************************** - * - * Timeout handling. DISTINCTLY not thread-safe, but all this stuff - * has to change for threads anyway. Note that this code allows only - * one timeout in progress at a time... - */ - -static APACHE_TLS conn_rec *volatile current_conn; -static APACHE_TLS request_rec *volatile timeout_req; -static APACHE_TLS const char *volatile timeout_name = NULL; -static APACHE_TLS int volatile alarms_blocked = 0; -static APACHE_TLS int volatile alarm_pending = 0; - -static void timeout(int sig) -{ - void *dirconf; - - if (alarms_blocked) { - alarm_pending = 1; - return; - } - if (exit_after_unblock) { - clean_child_exit(0); - } - - if (!current_conn) { - ap_longjmp(jmpbuffer, 1); - } - - if (timeout_req != NULL) - dirconf = timeout_req->per_dir_config; - else - dirconf = current_conn->server->lookup_defaults; - if (!current_conn->keptalive) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, - current_conn->server, "[client %s] %s timed out", - current_conn->remote_ip, - timeout_name ? timeout_name : "request"); - } - - if (timeout_req) { - /* Someone has asked for this transaction to just be aborted - * if it times out... - */ - - request_rec *log_req = timeout_req; - request_rec *save_req = timeout_req; - - /* avoid looping... if ap_log_transaction started another - * timer (say via rfc1413.c) we could loop... - */ - timeout_req = NULL; - - while (log_req->main || log_req->prev) { - /* Get back to original request... */ - if (log_req->main) - log_req = log_req->main; - else - log_req = log_req->prev; - } - - if (!current_conn->keptalive) { - /* in some cases we come here before setting the time */ - if (log_req->request_time == 0) { - log_req->request_time = time(0); - } - ap_log_transaction(log_req); - } - - ap_bsetflag(save_req->connection->client, B_EOUT, 1); - ap_bclose(save_req->connection->client); - - if (!ap_standalone) - exit(0); - - ap_longjmp(jmpbuffer, 1); - } - else { /* abort the connection */ - ap_bsetflag(current_conn->client, B_EOUT, 1); - ap_bclose(current_conn->client); - current_conn->aborted = 1; - } -} - -#ifndef TPF -/* - * These two called from alloc.c to protect its critical sections... - * Note that they can nest (as when destroying the sub_pools of a pool - * which is itself being cleared); we have to support that here. - */ - -API_EXPORT(void) ap_block_alarms(void) -{ - ++alarms_blocked; -} - -API_EXPORT(void) ap_unblock_alarms(void) -{ - --alarms_blocked; - if (alarms_blocked == 0) { - if (exit_after_unblock) { - /* We have a couple race conditions to deal with here, we can't - * allow a timeout that comes in this small interval to allow - * the child to jump back to the main loop. Instead we block - * alarms again, and then note that exit_after_unblock is - * being dealt with. We choose this way to solve this so that - * the common path through unblock_alarms() is really short. - */ - ++alarms_blocked; - exit_after_unblock = 0; - clean_child_exit(0); - } - if (alarm_pending) { - alarm_pending = 0; - timeout(0); - } - } -} -#endif /* TPF */ - -static APACHE_TLS void (*volatile alarm_fn) (int) = NULL; -#ifdef WIN32 -static APACHE_TLS unsigned int alarm_expiry_time = 0; -#endif /* WIN32 */ - -#ifndef WIN32 -static void alrm_handler(int sig) -{ - if (alarm_fn) { - (*alarm_fn) (sig); - } -} -#endif - -unsigned int ap_set_callback_and_alarm(void (*fn) (int), int x) -{ - unsigned int old; - -#ifdef WIN32 - old = alarm_expiry_time; - if (old) - old -= time(0); - if (x == 0) { - alarm_fn = NULL; - alarm_expiry_time = 0; - } - else { - alarm_fn = fn; - alarm_expiry_time = time(NULL) + x; - } -#else - if (alarm_fn && x && fn != alarm_fn) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, NULL, - "ap_set_callback_and_alarm: possible nested timer!"); - } - alarm_fn = fn; -#ifndef OPTIMIZE_TIMEOUTS - old = alarm(x); -#else - if (child_timeouts) { - old = alarm(x); - } - else { - /* Just note the timeout in our scoreboard, no need to call the system. - * We also note that the virtual time has gone forward. - */ - ap_check_signals(); - old = ap_scoreboard_image->servers[my_child_num].timeout_len; - ap_scoreboard_image->servers[my_child_num].timeout_len = x; - ++ap_scoreboard_image->servers[my_child_num].cur_vtime; - } -#endif -#endif - return (old); -} - - -#ifdef WIN32 -API_EXPORT(int) ap_check_alarm(void) -{ - if (alarm_expiry_time) { - unsigned int t; - - t = time(NULL); - if (t >= alarm_expiry_time) { - alarm_expiry_time = 0; - (*alarm_fn) (0); - return (-1); - } - else { - return (alarm_expiry_time - t); - } - } - else - return (0); -} -#endif /* WIN32 */ - - - -/* reset_timeout (request_rec *) resets the timeout in effect, - * as long as it hasn't expired already. - */ - -API_EXPORT(void) ap_reset_timeout(request_rec *r) -{ - int i; - - if (timeout_name) { /* timeout has been set */ - i = ap_set_callback_and_alarm(alarm_fn, r->server->timeout); - if (i == 0) /* timeout already expired, so set it back to 0 */ - ap_set_callback_and_alarm(alarm_fn, 0); - } -} - - - - -void ap_keepalive_timeout(char *name, request_rec *r) -{ - unsigned int to; - - timeout_req = r; - timeout_name = name; - - if (r->connection->keptalive) - to = r->server->keep_alive_timeout; - else - to = r->server->timeout; - ap_set_callback_and_alarm(timeout, to); - -} - -API_EXPORT(void) ap_hard_timeout(char *name, request_rec *r) -{ - timeout_req = r; - timeout_name = name; - - ap_set_callback_and_alarm(timeout, r->server->timeout); - -} - -API_EXPORT(void) ap_soft_timeout(char *name, request_rec *r) -{ - timeout_name = name; - - ap_set_callback_and_alarm(timeout, r->server->timeout); - -} - -API_EXPORT(void) ap_kill_timeout(request_rec *dummy) -{ - ap_check_signals(); - ap_set_callback_and_alarm(NULL, 0); - timeout_req = NULL; - timeout_name = NULL; -} - - -/* - * More machine-dependent networking gooo... on some systems, - * you've got to be *really* sure that all the packets are acknowledged - * before closing the connection, since the client will not be able - * to see the last response if their TCP buffer is flushed by a RST - * packet from us, which is what the server's TCP stack will send - * if it receives any request data after closing the connection. - * - * In an ideal world, this function would be accomplished by simply - * setting the socket option SO_LINGER and handling it within the - * server's TCP stack while the process continues on to the next request. - * Unfortunately, it seems that most (if not all) operating systems - * block the server process on close() when SO_LINGER is used. - * For those that don't, see USE_SO_LINGER below. For the rest, - * we have created a home-brew lingering_close. - * - * Many operating systems tend to block, puke, or otherwise mishandle - * calls to shutdown only half of the connection. You should define - * NO_LINGCLOSE in ap_config.h if such is the case for your system. - */ -#ifndef MAX_SECS_TO_LINGER -#define MAX_SECS_TO_LINGER 30 -#endif - -#ifdef USE_SO_LINGER -#define NO_LINGCLOSE /* The two lingering options are exclusive */ - -static void sock_enable_linger(int s) -{ - struct linger li; - - li.l_onoff = 1; - li.l_linger = MAX_SECS_TO_LINGER; - - if (setsockopt(s, SOL_SOCKET, SO_LINGER, - (char *) &li, sizeof(struct linger)) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, - "setsockopt: (SO_LINGER)"); - /* not a fatal error */ - } -} - -#else -#define sock_enable_linger(s) /* NOOP */ -#endif /* USE_SO_LINGER */ - -#ifndef NO_LINGCLOSE - -/* Special version of timeout for lingering_close */ - -static void lingerout(int sig) -{ - if (alarms_blocked) { - alarm_pending = 1; - return; - } - - if (!current_conn) { - ap_longjmp(jmpbuffer, 1); - } - ap_bsetflag(current_conn->client, B_EOUT, 1); - current_conn->aborted = 1; -} - -static void linger_timeout(void) -{ - timeout_name = "lingering close"; - - ap_set_callback_and_alarm(lingerout, MAX_SECS_TO_LINGER); -} - -/* Since many clients will abort a connection instead of closing it, - * attempting to log an error message from this routine will only - * confuse the webmaster. There doesn't seem to be any portable way to - * distinguish between a dropped connection and something that might be - * worth logging. - */ -static void lingering_close(request_rec *r) -{ - char dummybuf[512]; - struct timeval tv; - fd_set lfds; - int select_rv; - int lsd; - - /* Prevent a slow-drip client from holding us here indefinitely */ - - linger_timeout(); - - /* Send any leftover data to the client, but never try to again */ - - if (ap_bflush(r->connection->client) == -1) { - ap_kill_timeout(r); - ap_bclose(r->connection->client); - return; - } - ap_bsetflag(r->connection->client, B_EOUT, 1); - - /* Close our half of the connection --- send the client a FIN */ - - lsd = r->connection->client->fd; - - if ((shutdown(lsd, 1) != 0) || r->connection->aborted) { - ap_kill_timeout(r); - ap_bclose(r->connection->client); - return; - } - - /* Set up to wait for readable data on socket... */ - - FD_ZERO(&lfds); - - /* Wait for readable data or error condition on socket; - * slurp up any data that arrives... We exit when we go for an - * interval of tv length without getting any more data, get an error - * from select(), get an error or EOF on a read, or the timer expires. - */ - - do { - /* We use a 2 second timeout because current (Feb 97) browsers - * fail to close a connection after the server closes it. Thus, - * to avoid keeping the child busy, we are only lingering long enough - * for a client that is actively sending data on a connection. - * This should be sufficient unless the connection is massively - * losing packets, in which case we might have missed the RST anyway. - * These parameters are reset on each pass, since they might be - * changed by select. - */ - FD_SET(lsd, &lfds); - tv.tv_sec = 2; - tv.tv_usec = 0; - - select_rv = ap_select(lsd + 1, &lfds, NULL, NULL, &tv); - - } while ((select_rv > 0) && - (read(lsd, dummybuf, sizeof dummybuf) > 0)); - - /* Should now have seen final ack. Safe to finally kill socket */ - - ap_bclose(r->connection->client); - - ap_kill_timeout(r); -} -#endif /* ndef NO_LINGCLOSE */ - -/***************************************************************** - * dealing with other children - */ - -#ifndef NO_OTHER_CHILD -API_EXPORT(void) ap_register_other_child(int pid, - void (*maintenance) (int reason, void *, ap_wait_t status), - void *data, int write_fd) -{ - other_child_rec *ocr; - - ocr = ap_palloc(pconf, sizeof(*ocr)); - ocr->pid = pid; - ocr->maintenance = maintenance; - ocr->data = data; - ocr->write_fd = write_fd; - ocr->next = other_children; - other_children = ocr; -} - -/* note that since this can be called by a maintenance function while we're - * scanning the other_children list, all scanners should protect themself - * by loading ocr->next before calling any maintenance function. - */ -API_EXPORT(void) ap_unregister_other_child(void *data) -{ - other_child_rec **pocr, *nocr; - - for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) { - if ((*pocr)->data == data) { - nocr = (*pocr)->next; - (*(*pocr)->maintenance) (OC_REASON_UNREGISTER, (*pocr)->data, -1); - *pocr = nocr; - /* XXX: um, well we've just wasted some space in pconf ? */ - return; - } - } -} - -/* test to ensure that the write_fds are all still writable, otherwise - * invoke the maintenance functions as appropriate */ -static void probe_writable_fds(void) -{ - fd_set writable_fds; - int fd_max; - other_child_rec *ocr, *nocr; - struct timeval tv; - int rc; - - if (other_children == NULL) - return; - - fd_max = 0; - FD_ZERO(&writable_fds); - do { - for (ocr = other_children; ocr; ocr = ocr->next) { - if (ocr->write_fd == -1) - continue; - FD_SET(ocr->write_fd, &writable_fds); - if (ocr->write_fd > fd_max) { - fd_max = ocr->write_fd; - } - } - if (fd_max == 0) - return; - - tv.tv_sec = 0; - tv.tv_usec = 0; - rc = ap_select(fd_max + 1, NULL, &writable_fds, NULL, &tv); - } while (rc == -1 && errno == EINTR); - - if (rc == -1) { - /* XXX: uhh this could be really bad, we could have a bad file - * descriptor due to a bug in one of the maintenance routines */ - ap_log_unixerr("probe_writable_fds", "select", - "could not probe writable fds", server_conf); - return; - } - if (rc == 0) - return; - - for (ocr = other_children; ocr; ocr = nocr) { - nocr = ocr->next; - if (ocr->write_fd == -1) - continue; - if (FD_ISSET(ocr->write_fd, &writable_fds)) - continue; - (*ocr->maintenance) (OC_REASON_UNWRITABLE, ocr->data, -1); - } -} - -/* possibly reap an other_child, return 0 if yes, -1 if not */ -static int reap_other_child(int pid, ap_wait_t status) -{ - other_child_rec *ocr, *nocr; - - for (ocr = other_children; ocr; ocr = nocr) { - nocr = ocr->next; - if (ocr->pid != pid) - continue; - ocr->pid = -1; - (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status); - return 0; - } - return -1; -} -#endif - -/***************************************************************** - * - * Dealing with the scoreboard... a lot of these variables are global - * only to avoid getting clobbered by the longjmp() that happens when - * a hard timeout expires... - * - * We begin with routines which deal with the file itself... - */ - -#ifdef MULTITHREAD -/* - * In the multithreaded mode, have multiple threads - not multiple - * processes that need to talk to each other. Just use a simple - * malloc. But let the routines that follow, think that you have - * shared memory (so they use memcpy etc.) - */ - -static void reinit_scoreboard(pool *p) -{ - ap_assert(!ap_scoreboard_image); - ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE); - if (ap_scoreboard_image == NULL) { - fprintf(stderr, "Ouch! Out of memory reiniting scoreboard!\n"); - } - memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE); -} - -void cleanup_scoreboard(void) -{ - ap_assert(ap_scoreboard_image); - free(ap_scoreboard_image); - ap_scoreboard_image = NULL; -} - -API_EXPORT(void) ap_sync_scoreboard_image(void) -{ -} - - -#else /* MULTITHREAD */ -#if defined(USE_OS2_SCOREBOARD) - -/* The next two routines are used to access shared memory under OS/2. */ -/* This requires EMX v09c to be installed. */ - -caddr_t create_shared_heap(const char *name, size_t size) -{ - ULONG rc; - void *mem; - Heap_t h; - - rc = DosAllocSharedMem(&mem, name, size, - PAG_COMMIT | PAG_READ | PAG_WRITE); - if (rc != 0) - return NULL; - h = _ucreate(mem, size, !_BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED, - NULL, NULL); - if (h == NULL) - DosFreeMem(mem); - return (caddr_t) h; -} - -caddr_t get_shared_heap(const char *Name) -{ - - PVOID BaseAddress; /* Pointer to the base address of - the shared memory object */ - ULONG AttributeFlags; /* Flags describing characteristics - of the shared memory object */ - APIRET rc; /* Return code */ - - /* Request read and write access to */ - /* the shared memory object */ - AttributeFlags = PAG_WRITE | PAG_READ; - - rc = DosGetNamedSharedMem(&BaseAddress, Name, AttributeFlags); - - if (rc != 0) { - printf("DosGetNamedSharedMem error: return code = %ld", rc); - return 0; - } - - return BaseAddress; -} - -static void setup_shared_mem(pool *p) -{ - caddr_t m; - - int rc; - - m = (caddr_t) create_shared_heap("\\SHAREMEM\\SCOREBOARD", SCOREBOARD_SIZE); - if (m == 0) { - fprintf(stderr, "%s: Could not create OS/2 Shared memory pool.\n", - ap_server_argv0); - exit(APEXIT_INIT); - } - - rc = _uopen((Heap_t) m); - if (rc != 0) { - fprintf(stderr, - "%s: Could not uopen() newly created OS/2 Shared memory pool.\n", - ap_server_argv0); - } - ap_scoreboard_image = (scoreboard *) m; - ap_scoreboard_image->global.running_generation = 0; -} - -static void reopen_scoreboard(pool *p) -{ - caddr_t m; - int rc; - - m = (caddr_t) get_shared_heap("\\SHAREMEM\\SCOREBOARD"); - if (m == 0) { - fprintf(stderr, "%s: Could not find existing OS/2 Shared memory pool.\n", - ap_server_argv0); - exit(APEXIT_INIT); - } - - rc = _uopen((Heap_t) m); - ap_scoreboard_image = (scoreboard *) m; -} - -#elif defined(USE_POSIX_SCOREBOARD) -#include -/* - * POSIX 1003.4 style - * - * Note 1: - * As of version 4.23A, shared memory in QNX must reside under /dev/shmem, - * where no subdirectories allowed. - * - * POSIX shm_open() and shm_unlink() will take care about this issue, - * but to avoid confusion, I suggest to redefine scoreboard file name - * in httpd.conf to cut "logs/" from it. With default setup actual name - * will be "/dev/shmem/logs.apache_status". - * - * If something went wrong and Apache did not unlinked this object upon - * exit, you can remove it manually, using "rm -f" command. - * - * Note 2: - * in QNX defines MAP_ANON, but current implementation - * does NOT support BSD style anonymous mapping. So, the order of - * conditional compilation is important: - * this #ifdef section must be ABOVE the next one (BSD style). - * - * I tested this stuff and it works fine for me, but if it provides - * trouble for you, just comment out USE_MMAP_SCOREBOARD in QNX section - * of ap_config.h - * - * June 5, 1997, - * Igor N. Kovalenko -- infoh@mail.wplus.net - */ - -static void cleanup_shared_mem(void *d) -{ - shm_unlink(ap_scoreboard_fname); -} - -static void setup_shared_mem(pool *p) -{ - char buf[512]; - caddr_t m; - int fd; - - fd = shm_open(ap_scoreboard_fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - if (fd == -1) { - ap_snprintf(buf, sizeof(buf), "%s: could not open(create) scoreboard", - ap_server_argv0); - perror(buf); - exit(APEXIT_INIT); - } - if (ltrunc(fd, (off_t) SCOREBOARD_SIZE, SEEK_SET) == -1) { - ap_snprintf(buf, sizeof(buf), "%s: could not ltrunc scoreboard", - ap_server_argv0); - perror(buf); - shm_unlink(ap_scoreboard_fname); - exit(APEXIT_INIT); - } - if ((m = (caddr_t) mmap((caddr_t) 0, - (size_t) SCOREBOARD_SIZE, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, (off_t) 0)) == (caddr_t) - 1) { - ap_snprintf(buf, sizeof(buf), "%s: cannot mmap scoreboard", - ap_server_argv0); - perror(buf); - shm_unlink(ap_scoreboard_fname); - exit(APEXIT_INIT); - } - close(fd); - ap_register_cleanup(p, NULL, cleanup_shared_mem, ap_null_cleanup); - ap_scoreboard_image = (scoreboard *) m; - ap_scoreboard_image->global.running_generation = 0; -} - -static void reopen_scoreboard(pool *p) -{ -} - -#elif defined(USE_MMAP_SCOREBOARD) - -static void setup_shared_mem(pool *p) -{ - caddr_t m; - -#if defined(MAP_ANON) -/* BSD style */ -#ifdef CONVEXOS11 - /* - * 9-Aug-97 - Jeff Venters (venters@convex.hp.com) - * ConvexOS maps address space as follows: - * 0x00000000 - 0x7fffffff : Kernel - * 0x80000000 - 0xffffffff : User - * Start mmapped area 1GB above start of text. - * - * Also, the length requires a pointer as the actual length is - * returned (rounded up to a page boundary). - */ - { - unsigned len = SCOREBOARD_SIZE; - - m = mmap((caddr_t) 0xC0000000, &len, - PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, NOFD, 0); - } -#elif defined(MAP_TMPFILE) - { - char mfile[] = "/tmp/apache_shmem_XXXX"; - int fd = mkstemp(mfile); - if (fd == -1) { - perror("open"); - fprintf(stderr, "%s: Could not open %s\n", ap_server_argv0, mfile); - exit(APEXIT_INIT); - } - m = mmap((caddr_t) 0, SCOREBOARD_SIZE, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (m == (caddr_t) - 1) { - perror("mmap"); - fprintf(stderr, "%s: Could not mmap %s\n", ap_server_argv0, mfile); - exit(APEXIT_INIT); - } - close(fd); - unlink(mfile); - } -#else - m = mmap((caddr_t) 0, SCOREBOARD_SIZE, - PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); -#endif - if (m == (caddr_t) - 1) { - perror("mmap"); - fprintf(stderr, "%s: Could not mmap memory\n", ap_server_argv0); - exit(APEXIT_INIT); - } -#else -/* Sun style */ - int fd; - - fd = open("/dev/zero", O_RDWR); - if (fd == -1) { - perror("open"); - fprintf(stderr, "%s: Could not open /dev/zero\n", ap_server_argv0); - exit(APEXIT_INIT); - } - m = mmap((caddr_t) 0, SCOREBOARD_SIZE, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (m == (caddr_t) - 1) { - perror("mmap"); - fprintf(stderr, "%s: Could not mmap /dev/zero\n", ap_server_argv0); - exit(APEXIT_INIT); - } - close(fd); -#endif - ap_scoreboard_image = (scoreboard *) m; - ap_scoreboard_image->global.running_generation = 0; -} - -static void reopen_scoreboard(pool *p) -{ -} - -#elif defined(USE_SHMGET_SCOREBOARD) -static key_t shmkey = IPC_PRIVATE; -static int shmid = -1; - -static void setup_shared_mem(pool *p) -{ - struct shmid_ds shmbuf; -#ifdef MOVEBREAK - char *obrk; -#endif - - if ((shmid = shmget(shmkey, SCOREBOARD_SIZE, IPC_CREAT | SHM_R | SHM_W)) == -1) { -#ifdef LINUX - if (errno == ENOSYS) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf, - "Your kernel was built without CONFIG_SYSVIPC\n" - "%s: Please consult the Apache FAQ for details", - ap_server_argv0); - } -#endif - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "could not call shmget"); - exit(APEXIT_INIT); - } - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "created shared memory segment #%d", shmid); - -#ifdef MOVEBREAK - /* - * Some SysV systems place the shared segment WAY too close - * to the dynamic memory break point (sbrk(0)). This severely - * limits the use of malloc/sbrk in the program since sbrk will - * refuse to move past that point. - * - * To get around this, we move the break point "way up there", - * attach the segment and then move break back down. Ugly - */ - if ((obrk = sbrk(MOVEBREAK)) == (char *) -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "sbrk() could not move break"); - } -#endif - -#define BADSHMAT ((scoreboard *)(-1)) - if ((ap_scoreboard_image = (scoreboard *) shmat(shmid, 0, 0)) == BADSHMAT) { - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, "shmat error"); - /* - * We exit below, after we try to remove the segment - */ - } - else { /* only worry about permissions if we attached the segment */ - if (shmctl(shmid, IPC_STAT, &shmbuf) != 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "shmctl() could not stat segment #%d", shmid); - } - else { - shmbuf.shm_perm.uid = ap_user_id; - shmbuf.shm_perm.gid = ap_group_id; - if (shmctl(shmid, IPC_SET, &shmbuf) != 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "shmctl() could not set segment #%d", shmid); - } - } - } - /* - * We must avoid leaving segments in the kernel's - * (small) tables. - */ - if (shmctl(shmid, IPC_RMID, NULL) != 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, - "shmctl: IPC_RMID: could not remove shared memory segment #%d", - shmid); - } - if (ap_scoreboard_image == BADSHMAT) /* now bailout */ - exit(APEXIT_INIT); - -#ifdef MOVEBREAK - if (obrk == (char *) -1) - return; /* nothing else to do */ - if (sbrk(-(MOVEBREAK)) == (char *) -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "sbrk() could not move break back"); - } -#endif - ap_scoreboard_image->global.running_generation = 0; -} - -static void reopen_scoreboard(pool *p) -{ -} - -#elif defined(USE_TPF_SCOREBOARD) - -static void cleanup_scoreboard_heap() -{ - int rv; - rv = rsysc(ap_scoreboard_image, SCOREBOARD_FRAMES, SCOREBOARD_NAME); - if(rv == RSYSC_ERROR) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "rsysc() could not release scoreboard system heap"); - } -} - -static void setup_shared_mem(pool *p) -{ - cinfc(CINFC_WRITE, CINFC_CMMCTK2); - ap_scoreboard_image = (scoreboard *) gsysc(SCOREBOARD_FRAMES, SCOREBOARD_NAME); - - if (!ap_scoreboard_image) { - fprintf(stderr, "httpd: Could not create scoreboard system heap storage.\n"); - exit(APEXIT_INIT); - } - - ap_register_cleanup(p, NULL, cleanup_scoreboard_heap, ap_null_cleanup); - ap_scoreboard_image->global.running_generation = 0; -} - -static void reopen_scoreboard(pool *p) -{ - cinfc(CINFC_WRITE, CINFC_CMMCTK2); -} - -#else -#define SCOREBOARD_FILE -static scoreboard _scoreboard_image; -static int scoreboard_fd = -1; - -/* XXX: things are seriously screwed if we ever have to do a partial - * read or write ... we could get a corrupted scoreboard - */ -static int force_write(int fd, void *buffer, int bufsz) -{ - int rv, orig_sz = bufsz; - - do { - rv = write(fd, buffer, bufsz); - if (rv > 0) { - buffer = (char *) buffer + rv; - bufsz -= rv; - } - } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR)); - - return rv < 0 ? rv : orig_sz - bufsz; -} - -static int force_read(int fd, void *buffer, int bufsz) -{ - int rv, orig_sz = bufsz; - - do { - rv = read(fd, buffer, bufsz); - if (rv > 0) { - buffer = (char *) buffer + rv; - bufsz -= rv; - } - } while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR)); - - return rv < 0 ? rv : orig_sz - bufsz; -} - -static void cleanup_scoreboard_file(void *foo) -{ - unlink(ap_scoreboard_fname); -} - -void reopen_scoreboard(pool *p) -{ - if (scoreboard_fd != -1) - ap_pclosef(p, scoreboard_fd); - -#ifdef TPF - ap_scoreboard_fname = ap_server_root_relative(p, ap_scoreboard_fname); -#endif /* TPF */ - scoreboard_fd = ap_popenf(p, ap_scoreboard_fname, O_CREAT | O_BINARY | O_RDWR, 0666); - if (scoreboard_fd == -1) { - perror(ap_scoreboard_fname); - fprintf(stderr, "Cannot open scoreboard file:\n"); - clean_child_exit(1); - } -} -#endif - -/* Called by parent process */ -static void reinit_scoreboard(pool *p) -{ - int running_gen = 0; - if (ap_scoreboard_image) - running_gen = ap_scoreboard_image->global.running_generation; - -#ifndef SCOREBOARD_FILE - if (ap_scoreboard_image == NULL) { - setup_shared_mem(p); - } - memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE); - ap_scoreboard_image->global.running_generation = running_gen; -#else - ap_scoreboard_image = &_scoreboard_image; - ap_scoreboard_fname = ap_server_root_relative(p, ap_scoreboard_fname); - - scoreboard_fd = ap_popenf(p, ap_scoreboard_fname, O_CREAT | O_BINARY | O_RDWR, 0644); - if (scoreboard_fd == -1) { - perror(ap_scoreboard_fname); - fprintf(stderr, "Cannot open scoreboard file:\n"); - exit(APEXIT_INIT); - } - ap_register_cleanup(p, NULL, cleanup_scoreboard_file, ap_null_cleanup); - - memset((char *) ap_scoreboard_image, 0, sizeof(*ap_scoreboard_image)); - ap_scoreboard_image->global.running_generation = running_gen; - force_write(scoreboard_fd, ap_scoreboard_image, sizeof(*ap_scoreboard_image)); -#endif -} - -/* Routines called to deal with the scoreboard image - * --- note that we do *not* need write locks, since update_child_status - * only updates a *single* record in place, and only one process writes to - * a given scoreboard slot at a time (either the child process owning that - * slot, or the parent, noting that the child has died). - * - * As a final note --- setting the score entry to getpid() is always safe, - * since when the parent is writing an entry, it's only noting SERVER_DEAD - * anyway. - */ - -ap_inline void ap_sync_scoreboard_image(void) -{ -#ifdef SCOREBOARD_FILE - lseek(scoreboard_fd, 0L, 0); - force_read(scoreboard_fd, ap_scoreboard_image, sizeof(*ap_scoreboard_image)); -#endif -} - -#endif /* MULTITHREAD */ - -API_EXPORT(int) ap_exists_scoreboard_image(void) -{ - return (ap_scoreboard_image ? 1 : 0); -} - -static ap_inline void put_scoreboard_info(int child_num, - short_score *new_score_rec) -{ -#ifdef SCOREBOARD_FILE - lseek(scoreboard_fd, (long) child_num * sizeof(short_score), 0); - force_write(scoreboard_fd, new_score_rec, sizeof(short_score)); -#endif -} - -/* a clean exit from the parent with proper cleanup */ -static void clean_parent_exit(int code) __attribute__((noreturn)); -static void clean_parent_exit(int code) -{ - /* Clear the pool - including any registered cleanups */ - ap_destroy_pool(pglobal); - exit(code); -} - -int ap_update_child_status(int child_num, int status, request_rec *r) -{ - int old_status; - short_score *ss; - - if (child_num < 0) - return -1; - - ap_check_signals(); - - ap_sync_scoreboard_image(); - ss = &ap_scoreboard_image->servers[child_num]; - old_status = ss->status; - ss->status = status; -#ifdef OPTIMIZE_TIMEOUTS - ++ss->cur_vtime; -#endif - - if (ap_extended_status) { -#ifndef OPTIMIZE_TIMEOUTS - ss->last_used = time(NULL); -#endif - if (status == SERVER_READY || status == SERVER_DEAD) { - /* - * Reset individual counters - */ - if (status == SERVER_DEAD) { - ss->my_access_count = 0L; - ss->my_bytes_served = 0L; - } - ss->conn_count = (unsigned short) 0; - ss->conn_bytes = (unsigned long) 0; - } - if (r) { - conn_rec *c = r->connection; - ap_cpystrn(ss->client, ap_get_remote_host(c, r->per_dir_config, - REMOTE_NOLOOKUP), sizeof(ss->client)); - if (r->the_request == NULL) { - ap_cpystrn(ss->request, "NULL", sizeof(ss->request)); - } else if (r->parsed_uri.password == NULL) { - ap_cpystrn(ss->request, r->the_request, sizeof(ss->request)); - } else { - /* Don't reveal the password in the server-status view */ - ap_cpystrn(ss->request, ap_pstrcat(r->pool, r->method, " ", - ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD), - r->assbackwards ? NULL : " ", r->protocol, NULL), - sizeof(ss->request)); - } - ss->vhostrec = r->server; - } - } - if (status == SERVER_STARTING && r == NULL) { - /* clean up the slot's vhostrec pointer (maybe re-used) - * and mark the slot as belonging to a new generation. - */ - ss->vhostrec = NULL; - ap_scoreboard_image->parent[child_num].generation = ap_my_generation; -#ifdef SCOREBOARD_FILE - lseek(scoreboard_fd, XtOffsetOf(scoreboard, parent[child_num]), 0); - force_write(scoreboard_fd, &ap_scoreboard_image->parent[child_num], - sizeof(parent_score)); -#endif - } - put_scoreboard_info(child_num, ss); - - return old_status; -} - -static void update_scoreboard_global(void) -{ -#ifdef SCOREBOARD_FILE - lseek(scoreboard_fd, - (char *) &ap_scoreboard_image->global -(char *) ap_scoreboard_image, 0); - force_write(scoreboard_fd, &ap_scoreboard_image->global, - sizeof ap_scoreboard_image->global); -#endif -} - -void ap_time_process_request(int child_num, int status) -{ - short_score *ss; -#if defined(NO_GETTIMEOFDAY) && !defined(NO_TIMES) - struct tms tms_blk; -#endif - - if (child_num < 0) - return; - - ap_sync_scoreboard_image(); - ss = &ap_scoreboard_image->servers[child_num]; - - if (status == START_PREQUEST) { -#if defined(NO_GETTIMEOFDAY) -#ifndef NO_TIMES - if ((ss->start_time = times(&tms_blk)) == -1) -#endif /* NO_TIMES */ - ss->start_time = (clock_t) 0; -#else - if (gettimeofday(&ss->start_time, (struct timezone *) 0) < 0) - ss->start_time.tv_sec = - ss->start_time.tv_usec = 0L; -#endif - } - else if (status == STOP_PREQUEST) { -#if defined(NO_GETTIMEOFDAY) -#ifndef NO_TIMES - if ((ss->stop_time = times(&tms_blk)) == -1) -#endif - ss->stop_time = ss->start_time = (clock_t) 0; -#else - if (gettimeofday(&ss->stop_time, (struct timezone *) 0) < 0) - ss->stop_time.tv_sec = - ss->stop_time.tv_usec = - ss->start_time.tv_sec = - ss->start_time.tv_usec = 0L; -#endif - - } - - put_scoreboard_info(child_num, ss); -} - -static void increment_counts(int child_num, request_rec *r) -{ - long int bs = 0; - short_score *ss; - - ap_sync_scoreboard_image(); - ss = &ap_scoreboard_image->servers[child_num]; - - if (r->sent_bodyct) - ap_bgetopt(r->connection->client, BO_BYTECT, &bs); - -#ifndef NO_TIMES - times(&ss->times); -#endif - ss->access_count++; - ss->my_access_count++; - ss->conn_count++; - ss->bytes_served += (unsigned long) bs; - ss->my_bytes_served += (unsigned long) bs; - ss->conn_bytes += (unsigned long) bs; - - put_scoreboard_info(child_num, ss); -} - -static int find_child_by_pid(int pid) -{ - int i; - - for (i = 0; i < max_daemons_limit; ++i) - if (ap_scoreboard_image->parent[i].pid == pid) - return i; - - return -1; -} - -static void reclaim_child_processes(int terminate) -{ -#ifndef MULTITHREAD - int i, status; - long int waittime = 1024 * 16; /* in usecs */ - struct timeval tv; - int waitret, tries; - int not_dead_yet; -#ifndef NO_OTHER_CHILD - other_child_rec *ocr, *nocr; -#endif - - ap_sync_scoreboard_image(); - - for (tries = terminate ? 4 : 1; tries <= 9; ++tries) { - /* don't want to hold up progress any more than - * necessary, but we need to allow children a few moments to exit. - * Set delay with an exponential backoff. - */ - tv.tv_sec = waittime / 1000000; - tv.tv_usec = waittime % 1000000; - waittime = waittime * 4; - ap_select(0, NULL, NULL, NULL, &tv); - - /* now see who is done */ - not_dead_yet = 0; - for (i = 0; i < max_daemons_limit; ++i) { - int pid = ap_scoreboard_image->parent[i].pid; - - if (pid == my_pid || pid == 0) - continue; - - waitret = waitpid(pid, &status, WNOHANG); - if (waitret == pid || waitret == -1) { - ap_scoreboard_image->parent[i].pid = 0; - continue; - } - ++not_dead_yet; - switch (tries) { - case 1: /* 16ms */ - case 2: /* 82ms */ - break; - case 3: /* 344ms */ - /* perhaps it missed the SIGHUP, lets try again */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, - server_conf, - "child process %d did not exit, sending another SIGHUP", - pid); - kill(pid, SIGHUP); - waittime = 1024 * 16; - break; - case 4: /* 16ms */ - case 5: /* 82ms */ - case 6: /* 344ms */ - break; - case 7: /* 1.4sec */ - /* ok, now it's being annoying */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, - server_conf, - "child process %d still did not exit, sending a SIGTERM", - pid); - kill(pid, SIGTERM); - break; - case 8: /* 6 sec */ - /* die child scum */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf, - "child process %d still did not exit, sending a SIGKILL", - pid); - kill(pid, SIGKILL); - break; - case 9: /* 14 sec */ - /* gave it our best shot, but alas... If this really - * is a child we are trying to kill and it really hasn't - * exited, we will likely fail to bind to the port - * after the restart. - */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf, - "could not make child process %d exit, " - "attempting to continue anyway", pid); - break; - } - } -#ifndef NO_OTHER_CHILD - for (ocr = other_children; ocr; ocr = nocr) { - nocr = ocr->next; - if (ocr->pid == -1) - continue; - - waitret = waitpid(ocr->pid, &status, WNOHANG); - if (waitret == ocr->pid) { - ocr->pid = -1; - (*ocr->maintenance) (OC_REASON_DEATH, ocr->data, status); - } - else if (waitret == 0) { - (*ocr->maintenance) (OC_REASON_RESTART, ocr->data, -1); - ++not_dead_yet; - } - else if (waitret == -1) { - /* uh what the heck? they didn't call unregister? */ - ocr->pid = -1; - (*ocr->maintenance) (OC_REASON_LOST, ocr->data, -1); - } - } -#endif - if (!not_dead_yet) { - /* nothing left to wait for */ - break; - } - } -#endif /* ndef MULTITHREAD */ -} - - -#if defined(NEED_WAITPID) -/* - Systems without a real waitpid sometimes lose a child's exit while waiting - for another. Search through the scoreboard for missing children. - */ -int reap_children(ap_wait_t *status) -{ - int n, pid; - - for (n = 0; n < max_daemons_limit; ++n) { - ap_sync_scoreboard_image(); - if (ap_scoreboard_image->servers[n].status != SERVER_DEAD && - kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) { - ap_update_child_status(n, SERVER_DEAD, NULL); - /* just mark it as having a successful exit status */ - bzero((char *) status, sizeof(ap_wait_t)); - return(pid); - } - } - return 0; -} -#endif - -/* Finally, this routine is used by the caretaker process to wait for - * a while... - */ - -/* number of calls to wait_or_timeout between writable probes */ -#ifndef INTERVAL_OF_WRITABLE_PROBES -#define INTERVAL_OF_WRITABLE_PROBES 10 -#endif -static int wait_or_timeout_counter; - -static int wait_or_timeout(ap_wait_t *status) -{ -#ifdef WIN32 -#define MAXWAITOBJ MAXIMUM_WAIT_OBJECTS - HANDLE h[MAXWAITOBJ]; - int e[MAXWAITOBJ]; - int round, pi, hi, rv, err; - for (round = 0; round <= (HARD_SERVER_LIMIT - 1) / MAXWAITOBJ + 1; round++) { - hi = 0; - for (pi = round * MAXWAITOBJ; - (pi < (round + 1) * MAXWAITOBJ) && (pi < HARD_SERVER_LIMIT); - pi++) { - if (ap_scoreboard_image->servers[pi].status != SERVER_DEAD) { - e[hi] = pi; - h[hi++] = (HANDLE) ap_scoreboard_image->parent[pi].pid; - } - - } - if (hi > 0) { - rv = WaitForMultipleObjects(hi, h, FALSE, 10000); - if (rv == -1) - err = GetLastError(); - if ((WAIT_OBJECT_0 <= (unsigned int) rv) && ((unsigned int) rv < (WAIT_OBJECT_0 + hi))) - return (ap_scoreboard_image->parent[e[rv - WAIT_OBJECT_0]].pid); - else if ((WAIT_ABANDONED_0 <= (unsigned int) rv) && ((unsigned int) rv < (WAIT_ABANDONED_0 + hi))) - return (ap_scoreboard_image->parent[e[rv - WAIT_ABANDONED_0]].pid); - - } - } - return (-1); - -#else /* WIN32 */ - struct timeval tv; - int ret; - - ++wait_or_timeout_counter; - if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) { - wait_or_timeout_counter = 0; -#ifndef NO_OTHER_CHILD - probe_writable_fds(); -#endif - } - ret = waitpid(-1, status, WNOHANG); - if (ret == -1 && errno == EINTR) { - return -1; - } - if (ret > 0) { - return ret; - } -#ifdef NEED_WAITPID - if ((ret = reap_children(status)) > 0) { - return ret; - } -#endif - tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000; - tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000; - ap_select(0, NULL, NULL, NULL, &tv); - return -1; -#endif /* WIN32 */ -} - - -#if defined(NSIG) -#define NumSIG NSIG -#elif defined(_NSIG) -#define NumSIG _NSIG -#elif defined(__NSIG) -#define NumSIG __NSIG -#else -#define NumSIG 32 /* for 1998's unixes, this is still a good assumption */ -#endif - -#ifdef SYS_SIGLIST /* platform has sys_siglist[] */ -#define INIT_SIGLIST() /*nothing*/ -#else /* platform has no sys_siglist[], define our own */ -#define SYS_SIGLIST ap_sys_siglist -#define INIT_SIGLIST() siglist_init(); - -const char *ap_sys_siglist[NumSIG]; - -static void siglist_init(void) -{ - int sig; - - ap_sys_siglist[0] = "Signal 0"; -#ifdef SIGHUP - ap_sys_siglist[SIGHUP] = "Hangup"; -#endif -#ifdef SIGINT - ap_sys_siglist[SIGINT] = "Interrupt"; -#endif -#ifdef SIGQUIT - ap_sys_siglist[SIGQUIT] = "Quit"; -#endif -#ifdef SIGILL - ap_sys_siglist[SIGILL] = "Illegal instruction"; -#endif -#ifdef SIGTRAP - ap_sys_siglist[SIGTRAP] = "Trace/BPT trap"; -#endif -#ifdef SIGIOT - ap_sys_siglist[SIGIOT] = "IOT instruction"; -#endif -#ifdef SIGABRT - ap_sys_siglist[SIGABRT] = "Abort"; -#endif -#ifdef SIGEMT - ap_sys_siglist[SIGEMT] = "Emulator trap"; -#endif -#ifdef SIGFPE - ap_sys_siglist[SIGFPE] = "Arithmetic exception"; -#endif -#ifdef SIGKILL - ap_sys_siglist[SIGKILL] = "Killed"; -#endif -#ifdef SIGBUS - ap_sys_siglist[SIGBUS] = "Bus error"; -#endif -#ifdef SIGSEGV - ap_sys_siglist[SIGSEGV] = "Segmentation fault"; -#endif -#ifdef SIGSYS - ap_sys_siglist[SIGSYS] = "Bad system call"; -#endif -#ifdef SIGPIPE - ap_sys_siglist[SIGPIPE] = "Broken pipe"; -#endif -#ifdef SIGALRM - ap_sys_siglist[SIGALRM] = "Alarm clock"; -#endif -#ifdef SIGTERM - ap_sys_siglist[SIGTERM] = "Terminated"; -#endif -#ifdef SIGUSR1 - ap_sys_siglist[SIGUSR1] = "User defined signal 1"; -#endif -#ifdef SIGUSR2 - ap_sys_siglist[SIGUSR2] = "User defined signal 2"; -#endif -#ifdef SIGCLD - ap_sys_siglist[SIGCLD] = "Child status change"; -#endif -#ifdef SIGCHLD - ap_sys_siglist[SIGCHLD] = "Child status change"; -#endif -#ifdef SIGPWR - ap_sys_siglist[SIGPWR] = "Power-fail restart"; -#endif -#ifdef SIGWINCH - ap_sys_siglist[SIGWINCH] = "Window changed"; -#endif -#ifdef SIGURG - ap_sys_siglist[SIGURG] = "urgent socket condition"; -#endif -#ifdef SIGPOLL - ap_sys_siglist[SIGPOLL] = "Pollable event occurred"; -#endif -#ifdef SIGIO - ap_sys_siglist[SIGIO] = "socket I/O possible"; -#endif -#ifdef SIGSTOP - ap_sys_siglist[SIGSTOP] = "Stopped (signal)"; -#endif -#ifdef SIGTSTP - ap_sys_siglist[SIGTSTP] = "Stopped"; -#endif -#ifdef SIGCONT - ap_sys_siglist[SIGCONT] = "Continued"; -#endif -#ifdef SIGTTIN - ap_sys_siglist[SIGTTIN] = "Stopped (tty input)"; -#endif -#ifdef SIGTTOU - ap_sys_siglist[SIGTTOU] = "Stopped (tty output)"; -#endif -#ifdef SIGVTALRM - ap_sys_siglist[SIGVTALRM] = "virtual timer expired"; -#endif -#ifdef SIGPROF - ap_sys_siglist[SIGPROF] = "profiling timer expired"; -#endif -#ifdef SIGXCPU - ap_sys_siglist[SIGXCPU] = "exceeded cpu limit"; -#endif -#ifdef SIGXFSZ - ap_sys_siglist[SIGXFSZ] = "exceeded file size limit"; -#endif - for (sig=0; sig < sizeof(ap_sys_siglist)/sizeof(ap_sys_siglist[0]); ++sig) - if (ap_sys_siglist[sig] == NULL) - ap_sys_siglist[sig] = ""; -} -#endif /* platform has sys_siglist[] */ - - -/* handle all varieties of core dumping signals */ -static void sig_coredump(int sig) -{ - chdir(ap_coredump_dir); - signal(sig, SIG_DFL); -#ifndef WIN32 - kill(getpid(), sig); -#else - raise(sig); -#endif - /* At this point we've got sig blocked, because we're still inside - * the signal handler. When we leave the signal handler it will - * be unblocked, and we'll take the signal... and coredump or whatever - * is appropriate for this particular Unix. In addition the parent - * will see the real signal we received -- whereas if we called - * abort() here, the parent would only see SIGABRT. - */ -} - -/***************************************************************** - * Connection structures and accounting... - */ - -static void just_die(int sig) -{ /* SIGHUP to child process??? */ - /* if alarms are blocked we have to wait to die otherwise we might - * end up with corruption in alloc.c's internal structures */ - if (alarms_blocked) { - exit_after_unblock = 1; - } - else { - clean_child_exit(0); - } -} - -static int volatile usr1_just_die = 1; -static int volatile deferred_die; - -static void usr1_handler(int sig) -{ - if (usr1_just_die) { - just_die(sig); - } - deferred_die = 1; -} - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; -ap_generation_t volatile ap_my_generation=0; - -#ifdef WIN32 -/* - * Signalling Apache on NT. - * - * Under Unix, Apache can be told to shutdown or restart by sending various - * signals (HUP, USR, TERM). On NT we don't have easy access to signals, so - * we use "events" instead. The parent apache process goes into a loop - * where it waits forever for a set of events. Two of those events are - * called - * - * apPID_shutdown - * apPID_restart - * - * (where PID is the PID of the apache parent process). When one of these - * is signalled, the Apache parent performs the appropriate action. The events - * can become signalled through internal Apache methods (e.g. if the child - * finds a fatal error and needs to kill its parent), via the service - * control manager (the control thread will signal the shutdown event when - * requested to stop the Apache service), from the -k Apache command line, - * or from any external program which finds the Apache PID from the - * httpd.pid file. - * - * The signal_parent() function, below, is used to signal one of these events. - * It can be called by any child or parent process, since it does not - * rely on global variables. - * - * On entry, type gives the event to signal. 0 means shutdown, 1 means - * graceful restart. - */ - -static void signal_parent(int type) -{ - HANDLE e; - char *signal_name; - extern char signal_shutdown_name[]; - extern char signal_restart_name[]; - - /* after updating the shutdown_pending or restart flags, we need - * to wake up the parent process so it can see the changes. The - * parent will normally be waiting for either a child process - * to die, or for a signal on the "spache-signal" event. So set the - * "apache-signal" event here. - */ - - if (one_process) { - return; - } - - switch(type) { - case 0: signal_name = signal_shutdown_name; break; - case 1: signal_name = signal_restart_name; break; - default: return; - } - - APD2("signal_parent signalling event \"%s\"", signal_name); - - e = OpenEvent(EVENT_ALL_ACCESS, FALSE, signal_name); - if (!e) { - /* Um, problem, can't signal the parent, which means we can't - * signal ourselves to die. Ignore for now... - */ - ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "OpenEvent on %s event", signal_name); - return; - } - if (SetEvent(e) == 0) { - /* Same problem as above */ - ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "SetEvent on %s event", signal_name); - CloseHandle(e); - return; - } - CloseHandle(e); -} -#endif - -/* - * ap_start_shutdown() and ap_start_restart(), below, are a first stab at - * functions to initiate shutdown or restart without relying on signals. - * Previously this was initiated in sig_term() and restart() signal handlers, - * but we want to be able to start a shutdown/restart from other sources -- - * e.g. on Win32, from the service manager. Now the service manager can - * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that - * these functions can also be called by the child processes, since global - * variables are no longer used to pass on the required action to the parent. - */ - -void ap_start_shutdown(void) -{ -#ifndef WIN32 - if (shutdown_pending == 1) { - /* Um, is this _probably_ not an error, if the user has - * tried to do a shutdown twice quickly, so we won't - * worry about reporting it. - */ - return; - } - shutdown_pending = 1; -#else - signal_parent(0); /* get the parent process to wake up */ -#endif -} - -/* do a graceful restart if graceful == 1 */ -void ap_start_restart(int graceful) -{ -#ifndef WIN32 - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - is_graceful = graceful; -#else - signal_parent(1); /* get the parent process to wake up */ -#endif /* WIN32 */ -} - -static void sig_term(int sig) -{ - ap_start_shutdown(); -} - -static void restart(int sig) -{ -#ifndef WIN32 - ap_start_restart(sig == SIGUSR1); -#else - ap_start_restart(1); -#endif -} - -static void set_signals(void) -{ -#ifndef NO_USE_SIGACTION - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - if (!one_process) { - sa.sa_handler = sig_coredump; -#if defined(SA_ONESHOT) - sa.sa_flags = SA_ONESHOT; -#elif defined(SA_RESETHAND) - sa.sa_flags = SA_RESETHAND; -#endif - if (sigaction(SIGSEGV, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGSEGV)"); -#ifdef SIGBUS - if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGBUS)"); -#endif -#ifdef SIGABORT - if (sigaction(SIGABORT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABORT)"); -#endif -#ifdef SIGABRT - if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGABRT)"); -#endif -#ifdef SIGILL - if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGILL)"); -#endif - sa.sa_flags = 0; - } - sa.sa_handler = sig_term; - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGINT)"); -#endif -#ifdef SIGXCPU - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXCPU, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXCPU)"); -#endif -#ifdef SIGXFSZ - sa.sa_handler = SIG_DFL; - if (sigaction(SIGXFSZ, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGXFSZ)"); -#endif -#ifdef SIGPIPE - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and USR1 while we're busy processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, SIGUSR1); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGHUP)"); - if (sigaction(SIGUSR1, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "sigaction(SIGUSR1)"); -#else - if (!one_process) { - signal(SIGSEGV, sig_coredump); -#ifdef SIGBUS - signal(SIGBUS, sig_coredump); -#endif /* SIGBUS */ -#ifdef SIGABORT - signal(SIGABORT, sig_coredump); -#endif /* SIGABORT */ -#ifdef SIGABRT - signal(SIGABRT, sig_coredump); -#endif /* SIGABRT */ -#ifdef SIGILL - signal(SIGILL, sig_coredump); -#endif /* SIGILL */ -#ifdef SIGXCPU - signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - signal(SIGTERM, sig_term); -#ifdef SIGHUP - signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef SIGUSR1 - signal(SIGUSR1, restart); -#endif /* SIGUSR1 */ -#ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -static void detach(void) -{ -#if !defined(WIN32) - int x; - - chdir("/"); -#if !defined(MPE) && !defined(OS2) && !defined(TPF) -/* Don't detach for MPE because child processes can't survive the death of - the parent. */ - if ((x = fork()) > 0) - exit(0); - else if (x == -1) { - perror("fork"); - fprintf(stderr, "%s: unable to fork new process\n", ap_server_argv0); - exit(1); - } - RAISE_SIGSTOP(DETACH); -#endif -#ifndef NO_SETSID - if ((pgrp = setsid()) == -1) { - perror("setsid"); - fprintf(stderr, "%s: setsid failed\n", ap_server_argv0); - exit(1); - } -#elif defined(NEXT) || defined(NEWSOS) - if (setpgrp(0, getpid()) == -1 || (pgrp = getpgrp(0)) == -1) { - perror("setpgrp"); - fprintf(stderr, "%s: setpgrp or getpgrp failed\n", ap_server_argv0); - exit(1); - } -#elif defined(OS2) || defined(TPF) - /* OS/2 and TPF don't support process group IDs */ - pgrp = getpid(); -#elif defined(MPE) - /* MPE uses negative pid for process group */ - pgrp = -getpid(); -#else - if ((pgrp = setpgrp(getpid(), 0)) == -1) { - perror("setpgrp"); - fprintf(stderr, "%s: setpgrp failed\n", ap_server_argv0); - exit(1); - } -#endif - - /* close out the standard file descriptors */ - if (freopen("/dev/null", "r", stdin) == NULL) { - fprintf(stderr, "%s: unable to replace stdin with /dev/null: %s\n", - ap_server_argv0, strerror(errno)); - /* continue anyhow -- note we can't close out descriptor 0 because we - * have nothing to replace it with, and if we didn't have a descriptor - * 0 the next file would be created with that value ... leading to - * havoc. - */ - } - if (freopen("/dev/null", "w", stdout) == NULL) { - fprintf(stderr, "%s: unable to replace stdout with /dev/null: %s\n", - ap_server_argv0, strerror(errno)); - } - /* stderr is a tricky one, we really want it to be the error_log, - * but we haven't opened that yet. So leave it alone for now and it'll - * be reopened moments later. - */ -#endif /* ndef WIN32 */ -} - -/* Set group privileges. - * - * Note that we use the username as set in the config files, rather than - * the lookup of to uid --- the same uid may have multiple passwd entries, - * with different sets of groups for each. - */ - -static void set_group_privs(void) -{ -#ifndef WIN32 - if (!geteuid()) { - char *name; - - /* Get username if passed as a uid */ - - if (ap_user_name[0] == '#') { - struct passwd *ent; - uid_t uid = atoi(&ap_user_name[1]); - - if ((ent = getpwuid(uid)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, - "getpwuid: couldn't determine user name from uid %u, " - "you probably need to modify the User directive", - (unsigned)uid); - clean_child_exit(APEXIT_CHILDFATAL); - } - - name = ent->pw_name; - } - else - name = ap_user_name; - -#if !defined(OS2) && !defined(TPF) - /* OS/2 and TPF don't support groups. */ - - /* - * Set the GID before initgroups(), since on some platforms - * setgid() is known to zap the group list. - */ - if (setgid(ap_group_id) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, - "setgid: unable to set group id to Group %u", - (unsigned)ap_group_id); - clean_child_exit(APEXIT_CHILDFATAL); - } - - /* Reset `groups' attributes. */ - - if (initgroups(name, ap_group_id) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, - "initgroups: unable to set groups for User %s " - "and Group %u", name, (unsigned)ap_group_id); - clean_child_exit(APEXIT_CHILDFATAL); - } -#ifdef MULTIPLE_GROUPS - if (getgroups(NGROUPS_MAX, group_id_list) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, - "getgroups: unable to get group list"); - clean_child_exit(APEXIT_CHILDFATAL); - } -#endif /* MULTIPLE_GROUPS */ -#endif /* !defined(OS2) && !defined(TPF) */ - } -#endif /* ndef WIN32 */ -} - -/* check to see if we have the 'suexec' setuid wrapper installed */ -static int init_suexec(void) -{ -#ifndef WIN32 - struct stat wrapper; - - if ((stat(SUEXEC_BIN, &wrapper)) != 0) - return (ap_suexec_enabled); - - if ((wrapper.st_mode & S_ISUID) && wrapper.st_uid == 0) { - ap_suexec_enabled = 1; - } -#endif /* ndef WIN32 */ - return (ap_suexec_enabled); -} - -/***************************************************************** - * Connection structures and accounting... - */ - - -static conn_rec *new_connection(pool *p, server_rec *server, BUFF *inout, - const struct sockaddr_in *remaddr, - const struct sockaddr_in *saddr, - int child_num) -{ - conn_rec *conn = (conn_rec *) ap_pcalloc(p, sizeof(conn_rec)); - - /* Got a connection structure, so initialize what fields we can - * (the rest are zeroed out by pcalloc). - */ - - conn->child_num = child_num; - - conn->pool = p; - conn->local_addr = *saddr; - conn->local_ip = ap_pstrdup(conn->pool, - inet_ntoa(conn->local_addr.sin_addr)); - conn->server = server; /* just a guess for now */ - ap_update_vhost_given_ip(conn); - conn->base_server = conn->server; - conn->client = inout; - - conn->remote_addr = *remaddr; - conn->remote_ip = ap_pstrdup(conn->pool, - inet_ntoa(conn->remote_addr.sin_addr)); - - return conn; -} - -#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF) -static void sock_disable_nagle(int s) -{ - /* The Nagle algorithm says that we should delay sending partial - * packets in hopes of getting more data. We don't want to do - * this; we are not telnet. There are bad interactions between - * persistent connections and Nagle's algorithm that have very severe - * performance penalties. (Failing to disable Nagle is not much of a - * problem with simple HTTP.) - * - * In spite of these problems, failure here is not a shooting offense. - */ - int just_say_no = 1; - - if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no, - sizeof(int)) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, - "setsockopt: (TCP_NODELAY)"); - } -} - -#else -#define sock_disable_nagle(s) /* NOOP */ -#endif - - -static int make_sock(pool *p, const struct sockaddr_in *server) -{ - int s; - int one = 1; - char addr[512]; - - if (server->sin_addr.s_addr != htonl(INADDR_ANY)) - ap_snprintf(addr, sizeof(addr), "address %s port %d", - inet_ntoa(server->sin_addr), ntohs(server->sin_port)); - else - ap_snprintf(addr, sizeof(addr), "port %d", ntohs(server->sin_port)); - - /* note that because we're about to slack we don't use psocket */ - ap_block_alarms(); - if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, - "make_sock: failed to get a socket for %s", addr); - ap_unblock_alarms(); - exit(1); - } - - /* Solaris (probably versions 2.4, 2.5, and 2.5.1 with various levels - * of tcp patches) has some really weird bugs where if you dup the - * socket now it breaks things across SIGHUP restarts. It'll either - * be unable to bind, or it won't respond. - */ -#if defined (SOLARIS2) && SOLARIS2 < 260 -#define WORKAROUND_SOLARIS_BUG -#endif - - /* PR#1282 Unixware 1.x appears to have the same problem as solaris */ -#if defined (UW) && UW < 200 -#define WORKAROUND_SOLARIS_BUG -#endif - - /* PR#1973 NCR SVR4 systems appear to have the same problem */ -#if defined (MPRAS) -#define WORKAROUND_SOLARIS_BUG -#endif - -#ifndef WORKAROUND_SOLARIS_BUG -#ifndef BEOS /* this won't work for BeOS sockets!! */ - s = ap_slack(s, AP_SLACK_HIGH); -#endif - - ap_note_cleanups_for_socket(p, s); /* arrange to close on exec or restart */ -#ifdef TPF - os_note_additional_cleanups(p, s); -#endif /* TPF */ -#endif - -#ifndef MPE -/* MPE does not support SO_REUSEADDR and SO_KEEPALIVE */ -#ifndef _OSD_POSIX - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) { - ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, - "make_sock: for %s, setsockopt: (SO_REUSEADDR)", addr); -#ifdef BEOS - closesocket(s); -#else - close(s); -#endif - ap_unblock_alarms(); - return -1; - } -#endif /*_OSD_POSIX*/ - one = 1; -#ifdef SO_KEEPALIVE - if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(int)) < 0) { - ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, - "make_sock: for %s, setsockopt: (SO_KEEPALIVE)", addr); -#ifdef BEOS - closesocket(s); -#else - close(s); -#endif - - ap_unblock_alarms(); - return -1; - } -#endif -#endif - - sock_disable_nagle(s); - sock_enable_linger(s); - - /* - * To send data over high bandwidth-delay connections at full - * speed we must force the TCP window to open wide enough to keep the - * pipe full. The default window size on many systems - * is only 4kB. Cross-country WAN connections of 100ms - * at 1Mb/s are not impossible for well connected sites. - * If we assume 100ms cross-country latency, - * a 4kB buffer limits throughput to 40kB/s. - * - * To avoid this problem I've added the SendBufferSize directive - * to allow the web master to configure send buffer size. - * - * The trade-off of larger buffers is that more kernel memory - * is consumed. YMMV, know your customers and your network! - * - * -John Heidemann 25-Oct-96 - * - * If no size is specified, use the kernel default. - */ -#ifndef BEOS /* BeOS does not support SO_SNDBUF */ - if (server_conf->send_buffer_size) { - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, - (char *) &server_conf->send_buffer_size, sizeof(int)) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, - "make_sock: failed to set SendBufferSize for %s, " - "using default", addr); - /* not a fatal error */ - } - } -#endif - -#ifdef MPE -/* MPE requires CAP=PM and GETPRIVMODE to bind to ports less than 1024 */ - if (ntohs(server->sin_port) < 1024) - GETPRIVMODE(); -#endif - - if (bind(s, (struct sockaddr *) server, sizeof(struct sockaddr_in)) == -1) { - ap_log_error(APLOG_MARK, APLOG_CRIT, server_conf, - "make_sock: could not bind to %s", addr); -#ifdef MPE - if (ntohs(server->sin_port) < 1024) - GETUSERMODE(); -#endif - -#ifdef BEOS - closesocket(s); -#else - close(s); -#endif - ap_unblock_alarms(); - exit(1); - } -#ifdef MPE - if (ntohs(server->sin_port) < 1024) - GETUSERMODE(); -#endif - - if (listen(s, ap_listenbacklog) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "make_sock: unable to listen for connections on %s", addr); -#ifdef BEOS - closesocket(s); -#else - close(s); -#endif - ap_unblock_alarms(); - exit(1); - } - -#ifdef WORKAROUND_SOLARIS_BUG - s = ap_slack(s, AP_SLACK_HIGH); - - ap_note_cleanups_for_socket(p, s); /* arrange to close on exec or restart */ -#endif - ap_unblock_alarms(); - -#ifdef CHECK_FD_SETSIZE - /* protect various fd_sets */ - if (s >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL, - "make_sock: problem listening on %s, filedescriptor (%u) " - "larger than FD_SETSIZE (%u) " - "found, you probably need to rebuild Apache with a " - "larger FD_SETSIZE", addr, s, FD_SETSIZE); -#ifdef BEOS - closesocket(s); -#else - close(s); -#endif - return -1; - } -#endif - - return s; -} - - -/* - * During a restart we keep track of the old listeners here, so that we - * can re-use the sockets. We have to do this because we won't be able - * to re-open the sockets ("Address already in use"). - * - * Unlike the listeners ring, old_listeners is a NULL terminated list. - * - * copy_listeners() makes the copy, find_listener() finds an old listener - * and close_unused_listener() cleans up whatever wasn't used. - */ -static listen_rec *old_listeners; - -/* unfortunately copy_listeners may be called before listeners is a ring */ -static void copy_listeners(pool *p) -{ - listen_rec *lr; - - ap_assert(old_listeners == NULL); - if (ap_listeners == NULL) { - return; - } - lr = ap_listeners; - do { - listen_rec *nr = malloc(sizeof *nr); - if (nr == NULL) { - fprintf(stderr, "Ouch! malloc failed in copy_listeners()\n"); - exit(1); - } - *nr = *lr; - ap_kill_cleanups_for_socket(p, nr->fd); - nr->next = old_listeners; - ap_assert(!nr->used); - old_listeners = nr; - lr = lr->next; - } while (lr && lr != ap_listeners); -} - - -static int find_listener(listen_rec *lr) -{ - listen_rec *or; - - for (or = old_listeners; or; or = or->next) { - if (!memcmp(&or->local_addr, &lr->local_addr, sizeof(or->local_addr))) { - or->used = 1; - return or->fd; - } - } - return -1; -} - - -static void close_unused_listeners(void) -{ - listen_rec *or, *next; - - for (or = old_listeners; or; or = next) { - next = or->next; - if (!or->used) - closesocket(or->fd); - free(or); - } - old_listeners = NULL; -} - - -/* open sockets, and turn the listeners list into a singly linked ring */ -static void setup_listeners(pool *p) -{ - listen_rec *lr; - int fd; - - listenmaxfd = -1; - FD_ZERO(&listenfds); - lr = ap_listeners; - for (;;) { - fd = find_listener(lr); - if (fd < 0) { - fd = make_sock(p, &lr->local_addr); - } - else { - ap_note_cleanups_for_socket(p, fd); - } - if (fd >= 0) { - FD_SET(fd, &listenfds); - if (fd > listenmaxfd) - listenmaxfd = fd; - } - lr->fd = fd; - if (lr->next == NULL) - break; - lr = lr->next; - } - /* turn the list into a ring */ - lr->next = ap_listeners; - head_listener = ap_listeners; - close_unused_listeners(); - -#ifdef NO_SERIALIZED_ACCEPT - /* warn them about the starvation problem if they're using multiple - * sockets - */ - if (ap_listeners->next != ap_listeners) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, NULL, - "You cannot use multiple Listens safely on your system, " - "proceeding anyway. See src/PORTING, search for " - "SERIALIZED_ACCEPT."); - } -#endif -} - - -/* - * Find a listener which is ready for accept(). This advances the - * head_listener global. - */ -static ap_inline listen_rec *find_ready_listener(fd_set * main_fds) -{ - listen_rec *lr; - - lr = head_listener; - do { - if (FD_ISSET(lr->fd, main_fds)) { - head_listener = lr->next; - return (lr); - } - lr = lr->next; - } while (lr != head_listener); - return NULL; -} - - -#ifdef WIN32 -static int s_iInitCount = 0; - -static int AMCSocketInitialize(void) -{ - int iVersionRequested; - WSADATA wsaData; - int err; - - if (s_iInitCount > 0) { - s_iInitCount++; - return (0); - } - else if (s_iInitCount < 0) - return (s_iInitCount); - - /* s_iInitCount == 0. Do the initailization */ - iVersionRequested = MAKEWORD(1, 1); - err = WSAStartup((WORD) iVersionRequested, &wsaData); - if (err) { - s_iInitCount = -1; - return (s_iInitCount); - } - if (LOBYTE(wsaData.wVersion) != 1 || - HIBYTE(wsaData.wVersion) != 1) { - s_iInitCount = -2; - WSACleanup(); - return (s_iInitCount); - } - - s_iInitCount++; - return (s_iInitCount); - -} - - -static void AMCSocketCleanup(void) -{ - if (--s_iInitCount == 0) - WSACleanup(); - return; -} -#endif - -static void show_compile_settings(void) -{ - printf("Server version: %s\n", ap_get_server_version()); - printf("Server built: %s\n", ap_get_server_built()); - printf("Server's Module Magic Number: %u:%u\n", - MODULE_MAGIC_NUMBER_MAJOR, MODULE_MAGIC_NUMBER_MINOR); - printf("Server compiled with....\n"); -#ifdef BIG_SECURITY_HOLE - printf(" -D BIG_SECURITY_HOLE\n"); -#endif -#ifdef SECURITY_HOLE_PASS_AUTHORIZATION - printf(" -D SECURITY_HOLE_PASS_AUTHORIZATION\n"); -#endif -#ifdef HAVE_MMAP - printf(" -D HAVE_MMAP\n"); -#endif -#ifdef HAVE_SHMGET - printf(" -D HAVE_SHMGET\n"); -#endif -#ifdef USE_MMAP_SCOREBOARD - printf(" -D USE_MMAP_SCOREBOARD\n"); -#endif -#ifdef USE_SHMGET_SCOREBOARD - printf(" -D USE_SHMGET_SCOREBOARD\n"); -#endif -#ifdef USE_OS2_SCOREBOARD - printf(" -D USE_OS2_SCOREBOARD\n"); -#endif -#ifdef USE_POSIX_SCOREBOARD - printf(" -D USE_POSIX_SCOREBOARD\n"); -#endif -#ifdef USE_MMAP_FILES - printf(" -D USE_MMAP_FILES\n"); -#ifdef MMAP_SEGMENT_SIZE - printf(" -D MMAP_SEGMENT_SIZE=%ld\n",(long)MMAP_SEGMENT_SIZE); -#endif -#endif /*USE_MMAP_FILES*/ -#ifdef NO_WRITEV - printf(" -D NO_WRITEV\n"); -#endif -#ifdef NO_LINGCLOSE - printf(" -D NO_LINGCLOSE\n"); -#endif -#ifdef USE_FCNTL_SERIALIZED_ACCEPT - printf(" -D USE_FCNTL_SERIALIZED_ACCEPT\n"); -#endif -#ifdef USE_FLOCK_SERIALIZED_ACCEPT - printf(" -D USE_FLOCK_SERIALIZED_ACCEPT\n"); -#endif -#ifdef USE_USLOCK_SERIALIZED_ACCEPT - printf(" -D USE_USLOCK_SERIALIZED_ACCEPT\n"); -#endif -#ifdef USE_SYSVSEM_SERIALIZED_ACCEPT - printf(" -D USE_SYSVSEM_SERIALIZED_ACCEPT\n"); -#endif -#ifdef USE_PTHREAD_SERIALIZED_ACCEPT - printf(" -D USE_PTHREAD_SERIALIZED_ACCEPT\n"); -#endif -#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT - printf(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n"); -#endif -#ifdef NO_OTHER_CHILD - printf(" -D NO_OTHER_CHILD\n"); -#endif -#ifdef NO_RELIABLE_PIPED_LOGS - printf(" -D NO_RELIABLE_PIPED_LOGS\n"); -#endif -#ifdef BUFFERED_LOGS - printf(" -D BUFFERED_LOGS\n"); -#ifdef PIPE_BUF - printf(" -D PIPE_BUF=%ld\n",(long)PIPE_BUF); -#endif -#endif -#ifdef MULTITHREAD - printf(" -D MULTITHREAD\n"); -#endif -#ifdef CHARSET_EBCDIC - printf(" -D CHARSET_EBCDIC\n"); -#endif -#ifdef NEED_HASHBANG_EMUL - printf(" -D NEED_HASHBANG_EMUL\n"); -#endif -#ifdef SHARED_CORE - printf(" -D SHARED_CORE\n"); -#endif - -/* This list displays the compiled-in default paths: */ -#ifdef HTTPD_ROOT - printf(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n"); -#endif -#ifdef SUEXEC_BIN - printf(" -D SUEXEC_BIN=\"" SUEXEC_BIN "\"\n"); -#endif -#if defined(SHARED_CORE) && defined(SHARED_CORE_DIR) - printf(" -D SHARED_CORE_DIR=\"" SHARED_CORE_DIR "\"\n"); -#endif -#ifdef DEFAULT_PIDLOG - printf(" -D DEFAULT_PIDLOG=\"" DEFAULT_PIDLOG "\"\n"); -#endif -#ifdef DEFAULT_SCOREBOARD - printf(" -D DEFAULT_SCOREBOARD=\"" DEFAULT_SCOREBOARD "\"\n"); -#endif -#ifdef DEFAULT_LOCKFILE - printf(" -D DEFAULT_LOCKFILE=\"" DEFAULT_LOCKFILE "\"\n"); -#endif -#ifdef DEFAULT_XFERLOG - printf(" -D DEFAULT_XFERLOG=\"" DEFAULT_XFERLOG "\"\n"); -#endif -#ifdef DEFAULT_ERRORLOG - printf(" -D DEFAULT_ERRORLOG=\"" DEFAULT_ERRORLOG "\"\n"); -#endif -#ifdef TYPES_CONFIG_FILE - printf(" -D TYPES_CONFIG_FILE=\"" TYPES_CONFIG_FILE "\"\n"); -#endif -#ifdef SERVER_CONFIG_FILE - printf(" -D SERVER_CONFIG_FILE=\"" SERVER_CONFIG_FILE "\"\n"); -#endif -#ifdef ACCESS_CONFIG_FILE - printf(" -D ACCESS_CONFIG_FILE=\"" ACCESS_CONFIG_FILE "\"\n"); -#endif -#ifdef RESOURCE_CONFIG_FILE - printf(" -D RESOURCE_CONFIG_FILE=\"" RESOURCE_CONFIG_FILE "\"\n"); -#endif -} - - -/* Some init code that's common between win32 and unix... well actually - * some of it is #ifdef'd but was duplicated before anyhow. This stuff - * is still a mess. - */ -static void common_init(void) -{ - INIT_SIGLIST() -#ifdef AUX3 - (void) set42sig(); -#endif - -#ifdef WIN32 - /* Initialize the stupid sockets */ - AMCSocketInitialize(); -#endif /* WIN32 */ - - pglobal = ap_init_alloc(); - pconf = ap_make_sub_pool(pglobal); - plog = ap_make_sub_pool(pglobal); - ptrans = ap_make_sub_pool(pconf); - - ap_util_init(); - ap_util_uri_init(); - - pcommands = ap_make_sub_pool(NULL); - ap_server_pre_read_config = ap_make_array(pcommands, 1, sizeof(char *)); - ap_server_post_read_config = ap_make_array(pcommands, 1, sizeof(char *)); - ap_server_config_defines = ap_make_array(pcommands, 1, sizeof(char *)); -} - -#ifndef MULTITHREAD -/***************************************************************** - * Child process main loop. - * The following vars are static to avoid getting clobbered by longjmp(); - * they are really private to child_main. - */ - -static int srv; -static int csd; -static int dupped_csd; -static int requests_this_child; -static fd_set main_fds; - -API_EXPORT(void) ap_child_terminate(request_rec *r) -{ - r->connection->keepalive = 0; - requests_this_child = ap_max_requests_per_child = 1; -} - -static void child_main(int child_num_arg) -{ - NET_SIZE_T clen; - struct sockaddr sa_server; - struct sockaddr sa_client; - listen_rec *lr; - - /* All of initialization is a critical section, we don't care if we're - * told to HUP or USR1 before we're done initializing. For example, - * we could be half way through child_init_modules() when a restart - * signal arrives, and we'd have no real way to recover gracefully - * and exit properly. - * - * I suppose a module could take forever to initialize, but that would - * be either a broken module, or a broken configuration (i.e. network - * problems, file locking problems, whatever). -djg - */ - ap_block_alarms(); - - my_pid = getpid(); - csd = -1; - dupped_csd = -1; - my_child_num = child_num_arg; - requests_this_child = 0; - - /* Get a sub pool for global allocations in this child, so that - * we can have cleanups occur when the child exits. - */ - pchild = ap_make_sub_pool(pconf); - - /* needs to be done before we switch UIDs so we have permissions */ - reopen_scoreboard(pchild); - SAFE_ACCEPT(accept_mutex_child_init(pchild)); - - set_group_privs(); -#ifdef MPE - /* Only try to switch if we're running as MANAGER.SYS */ - if (geteuid() == 1 && ap_user_id > 1) { - GETPRIVMODE(); - if (setuid(ap_user_id) == -1) { - GETUSERMODE(); - ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, - "setuid: unable to change to uid: %d", ap_user_id); - exit(1); - } - GETUSERMODE(); - } -#else - /* Only try to switch if we're running as root */ - if (!geteuid() && ( -#ifdef _OSD_POSIX - os_init_job_environment(server_conf, ap_user_name, one_process) != 0 || -#endif - setuid(ap_user_id) == -1)) { - ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, - "setuid: unable to change to uid: %ld", (long) ap_user_id); - clean_child_exit(APEXIT_CHILDFATAL); - } -#endif - - ap_child_init_modules(pchild, server_conf); - - /* done with the initialization critical section */ - ap_unblock_alarms(); - - (void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL); - - /* - * Setup the jump buffers so that we can return here after a timeout - */ - ap_setjmp(jmpbuffer); -#ifndef OS2 -#ifdef SIGURG - signal(SIGURG, timeout); -#endif -#endif - signal(SIGALRM, alrm_handler); -#ifdef TPF - signal(SIGHUP, just_die); - signal(SIGTERM, just_die); - signal(SIGUSR1, just_die); -#endif /* TPF */ - -#ifdef OS2 -/* Stop Ctrl-C/Ctrl-Break signals going to child processes */ - { - unsigned long ulTimes; - DosSetSignalExceptionFocus(0, &ulTimes); - } -#endif - - while (1) { - BUFF *conn_io; - request_rec *r; - - /* Prepare to receive a SIGUSR1 due to graceful restart so that - * we can exit cleanly. Since we're between connections right - * now it's the right time to exit, but we might be blocked in a - * system call when the graceful restart request is made. */ - usr1_just_die = 1; - signal(SIGUSR1, usr1_handler); - - /* - * (Re)initialize this child to a pre-connection state. - */ - - ap_kill_timeout(0); /* Cancel any outstanding alarms. */ - current_conn = NULL; - - ap_clear_pool(ptrans); - - ap_sync_scoreboard_image(); - if (ap_scoreboard_image->global.running_generation != ap_my_generation) { - clean_child_exit(0); - } - -#ifndef WIN32 - if ((ap_max_requests_per_child > 0 - && requests_this_child++ >= ap_max_requests_per_child)) { - clean_child_exit(0); - } -#else - ++requests_this_child; -#endif - - (void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL); - - /* - * Wait for an acceptable connection to arrive. - */ - - /* Lock around "accept", if necessary */ - SAFE_ACCEPT(accept_mutex_on()); - - for (;;) { - if (ap_listeners->next != ap_listeners) { - /* more than one socket */ - memcpy(&main_fds, &listenfds, sizeof(fd_set)); - srv = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, NULL); - - if (srv < 0 && errno != EINTR) { - /* Single Unix documents select as returning errnos - * EBADF, EINTR, and EINVAL... and in none of those - * cases does it make sense to continue. In fact - * on Linux 2.0.x we seem to end up with EFAULT - * occasionally, and we'd loop forever due to it. - */ - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "select: (listen)"); - clean_child_exit(1); - } - - if (srv <= 0) - continue; - - lr = find_ready_listener(&main_fds); - if (lr == NULL) - continue; - sd = lr->fd; - } - else { - /* only one socket, just pretend we did the other stuff */ - sd = ap_listeners->fd; - } - - /* if we accept() something we don't want to die, so we have to - * defer the exit - */ - deferred_die = 0; - usr1_just_die = 0; - for (;;) { - clen = sizeof(sa_client); - csd = ap_accept(sd, &sa_client, &clen); - if (csd >= 0 || errno != EINTR) - break; - if (deferred_die) { - /* we didn't get a socket, and we were told to die */ - clean_child_exit(0); - } - } - - if (csd >= 0) - break; /* We have a socket ready for reading */ - else { - - /* Our old behaviour here was to continue after accept() - * errors. But this leads us into lots of troubles - * because most of the errors are quite fatal. For - * example, EMFILE can be caused by slow descriptor - * leaks (say in a 3rd party module, or libc). It's - * foolish for us to continue after an EMFILE. We also - * seem to tickle kernel bugs on some platforms which - * lead to never-ending loops here. So it seems best - * to just exit in most cases. - */ - switch (errno) { -#ifdef EPROTO - /* EPROTO on certain older kernels really means - * ECONNABORTED, so we need to ignore it for them. - * See discussion in new-httpd archives nh.9701 - * search for EPROTO. - * - * Also see nh.9603, search for EPROTO: - * There is potentially a bug in Solaris 2.x x<6, - * and other boxes that implement tcp sockets in - * userland (i.e. on top of STREAMS). On these - * systems, EPROTO can actually result in a fatal - * loop. See PR#981 for example. It's hard to - * handle both uses of EPROTO. - */ - case EPROTO: -#endif -#ifdef ECONNABORTED - case ECONNABORTED: -#endif - /* Linux generates the rest of these, other tcp - * stacks (i.e. bsd) tend to hide them behind - * getsockopt() interfaces. They occur when - * the net goes sour or the client disconnects - * after the three-way handshake has been done - * in the kernel but before userland has picked - * up the socket. - */ -#ifdef ECONNRESET - case ECONNRESET: -#endif -#ifdef ETIMEDOUT - case ETIMEDOUT: -#endif -#ifdef EHOSTUNREACH - case EHOSTUNREACH: -#endif -#ifdef ENETUNREACH - case ENETUNREACH: -#endif - break; -#ifdef ENETDOWN - case ENETDOWN: - /* - * When the network layer has been shut down, there - * is not much use in simply exiting: the parent - * would simply re-create us (and we'd fail again). - * Use the CHILDFATAL code to tear the server down. - * @@@ Martin's idea for possible improvement: - * A different approach would be to define - * a new APEXIT_NETDOWN exit code, the reception - * of which would make the parent shutdown all - * children, then idle-loop until it detected that - * the network is up again, and restart the children. - * Ben Hyde noted that temporary ENETDOWN situations - * occur in mobile IP. - */ - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "accept: giving up."); - clean_child_exit(APEXIT_CHILDFATAL); -#endif /*ENETDOWN*/ - -#ifdef TPF - case EINACT: - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "offload device inactive"); - clean_child_exit(APEXIT_CHILDFATAL); - break; - default: - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf, - "select/accept error (%u)", errno); - clean_child_exit(APEXIT_CHILDFATAL); -#else - default: - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "accept: (client socket)"); - clean_child_exit(1); -#endif - } - } - - /* go around again, safe to die */ - usr1_just_die = 1; - if (deferred_die) { - /* ok maybe not, see ya later */ - clean_child_exit(0); - } - /* or maybe we missed a signal, you never know on systems - * without reliable signals - */ - ap_sync_scoreboard_image(); - if (ap_scoreboard_image->global.running_generation != ap_my_generation) { - clean_child_exit(0); - } - } - - SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ - -#ifdef TPF - if (csd == 0) /* 0 is invalid socket for TPF */ - continue; -#endif - - /* We've got a socket, let's at least process one request off the - * socket before we accept a graceful restart request. - */ - signal(SIGUSR1, SIG_IGN); - - ap_note_cleanups_for_fd(ptrans, csd); - - /* protect various fd_sets */ -#ifdef CHECK_FD_SETSIZE - if (csd >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL, - "[csd] filedescriptor (%u) larger than FD_SETSIZE (%u) " - "found, you probably need to rebuild Apache with a " - "larger FD_SETSIZE", csd, FD_SETSIZE); - continue; - } -#endif - - /* - * We now have a connection, so set it up with the appropriate - * socket options, file descriptors, and read/write buffers. - */ - - clen = sizeof(sa_server); - if (getsockname(csd, &sa_server, &clen) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "getsockname"); - continue; - } - - sock_disable_nagle(csd); - - (void) ap_update_child_status(my_child_num, SERVER_BUSY_READ, - (request_rec *) NULL); - - conn_io = ap_bcreate(ptrans, B_RDWR | B_SOCKET); - -#ifdef B_SFIO - (void) sfdisc(conn_io->sf_in, SF_POPDISC); - sfdisc(conn_io->sf_in, bsfio_new(conn_io->pool, conn_io)); - sfsetbuf(conn_io->sf_in, NULL, 0); - - (void) sfdisc(conn_io->sf_out, SF_POPDISC); - sfdisc(conn_io->sf_out, bsfio_new(conn_io->pool, conn_io)); - sfsetbuf(conn_io->sf_out, NULL, 0); -#endif - - dupped_csd = csd; -#if defined(NEED_DUPPED_CSD) - if ((dupped_csd = dup(csd)) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "dup: couldn't duplicate csd"); - dupped_csd = csd; /* Oh well... */ - } - ap_note_cleanups_for_fd(ptrans, dupped_csd); - - /* protect various fd_sets */ -#ifdef CHECK_FD_SETSIZE - if (dupped_csd >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL, - "[dupped_csd] filedescriptor (%u) larger than FD_SETSIZE (%u) " - "found, you probably need to rebuild Apache with a " - "larger FD_SETSIZE", dupped_csd, FD_SETSIZE); - continue; - } -#endif -#endif - ap_bpushfd(conn_io, csd, dupped_csd); - - current_conn = new_connection(ptrans, server_conf, conn_io, - (struct sockaddr_in *) &sa_client, - (struct sockaddr_in *) &sa_server, - my_child_num); - - /* - * Read and process each request found on our connection - * until no requests are left or we decide to close. - */ - - while ((r = ap_read_request(current_conn)) != NULL) { - - /* read_request_line has already done a - * signal (SIGUSR1, SIG_IGN); - */ - - (void) ap_update_child_status(my_child_num, SERVER_BUSY_WRITE, r); - - /* process the request if it was read without error */ - - if (r->status == HTTP_OK) - ap_process_request(r); - - if(ap_extended_status) - increment_counts(my_child_num, r); - - if (!current_conn->keepalive || current_conn->aborted) - break; - - ap_destroy_pool(r->pool); - (void) ap_update_child_status(my_child_num, SERVER_BUSY_KEEPALIVE, - (request_rec *) NULL); - - ap_sync_scoreboard_image(); - if (ap_scoreboard_image->global.running_generation != ap_my_generation) { - ap_bclose(conn_io); - clean_child_exit(0); - } - - /* In case we get a graceful restart while we're blocked - * waiting for the request. - * - * XXX: This isn't perfect, we might actually read the - * request and then just die without saying anything to - * the client. This can be fixed by using deferred_die - * but you have to teach buff.c about it so that it can handle - * the EINTR properly. - * - * In practice though browsers (have to) expect keepalive - * connections to close before receiving a response because - * of network latencies and server timeouts. - */ - usr1_just_die = 1; - signal(SIGUSR1, usr1_handler); - } - - /* - * Close the connection, being careful to send out whatever is still - * in our buffers. If possible, try to avoid a hard close until the - * client has ACKed our FIN and/or has stopped sending us data. - */ - -#ifdef NO_LINGCLOSE - ap_bclose(conn_io); /* just close it */ -#else - if (r && r->connection - && !r->connection->aborted - && r->connection->client - && (r->connection->client->fd >= 0)) { - - lingering_close(r); - } - else { - ap_bsetflag(conn_io, B_EOUT, 1); - ap_bclose(conn_io); - } -#endif - } -} - -#ifdef TPF -static void reset_tpf_listeners(APACHE_TPF_INPUT *input_parms) -{ - int count; - listen_rec *lr; - - count = 0; - listenmaxfd = -1; - FD_ZERO(&listenfds); - lr = ap_listeners; - - for(;;) { - lr->fd = input_parms->listeners[count]; - if(lr->fd >= 0) { - FD_SET(lr->fd, &listenfds); - if(lr->fd > listenmaxfd) - listenmaxfd = lr->fd; - } - if(lr->next == NULL) - break; - lr = lr->next; - count++; - } - lr->next = ap_listeners; - head_listener = ap_listeners; - close_unused_listeners(); -} - -#endif /* TPF */ - -static int make_child(server_rec *s, int slot, time_t now) -{ - int pid; - - if (slot + 1 > max_daemons_limit) { - max_daemons_limit = slot + 1; - } - - if (one_process) { - signal(SIGHUP, just_die); - signal(SIGINT, just_die); -#ifdef SIGQUIT - signal(SIGQUIT, SIG_DFL); -#endif - signal(SIGTERM, just_die); - child_main(slot); - } - - /* avoid starvation */ - head_listener = head_listener->next; - - Explain1("Starting new child in slot %d", slot); - (void) ap_update_child_status(slot, SERVER_STARTING, (request_rec *) NULL); - - -#ifdef _OSD_POSIX - /* BS2000 requires a "special" version of fork() before a setuid() call */ - if ((pid = os_fork(ap_user_name)) == -1) { -#elif defined(TPF) - if ((pid = os_fork(s, slot)) == -1) { -#else - if ((pid = fork()) == -1) { -#endif - ap_log_error(APLOG_MARK, APLOG_ERR, s, "fork: Unable to fork new process"); - - /* fork didn't succeed. Fix the scoreboard or else - * it will say SERVER_STARTING forever and ever - */ - (void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL); - - /* In case system resources are maxxed out, we don't want - Apache running away with the CPU trying to fork over and - over and over again. */ - sleep(10); - - return -1; - } - - if (!pid) { -#ifdef AIX_BIND_PROCESSOR -/* by default AIX binds to a single processor - * this bit unbinds children which will then bind to another cpu - */ -#include - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf, - "processor unbind failed %d", status); - } -#endif - RAISE_SIGSTOP(MAKE_CHILD); - MONCONTROL(1); - /* Disable the restart signal handlers and enable the just_die stuff. - * Note that since restart() just notes that a restart has been - * requested there's no race condition here. - */ - signal(SIGHUP, just_die); - signal(SIGUSR1, just_die); - signal(SIGTERM, just_die); - child_main(slot); - } - -#ifdef OPTIMIZE_TIMEOUTS - ap_scoreboard_image->parent[slot].last_rtime = now; -#endif - ap_scoreboard_image->parent[slot].pid = pid; -#ifdef SCOREBOARD_FILE - lseek(scoreboard_fd, XtOffsetOf(scoreboard, parent[slot]), 0); - force_write(scoreboard_fd, &ap_scoreboard_image->parent[slot], - sizeof(parent_score)); -#endif - - return 0; -} - - -/* start up a bunch of children */ -static void startup_children(int number_to_start) -{ - int i; - time_t now = time(0); - - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) { - continue; - } - if (make_child(server_conf, i, now) < 0) { - break; - } - --number_to_start; - } -} - - -/* - * idle_spawn_rate is the number of children that will be spawned on the - * next maintenance cycle if there aren't enough idle servers. It is - * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by - * without the need to spawn. - */ -static int idle_spawn_rate = 1; -#ifndef MAX_SPAWN_RATE -#define MAX_SPAWN_RATE (32) -#endif -static int hold_off_on_exponential_spawning; - -static void perform_idle_server_maintenance(void) -{ - int i; - int to_kill; - int idle_count; - short_score *ss; - time_t now = time(0); - int free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead; - int total_non_dead; - - /* initialize the free_list */ - free_length = 0; - - to_kill = -1; - idle_count = 0; - last_non_dead = -1; - total_non_dead = 0; - - ap_sync_scoreboard_image(); - for (i = 0; i < ap_daemons_limit; ++i) { - int status; - - if (i >= max_daemons_limit && free_length == idle_spawn_rate) - break; - ss = &ap_scoreboard_image->servers[i]; - status = ss->status; - if (status == SERVER_DEAD) { - /* try to keep children numbers as low as possible */ - if (free_length < idle_spawn_rate) { - free_slots[free_length] = i; - ++free_length; - } - } - else { - /* We consider a starting server as idle because we started it - * at least a cycle ago, and if it still hasn't finished starting - * then we're just going to swamp things worse by forking more. - * So we hopefully won't need to fork more if we count it. - * This depends on the ordering of SERVER_READY and SERVER_STARTING. - */ - if (status <= SERVER_READY) { - ++ idle_count; - /* always kill the highest numbered child if we have to... - * no really well thought out reason ... other than observing - * the server behaviour under linux where lower numbered children - * tend to service more hits (and hence are more likely to have - * their data in cpu caches). - */ - to_kill = i; - } - - ++total_non_dead; - last_non_dead = i; -#ifdef OPTIMIZE_TIMEOUTS - if (ss->timeout_len) { - /* if it's a live server, with a live timeout then - * start checking its timeout */ - parent_score *ps = &ap_scoreboard_image->parent[i]; - if (ss->cur_vtime != ps->last_vtime) { - /* it has made progress, so update its last_rtime, - * last_vtime */ - ps->last_rtime = now; - ps->last_vtime = ss->cur_vtime; - } - else if (ps->last_rtime + ss->timeout_len < now) { - /* no progress, and the timeout length has been exceeded */ - ss->timeout_len = 0; - kill(ps->pid, SIGALRM); - } - } -#endif - } - } - max_daemons_limit = last_non_dead + 1; - if (idle_count > ap_daemons_max_free) { - /* kill off one child... we use SIGUSR1 because that'll cause it to - * shut down gracefully, in case it happened to pick up a request - * while we were counting - */ - kill(ap_scoreboard_image->parent[to_kill].pid, SIGUSR1); - idle_spawn_rate = 1; - } - else if (idle_count < ap_daemons_min_free) { - /* terminate the free list */ - if (free_length == 0) { - /* only report this condition once */ - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf, - "server reached MaxClients setting, consider" - " raising the MaxClients setting"); - reported = 1; - } - idle_spawn_rate = 1; - } - else { - if (idle_spawn_rate >= 8) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "server seems busy, (you may need " - "to increase StartServers, or Min/MaxSpareServers), " - "spawning %d children, there are %d idle, and " - "%d total children", idle_spawn_rate, - idle_count, total_non_dead); - } - for (i = 0; i < free_length; ++i) { -#ifdef TPF - if(make_child(server_conf, free_slots[i], now) == -1) { - if(free_length == 1) { - shutdown_pending = 1; - ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, - "No active child processes: shutting down"); - } - } -#else - make_child(server_conf, free_slots[i], now); -#endif /* TPF */ - } - /* the next time around we want to spawn twice as many if this - * wasn't good enough, but not if we've just done a graceful - */ - if (hold_off_on_exponential_spawning) { - --hold_off_on_exponential_spawning; - } - else if (idle_spawn_rate < MAX_SPAWN_RATE) { - idle_spawn_rate *= 2; - } - } - } - else { - idle_spawn_rate = 1; - } -} - - -static void process_child_status(int pid, ap_wait_t status) -{ - /* Child died... if it died due to a fatal error, - * we should simply bail out. - */ - if ((WIFEXITED(status)) && - WEXITSTATUS(status) == APEXIT_CHILDFATAL) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, server_conf, - "Child %d returned a Fatal error... \n" - "Apache is exiting!", - pid); - exit(APEXIT_CHILDFATAL); - } - if (WIFSIGNALED(status)) { - switch (WTERMSIG(status)) { - case SIGTERM: - case SIGHUP: - case SIGUSR1: - case SIGKILL: - break; - default: -#ifdef SYS_SIGLIST -#ifdef WCOREDUMP - if (WCOREDUMP(status)) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, - server_conf, - "child pid %d exit signal %s (%d), " - "possible coredump in %s", - pid, (WTERMSIG(status) >= NumSIG) ? "" : - SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status), - ap_coredump_dir); - } - else { -#endif - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, - server_conf, - "child pid %d exit signal %s (%d)", pid, - SYS_SIGLIST[WTERMSIG(status)], WTERMSIG(status)); -#ifdef WCOREDUMP - } -#endif -#else - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, - server_conf, - "child pid %d exit signal %d", - pid, WTERMSIG(status)); -#endif - } - } -} - - -/***************************************************************** - * Executive routines. - */ - -#ifndef STANDALONE_MAIN -#define STANDALONE_MAIN standalone_main - -static void standalone_main(int argc, char **argv) -{ - int remaining_children_to_start; - -#ifdef OS2 - printf("%s \n", ap_get_server_version()); -#endif - - ap_standalone = 1; - - is_graceful = 0; - - if (!one_process) { - detach(); - } - else { - MONCONTROL(1); - } - - my_pid = getpid(); - - do { - copy_listeners(pconf); - if (!is_graceful) { - ap_restart_time = time(NULL); - } -#ifdef SCOREBOARD_FILE - else if (scoreboard_fd != -1) { - ap_kill_cleanup(pconf, NULL, cleanup_scoreboard_file); - ap_kill_cleanups_for_fd(pconf, scoreboard_fd); - } -#endif - ap_clear_pool(pconf); - ptrans = ap_make_sub_pool(pconf); - - server_conf = ap_read_config(pconf, ptrans, ap_server_confname); - setup_listeners(pconf); - ap_clear_pool(plog); - ap_open_logs(server_conf, plog); - ap_log_pid(pconf, ap_pid_fname); - ap_set_version(); /* create our server_version string */ - ap_init_modules(pconf, server_conf); - version_locked++; /* no more changes to server_version */ - SAFE_ACCEPT(accept_mutex_init(pconf)); - if (!is_graceful) { - reinit_scoreboard(pconf); - } -#ifdef SCOREBOARD_FILE - else { - ap_scoreboard_fname = ap_server_root_relative(pconf, ap_scoreboard_fname); - ap_note_cleanups_for_fd(pconf, scoreboard_fd); - } -#endif - - set_signals(); - - if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */ - ap_daemons_max_free = ap_daemons_min_free + 1; - - /* If we're doing a graceful_restart then we're going to see a lot - * of children exiting immediately when we get into the main loop - * below (because we just sent them SIGUSR1). This happens pretty - * rapidly... and for each one that exits we'll start a new one until - * we reach at least daemons_min_free. But we may be permitted to - * start more than that, so we'll just keep track of how many we're - * supposed to start up without the 1 second penalty between each fork. - */ - remaining_children_to_start = ap_daemons_to_start; - if (remaining_children_to_start > ap_daemons_limit) { - remaining_children_to_start = ap_daemons_limit; - } - if (!is_graceful) { - startup_children(remaining_children_to_start); - remaining_children_to_start = 0; - } - else { - /* give the system some time to recover before kicking into - * exponential mode */ - hold_off_on_exponential_spawning = 10; - } - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - if (ap_suexec_enabled) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, - "suEXEC mechanism enabled (wrapper: %s)", SUEXEC_BIN); - } - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "Server built: %s", ap_get_server_built()); - restart_pending = shutdown_pending = 0; - - while (!restart_pending && !shutdown_pending) { - int child_slot; - ap_wait_t status; - int pid = wait_or_timeout(&status); - - /* XXX: if it takes longer than 1 second for all our children - * to start up and get into IDLE state then we may spawn an - * extra child - */ - if (pid >= 0) { - process_child_status(pid, status); - /* non-fatal death... note that it's gone in the scoreboard. */ - ap_sync_scoreboard_image(); - child_slot = find_child_by_pid(pid); - Explain2("Reaping child %d slot %d", pid, child_slot); - if (child_slot >= 0) { - (void) ap_update_child_status(child_slot, SERVER_DEAD, - (request_rec *) NULL); - if (remaining_children_to_start - && child_slot < ap_daemons_limit) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(server_conf, child_slot, time(0)); - --remaining_children_to_start; - } -#ifndef NO_OTHER_CHILD - } - else if (reap_other_child(pid, status) == 0) { - /* handled */ -#endif - } - else if (is_graceful) { - /* Great, we've probably just lost a slot in the - * scoreboard. Somehow we don't know about this - * child. - */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, server_conf, - "long lost child came home! (pid %d)", pid); - } - /* Don't perform idle maintenance when a child dies, - * only do it when there's a timeout. Remember only a - * finite number of children can die, and it's pretty - * pathological for a lot to die suddenly. - */ - continue; - } - else if (remaining_children_to_start) { - /* we hit a 1 second timeout in which none of the previous - * generation of children needed to be reaped... so assume - * they're all done, and pick up the slack if any is left. - */ - startup_children(remaining_children_to_start); - remaining_children_to_start = 0; - /* In any event we really shouldn't do the code below because - * few of the servers we just started are in the IDLE state - * yet, so we'd mistakenly create an extra server. - */ - continue; - } - - perform_idle_server_maintenance(); -#ifdef TPF - shutdown_pending = os_check_server(tpf_server_name); - ap_check_signals(); - sleep(1); -#endif /*TPF */ - } - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - */ - if (ap_killpg(pgrp, SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGTERM"); - } - reclaim_child_processes(1); /* Start with SIGTERM */ - - /* cleanup pid file on normal shutdown */ - { - const char *pidfile = NULL; - pidfile = ap_server_root_relative (pconf, ap_pid_fname); - if ( pidfile != NULL && unlink(pidfile) == 0) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, - server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, - "caught SIGTERM, shutting down"); - clean_parent_exit(0); - } - - /* we've been told to restart */ - signal(SIGHUP, SIG_IGN); - signal(SIGUSR1, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - clean_parent_exit(0); - } - - /* advance to the next generation */ - /* XXX: we really need to make sure this new generation number isn't in - * use by any of the children. - */ - ++ap_my_generation; - ap_scoreboard_image->global.running_generation = ap_my_generation; - update_scoreboard_global(); - - if (is_graceful) { -#ifndef SCOREBOARD_FILE - int i; -#endif - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, - "SIGUSR1 received. Doing graceful restart"); - - /* kill off the idle ones */ - if (ap_killpg(pgrp, SIGUSR1) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGUSR1"); - } -#ifndef SCOREBOARD_FILE - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. But we can't really - * do it if we're in a SCOREBOARD_FILE because it'll cause - * corruption too easily. - */ - ap_sync_scoreboard_image(); - for (i = 0; i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) { - ap_scoreboard_image->servers[i].status = SERVER_GRACEFUL; - } - } -#endif - } - else { - /* Kill 'em off */ - if (ap_killpg(pgrp, SIGHUP) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "killpg SIGHUP"); - } - reclaim_child_processes(0); /* Not when just starting up */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, server_conf, - "SIGHUP received. Attempting to restart"); - } - } while (restart_pending); - - /*add_common_vars(NULL);*/ -} /* standalone_main */ -#else -/* prototype */ -void STANDALONE_MAIN(int argc, char **argv); -#endif /* STANDALONE_MAIN */ - -extern char *optarg; -extern int optind; - -int REALMAIN(int argc, char *argv[]) -{ - int c; - int sock_in; - int sock_out; - char *s; - -#ifdef SecureWare - if (set_auth_parameters(argc, argv) < 0) - perror("set_auth_parameters"); - if (getluid() < 0) - if (setluid(getuid()) < 0) - perror("setluid"); - if (setreuid(0, 0) < 0) - perror("setreuid"); -#endif - -#ifdef SOCKS - SOCKSinit(argv[0]); -#endif - -#ifdef TPF - APACHE_TPF_INPUT input_parms; - ecbptr()->ebrout = PRIMECRAS; - input_parms = * (APACHE_TPF_INPUT *)(&(ecbptr()->ebw000)); -#endif - - MONCONTROL(0); - - common_init(); - - if ((s = strrchr(argv[0], PATHSEPARATOR)) != NULL) { - ap_server_argv0 = ++s; - } - else { - ap_server_argv0 = argv[0]; - } - - ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root)); - ap_cpystrn(ap_server_confname, SERVER_CONFIG_FILE, sizeof(ap_server_confname)); - - ap_setup_prelinked_modules(); - - while ((c = getopt(argc, argv, - "D:C:c:xXd:f:vVlLR:StTh" -#ifdef DEBUG_SIGSTOP - "Z:" -#endif - )) != -1) { - char **new; - switch (c) { - case 'c': - new = (char **)ap_push_array(ap_server_post_read_config); - *new = ap_pstrdup(pcommands, optarg); - break; - case 'C': - new = (char **)ap_push_array(ap_server_pre_read_config); - *new = ap_pstrdup(pcommands, optarg); - break; - case 'D': - new = (char **)ap_push_array(ap_server_config_defines); - *new = ap_pstrdup(pcommands, optarg); - break; - case 'd': - ap_cpystrn(ap_server_root, optarg, sizeof(ap_server_root)); - break; - case 'f': - ap_cpystrn(ap_server_confname, optarg, sizeof(ap_server_confname)); - break; - case 'v': - ap_set_version(); - printf("Server version: %s\n", ap_get_server_version()); - printf("Server built: %s\n", ap_get_server_built()); - exit(0); - case 'V': - ap_set_version(); - show_compile_settings(); - exit(0); - case 'l': - ap_show_modules(); - exit(0); - case 'L': - ap_show_directives(); - exit(0); - case 'X': - ++one_process; /* Weird debugging mode. */ - break; -#ifdef TPF - case 'x': - os_tpf_child(&input_parms); - set_signals(); - break; -#endif -#ifdef DEBUG_SIGSTOP - case 'Z': - raise_sigstop_flags = atoi(optarg); - break; -#endif -#ifdef SHARED_CORE - case 'R': - /* just ignore this option here, because it has only - * effect when SHARED_CORE is used and then it was - * already handled in the Shared Core Bootstrap - * program. - */ - break; -#endif - case 'S': - ap_dump_settings = 1; - break; - case 't': - ap_configtestonly = 1; - ap_docrootcheck = 1; - break; - case 'T': - ap_configtestonly = 1; - ap_docrootcheck = 0; - break; - case 'h': - usage(argv[0]); - case '?': - usage(argv[0]); - } - } - - ap_suexec_enabled = init_suexec(); - server_conf = ap_read_config(pconf, ptrans, ap_server_confname); - - if (ap_configtestonly) { - fprintf(stderr, "Syntax OK\n"); - exit(0); - } - if (ap_dump_settings) { - exit(0); - } - - child_timeouts = !ap_standalone || one_process; - -#ifndef TPF - if (ap_standalone) { - ap_open_logs(server_conf, plog); - ap_set_version(); - ap_init_modules(pconf, server_conf); - version_locked++; - STANDALONE_MAIN(argc, argv); - } -#else - if (ap_standalone) { - if(!tpf_child) { - memcpy(tpf_server_name, input_parms.inetd_server.servname, INETD_SERVNAME_LENGTH); - tpf_server_name[INETD_SERVNAME_LENGTH+1] = '\0'; - ap_open_logs(server_conf, pconf); - } - ap_set_version(); - ap_init_modules(pconf, server_conf); - version_locked++; - if(tpf_child) { - copy_listeners(pconf); - reset_tpf_listeners(&input_parms); - server_conf->error_log = NULL; -#ifdef SCOREBOARD_FILE - scoreboard_fd = input_parms.scoreboard_fd; - ap_scoreboard_image = &_scoreboard_image; -#else /* must be USE_TPF_SCOREBOARD or USE_SHMGET_SCOREBOARD */ - ap_scoreboard_image = (scoreboard *)input_parms.scoreboard_heap; -#endif - child_main(input_parms.slot); - } - else - STANDALONE_MAIN(argc, argv); - } -#endif - else { - conn_rec *conn; - request_rec *r; - struct sockaddr sa_server, sa_client; - BUFF *cio; - NET_SIZE_T l; - - ap_set_version(); - /* Yes this is called twice. */ - ap_init_modules(pconf, server_conf); - version_locked++; - ap_open_logs(server_conf, plog); - ap_init_modules(pconf, server_conf); - set_group_privs(); - -#ifdef MPE - /* Only try to switch if we're running as MANAGER.SYS */ - if (geteuid() == 1 && ap_user_id > 1) { - GETPRIVMODE(); - if (setuid(ap_user_id) == -1) { - GETUSERMODE(); - ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, - "setuid: unable to change to uid: %d", ap_user_id); - exit(1); - } - GETUSERMODE(); - } -#else - /* Only try to switch if we're running as root */ - if (!geteuid() && setuid(ap_user_id) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, server_conf, - "setuid: unable to change to uid: %ld", - (long) ap_user_id); - exit(1); - } -#endif - if (ap_setjmp(jmpbuffer)) { - exit(0); - } - -#ifdef TPF -/* TPF only passes the incoming socket number from the internet daemon - in ebw000 */ - sock_in = * (int*)(&(ecbptr()->ebw000)); - sock_out = * (int*)(&(ecbptr()->ebw000)); -/* TPF also needs a signal set for alarm in inetd mode */ - signal(SIGALRM, alrm_handler); -#elif defined(MPE) -/* HP MPE 5.5 inetd only passes the incoming socket as stdin (fd 0), whereas - HPUX inetd passes the incoming socket as stdin (fd 0) and stdout (fd 1). - Go figure. SR 5003355016 has been submitted to request that the existing - functionality be documented, and then to enhance the functionality to be - like HPUX. */ - sock_in = fileno(stdin); - sock_out = fileno(stdin); -#else - sock_in = fileno(stdin); - sock_out = fileno(stdout); -#endif - - l = sizeof(sa_client); - if ((getpeername(sock_in, &sa_client, &l)) < 0) { -/* get peername will fail if the input isn't a socket */ - perror("getpeername"); - memset(&sa_client, '\0', sizeof(sa_client)); - } - - l = sizeof(sa_server); - if (getsockname(sock_in, &sa_server, &l) < 0) { - perror("getsockname"); - fprintf(stderr, "Error getting local address\n"); - exit(1); - } - server_conf->port = ntohs(((struct sockaddr_in *) &sa_server)->sin_port); - cio = ap_bcreate(ptrans, B_RDWR | B_SOCKET); - cio->fd = sock_out; - cio->fd_in = sock_in; - conn = new_connection(ptrans, server_conf, cio, - (struct sockaddr_in *) &sa_client, - (struct sockaddr_in *) &sa_server, -1); - - while ((r = ap_read_request(conn)) != NULL) { - - if (r->status == HTTP_OK) - ap_process_request(r); - - if (!conn->keepalive || conn->aborted) - break; - - ap_destroy_pool(r->pool); - } - - ap_bclose(cio); - } - exit(0); -} - -#else /* ndef MULTITHREAD */ - - -/********************************************************************** - * Multithreaded implementation - * - * This code is fairly specific to Win32. - * - * The model used to handle requests is a set of threads. One "main" - * thread listens for new requests. When something becomes - * available, it does a select and places the newly available socket - * onto a list of "jobs" (add_job()). Then any one of a fixed number - * of "worker" threads takes the top job off the job list with - * remove_job() and handles that connection to completion. After - * the connection has finished the thread is free to take another - * job from the job list. - * - * In the code, the "main" thread is running within the worker_main() - * function. The first thing this function does is create the - * worker threads, which operate in the child_sub_main() function. The - * main thread then goes into a loop within worker_main() where they - * do a select() on the listening sockets. The select times out once - * per second so that the thread can check for an "exit" signal - * from the parent process (see below). If this signal is set, the - * thread can exit, but only after it has accepted all incoming - * connections already in the listen queue (since Win32 appears - * to through away listened but unaccepted connections when a - * process dies). - * - * Because the main and worker threads exist within a single process - * they are vulnerable to crashes or memory leaks (crashes can also - * be caused within modules, of course). There also needs to be a - * mechanism to perform restarts and shutdowns. This is done by - * creating the main & worker threads within a subprocess. A - * main process (the "parent process") creates one (or more) - * processes to do the work, then the parent sits around waiting - * for the working process to die, in which case it starts a new - * one. The parent process also handles restarts (by creating - * a new working process then signalling the previous working process - * exit ) and shutdowns (by signalling the working process to exit). - * The parent process operates within the master_main() function. This - * process also handles requests from the service manager (NT only). - * - * Signalling between the parent and working process uses a Win32 - * event. Each child has a unique name for the event, which is - * passed to it with the -Z argument when the child is spawned. The - * parent sets (signals) this event to tell the child to die. - * At present all children do a graceful die - they finish all - * current jobs _and_ empty the listen queue before they exit. - * A non-graceful die would need a second event. The -Z argument in - * the child is also used to create the shutdown and restart events, - * since the prefix (apPID) contains the parent process PID. - * - * The code below starts with functions at the lowest level - - * worker threads, and works up to the top level - the main() - * function of the parent process. - * - * The scoreboard (in process memory) contains details of the worker - * threads (within the active working process). There is no shared - * "scoreboard" between processes, since only one is ever active - * at once (or at most, two, when one has been told to shutdown but - * is processes outstanding requests, and a new one has been started). - * This is controlled by a "start_mutex" which ensures only one working - * process is active at once. - **********************************************************************/ - -/* The code protected by #ifdef UNGRACEFUL_RESTARTS/#endif sections - * could implement a sort-of ungraceful restart for Win32. instead of - * graceful restarts. - * - * However it does not work too well because it does not intercept a - * connection already in progress (in child_sub_main()). We'd have to - * get that to poll on the exit event. - */ - -/* - * Definition of jobs, shared by main and worker threads. - */ - -typedef struct joblist_s { - struct joblist_s *next; - int sock; -} joblist; - -/* - * Globals common to main and worker threads. This structure is not - * used by the parent process. - */ - -typedef struct globals_s { -#ifdef UNGRACEFUL_RESTART - HANDLE thread_exit_event; -#else - int exit_now; -#endif - semaphore *jobsemaphore; - joblist *jobhead; - joblist *jobtail; - mutex *jobmutex; - int jobcount; -} globals; - -globals allowed_globals = -{0, NULL, NULL, NULL, NULL, 0}; - -/* - * add_job()/remove_job() - add or remove an accepted socket from the - * list of sockets connected to clients. allowed_globals.jobmutex protects - * against multiple concurrent access to the linked list of jobs. - */ - -void add_job(int sock) -{ - joblist *new_job; - - ap_assert(allowed_globals.jobmutex); - /* TODO: If too many jobs in queue, sleep, check for problems */ - ap_acquire_mutex(allowed_globals.jobmutex); - new_job = (joblist *) malloc(sizeof(joblist)); - if (new_job == NULL) { - fprintf(stderr, "Ouch! Out of memory in add_job()!\n"); - } - new_job->next = NULL; - new_job->sock = sock; - if (allowed_globals.jobtail != NULL) - allowed_globals.jobtail->next = new_job; - allowed_globals.jobtail = new_job; - if (!allowed_globals.jobhead) - allowed_globals.jobhead = new_job; - allowed_globals.jobcount++; - release_semaphore(allowed_globals.jobsemaphore); - ap_release_mutex(allowed_globals.jobmutex); -} - -int remove_job(void) -{ - joblist *job; - int sock; - -#ifdef UNGRACEFUL_RESTART - HANDLE hObjects[2]; - int rv; - - hObjects[0] = allowed_globals.jobsemaphore; - hObjects[1] = allowed_globals.thread_exit_event; - - rv = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE); - ap_assert(rv != WAIT_FAILED); - if (rv == WAIT_OBJECT_0 + 1) { - /* thread_exit_now */ - APD1("thread got exit now event"); - return -1; - } - /* must be semaphore */ -#else - acquire_semaphore(allowed_globals.jobsemaphore); -#endif - ap_assert(allowed_globals.jobmutex); - -#ifdef UNGRACEFUL_RESTART - if (!allowed_globals.jobhead) { -#else - ap_acquire_mutex(allowed_globals.jobmutex); - if (allowed_globals.exit_now && !allowed_globals.jobhead) { -#endif - ap_release_mutex(allowed_globals.jobmutex); - return (-1); - } - job = allowed_globals.jobhead; - ap_assert(job); - allowed_globals.jobhead = job->next; - if (allowed_globals.jobhead == NULL) - allowed_globals.jobtail = NULL; - ap_release_mutex(allowed_globals.jobmutex); - sock = job->sock; - free(job); - return (sock); -} - -/* - * child_sub_main() - this is the main loop for the worker threads - * - * Each thread runs within this function. They wait within remove_job() - * for a job to become available, then handle all the requests on that - * connection until it is closed, then return to remove_job(). - * - * The worker thread will exit when it removes a job which contains - * socket number -1. This provides a graceful thread exit, since - * it will never exit during a connection. - * - * This code in this function is basically equivalent to the child_main() - * from the multi-process (Unix) environment, except that we - * - * - do not call child_init_modules (child init API phase) - * - block in remove_job, and when unblocked we have an already - * accepted socket, instead of blocking on a mutex or select(). - */ - -static void child_sub_main(int child_num) -{ - NET_SIZE_T clen; - struct sockaddr sa_server; - struct sockaddr sa_client; - pool *ptrans; - int requests_this_child = 0; - int csd = -1; - int dupped_csd = -1; - int srv = 0; - - ptrans = ap_make_sub_pool(pconf); - - (void) ap_update_child_status(child_num, SERVER_READY, (request_rec *) NULL); - - /* - * Setup the jump buffers so that we can return here after a timeout. - */ -#if defined(USE_LONGJMP) - setjmp(jmpbuffer); -#else - sigsetjmp(jmpbuffer, 1); -#endif -#ifdef SIGURG - signal(SIGURG, timeout); -#endif - - while (1) { - BUFF *conn_io; - request_rec *r; - - /* - * (Re)initialize this child to a pre-connection state. - */ - - ap_set_callback_and_alarm(NULL, 0); /* Cancel any outstanding alarms */ - timeout_req = NULL; /* No request in progress */ - current_conn = NULL; - - ap_clear_pool(ptrans); - - (void) ap_update_child_status(child_num, SERVER_READY, - (request_rec *) NULL); - - /* Get job from the job list. This will block until a job is ready. - * If -1 is returned then the main thread wants us to exit. - */ - csd = remove_job(); - if (csd == -1) - break; /* time to exit */ - requests_this_child++; - - ap_note_cleanups_for_socket(ptrans, csd); - - /* - * We now have a connection, so set it up with the appropriate - * socket options, file descriptors, and read/write buffers. - */ - - clen = sizeof(sa_server); - if (getsockname(csd, &sa_server, &clen) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf, "getsockname"); - continue; - } - clen = sizeof(sa_client); - if ((getpeername(csd, &sa_client, &clen)) < 0) { - /* get peername will fail if the input isn't a socket */ - perror("getpeername"); - memset(&sa_client, '\0', sizeof(sa_client)); - } - - sock_disable_nagle(csd); - - (void) ap_update_child_status(child_num, SERVER_BUSY_READ, - (request_rec *) NULL); - - conn_io = ap_bcreate(ptrans, B_RDWR | B_SOCKET); - dupped_csd = csd; -#if defined(NEED_DUPPED_CSD) - if ((dupped_csd = dup(csd)) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "dup: couldn't duplicate csd"); - dupped_csd = csd; /* Oh well... */ - } - ap_note_cleanups_for_socket(ptrans, dupped_csd); -#endif - ap_bpushfd(conn_io, csd, dupped_csd); - - current_conn = new_connection(ptrans, server_conf, conn_io, - (struct sockaddr_in *) &sa_client, - (struct sockaddr_in *) &sa_server, - child_num); - - /* - * Read and process each request found on our connection - * until no requests are left or we decide to close. - */ - - while ((r = ap_read_request(current_conn)) != NULL) { - (void) ap_update_child_status(child_num, SERVER_BUSY_WRITE, r); - - if (r->status == HTTP_OK) - ap_process_request(r); - - if (ap_extended_status) - increment_counts(child_num, r); - - if (!current_conn->keepalive || current_conn->aborted) - break; - - ap_destroy_pool(r->pool); - (void) ap_update_child_status(child_num, SERVER_BUSY_KEEPALIVE, - (request_rec *) NULL); - - ap_sync_scoreboard_image(); - } - - /* - * Close the connection, being careful to send out whatever is still - * in our buffers. If possible, try to avoid a hard close until the - * client has ACKed our FIN and/or has stopped sending us data. - */ - ap_kill_cleanups_for_socket(ptrans, csd); - -#ifdef NO_LINGCLOSE - ap_bclose(conn_io); /* just close it */ -#else - if (r && r->connection - && !r->connection->aborted - && r->connection->client - && (r->connection->client->fd >= 0)) { - - lingering_close(r); - } - else { - ap_bsetflag(conn_io, B_EOUT, 1); - ap_bclose(conn_io); - } -#endif - } - ap_destroy_pool(ptrans); - (void) ap_update_child_status(child_num, SERVER_DEAD, NULL); -} - - -void child_main(int child_num_arg) -{ - /* - * Only reason for this function, is to pass in - * arguments to child_sub_main() on its stack so - * that longjump doesn't try to corrupt its local - * variables and I don't need to make those - * damn variables static/global - */ - child_sub_main(child_num_arg); -} - - - -void cleanup_thread(thread **handles, int *thread_cnt, int thread_to_clean) -{ - int i; - - free_thread(handles[thread_to_clean]); - for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++) - handles[i] = handles[i + 1]; - (*thread_cnt)--; -} -#ifdef WIN32 -/* - * The Win32 call WaitForMultipleObjects will only allow you to wait for - * a maximum of MAXIMUM_WAIT_OBJECTS (current 64). Since the threading - * model in the multithreaded version of apache wants to use this call, - * we are restricted to a maximum of 64 threads. This is a simplistic - * routine that will increase this size. - */ -static DWORD wait_for_many_objects(DWORD nCount, CONST HANDLE *lpHandles, - DWORD dwSeconds) -{ - time_t tStopTime; - DWORD dwRet = WAIT_TIMEOUT; - DWORD dwIndex=0; - BOOL bFirst = TRUE; - - tStopTime = time(NULL) + dwSeconds; - - do { - if (!bFirst) - Sleep(1000); - else - bFirst = FALSE; - - for (dwIndex = 0; dwIndex * MAXIMUM_WAIT_OBJECTS < nCount; dwIndex++) { - dwRet = WaitForMultipleObjects( - min(MAXIMUM_WAIT_OBJECTS, - nCount - (dwIndex * MAXIMUM_WAIT_OBJECTS)), - lpHandles + (dwIndex * MAXIMUM_WAIT_OBJECTS), - 0, 0); - - if (dwRet != WAIT_TIMEOUT) { - break; - } - } - } while((time(NULL) < tStopTime) && (dwRet == WAIT_TIMEOUT)); - - return dwRet; -} -#endif -/***************************************************************** - * Executive routines. - */ - -extern void main_control_server(void *); /* in hellop.c */ - -event *exit_event; -mutex *start_mutex; - -#define MAX_SIGNAL_NAME 30 /* Long enough for apPID_shutdown, where PID is an int */ -char signal_name_prefix[MAX_SIGNAL_NAME]; -char signal_restart_name[MAX_SIGNAL_NAME]; -char signal_shutdown_name[MAX_SIGNAL_NAME]; - -#define MAX_SELECT_ERRORS 100 - -/* - * Initialise the signal names, in the global variables signal_name_prefix, - * signal_restart_name and signal_shutdown_name. - */ - -void setup_signal_names(char *prefix) -{ - ap_snprintf(signal_name_prefix, sizeof(signal_name_prefix), prefix); - ap_snprintf(signal_shutdown_name, sizeof(signal_shutdown_name), - "%s_shutdown", signal_name_prefix); - ap_snprintf(signal_restart_name, sizeof(signal_restart_name), - "%s_restart", signal_name_prefix); - - APD2("signal prefix %s", signal_name_prefix); -} - -static void setup_inherited_listeners(pool *p) -{ - HANDLE pipe; - listen_rec *lr; - int fd; - WSAPROTOCOL_INFO WSAProtocolInfo; - DWORD BytesRead; - - /* Open the pipe to the parent process to receive the inherited socket - * data. The sockets have been set to listening in the parent process. - */ - pipe = GetStdHandle(STD_INPUT_HANDLE); - - /* Setup the listeners */ - listenmaxfd = -1; - FD_ZERO(&listenfds); - lr = ap_listeners; - - FD_ZERO(&listenfds); - - for (;;) { - fd = find_listener(lr); - if (fd < 0) { - if (!ReadFile(pipe, - &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), - &BytesRead, - (LPOVERLAPPED) NULL)){ - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR|APLOG_CRIT, server_conf, - "setup_inherited_listeners: Unable to read socket data from parent"); - exit(1); - } - fd = WSASocket(FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - &WSAProtocolInfo, - 0, - 0); - if (fd == INVALID_SOCKET) { - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR|APLOG_CRIT, server_conf, - "setup_inherited_listeners: WSASocket failed to get inherit the socket."); - exit(1); - } - APD2("setup_inherited_listeners: WSASocket() returned socket %d", fd); - } - else { - ap_note_cleanups_for_socket(p, fd); - } - if (fd >= 0) { - FD_SET(fd, &listenfds); - if (fd > listenmaxfd) - listenmaxfd = fd; - } - lr->fd = fd; - if (lr->next == NULL) - break; - lr = lr->next; - } - /* turn the list into a ring */ - lr->next = ap_listeners; - head_listener = ap_listeners; - close_unused_listeners(); - CloseHandle(pipe); - return; -} - -/* - * worker_main() is main loop for the child process. The loop in - * this function becomes the controlling thread for the actually working - * threads (which run in a loop in child_sub_main()). - */ - -void worker_main(void) -{ - int nthreads; - fd_set main_fds; - int srv; - int clen; - int csd; - struct sockaddr_in sa_client; - int total_jobs = 0; - thread **child_handles; - int rv; - time_t end_time; - int i; - struct timeval tv; - int wait_time = 1; - int max_jobs_per_exe; - int max_jobs_after_exit_request; - HANDLE hObjects[2]; - int count_select_errors = 0; - pool *pchild; - - pchild = ap_make_sub_pool(pconf); - - ap_standalone = 1; - sd = -1; - nthreads = ap_threads_per_child; - max_jobs_after_exit_request = ap_excess_requests_per_child; - max_jobs_per_exe = ap_max_requests_per_child; - if (nthreads <= 0) - nthreads = 40; - if (max_jobs_per_exe <= 0) - max_jobs_per_exe = 0; - if (max_jobs_after_exit_request <= 0) - max_jobs_after_exit_request = max_jobs_per_exe / 10; - - if (!one_process) - detach(); - - my_pid = getpid(); - - ++ap_my_generation; - - copy_listeners(pconf); - ap_restart_time = time(NULL); - - reinit_scoreboard(pconf); - - /* - * Wait until we have permission to start accepting connections. - * start_mutex is used to ensure that only one child ever - * goes into the listen/accept loop at once. Also wait on exit_event, - * in case we (this child) is told to die before we get a chance to - * serve any requests. - */ - hObjects[0] = (HANDLE)start_mutex; - hObjects[1] = (HANDLE)exit_event; - rv = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE); - if (rv == WAIT_FAILED) { - ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "Waiting for start_mutex or exit_event -- process will exit"); - - ap_destroy_pool(pchild); - cleanup_scoreboard(); - exit(0); - } - if (rv == WAIT_OBJECT_0 + 1) { - /* exit event signalled - exit now */ - ap_destroy_pool(pchild); - cleanup_scoreboard(); - exit(0); - } - /* start_mutex obtained, continue into the select() loop */ - if (one_process) { - setup_listeners(pconf); - } else { - /* Get listeners from the parent process */ - setup_inherited_listeners(pconf); - } - - if (listenmaxfd == -1) { - /* Help, no sockets were made, better log something and exit */ - ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_NOERRNO, NULL, - "No sockets were created for listening"); - - signal_parent(0); /* tell parent to die */ - - ap_destroy_pool(pchild); - cleanup_scoreboard(); - exit(0); - } - set_signals(); - - /* - * - Initialize allowed_globals - * - Create the thread table - * - Spawn off threads - * - Create listen socket set (done above) - * - loop { - * wait for request - * create new job - * } while (!time to exit) - * - Close all listeners - * - Wait for all threads to complete - * - Exit - */ - - ap_child_init_modules(pconf, server_conf); - - allowed_globals.jobsemaphore = create_semaphore(0); - allowed_globals.jobmutex = ap_create_mutex(NULL); - - /* spawn off the threads */ - child_handles = (thread *) alloca(nthreads * sizeof(int)); - for (i = 0; i < nthreads; i++) { - child_handles[i] = create_thread((void (*)(void *)) child_main, (void *) i); - } - if (nthreads > max_daemons_limit) { - max_daemons_limit = nthreads; - } - - while (1) { - if (max_jobs_per_exe && (total_jobs > max_jobs_per_exe)) { - /* MaxRequestsPerChild hit... - */ - break; - } - /* Always check for the exit event being signaled. - */ - rv = WaitForSingleObject(exit_event, 0); - ap_assert((rv == WAIT_TIMEOUT) || (rv == WAIT_OBJECT_0)); - if (rv == WAIT_OBJECT_0) { - APD1("child: exit event signalled, exiting"); - break; - } - - tv.tv_sec = wait_time; - tv.tv_usec = 0; - - memcpy(&main_fds, &listenfds, sizeof(fd_set)); - srv = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); -#ifdef WIN32 - if (srv == SOCKET_ERROR) { - /* Map the Win32 error into a standard Unix error condition */ - errno = WSAGetLastError(); - srv = -1; - } -#endif /* WIN32 */ - - if (srv < 0) { - /* Error occurred - if EINTR, loop around with problem */ - if (errno != EINTR) { - /* A "real" error occurred, log it and increment the count of - * select errors. This count is used to ensure we don't go into - * a busy loop of continuous errors. - */ - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, "select: (listen)"); - count_select_errors++; - if (count_select_errors > MAX_SELECT_ERRORS) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, server_conf, - "Too many errors in select loop. Child process exiting."); - break; - } - } - continue; - } - count_select_errors = 0; /* reset count of errors */ - if (srv == 0) { - continue; - } - - { - listen_rec *lr; - - lr = find_ready_listener(&main_fds); - if (lr != NULL) { - sd = lr->fd; - } - } - do { - clen = sizeof(sa_client); - csd = accept(sd, (struct sockaddr *) &sa_client, &clen); -#ifdef WIN32 - if (csd == INVALID_SOCKET) { - csd = -1; - errno = WSAGetLastError(); - } -#endif /* WIN32 */ - } while (csd < 0 && errno == EINTR); - - if (csd < 0) { -#if defined(EPROTO) && defined(ECONNABORTED) - if ((errno != EPROTO) && (errno != ECONNABORTED)) -#elif defined(EPROTO) - if (errno != EPROTO) -#elif defined(ECONNABORTED) - if (errno != ECONNABORTED) +#ifdef USE_OS2_SCOREBOARD + printf(" -D USE_OS2_SCOREBOARD\n"); #endif - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "accept: (client socket)"); - } - else { - add_job(csd); - total_jobs++; - } - } - - APD2("process PID %d exiting", my_pid); - - /* Get ready to shutdown and exit */ - allowed_globals.exit_now = 1; - ap_release_mutex(start_mutex); - -#ifdef UNGRACEFUL_RESTART - SetEvent(allowed_globals.thread_exit_event); -#else - for (i = 0; i < nthreads; i++) { - add_job(-1); - } +#ifdef USE_POSIX_SCOREBOARD + printf(" -D USE_POSIX_SCOREBOARD\n"); #endif - - APD2("process PID %d waiting for worker threads to exit", my_pid); - /* Wait for all your children */ - end_time = time(NULL) + 180; - while (nthreads) { - rv = wait_for_many_objects(nthreads, child_handles, - end_time - time(NULL)); - if (rv != WAIT_TIMEOUT) { - rv = rv - WAIT_OBJECT_0; - ap_assert((rv >= 0) && (rv < nthreads)); - cleanup_thread(child_handles, &nthreads, rv); - continue; - } - break; - } - - APD2("process PID %d killing remaining worker threads", my_pid); - for (i = 0; i < nthreads; i++) { - kill_thread(child_handles[i]); - free_thread(child_handles[i]); - } -#ifdef UNGRACEFUL_RESTART - ap_assert(CloseHandle(allowed_globals.thread_exit_event)); +#ifdef USE_MMAP_FILES + printf(" -D USE_MMAP_FILES\n"); +#ifdef MMAP_SEGMENT_SIZE + printf(" -D MMAP_SEGMENT_SIZE=%ld\n",(long)MMAP_SEGMENT_SIZE); +#endif +#endif /*USE_MMAP_FILES*/ +#ifdef NO_WRITEV + printf(" -D NO_WRITEV\n"); +#endif +#ifdef NO_LINGCLOSE + printf(" -D NO_LINGCLOSE\n"); +#endif +#ifdef USE_FCNTL_SERIALIZED_ACCEPT + printf(" -D USE_FCNTL_SERIALIZED_ACCEPT\n"); +#endif +#ifdef USE_FLOCK_SERIALIZED_ACCEPT + printf(" -D USE_FLOCK_SERIALIZED_ACCEPT\n"); +#endif +#ifdef USE_USLOCK_SERIALIZED_ACCEPT + printf(" -D USE_USLOCK_SERIALIZED_ACCEPT\n"); +#endif +#ifdef USE_SYSVSEM_SERIALIZED_ACCEPT + printf(" -D USE_SYSVSEM_SERIALIZED_ACCEPT\n"); +#endif +#ifdef USE_PTHREAD_SERIALIZED_ACCEPT + printf(" -D USE_PTHREAD_SERIALIZED_ACCEPT\n"); +#endif +#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT + printf(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n"); +#endif +#ifdef HAS_OTHER_CHILD + printf(" -D HAS_OTHER_CHILD\n"); +#endif +#ifdef NO_RELIABLE_PIPED_LOGS + printf(" -D NO_RELIABLE_PIPED_LOGS\n"); +#endif +#ifdef BUFFERED_LOGS + printf(" -D BUFFERED_LOGS\n"); +#ifdef PIPE_BUF + printf(" -D PIPE_BUF=%ld\n",(long)PIPE_BUF); +#endif +#endif +#ifdef MULTITHREAD + printf(" -D MULTITHREAD\n"); +#endif +#ifdef CHARSET_EBCDIC + printf(" -D CHARSET_EBCDIC\n"); +#endif +#ifdef NEED_HASHBANG_EMUL + printf(" -D NEED_HASHBANG_EMUL\n"); +#endif +#ifdef SHARED_CORE + printf(" -D SHARED_CORE\n"); #endif - destroy_semaphore(allowed_globals.jobsemaphore); - ap_destroy_mutex(allowed_globals.jobmutex); - - ap_child_exit_modules(pconf, server_conf); - ap_destroy_pool(pchild); - - cleanup_scoreboard(); - - APD2("process PID %d exited", my_pid); - clean_parent_exit(0); -} /* standalone_main */ - -/* - * Spawn a child Apache process. The child process has the command line arguments from - * argc and argv[], plus a -Z argument giving the name of an event. The child should - * open and poll or wait on this event. When it is signalled, the child should die. - * prefix is a prefix string for the event name. - * - * The child_num argument on entry contains a serial number for this child (used to create - * a unique event name). On exit, this number will have been incremented by one, ready - * for the next call. - * - * On exit, the value pointed to be *ev will contain the event created - * to signal the new child process. - * - * The return value is the handle to the child process if successful, else -1. If -1 is - * returned the error will already have been logged by ap_log_error(). - */ - -/********************************************************************** - * master_main - this is the parent (main) process. We create a - * child process to do the work, then sit around waiting for either - * the child to exit, or a restart or exit signal. If the child dies, - * we just respawn a new one. If we have a shutdown or graceful restart, - * tell the child to die when it is ready. If it is a non-graceful - * restart, force the child to die immediately. - **********************************************************************/ - -#define MAX_PROCESSES 50 /* must be < MAX_WAIT_OBJECTS-1 */ - -static void cleanup_process(HANDLE *handles, HANDLE *events, int position, int *processes) -{ - int i; - int handle = 0; - - CloseHandle(handles[position]); - CloseHandle(events[position]); - - handle = (int)handles[position]; - - for (i = position; i < (*processes)-1; i++) { - handles[i] = handles[i + 1]; - events[i] = events[i + 1]; - } - (*processes)--; - - APD4("cleanup_processes: removed child in slot %d handle %d, max=%d", position, handle, *processes); -} - -static int create_process(pool *p, HANDLE *handles, HANDLE *events, - int *processes, int *child_num, char *kill_event_name, int argc, char **argv) -{ - - int rv, i; - HANDLE kill_event; - char buf[1024]; - char exit_event_name[40]; /* apPID_C# */ - char *pCommand; - - STARTUPINFO si; /* Filled in prior to call to CreateProcess */ - PROCESS_INFORMATION pi; /* filled in on call to CreateProces */ - LPWSAPROTOCOL_INFO lpWSAProtocolInfo; - listen_rec *lr; - DWORD BytesWritten; - HANDLE hPipeRead = NULL; - HANDLE hPipeWrite = NULL; - SECURITY_ATTRIBUTES sa = {0}; - - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - /* Build the command line. Should look something like this: - * C:/apache/bin/apache.exe -Z exit_event -f ap_server_confname - * First, get the path to the executable... - */ - rv = GetModuleFileName(NULL, buf, sizeof(buf)); - if (rv == sizeof(buf)) { - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, server_conf, - "Parent: Path to Apache process too long"); - return -1; - } else if (rv == 0) { - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, server_conf, - "Parent: GetModuleFileName() returned NULL for current process."); - return -1; - } - - /* Create the exit event (apPID_C#). Parent signals this event to tell the - * child to exit - */ - ap_snprintf(exit_event_name, sizeof(exit_event_name), "%s_C%d", kill_event_name, ++(*child_num)); - kill_event = CreateEvent(NULL, TRUE, FALSE, exit_event_name); - if (!kill_event) { - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, server_conf, - "Parent: Could not create exit event for child process"); - return -1; - } - - pCommand = ap_psprintf(p, "\"%s\" -Z %s -f \"%s\"", buf, exit_event_name, ap_server_confname); - - for (i = 1; i < argc; i++) { - pCommand = ap_pstrcat(p, pCommand, " ", argv[i], NULL); - } - - /* Create a pipe to send socket info to the child */ - if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) { - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, server_conf, - "Parent: Unable to create pipe to child process.\n"); - return -1; - } - - /* Give the read in of teh pipe (hPipeRead) to the child as stdin. The - * parent will write the socket data to the child on this pipe. - */ - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - si.wShowWindow = SW_HIDE; - si.hStdInput = hPipeRead; - - if (!CreateProcess(NULL, pCommand, NULL, NULL, - TRUE, /* Inherit handles */ - 0, /* Creation flags */ - NULL, NULL, - &si, &pi)) { - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, server_conf, - "Parent: Not able to create the child process."); - /* - * We must close the handles to the new process and its main thread - * to prevent handle and memory leaks. - */ - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - return -1; - } - else { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, server_conf, - "Parent: Created child process %d", pi.dwProcessId); - - /* Assume the child process lives. Update the process and event tables */ - handles[*processes] = pi.hProcess; - events[*processes] = kill_event; - (*processes)++; - - /* We never store the thread's handle, so close it now. */ - CloseHandle(pi.hThread); - - /* Run the chain of open sockets. For each socket, duplicate it - * for the target process then send the WSAPROTOCOL_INFO - * (returned by dup socket) to the child */ - lr = ap_listeners; - while (lr != NULL) { - lpWSAProtocolInfo = ap_pcalloc(p, sizeof(WSAPROTOCOL_INFO)); - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, server_conf, - "Parent: Duplicating socket %d and sending it to child process %d", lr->fd, pi.dwProcessId); - if (WSADuplicateSocket(lr->fd, - pi.dwProcessId, - lpWSAProtocolInfo) == SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, server_conf, - "Parent: WSADuplicateSocket failed for socket %d.", lr->fd ); - return -1; - } - - if (!WriteFile(hPipeWrite, lpWSAProtocolInfo, (DWORD) sizeof(WSAPROTOCOL_INFO), - &BytesWritten, - (LPOVERLAPPED) NULL)) { - ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, server_conf, - "Parent: Unable to write duplicated socket %d to the child.", lr->fd ); - return -1; - } - - lr = lr->next; - if (lr == ap_listeners) - break; - } - } - CloseHandle(hPipeRead); - CloseHandle(hPipeWrite); - - return 0; -} - -/* To share the semaphores with other processes, we need a NULL ACL - * Code from MS KB Q106387 - */ - -static PSECURITY_ATTRIBUTES GetNullACL() -{ - PSECURITY_DESCRIPTOR pSD; - PSECURITY_ATTRIBUTES sa; - - sa = (PSECURITY_ATTRIBUTES) LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES)); - pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, - SECURITY_DESCRIPTOR_MIN_LENGTH); - if (pSD == NULL || sa == NULL) { - return NULL; - } - /* - * We can safely use GetLastError() here without presetting it; - * {Initialize,Set}SecurityDescriptor() have been verified as clearing it - * on successful completion. - */ - if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) - || GetLastError()) { - LocalFree( pSD ); - LocalFree( sa ); - return NULL; - } - if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE) - || GetLastError()) { - LocalFree( pSD ); - LocalFree( sa ); - return NULL; - } - sa->nLength = sizeof(sa); - sa->lpSecurityDescriptor = pSD; - sa->bInheritHandle = TRUE; - return sa; -} - - -static void CleanNullACL( void *sa ) { - if( sa ) { - LocalFree( ((PSECURITY_ATTRIBUTES)sa)->lpSecurityDescriptor); - LocalFree( sa ); - } -} - -int master_main(int argc, char **argv) -{ - /* returns NULL if invalid (Win95?) */ - PSECURITY_ATTRIBUTES sa = GetNullACL(); - int nchild = ap_daemons_to_start; - int child_num = 0; - int rv, cld; - char signal_prefix_string[100]; - int i; - time_t tmstart; - HANDLE signal_shutdown_event; /* used to signal shutdown to parent */ - HANDLE signal_restart_event; /* used to signal a restart to parent */ - HANDLE process_handles[MAX_PROCESSES]; - HANDLE process_kill_events[MAX_PROCESSES]; - int current_live_processes = 0; /* number of child process we know about */ - int processes_to_create = 0; /* number of child processes to create */ - pool *pparent = NULL; /* pool for the parent process. Cleaned on each restart */ - - nchild = 1; /* only allowed one child process for current generation */ - processes_to_create = nchild; - - is_graceful = 0; - - ap_snprintf(signal_prefix_string, sizeof(signal_prefix_string), - "ap%d", getpid()); - setup_signal_names(signal_prefix_string); - - /* Create shutdown event, apPID_shutdown, where PID is the parent - * Apache process ID. Shutdown is signaled by 'apache -k shutdown'. - */ - signal_shutdown_event = CreateEvent(sa, TRUE, FALSE, signal_shutdown_name); - if (!signal_shutdown_event) { - ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "master_main: Cannot create shutdown event %s", signal_shutdown_name); - CleanNullACL((void *)sa); - exit(1); - } - - /* Create restart event, apPID_restart, where PID is the parent - * Apache process ID. Restart is signaled by 'apache -k restart'. - */ - signal_restart_event = CreateEvent(sa, TRUE, FALSE, signal_restart_name); - if (!signal_restart_event) { - CloseHandle(signal_shutdown_event); - ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf, - "master_main: Cannot create restart event %s", signal_restart_name); - CleanNullACL((void *)sa); - exit(1); - } - CleanNullACL((void *)sa); - - /* Create the start mutex, apPID, where PID is the parent Apache process ID. - * Ths start mutex is used during a restart to prevent more than one - * child process from entering the accept loop at once. - */ - start_mutex = ap_create_mutex(signal_prefix_string); - restart_pending = shutdown_pending = 0; - - do { /* restart-pending */ - if (!is_graceful) { - ap_restart_time = time(NULL); - } - copy_listeners(pconf); - ap_clear_pool(pconf); - pparent = ap_make_sub_pool(pconf); - - server_conf = ap_read_config(pconf, pparent, ap_server_confname); - setup_listeners(pconf); - ap_clear_pool(plog); - ap_open_logs(server_conf, plog); - ap_set_version(); - ap_init_modules(pconf, server_conf); - version_locked++; - service_set_status(SERVICE_START_PENDING); - /* Create child processes */ - while (processes_to_create--) { - if (create_process(pconf, process_handles, process_kill_events, - ¤t_live_processes, &child_num, signal_prefix_string, argc, argv) < 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "master_main: create child process failed. Exiting."); - goto die_now; - } - } - service_set_status(SERVICE_RUNNING); - restart_pending = shutdown_pending = 0; - - /* Wait for either the shutdown or restart events to be signaled */ - process_handles[current_live_processes] = signal_shutdown_event; - process_handles[current_live_processes+1] = signal_restart_event; - rv = WaitForMultipleObjects(current_live_processes+2, (HANDLE *)process_handles, - FALSE, INFINITE); - if (rv == WAIT_FAILED) { - /* Something serious is wrong */ - ap_log_error(APLOG_MARK,APLOG_CRIT|APLOG_WIN32ERROR, server_conf, - "master_main: : WaitForMultipeObjects on process handles and apache-signal -- doing shutdown"); - shutdown_pending = 1; - break; - } - if (rv == WAIT_TIMEOUT) { - /* Hey, this cannot happen */ - ap_log_error(APLOG_MARK, APLOG_ERR, server_conf, - "master_main: WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT"); - shutdown_pending = 1; - } - - cld = rv - WAIT_OBJECT_0; - APD4("main process: wait finished, cld=%d handle %d (max=%d)", cld, process_handles[cld], current_live_processes); - if (cld == current_live_processes) { - /* apPID_shutdown event signalled, we should exit now */ - shutdown_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "master_main: Shutdown event signaled. Shutting the server down."); - if (ResetEvent(signal_shutdown_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "ResetEvent(signal_shutdown_event)"); - } - /* Signal each child processes to die */ - for (i = 0; i < current_live_processes; i++) { - APD3("master_main: signalling child %d, handle %d to die", i, process_handles[i]); - if (SetEvent(process_kill_events[i]) == 0) - ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "master_main: SetEvent for child process in slot #%d failed", i); - } - break; - } else if (cld == current_live_processes+1) { - /* apPID_restart event signalled, restart the child process */ - int children_to_kill = current_live_processes; - restart_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "master_main: Restart event signaled. Doing a graceful restart."); - if (ResetEvent(signal_restart_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "master_main: ResetEvent(signal_restart_event) failed."); - } - /* Signal each child process to die */ - for (i = 0; i < children_to_kill; i++) { - APD3("master_main: signalling child #%d handle %d to die", i, process_handles[i]); - if (SetEvent(process_kill_events[i]) == 0) - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, server_conf, - "master_main: SetEvent for child process in slot #%d failed", i); - /* Remove the process (and event) from the process table */ - cleanup_process(process_handles, process_kill_events, i, ¤t_live_processes); - } - processes_to_create = nchild; - ++ap_my_generation; - continue; - } else { - /* A child process must have exited because of MaxRequestPerChild being hit - * or a fatal error condition (seg fault, etc.). Remove the dead process - * from the process_handles and process_kill_events table and create a new - * child process. - */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf, - "master_main: Child processed exited (due to MaxRequestsPerChild?). Restarting the child process."); - ap_assert(cld < current_live_processes); - cleanup_process(process_handles, process_kill_events, cld, ¤t_live_processes); - APD2("main_process: child in slot %d died", rv); - processes_to_create = 1; - continue; - } - - } while (1); - - /* If we dropped out of the loop we definitly want to die completely. We need to - * make sure we wait for all the child process to exit first. - */ - - APD2("*** main process shutdown, processes=%d ***", current_live_processes); - -die_now: - - tmstart = time(NULL); - while (current_live_processes && ((tmstart+60) > time(NULL))) { - service_set_status(SERVICE_STOP_PENDING); - rv = WaitForMultipleObjects(current_live_processes, (HANDLE *)process_handles, FALSE, 2000); - if (rv == WAIT_TIMEOUT) - continue; - ap_assert(rv != WAIT_FAILED); - cld = rv - WAIT_OBJECT_0; - ap_assert(rv < current_live_processes); - APD4("main_process: child in #%d handle %d died, left=%d", - rv, process_handles[rv], current_live_processes); - cleanup_process(process_handles, process_kill_events, cld, ¤t_live_processes); - } - for (i = 0; i < current_live_processes; i++) { - ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO, server_conf, - "forcing termination of child #%d (handle %d)", i, process_handles[i]); - TerminateProcess((HANDLE) process_handles[i], 1); - } - - CloseHandle(signal_restart_event); - CloseHandle(signal_shutdown_event); - - /* cleanup pid file on normal shutdown */ - { - const char *pidfile = NULL; - pidfile = ap_server_root_relative (pparent, ap_pid_fname); - if ( pidfile != NULL && unlink(pidfile) == 0) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, - server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - if (pparent) { - ap_destroy_pool(pparent); - } - - ap_destroy_mutex(start_mutex); - service_set_status(SERVICE_STOPPED); - return (0); +/* This list displays the compiled-in default paths: */ +#ifdef HTTPD_ROOT + printf(" -D HTTPD_ROOT=\"" HTTPD_ROOT "\"\n"); +#endif +#ifdef SUEXEC_BIN + printf(" -D SUEXEC_BIN=\"" SUEXEC_BIN "\"\n"); +#endif +#if defined(SHARED_CORE) && defined(SHARED_CORE_DIR) + printf(" -D SHARED_CORE_DIR=\"" SHARED_CORE_DIR "\"\n"); +#endif +#ifdef DEFAULT_PIDLOG + printf(" -D DEFAULT_PIDLOG=\"" DEFAULT_PIDLOG "\"\n"); +#endif +#ifdef DEFAULT_SCOREBOARD + printf(" -D DEFAULT_SCOREBOARD=\"" DEFAULT_SCOREBOARD "\"\n"); +#endif +#ifdef DEFAULT_LOCKFILE + printf(" -D DEFAULT_LOCKFILE=\"" DEFAULT_LOCKFILE "\"\n"); +#endif +#ifdef DEFAULT_XFERLOG + printf(" -D DEFAULT_XFERLOG=\"" DEFAULT_XFERLOG "\"\n"); +#endif +#ifdef DEFAULT_ERRORLOG + printf(" -D DEFAULT_ERRORLOG=\"" DEFAULT_ERRORLOG "\"\n"); +#endif +#ifdef TYPES_CONFIG_FILE + printf(" -D TYPES_CONFIG_FILE=\"" TYPES_CONFIG_FILE "\"\n"); +#endif +#ifdef SERVER_CONFIG_FILE + printf(" -D SERVER_CONFIG_FILE=\"" SERVER_CONFIG_FILE "\"\n"); +#endif +#ifdef ACCESS_CONFIG_FILE + printf(" -D ACCESS_CONFIG_FILE=\"" ACCESS_CONFIG_FILE "\"\n"); +#endif +#ifdef RESOURCE_CONFIG_FILE + printf(" -D RESOURCE_CONFIG_FILE=\"" RESOURCE_CONFIG_FILE "\"\n"); +#endif } -/* - * Send signal to a running Apache. On entry signal should contain - * either "shutdown" or "restart" - */ - -int send_signal(pool *p, char *signal) +static void usage(char *bin) { - char prefix[20]; - FILE *fp; - int nread; - char *fname; - int end; - - fname = ap_server_root_relative (p, ap_pid_fname); - - fp = fopen(fname, "r"); - if (!fp) { - printf("Cannot read apache PID file %s\n", fname); - return FALSE; - } - prefix[0] = 'a'; - prefix[1] = 'p'; - - nread = fread(prefix+2, 1, sizeof(prefix)-3, fp); - if (nread == 0) { - fclose(fp); - printf("PID file %s was empty\n", fname); - return FALSE; - } - fclose(fp); - - /* Terminate the prefix string */ - end = 2 + nread - 1; - while (end > 0 && (prefix[end] == '\r' || prefix[end] == '\n')) - end--; - prefix[end + 1] = '\0'; - - setup_signal_names(prefix); - - if (!strcasecmp(signal, "shutdown")) - ap_start_shutdown(); - else if (!strcasecmp(signal, "restart")) - ap_start_restart(1); - else { - printf("Unknown signal name \"%s\". Use either shutdown or restart.\n", - signal); - return FALSE; - } - return TRUE; -} + char pad[MAX_STRING_LEN]; + unsigned i; -void post_parse_init() -{ - ap_set_version(); - ap_init_modules(pconf, server_conf); - ap_suexec_enabled = init_suexec(); - version_locked++; - ap_open_logs(server_conf, plog); - set_group_privs(); + for (i = 0; i < strlen(bin); i++) + pad[i] = ' '; + pad[i] = '\0'; +#ifdef SHARED_CORE + fprintf(stderr, "Usage: %s [-R directory] [-D name] [-d directory] [-f file]\n", bin); +#else + fprintf(stderr, "Usage: %s [-D name] [-d directory] [-f file]\n", bin); +#endif + fprintf(stderr, " %s [-C \"directive\"] [-c \"directive\"]\n", pad); + fprintf(stderr, " %s [-v] [-V] [-h] [-l] [-L] [-S] [-t] [-T]\n", pad); + fprintf(stderr, "Options:\n"); +#ifdef SHARED_CORE + fprintf(stderr, " -R directory : specify an alternate location for shared object files\n"); +#endif + fprintf(stderr, " -D name : define a name for use in directives\n"); + fprintf(stderr, " -d directory : specify an alternate initial ServerRoot\n"); + fprintf(stderr, " -f file : specify an alternate ServerConfigFile\n"); + fprintf(stderr, " -C \"directive\" : process directive before reading config files\n"); + fprintf(stderr, " -c \"directive\" : process directive after reading config files\n"); + fprintf(stderr, " -v : show version number\n"); + fprintf(stderr, " -V : show compile settings\n"); + fprintf(stderr, " -h : list available command line options (this page)\n"); + fprintf(stderr, " -l : list compiled-in modules\n"); + fprintf(stderr, " -L : list available configuration directives\n"); + /* TODOC: -S has been replaced by '-t -D DUMP_VHOSTS' */ + /* fprintf(stderr, " -S : show parsed settings (currently only vhost settings)\n"); */ + fprintf(stderr, " -t : run syntax check for config files (with docroot check)\n"); + fprintf(stderr, " -T : run syntax check for config files (without docroot check)\n"); + /* TODOC: -X goes away, expect MPMs to use -D options */ + exit(1); } -int service_init() -{ - common_init(); - - ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root)); - if (ap_registry_get_service_conf(pconf, ap_server_confname, sizeof(ap_server_confname), - ap_server_argv0)) - return FALSE; - - ap_setup_prelinked_modules(); - server_conf = ap_read_config(pconf, ptrans, ap_server_confname); - ap_log_pid(pconf, ap_pid_fname); - post_parse_init(); - return TRUE; -} +pool *g_pHookPool; -#ifdef WIN32 -__declspec(dllexport) - int apache_main(int argc, char *argv[]) -#else -int REALMAIN(int argc, char *argv[]) -#endif +int main(int argc, char **argv) { int c; - int child = 0; - char *cp; + int configtestonly = 0; char *s; - char *service_name = NULL; - int install = 0; - int conf_specified = 0; - char *signal_to_send = NULL; - char cwd[MAX_STRING_LEN]; - - /* Service application - * Configuration file in registry at: - * HKLM\System\CurrentControlSet\Services\[Svc name]\Parameters\ConfPath - */ - if (isProcessService()) { - service_main(master_main, argc, argv); - clean_parent_exit(0); - } - - /* Console application or a child process. */ - + const char *confname = SERVER_CONFIG_FILE; + const char *def_server_root = HTTPD_ROOT; + server_rec *server_conf; + pool *pglobal; /* Global pool */ + pool *pconf; /* Pool for config stuff */ + pool *plog; /* Pool for error-logging files */ + pool *ptemp; /* Pool for temporart config stuff */ + pool *pcommands; /* Pool for -C and -c switches */ + extern char *optarg; + + /* TODO: PATHSEPARATOR should be one of the os defines */ +#define PATHSEPARATOR '/' if ((s = strrchr(argv[0], PATHSEPARATOR)) != NULL) { - ap_server_argv0 = ++s; + ap_server_argv0 = ++s; } else { - ap_server_argv0 = argv[0]; + ap_server_argv0 = argv[0]; } - common_init(); - ap_setup_prelinked_modules(); + ap_util_init(); + ap_util_uri_init(); - if(!GetCurrentDirectory(sizeof(cwd),cwd)) { - ap_log_error(APLOG_MARK,APLOG_WIN32ERROR, NULL, - "GetCurrentDirectory() failure"); - return -1; - } + pglobal = ap_init_alloc(); + g_pHookPool=pglobal; + + pcommands = ap_make_sub_pool(pglobal); + ap_server_pre_read_config = ap_make_array(pcommands, 1, sizeof(char *)); + ap_server_post_read_config = ap_make_array(pcommands, 1, sizeof(char *)); + ap_server_config_defines = ap_make_array(pcommands, 1, sizeof(char *)); - ap_cpystrn(cwd, ap_os_canonical_filename(pcommands, cwd), sizeof(cwd)); - ap_cpystrn(ap_server_root, cwd, sizeof(ap_server_root)); + ap_setup_prelinked_modules(); - while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLZ:iusStThk:n:")) != -1) { + while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLR:th")) != -1) { char **new; - switch (c) { - case 'c': + switch (c) { + case 'c': new = (char **)ap_push_array(ap_server_post_read_config); *new = ap_pstrdup(pcommands, optarg); break; @@ -6293,68 +282,17 @@ int REALMAIN(int argc, char *argv[]) new = (char **)ap_push_array(ap_server_pre_read_config); *new = ap_pstrdup(pcommands, optarg); break; - case 'D': - new = (char **)ap_push_array(ap_server_config_defines); - *new = ap_pstrdup(pcommands, optarg); - break; -#ifdef WIN32 - case 'Z': - exit_event = open_event(optarg); - APD2("child: opened process event %s", optarg); - cp = strchr(optarg, '_'); - ap_assert(cp); - *cp = 0; - setup_signal_names(optarg); - start_mutex = ap_open_mutex(signal_name_prefix); - ap_assert(start_mutex); - child = 1; - break; - case 'n': - service_name = ap_pstrdup(pcommands, optarg); - if (isValidService(optarg)) { - ap_registry_get_service_conf(pconf, ap_server_confname, sizeof(ap_server_confname), - optarg); - conf_specified = 1; - } - break; - case 'i': - install = 1; - break; - case 'u': - install = -1; - break; - case 'S': - ap_dump_settings = 1; - break; - case 'k': - signal_to_send = optarg; - break; -#endif /* WIN32 */ case 'd': - optarg = ap_os_canonical_filename(pcommands, optarg); - if (!ap_os_is_path_absolute(optarg)) { - optarg = ap_pstrcat(pcommands, cwd, optarg, NULL); - ap_getparents(optarg); - } - if (optarg[strlen(optarg)-1] != '/') - optarg = ap_pstrcat(pcommands, optarg, "/", NULL); - ap_cpystrn(ap_server_root, - optarg, - sizeof(ap_server_root)); + def_server_root = optarg; break; case 'f': - ap_cpystrn(ap_server_confname, - ap_os_canonical_filename(pcommands, optarg), - sizeof(ap_server_confname)); - conf_specified = 1; + confname = optarg; break; case 'v': - ap_set_version(); printf("Server version: %s\n", ap_get_server_version()); printf("Server built: %s\n", ap_get_server_built()); exit(0); case 'V': - ap_set_version(); show_compile_settings(); exit(0); case 'l': @@ -6363,287 +301,66 @@ int REALMAIN(int argc, char *argv[]) case 'L': ap_show_directives(); exit(0); - case 'X': - ++one_process; /* Weird debugging mode. */ - break; case 't': - ap_configtestonly = 1; - ap_docrootcheck = 1; - break; - case 'T': - ap_configtestonly = 1; - ap_docrootcheck = 0; + configtestonly = 1; break; case 'h': - usage(ap_server_argv0); + usage(argv[0]); case '?': - usage(ap_server_argv0); - } /* switch */ - } /* while */ - - /* ServerConfFile is found in this order: - * (1) -f or -n - * (2) [-d]/SERVER_CONFIG_FILE - * (3) ./SERVER_CONFIG_FILE - * (4) [Registry: HKLM\Software\[product]\ServerRoot]/SERVER_CONFIG_FILE - * (5) /HTTPD_ROOT/SERVER_CONFIG_FILE - */ - - if (!conf_specified) { - ap_cpystrn(ap_server_confname, SERVER_CONFIG_FILE, sizeof(ap_server_confname)); - if (access(ap_server_root_relative(pcommands, ap_server_confname), 0)) { - ap_registry_get_server_root(pconf, ap_server_root, sizeof(ap_server_root)); - if (!*ap_server_root) - ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root)); - ap_cpystrn(ap_server_root, ap_os_canonical_filename(pcommands, ap_server_root), - sizeof(ap_server_root)); - } - } - - if (!ap_os_is_path_absolute(ap_server_confname)) { - char *full_conf_path; - - full_conf_path = ap_pstrcat(pcommands, ap_server_root, "/", ap_server_confname, NULL); - full_conf_path = ap_os_canonical_filename(pcommands, full_conf_path); - ap_cpystrn(ap_server_confname, full_conf_path, sizeof(ap_server_confname)); - } - ap_getparents(ap_server_confname); - ap_no2slash(ap_server_confname); - -#ifdef WIN32 - if (install) { - if (!service_name) - service_name = ap_pstrdup(pconf, DEFAULTSERVICENAME); - if (install > 0) - InstallService(service_name, ap_server_root_relative(pcommands, ap_server_confname)); - else - RemoveService(service_name); - clean_parent_exit(0); - } - - if (service_name && signal_to_send) { - send_signal_to_service(service_name, signal_to_send); - clean_parent_exit(0); + usage(argv[0]); + } } - if (service_name && !conf_specified) { - printf("Unknown service: %s\n", service_name); - clean_parent_exit(0); - } -#endif - server_conf = ap_read_config(pconf, ptrans, ap_server_confname); + pconf = ap_make_sub_pool(pglobal); + plog = ap_make_sub_pool(pglobal); + ptemp = ap_make_sub_pool(pconf); - if (ap_configtestonly) { - fprintf(stderr, "%s: Syntax OK\n", ap_server_root_relative(pcommands, ap_server_confname)); - clean_parent_exit(0); - } + /* for legacy reasons, we read the configuration twice before + we actually serve any requests */ - if (ap_dump_settings) { - clean_parent_exit(0); - } + ap_server_root = def_server_root; + ap_run_pre_config(pconf, plog, ptemp); + server_conf = ap_read_config(pconf, ptemp, confname); - /* Treat -k start confpath as just -f confpath */ - if (signal_to_send && strcasecmp(signal_to_send, "start")) { - send_signal(pconf, signal_to_send); - clean_parent_exit(0); + if (configtestonly) { + fprintf(stderr, "Syntax OK\n"); + exit(0); } - if (!child && !ap_dump_settings) { - ap_log_pid(pconf, ap_pid_fname); - } + ap_clear_pool(plog); + ap_run_open_logs(pconf, plog, ptemp, server_conf); + ap_post_config_hook(pconf, plog, ptemp, server_conf); + ap_clear_pool(ptemp); - post_parse_init(); + for (;;) { + ap_clear_pool(pconf); + ptemp = ap_make_sub_pool(pconf); + ap_server_root = def_server_root; + ap_run_pre_config(pconf, plog, ptemp); + server_conf = ap_read_config(pconf, ptemp, confname); + ap_clear_pool(plog); + ap_run_open_logs(pconf, plog, ptemp, server_conf); + ap_post_config_hook(pconf, plog, ptemp, server_conf); + ap_destroy_pool(ptemp); -#ifdef OS2 - printf("%s running...\n", ap_get_server_version()); -#endif -#ifdef WIN32 - if (!child) { - printf("%s running...\n", ap_get_server_version()); - } -#endif - if (one_process && !exit_event) - exit_event = create_event(0, 0, NULL); - if (one_process && !start_mutex) - start_mutex = ap_create_mutex(NULL); - /* - * In the future, the main will spawn off a couple - * of children and monitor them. As soon as a child - * exits, it spawns off a new one - */ - if (child || one_process) { - if (!exit_event || !start_mutex) - exit(-1); - worker_main(); - ap_destroy_mutex(start_mutex); - destroy_event(exit_event); + if (ap_mpm_run(pconf, plog, server_conf)) break; } - else - master_main(argc, argv); - - clean_parent_exit(0); - return 0; /* purely to avoid a warning */ -} - -#endif /* ndef MULTITHREAD */ - -#else /* ndef SHARED_CORE_TIESTATIC */ - -/* -** Standalone Tie Program for Shared Core support -** -** It's purpose is to tie the static libraries and -** the shared core library under link-time and -** passing execution control to the real main function -** in the shared core library under run-time. -*/ - -extern int ap_main(int argc, char *argv[]); -int main(int argc, char *argv[]) -{ - return ap_main(argc, argv); -} - -#endif /* ndef SHARED_CORE_TIESTATIC */ -#else /* ndef SHARED_CORE_BOOTSTRAP */ - -#ifdef OS2 -/* Shared core loader for OS/2 */ - -int ap_main(int argc, char *argv[]); /* Load time linked from libhttpd.dll */ - -int main(int argc, char *argv[]) -{ - return ap_main(argc, argv); + ap_clear_pool(pconf); + ap_clear_pool(plog); + ap_destroy_pool(pglobal); + exit(0); } -#else - -/* -** Standalone Bootstrap Program for Shared Core support -** -** It's purpose is to initialise the LD_LIBRARY_PATH -** environment variable therewith the Unix loader is able -** to start the Standalone Tie Program (see above) -** and then replacing itself with this program by -** immediately passing execution to it. -*/ - -#include -#include -#include - -#include "ap_config.h" -#include "httpd.h" - -#if defined(HPUX) || defined(HPUX10) || defined(HPUX11) -#define VARNAME "SHLIB_PATH" -#else -#define VARNAME "LD_LIBRARY_PATH" -#endif - -#ifndef SHARED_CORE_DIR -#define SHARED_CORE_DIR HTTPD_ROOT "/libexec" -#endif - -#ifndef SHARED_CORE_EXECUTABLE_PROGRAM -#define SHARED_CORE_EXECUTABLE_PROGRAM "lib" TARGET ".ep" -#endif - -extern char *optarg; -extern int optind; - -int main(int argc, char *argv[], char *envp[]) +/* force Expat to be linked into the server executable */ +#if defined(USE_EXPAT) && !defined(SHARED_CORE_BOOTSTRAP) +#include "xmlparse.h" +const XML_LChar *suck_in_expat(void); +const XML_LChar *suck_in_expat(void) { - char prog[MAX_STRING_LEN]; - char llp_buf[MAX_STRING_LEN]; - char **llp_slot; - char *llp_existing; - char *llp_dir; - char **envpnew; - int c, i, l; - - /* - * parse argument line, - * but only handle the -L option - */ - llp_dir = SHARED_CORE_DIR; - while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLR:SZ:tTh")) != -1) { - switch (c) { - case 'D': - case 'C': - case 'c': - case 'X': - case 'd': - case 'f': - case 'v': - case 'V': - case 'l': - case 'L': - case 'S': - case 'Z': - case 't': - case 'T': - case 'h': - case '?': - break; - case 'R': - llp_dir = strdup(optarg); - break; - } - } - - /* - * create path to SHARED_CORE_EXECUTABLE_PROGRAM - */ - ap_snprintf(prog, sizeof(prog), "%s/%s", llp_dir, SHARED_CORE_EXECUTABLE_PROGRAM); - - /* - * adjust process environment therewith the Unix loader - * is able to start the SHARED_CORE_EXECUTABLE_PROGRAM. - */ - llp_slot = NULL; - llp_existing = NULL; - l = strlen(VARNAME); - for (i = 0; envp[i] != NULL; i++) { - if (strncmp(envp[i], VARNAME "=", l+1) == 0) { - llp_slot = &envp[i]; - llp_existing = strchr(envp[i], '=') + 1; - } - } - if (llp_slot == NULL) { - envpnew = (char **)malloc(sizeof(char *)*(i + 2)); - if (envpnew == NULL) { - fprintf(stderr, "Ouch! Out of memory generating envpnew!\n"); - } - memcpy(envpnew, envp, sizeof(char *)*i); - envp = envpnew; - llp_slot = &envp[i++]; - envp[i] = NULL; - } - if (llp_existing != NULL) - ap_snprintf(llp_buf, sizeof(llp_buf), "%s=%s:%s", VARNAME, llp_dir, llp_existing); - else - ap_snprintf(llp_buf, sizeof(llp_buf), "%s=%s", VARNAME, llp_dir); - *llp_slot = strdup(llp_buf); - - /* - * finally replace our process with - * the SHARED_CORE_EXECUTABLE_PROGRAM - */ - if (execve(prog, argv, envp) == -1) { - fprintf(stderr, - "%s: Unable to exec Shared Core Executable Program `%s'\n", - argv[0], prog); - return 1; - } - else - return 0; + return XML_ErrorString(XML_ERROR_NONE); } - -#endif /* def OS2 */ -#endif /* ndef SHARED_CORE_BOOTSTRAP */ +#endif /* USE_EXPAT */ #ifndef SHARED_CORE_BOOTSTRAP /* @@ -6657,13 +374,3 @@ void suck_in_ap_validate_password(void) } #endif -/* force Expat to be linked into the server executable */ -#if defined(USE_EXPAT) && !defined(SHARED_CORE_BOOTSTRAP) -#include "xmlparse.h" -const XML_LChar *suck_in_expat(void); -const XML_LChar *suck_in_expat(void) -{ - return XML_ErrorString(XML_ERROR_NONE); -} -#endif /* USE_EXPAT */ - diff --git a/server/util_script.c b/server/util_script.c index 467dd2964c..b8d6695b52 100644 --- a/server/util_script.c +++ b/server/util_script.c @@ -58,11 +58,10 @@ #define CORE_PRIVATE #include "httpd.h" #include "http_config.h" -#include "http_conf_globals.h" #include "http_main.h" #include "http_log.h" +#include "http_core.h" #include "http_protocol.h" -#include "http_core.h" /* For document_root. Sigh... */ #include "http_request.h" /* for sub_req_lookup_uri() */ #include "util_script.h" #include "util_date.h" /* For parseHTTPdate() */ @@ -285,11 +284,11 @@ API_EXPORT(void) ap_add_common_vars(request_rec *r) ap_table_addn(e, "REMOTE_PORT", ap_psprintf(r->pool, "%d", ntohs(c->remote_addr.sin_port))); - if (c->user) { - ap_table_addn(e, "REMOTE_USER", c->user); + if (r->user) { + ap_table_addn(e, "REMOTE_USER", r->user); } - if (c->ap_auth_type) { - ap_table_addn(e, "AUTH_TYPE", c->ap_auth_type); + if (r->ap_auth_type) { + ap_table_addn(e, "AUTH_TYPE", r->ap_auth_type); } rem_logname = ap_get_remote_logname(r); if (rem_logname) { diff --git a/server/util_uri.c b/server/util_uri.c index 10eb5dc0d0..5d9a1e6f86 100644 --- a/server/util_uri.c +++ b/server/util_uri.c @@ -61,7 +61,6 @@ #include "httpd.h" #include "http_log.h" -#include "http_conf_globals.h" /* for user_id & group_id */ #include "util_uri.h" /* Some WWW schemes and their default ports; this is basically /etc/services */